@lukoweb/apitogo 0.2.16 → 0.2.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/cli.js +110 -40
- package/package.json +1 -1
- package/src/config/v2/docs-navigation.ts +72 -0
- package/src/config/v2/home-redirect.ts +19 -2
- package/src/config/v2/wrapper.ts +27 -10
package/dist/cli/cli.js
CHANGED
|
@@ -7699,15 +7699,84 @@ function stableJson(value) {
|
|
|
7699
7699
|
}
|
|
7700
7700
|
|
|
7701
7701
|
// src/config/v2/wrapper.ts
|
|
7702
|
-
import { mkdir as mkdir4, readFile as
|
|
7702
|
+
import { mkdir as mkdir4, readFile as readFile6, rename as rename2, rm as rm2, writeFile as writeFile5 } from "node:fs/promises";
|
|
7703
7703
|
import path12 from "node:path";
|
|
7704
7704
|
|
|
7705
|
+
// src/config/v2/docs-navigation.ts
|
|
7706
|
+
var DOCS_NAVIGATION_LABEL = "Documentation";
|
|
7707
|
+
var emptyBranch = () => ({ pages: /* @__PURE__ */ new Set(), folders: /* @__PURE__ */ new Map() });
|
|
7708
|
+
function folderLabel(name) {
|
|
7709
|
+
const words = name.replace(/[-_]+/g, " ").trim();
|
|
7710
|
+
return words.charAt(0).toUpperCase() + words.slice(1);
|
|
7711
|
+
}
|
|
7712
|
+
var byName = (a, b) => a.localeCompare(b);
|
|
7713
|
+
var toItems = (branch, prefix) => {
|
|
7714
|
+
const pages = [...branch.pages].sort(
|
|
7715
|
+
(a, b) => a === "index" ? -1 : b === "index" ? 1 : byName(a, b)
|
|
7716
|
+
);
|
|
7717
|
+
const folders = [...branch.folders.keys()].sort(byName);
|
|
7718
|
+
return [
|
|
7719
|
+
// The index page of a folder is the folder's own address, so the sidebar also shows on `/`.
|
|
7720
|
+
...pages.map(
|
|
7721
|
+
(page) => page === "index" ? {
|
|
7722
|
+
type: "doc",
|
|
7723
|
+
file: `${prefix}${page}`,
|
|
7724
|
+
path: prefix === "" ? "/" : `/${prefix.slice(0, -1)}`
|
|
7725
|
+
} : `${prefix}${page}`
|
|
7726
|
+
),
|
|
7727
|
+
...folders.map(
|
|
7728
|
+
(folder) => ({
|
|
7729
|
+
type: "category",
|
|
7730
|
+
label: folderLabel(folder),
|
|
7731
|
+
collapsible: true,
|
|
7732
|
+
collapsed: false,
|
|
7733
|
+
items: toItems(
|
|
7734
|
+
branch.folders.get(folder) ?? emptyBranch(),
|
|
7735
|
+
`${prefix}${folder}/`
|
|
7736
|
+
)
|
|
7737
|
+
})
|
|
7738
|
+
)
|
|
7739
|
+
];
|
|
7740
|
+
};
|
|
7741
|
+
function docsNavigation(routes) {
|
|
7742
|
+
const root = emptyBranch();
|
|
7743
|
+
for (const route of routes) {
|
|
7744
|
+
const parts = route.split("/").filter(Boolean);
|
|
7745
|
+
const page = parts.pop();
|
|
7746
|
+
if (!page) continue;
|
|
7747
|
+
const branch = parts.reduce((current, folder) => {
|
|
7748
|
+
const next = current.folders.get(folder) ?? emptyBranch();
|
|
7749
|
+
current.folders.set(folder, next);
|
|
7750
|
+
return next;
|
|
7751
|
+
}, root);
|
|
7752
|
+
branch.pages.add(page);
|
|
7753
|
+
}
|
|
7754
|
+
const items = toItems(root, "");
|
|
7755
|
+
return items.length === 0 ? [] : [{ type: "category", label: DOCS_NAVIGATION_LABEL, items }];
|
|
7756
|
+
}
|
|
7757
|
+
|
|
7705
7758
|
// src/config/v2/home-redirect.ts
|
|
7706
7759
|
import path11 from "node:path";
|
|
7707
7760
|
import { glob as glob2 } from "glob";
|
|
7708
7761
|
import globParent from "glob-parent";
|
|
7762
|
+
|
|
7763
|
+
// src/lib/util/readFrontmatter.ts
|
|
7764
|
+
import { readFile as readFile5 } from "node:fs/promises";
|
|
7765
|
+
import matter from "gray-matter";
|
|
7766
|
+
import { parse as parse2, stringify } from "yaml";
|
|
7767
|
+
var yaml = {
|
|
7768
|
+
parse: (input5) => parse2(input5) ?? {},
|
|
7769
|
+
stringify: (obj) => stringify(obj)
|
|
7770
|
+
};
|
|
7771
|
+
var readFrontmatter = async (filePath) => {
|
|
7772
|
+
const content = await readFile5(filePath, "utf-8");
|
|
7773
|
+
const normalizedContent = content.replace(/\r\n/g, "\n");
|
|
7774
|
+
return matter(normalizedContent, { engines: { yaml } });
|
|
7775
|
+
};
|
|
7776
|
+
|
|
7777
|
+
// src/config/v2/home-redirect.ts
|
|
7709
7778
|
var IGNORED = ["**/node_modules/**", "**/dist/**", "**/.git/**"];
|
|
7710
|
-
async function docRoutes(patterns) {
|
|
7779
|
+
async function docRoutes(patterns, options = {}) {
|
|
7711
7780
|
const excluded = patterns.filter((pattern) => pattern.startsWith("!")).map((pattern) => pattern.slice(1));
|
|
7712
7781
|
const included = patterns.filter((pattern) => !pattern.startsWith("!"));
|
|
7713
7782
|
const routes = await Promise.all(
|
|
@@ -7718,7 +7787,13 @@ async function docRoutes(patterns) {
|
|
|
7718
7787
|
ignore: [...IGNORED, ...excluded]
|
|
7719
7788
|
});
|
|
7720
7789
|
const parent = globParent(pattern);
|
|
7721
|
-
|
|
7790
|
+
const published = options.includeDrafts ? files : (await Promise.all(
|
|
7791
|
+
files.map(async (file) => ({
|
|
7792
|
+
file,
|
|
7793
|
+
draft: (await readFrontmatter(file)).data.draft === true
|
|
7794
|
+
}))
|
|
7795
|
+
)).filter(({ draft }) => !draft).map(({ file }) => file);
|
|
7796
|
+
return published.map(
|
|
7722
7797
|
(file) => `/${path11.posix.relative(parent, file).replace(/\.mdx?$/, "")}`
|
|
7723
7798
|
);
|
|
7724
7799
|
})
|
|
@@ -7875,8 +7950,19 @@ function planPortal(profile, manifest) {
|
|
|
7875
7950
|
var SITE_CONFIG_FILE = "apitogo.config.json";
|
|
7876
7951
|
var REFERENCE_SPEC_FILE = "openapi/gateway.json";
|
|
7877
7952
|
var API_REFERENCE_PATH = "api";
|
|
7878
|
-
function buildSiteConfig(resolved, plan2, theme,
|
|
7953
|
+
function buildSiteConfig(resolved, plan2, theme, extras = {}) {
|
|
7879
7954
|
const portal = resolved.portal;
|
|
7955
|
+
const redirects = extras.redirects ?? [];
|
|
7956
|
+
const navigation = [
|
|
7957
|
+
...extras.docsNavigation ?? [],
|
|
7958
|
+
...plan2.apiReference ? [
|
|
7959
|
+
{
|
|
7960
|
+
type: "link",
|
|
7961
|
+
to: `/${API_REFERENCE_PATH}`,
|
|
7962
|
+
label: "API Reference"
|
|
7963
|
+
}
|
|
7964
|
+
] : []
|
|
7965
|
+
];
|
|
7880
7966
|
return {
|
|
7881
7967
|
site: {
|
|
7882
7968
|
title: portal?.name ?? resolved.project.name,
|
|
@@ -7900,15 +7986,9 @@ function buildSiteConfig(resolved, plan2, theme, redirects = []) {
|
|
|
7900
7986
|
input: `./${REFERENCE_SPEC_FILE}`,
|
|
7901
7987
|
path: API_REFERENCE_PATH
|
|
7902
7988
|
}
|
|
7903
|
-
],
|
|
7904
|
-
navigation: [
|
|
7905
|
-
{
|
|
7906
|
-
type: "link",
|
|
7907
|
-
to: `/${API_REFERENCE_PATH}`,
|
|
7908
|
-
label: "API Reference"
|
|
7909
|
-
}
|
|
7910
7989
|
]
|
|
7911
7990
|
} : {},
|
|
7991
|
+
...navigation.length > 0 ? { navigation } : {},
|
|
7912
7992
|
...redirects.length > 0 ? { redirects } : {},
|
|
7913
7993
|
...theme !== void 0 ? { theme } : {},
|
|
7914
7994
|
...plan2.auth ? { authentication: { type: "openid", ...plan2.auth } } : {},
|
|
@@ -7943,7 +8023,7 @@ async function readTheme(resolved) {
|
|
|
7943
8023
|
const file = resolved.portal?.theme;
|
|
7944
8024
|
if (!file) return void 0;
|
|
7945
8025
|
try {
|
|
7946
|
-
return JSON.parse(await
|
|
8026
|
+
return JSON.parse(await readFile6(file, "utf8"));
|
|
7947
8027
|
} catch {
|
|
7948
8028
|
return void 0;
|
|
7949
8029
|
}
|
|
@@ -8001,9 +8081,12 @@ async function preparePortal(resolved, manifest, mode, options = {}) {
|
|
|
8001
8081
|
});
|
|
8002
8082
|
}
|
|
8003
8083
|
}
|
|
8084
|
+
const hostedDocRoutes = plan2.docs ? await docRoutes(profile.docs.content, {
|
|
8085
|
+
includeDrafts: mode === "development"
|
|
8086
|
+
}) : [];
|
|
8004
8087
|
const home = homeRedirect({
|
|
8005
8088
|
hostsDocs: plan2.docs,
|
|
8006
|
-
docRoutes:
|
|
8089
|
+
docRoutes: hostedDocRoutes,
|
|
8007
8090
|
externalDocsUrl: profile.docs.url,
|
|
8008
8091
|
apiReferencePath: plan2.apiReference ? `/${API_REFERENCE_PATH}` : void 0,
|
|
8009
8092
|
userPanel: plan2.userPanel
|
|
@@ -8012,7 +8095,10 @@ async function preparePortal(resolved, manifest, mode, options = {}) {
|
|
|
8012
8095
|
resolved,
|
|
8013
8096
|
plan2,
|
|
8014
8097
|
await readTheme(resolved),
|
|
8015
|
-
|
|
8098
|
+
{
|
|
8099
|
+
redirects: home ? [home] : [],
|
|
8100
|
+
docsNavigation: docsNavigation(hostedDocRoutes)
|
|
8101
|
+
}
|
|
8016
8102
|
);
|
|
8017
8103
|
const wrapper = renderWrapper(plan2);
|
|
8018
8104
|
const wrapperPath = path12.join(resolved.state.generatedDir, WRAPPER_FILE);
|
|
@@ -8057,7 +8143,7 @@ async function preparePortal(resolved, manifest, mode, options = {}) {
|
|
|
8057
8143
|
|
|
8058
8144
|
// src/config/v2/workspace.ts
|
|
8059
8145
|
import { createHash as createHash2 } from "node:crypto";
|
|
8060
|
-
import { access as access2, lstat, readFile as
|
|
8146
|
+
import { access as access2, lstat, readFile as readFile7, rm as rm3, symlink } from "node:fs/promises";
|
|
8061
8147
|
import path13 from "node:path";
|
|
8062
8148
|
import { glob as glob3 } from "glob";
|
|
8063
8149
|
var exists2 = (file) => access2(file).then(
|
|
@@ -8086,7 +8172,7 @@ async function materializeWorkspace(resolved, prepared) {
|
|
|
8086
8172
|
return root;
|
|
8087
8173
|
}
|
|
8088
8174
|
async function configFingerprint(configPath) {
|
|
8089
|
-
const text = await
|
|
8175
|
+
const text = await readFile7(configPath, "utf8");
|
|
8090
8176
|
try {
|
|
8091
8177
|
const raw = JSON.parse(text);
|
|
8092
8178
|
if (raw.project) {
|
|
@@ -8135,7 +8221,7 @@ async function portalArtifactHash(resolved, manifestText, cliVersion, wrapper =
|
|
|
8135
8221
|
for (const file of files) {
|
|
8136
8222
|
hash2.update(`file:${path13.relative(resolved.configDir, file)}
|
|
8137
8223
|
`);
|
|
8138
|
-
hash2.update(await
|
|
8224
|
+
hash2.update(await readFile7(file));
|
|
8139
8225
|
}
|
|
8140
8226
|
return hash2.digest("hex");
|
|
8141
8227
|
}
|
|
@@ -8602,7 +8688,7 @@ async function clearProjectId(dir, projectId) {
|
|
|
8602
8688
|
|
|
8603
8689
|
// src/config/v2/ledger.ts
|
|
8604
8690
|
init_invariant();
|
|
8605
|
-
import { mkdir as mkdir6, readFile as
|
|
8691
|
+
import { mkdir as mkdir6, readFile as readFile8, rename as rename4, rm as rm5, writeFile as writeFile7 } from "node:fs/promises";
|
|
8606
8692
|
import path15 from "node:path";
|
|
8607
8693
|
var LEDGER_VERSION = 1;
|
|
8608
8694
|
var LedgerError = class extends ApitogoError {
|
|
@@ -8619,7 +8705,7 @@ var emptyLedger = () => ({
|
|
|
8619
8705
|
async function readLedger(state) {
|
|
8620
8706
|
let text;
|
|
8621
8707
|
try {
|
|
8622
|
-
text = await
|
|
8708
|
+
text = await readFile8(state.file, "utf8");
|
|
8623
8709
|
} catch (error) {
|
|
8624
8710
|
if (error.code === "ENOENT")
|
|
8625
8711
|
return emptyLedger();
|
|
@@ -9721,7 +9807,7 @@ import {
|
|
|
9721
9807
|
// package.json
|
|
9722
9808
|
var package_default = {
|
|
9723
9809
|
name: "@lukoweb/apitogo",
|
|
9724
|
-
version: "0.2.
|
|
9810
|
+
version: "0.2.17",
|
|
9725
9811
|
type: "module",
|
|
9726
9812
|
sideEffects: [
|
|
9727
9813
|
"**/*.css",
|
|
@@ -11507,7 +11593,7 @@ var lookup = (schema2, path101, filePath) => {
|
|
|
11507
11593
|
}
|
|
11508
11594
|
return val;
|
|
11509
11595
|
};
|
|
11510
|
-
var
|
|
11596
|
+
var stringify2 = (obj, indent = 2) => JSON.stringify(obj, null, indent);
|
|
11511
11597
|
var generateCode = (schema2, filePath) => {
|
|
11512
11598
|
const { refMap, siblingsMap } = createLocalRefMap(schema2);
|
|
11513
11599
|
const lines = [];
|
|
@@ -11524,7 +11610,7 @@ var generateCode = (schema2, filePath) => {
|
|
|
11524
11610
|
mergedRefs.set(uniqueKey, varName);
|
|
11525
11611
|
lines.push(`const ${varName} = {};`);
|
|
11526
11612
|
}
|
|
11527
|
-
const toCode = (obj) => replaceMarkers(
|
|
11613
|
+
const toCode = (obj) => replaceMarkers(stringify2(setRefMarkers(obj, refMap)), mergedRefs);
|
|
11528
11614
|
const deferred = [];
|
|
11529
11615
|
for (const [refPath, index] of refMap) {
|
|
11530
11616
|
const value = lookup(schema2, refPath, filePath);
|
|
@@ -11535,7 +11621,7 @@ var generateCode = (schema2, filePath) => {
|
|
|
11535
11621
|
const siblingEntry = value.__uniqueRefKey && siblingsMap.get(value.__uniqueRefKey);
|
|
11536
11622
|
const target = siblingEntry ? deferred : lines;
|
|
11537
11623
|
target.push(
|
|
11538
|
-
siblingEntry ? `Object.assign(__refs[${index}], __refMap["${siblingEntry.refPath}"], ${
|
|
11624
|
+
siblingEntry ? `Object.assign(__refs[${index}], __refMap["${siblingEntry.refPath}"], ${stringify2(siblingEntry.siblings)});` : `Object.assign(__refs[${index}], ${toCode(value)});`,
|
|
11539
11625
|
`Object.defineProperty(__refs[${index}], "__$ref", { value: __refMapPaths[${index}], enumerable: false });`
|
|
11540
11626
|
);
|
|
11541
11627
|
}
|
|
@@ -11544,7 +11630,7 @@ var generateCode = (schema2, filePath) => {
|
|
|
11544
11630
|
const varName = mergedRefs.get(uniqueKey);
|
|
11545
11631
|
const refIndex = refMap.get(refPath);
|
|
11546
11632
|
lines.push(
|
|
11547
|
-
`Object.assign(${varName}, __refMap["${refPath}"], ${
|
|
11633
|
+
`Object.assign(${varName}, __refMap["${refPath}"], ${stringify2(siblings)});`,
|
|
11548
11634
|
`Object.defineProperty(${varName}, "__$ref", { value: __refMapPaths[${refIndex}], enumerable: false });`
|
|
11549
11635
|
);
|
|
11550
11636
|
}
|
|
@@ -11806,22 +11892,6 @@ import { glob as glob4 } from "glob";
|
|
|
11806
11892
|
import { fromMarkdown } from "mdast-util-from-markdown";
|
|
11807
11893
|
import { mdxFromMarkdown } from "mdast-util-mdx";
|
|
11808
11894
|
import { mdxjs } from "micromark-extension-mdxjs";
|
|
11809
|
-
|
|
11810
|
-
// src/lib/util/readFrontmatter.ts
|
|
11811
|
-
import { readFile as readFile8 } from "node:fs/promises";
|
|
11812
|
-
import matter from "gray-matter";
|
|
11813
|
-
import { parse as parse2, stringify as stringify2 } from "yaml";
|
|
11814
|
-
var yaml = {
|
|
11815
|
-
parse: (input5) => parse2(input5) ?? {},
|
|
11816
|
-
stringify: (obj) => stringify2(obj)
|
|
11817
|
-
};
|
|
11818
|
-
var readFrontmatter = async (filePath) => {
|
|
11819
|
-
const content = await readFile8(filePath, "utf-8");
|
|
11820
|
-
const normalizedContent = content.replace(/\r\n/g, "\n");
|
|
11821
|
-
return matter(normalizedContent, { engines: { yaml } });
|
|
11822
|
-
};
|
|
11823
|
-
|
|
11824
|
-
// src/config/validators/NavigationSchema.ts
|
|
11825
11895
|
init_ZudokuConfig();
|
|
11826
11896
|
var extractTitleFromContent = (content) => content.match(/^\s*#\s(.*)$/m)?.at(1);
|
|
11827
11897
|
var isMdxJsxElement = (node) => node.type === "mdxJsxTextElement";
|
package/package.json
CHANGED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { InputNavigationItem } from "../validators/InputNavigationSchema.js";
|
|
2
|
+
|
|
3
|
+
/** Label of the one header tab that holds the sidebar made from the docs pages. */
|
|
4
|
+
export const DOCS_NAVIGATION_LABEL = "Documentation";
|
|
5
|
+
|
|
6
|
+
type Branch = { pages: Set<string>; folders: Map<string, Branch> };
|
|
7
|
+
|
|
8
|
+
const emptyBranch = (): Branch => ({ pages: new Set(), folders: new Map() });
|
|
9
|
+
|
|
10
|
+
/** "getting-started" becomes "Getting started". */
|
|
11
|
+
export function folderLabel(name: string): string {
|
|
12
|
+
const words = name.replace(/[-_]+/g, " ").trim();
|
|
13
|
+
return words.charAt(0).toUpperCase() + words.slice(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const byName = (a: string, b: string) => a.localeCompare(b);
|
|
17
|
+
|
|
18
|
+
const toItems = (branch: Branch, prefix: string): InputNavigationItem[] => {
|
|
19
|
+
const pages = [...branch.pages].sort((a, b) =>
|
|
20
|
+
a === "index" ? -1 : b === "index" ? 1 : byName(a, b),
|
|
21
|
+
);
|
|
22
|
+
const folders = [...branch.folders.keys()].sort(byName);
|
|
23
|
+
return [
|
|
24
|
+
// The index page of a folder is the folder's own address, so the sidebar also shows on `/`.
|
|
25
|
+
...pages.map(
|
|
26
|
+
(page): InputNavigationItem =>
|
|
27
|
+
page === "index"
|
|
28
|
+
? {
|
|
29
|
+
type: "doc",
|
|
30
|
+
file: `${prefix}${page}`,
|
|
31
|
+
path: prefix === "" ? "/" : `/${prefix.slice(0, -1)}`,
|
|
32
|
+
}
|
|
33
|
+
: `${prefix}${page}`,
|
|
34
|
+
),
|
|
35
|
+
...folders.map(
|
|
36
|
+
(folder): InputNavigationItem => ({
|
|
37
|
+
type: "category",
|
|
38
|
+
label: folderLabel(folder),
|
|
39
|
+
collapsible: true,
|
|
40
|
+
collapsed: false,
|
|
41
|
+
items: toItems(
|
|
42
|
+
branch.folders.get(folder) ?? emptyBranch(),
|
|
43
|
+
`${prefix}${folder}/`,
|
|
44
|
+
),
|
|
45
|
+
}),
|
|
46
|
+
),
|
|
47
|
+
];
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The sidebar for hosted docs, made from the pages themselves: the index page first, then the other pages by
|
|
52
|
+
* name, then one section per folder. `routes` are the docs plugin's route paths (`/overview`, `/guides/style`).
|
|
53
|
+
* Without pages there is nothing to navigate, so the result is empty.
|
|
54
|
+
*/
|
|
55
|
+
export function docsNavigation(routes: string[]): InputNavigationItem[] {
|
|
56
|
+
const root = emptyBranch();
|
|
57
|
+
for (const route of routes) {
|
|
58
|
+
const parts = route.split("/").filter(Boolean);
|
|
59
|
+
const page = parts.pop();
|
|
60
|
+
if (!page) continue;
|
|
61
|
+
const branch = parts.reduce((current, folder) => {
|
|
62
|
+
const next = current.folders.get(folder) ?? emptyBranch();
|
|
63
|
+
current.folders.set(folder, next);
|
|
64
|
+
return next;
|
|
65
|
+
}, root);
|
|
66
|
+
branch.pages.add(page);
|
|
67
|
+
}
|
|
68
|
+
const items = toItems(root, "");
|
|
69
|
+
return items.length === 0
|
|
70
|
+
? []
|
|
71
|
+
: [{ type: "category", label: DOCS_NAVIGATION_LABEL, items }];
|
|
72
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { glob } from "glob";
|
|
3
3
|
import globParent from "glob-parent";
|
|
4
|
+
import { readFrontmatter } from "../../lib/util/readFrontmatter.js";
|
|
4
5
|
|
|
5
6
|
export type HomeRedirect = { from: string; to: string };
|
|
6
7
|
|
|
@@ -10,7 +11,10 @@ const IGNORED = ["**/node_modules/**", "**/dist/**", "**/.git/**"];
|
|
|
10
11
|
* The routes the docs plugin gives the pages these globs match: the path inside the glob's folder, without the
|
|
11
12
|
* extension. Missing folders and negated globs are fine, they just match nothing.
|
|
12
13
|
*/
|
|
13
|
-
export async function docRoutes(
|
|
14
|
+
export async function docRoutes(
|
|
15
|
+
patterns: string[],
|
|
16
|
+
options: { includeDrafts?: boolean } = {},
|
|
17
|
+
): Promise<string[]> {
|
|
14
18
|
const excluded = patterns
|
|
15
19
|
.filter((pattern) => pattern.startsWith("!"))
|
|
16
20
|
.map((pattern) => pattern.slice(1));
|
|
@@ -24,7 +28,20 @@ export async function docRoutes(patterns: string[]): Promise<string[]> {
|
|
|
24
28
|
ignore: [...IGNORED, ...excluded],
|
|
25
29
|
});
|
|
26
30
|
const parent = globParent(pattern);
|
|
27
|
-
|
|
31
|
+
// The docs plugin leaves draft pages out of a production build, so the routes must too.
|
|
32
|
+
const published = options.includeDrafts
|
|
33
|
+
? files
|
|
34
|
+
: (
|
|
35
|
+
await Promise.all(
|
|
36
|
+
files.map(async (file) => ({
|
|
37
|
+
file,
|
|
38
|
+
draft: (await readFrontmatter(file)).data.draft === true,
|
|
39
|
+
})),
|
|
40
|
+
)
|
|
41
|
+
)
|
|
42
|
+
.filter(({ draft }) => !draft)
|
|
43
|
+
.map(({ file }) => file);
|
|
44
|
+
return published.map(
|
|
28
45
|
(file) =>
|
|
29
46
|
`/${path.posix.relative(parent, file).replace(/\.mdx?$/, "")}`,
|
|
30
47
|
);
|
package/src/config/v2/wrapper.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { docsNavigation } from "./docs-navigation.js";
|
|
3
4
|
import { ConfigError, type ConfigIssue } from "./errors.js";
|
|
4
5
|
import {
|
|
5
6
|
ReferenceSpecError,
|
|
@@ -244,9 +245,23 @@ export function buildSiteConfig(
|
|
|
244
245
|
resolved: ResolvedConfigV2,
|
|
245
246
|
plan: PortalPlan,
|
|
246
247
|
theme?: unknown,
|
|
247
|
-
|
|
248
|
+
extras: { redirects?: HomeRedirect[]; docsNavigation?: unknown[] } = {},
|
|
248
249
|
): Record<string, unknown> {
|
|
249
250
|
const portal = resolved.portal;
|
|
251
|
+
const redirects = extras.redirects ?? [];
|
|
252
|
+
// One header tab for the docs sidebar, and the API reference as a link next to it.
|
|
253
|
+
const navigation = [
|
|
254
|
+
...(extras.docsNavigation ?? []),
|
|
255
|
+
...(plan.apiReference
|
|
256
|
+
? [
|
|
257
|
+
{
|
|
258
|
+
type: "link",
|
|
259
|
+
to: `/${API_REFERENCE_PATH}`,
|
|
260
|
+
label: "API Reference",
|
|
261
|
+
},
|
|
262
|
+
]
|
|
263
|
+
: []),
|
|
264
|
+
];
|
|
250
265
|
return {
|
|
251
266
|
site: {
|
|
252
267
|
title: portal?.name ?? resolved.project.name,
|
|
@@ -276,15 +291,9 @@ export function buildSiteConfig(
|
|
|
276
291
|
path: API_REFERENCE_PATH,
|
|
277
292
|
},
|
|
278
293
|
],
|
|
279
|
-
navigation: [
|
|
280
|
-
{
|
|
281
|
-
type: "link",
|
|
282
|
-
to: `/${API_REFERENCE_PATH}`,
|
|
283
|
-
label: "API Reference",
|
|
284
|
-
},
|
|
285
|
-
],
|
|
286
294
|
}
|
|
287
295
|
: {}),
|
|
296
|
+
...(navigation.length > 0 ? { navigation } : {}),
|
|
288
297
|
...(redirects.length > 0 ? { redirects } : {}),
|
|
289
298
|
...(theme !== undefined ? { theme } : {}),
|
|
290
299
|
...(plan.auth ? { authentication: { type: "openid", ...plan.auth } } : {}),
|
|
@@ -433,9 +442,14 @@ export async function preparePortal(
|
|
|
433
442
|
});
|
|
434
443
|
}
|
|
435
444
|
}
|
|
445
|
+
const hostedDocRoutes = plan.docs
|
|
446
|
+
? await docRoutes(profile.docs.content, {
|
|
447
|
+
includeDrafts: mode === "development",
|
|
448
|
+
})
|
|
449
|
+
: [];
|
|
436
450
|
const home = homeRedirect({
|
|
437
451
|
hostsDocs: plan.docs,
|
|
438
|
-
docRoutes:
|
|
452
|
+
docRoutes: hostedDocRoutes,
|
|
439
453
|
externalDocsUrl: profile.docs.url,
|
|
440
454
|
apiReferencePath: plan.apiReference ? `/${API_REFERENCE_PATH}` : undefined,
|
|
441
455
|
userPanel: plan.userPanel,
|
|
@@ -444,7 +458,10 @@ export async function preparePortal(
|
|
|
444
458
|
resolved,
|
|
445
459
|
plan,
|
|
446
460
|
await readTheme(resolved),
|
|
447
|
-
|
|
461
|
+
{
|
|
462
|
+
redirects: home ? [home] : [],
|
|
463
|
+
docsNavigation: docsNavigation(hostedDocRoutes),
|
|
464
|
+
},
|
|
448
465
|
);
|
|
449
466
|
const wrapper = renderWrapper(plan);
|
|
450
467
|
const wrapperPath = path.join(resolved.state.generatedDir, WRAPPER_FILE);
|