@takazudo/zudo-doc 1.2.0 → 2.0.0
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/chrome/derive.d.ts +68 -0
- package/dist/chrome/derive.js +231 -0
- package/dist/chrome/index.d.ts +37 -0
- package/dist/chrome/index.js +43 -0
- package/dist/content.css +25 -9
- package/dist/doc-body-end/index.d.ts +9 -11
- package/dist/doc-body-end/index.js +4 -2
- package/dist/doc-content-header/index.d.ts +10 -2
- package/dist/doc-content-header/index.js +8 -8
- package/dist/doc-history-area/index.d.ts +10 -25
- package/dist/doc-history-area/index.js +14 -10
- package/dist/doc-metainfo-area/index.d.ts +9 -15
- package/dist/doc-metainfo-area/index.js +6 -2
- package/dist/doc-page-renderer/index.d.ts +11 -2
- package/dist/doc-page-renderer/index.js +22 -15
- package/dist/doc-page-shell/index.d.ts +11 -3
- package/dist/doc-page-shell/index.js +21 -14
- package/dist/doc-pager/index.d.ts +6 -7
- package/dist/doc-pager/index.js +2 -2
- package/dist/doc-route-entries/index.d.ts +22 -46
- package/dist/doc-route-entries/index.js +15 -10
- package/dist/doc-tags-area/index.d.ts +9 -19
- package/dist/doc-tags-area/index.js +12 -2
- package/dist/factory-context/index.d.ts +163 -1
- package/dist/footer-with-defaults/index.d.ts +12 -13
- package/dist/footer-with-defaults/index.js +8 -10
- package/dist/head-with-defaults/index.d.ts +12 -16
- package/dist/head-with-defaults/index.js +7 -9
- package/dist/header-with-defaults/index.d.ts +10 -31
- package/dist/header-with-defaults/index.js +15 -18
- package/dist/integrations/claude-resources/generate.js +48 -11
- package/dist/nav-source-docs/index.d.ts +20 -54
- package/dist/nav-source-docs/index.js +9 -10
- package/dist/route-context/index.d.ts +24 -0
- package/dist/route-context/index.js +147 -0
- package/dist/route-enumerators/index.d.ts +25 -74
- package/dist/route-enumerators/index.js +17 -18
- package/dist/routes/_chrome.d.ts +6 -25
- package/dist/routes/_chrome.js +14 -387
- package/dist/routes/_context.d.ts +10 -43
- package/dist/routes/_context.js +29 -157
- package/dist/safelist.css +1 -1
- package/dist/sidebar-with-defaults/index.d.ts +8 -15
- package/dist/sidebar-with-defaults/index.js +6 -10
- package/dist/tag-pages/index.d.ts +12 -3
- package/dist/tag-pages/index.js +24 -19
- package/dist/versions-page/index.d.ts +10 -3
- package/dist/versions-page/index.js +18 -14
- package/eject/doc-pager/index.tsx +8 -10
- package/package.json +14 -6
- package/routes-src/_chrome.tsx +31 -552
- package/routes-src/_context.ts +37 -269
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
import type { JSX } from "preact";
|
|
4
4
|
import type { HeadProps } from "../head/types.js";
|
|
5
5
|
import type { ColorSchemeProviderColorMode } from "../theme/color-scheme-provider.js";
|
|
6
|
+
import type { ChromeContext } from "../factory-context/index.js";
|
|
7
|
+
import type { Settings } from "../settings.js";
|
|
6
8
|
export interface HeadWithDefaultsProps {
|
|
7
9
|
/** Page title forwarded to og:title. Required. */
|
|
8
10
|
title: string;
|
|
@@ -14,7 +16,8 @@ export interface HeadWithDefaultsProps {
|
|
|
14
16
|
*/
|
|
15
17
|
canonical?: string;
|
|
16
18
|
}
|
|
17
|
-
/** Settings subset read by {@link createHeadWithDefaults}.
|
|
19
|
+
/** Settings subset read by {@link createHeadWithDefaults}. Retained for the
|
|
20
|
+
* `HeadProps`/`ColorSchemeProviderColorMode` type references it documents. */
|
|
18
21
|
export interface HeadWithDefaultsSettings {
|
|
19
22
|
metaTags: {
|
|
20
23
|
description?: boolean | null;
|
|
@@ -29,21 +32,14 @@ export interface HeadWithDefaultsSettings {
|
|
|
29
32
|
colorMode?: ColorSchemeProviderColorMode | null | false;
|
|
30
33
|
sidebarResizer?: boolean;
|
|
31
34
|
}
|
|
32
|
-
/** Factory dependencies injected by the host stub. */
|
|
33
|
-
export interface HeadWithDefaultsDeps {
|
|
34
|
-
settings: HeadWithDefaultsSettings;
|
|
35
|
-
composeMetaTitle: (title: string) => string;
|
|
36
|
-
withBase: (path: string) => string;
|
|
37
|
-
absoluteUrl: (pageUrl: string) => string | undefined;
|
|
38
|
-
generateCssCustomProperties: () => string;
|
|
39
|
-
generateLightDarkCssProperties: () => string;
|
|
40
|
-
}
|
|
41
35
|
/**
|
|
42
|
-
* Create a `HeadWithDefaults` component
|
|
43
|
-
*
|
|
36
|
+
* Create a `HeadWithDefaults` component from the unified {@link ChromeContext}
|
|
37
|
+
* (epic Collapse Wiring Shells #2420, FACTORIES #2424 — breaking signature).
|
|
44
38
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* `
|
|
39
|
+
* Derives its old `{ settings, composeMetaTitle, withBase, absoluteUrl,
|
|
40
|
+
* generate* }` bag from the context: `settings`/`withBase`/`absoluteUrl` are
|
|
41
|
+
* read directly, while `composeMetaTitle` and the color-scheme CSS generators
|
|
42
|
+
* are reconstructed from the context's `siteName` + `colorSchemes` payload via
|
|
43
|
+
* the shared `chrome/derive` helpers (identical to the pre-collapse wiring).
|
|
48
44
|
*/
|
|
49
|
-
export declare function createHeadWithDefaults(
|
|
45
|
+
export declare function createHeadWithDefaults<S extends Settings = Settings>(ctx: ChromeContext<S>): (props: HeadWithDefaultsProps) => JSX.Element;
|
|
@@ -2,15 +2,13 @@ import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
|
|
|
2
2
|
import { OgTags, TwitterCard } from "../head/index.js";
|
|
3
3
|
import { SIDEBAR_RESIZER_RESTORE_SCRIPT } from "../sidebar-resizer/index.js";
|
|
4
4
|
import ColorSchemeProvider from "../theme/color-scheme-provider.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
generateLightDarkCssProperties
|
|
13
|
-
} = deps;
|
|
5
|
+
import { deriveComposeMetaTitle, deriveColorSchemeGenerators } from "../chrome/derive.js";
|
|
6
|
+
function createHeadWithDefaults(ctx) {
|
|
7
|
+
const settings = ctx.settings;
|
|
8
|
+
const composeMetaTitle = deriveComposeMetaTitle(ctx);
|
|
9
|
+
const withBase = ctx.withBase;
|
|
10
|
+
const absoluteUrl = ctx.absoluteUrl;
|
|
11
|
+
const { generateCssCustomProperties, generateLightDarkCssProperties } = deriveColorSchemeGenerators(ctx);
|
|
14
12
|
function HeadWithDefaults({
|
|
15
13
|
title,
|
|
16
14
|
description,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/** @jsxRuntime automatic */
|
|
2
2
|
/** @jsxImportSource preact */
|
|
3
3
|
import type { JSX } from "preact";
|
|
4
|
-
import type {
|
|
5
|
-
import type {
|
|
4
|
+
import type { ChromeContext } from "../factory-context/index.js";
|
|
5
|
+
import type { Settings } from "../settings.js";
|
|
6
6
|
export interface HeaderWithDefaultsProps {
|
|
7
7
|
/** Active locale; defaults to the configured defaultLocale. */
|
|
8
8
|
lang?: string;
|
|
@@ -44,34 +44,13 @@ export interface HeaderWithDefaultsSettings {
|
|
|
44
44
|
versions?: HeaderVersionEntry[] | false;
|
|
45
45
|
githubUrl?: string | false;
|
|
46
46
|
}
|
|
47
|
-
/** Dependencies injected by the host stub. */
|
|
48
|
-
export interface HeaderWithDefaultsDeps {
|
|
49
|
-
settings: HeaderWithDefaultsSettings;
|
|
50
|
-
defaultLocale: string;
|
|
51
|
-
locales: readonly string[];
|
|
52
|
-
t: (key: string, lang: string) => string;
|
|
53
|
-
withBase: (path: string) => string;
|
|
54
|
-
stripBase: (path: string) => string;
|
|
55
|
-
docsUrl: (slug: string, lang: string) => string;
|
|
56
|
-
navHref: (path: string, lang: string | undefined, version: string | undefined) => string;
|
|
57
|
-
versionedDocsUrl: (slug: string, versionSlug: string, lang: string) => string;
|
|
58
|
-
buildLocaleLinksForNav: (currentPath: string, lang: string, localeCount: number) => LocaleLink[] | undefined;
|
|
59
|
-
buildRootMenuItems: (lang: string, currentVersion: string | undefined) => SidebarRootMenuItem[];
|
|
60
|
-
buildSidebarNodes: (lang: string, navSection: string | undefined, currentVersion: string | undefined) => SidebarNavNode[];
|
|
61
|
-
getThemeDefaultMode: () => "light" | "dark" | undefined;
|
|
62
|
-
buildGitHubRepoUrl: () => string | null;
|
|
63
|
-
SearchWidget: (props: {
|
|
64
|
-
placeholderText: string;
|
|
65
|
-
shortcutHint: string;
|
|
66
|
-
resultCountTemplate: string;
|
|
67
|
-
searchLabel: string;
|
|
68
|
-
searchUnavailableText: string;
|
|
69
|
-
loadingIndexText: string;
|
|
70
|
-
noResultsText: string;
|
|
71
|
-
}) => JSX.Element;
|
|
72
|
-
}
|
|
73
47
|
/**
|
|
74
|
-
* Create a `HeaderWithDefaults` component
|
|
75
|
-
*
|
|
48
|
+
* Create a `HeaderWithDefaults` component from the unified {@link ChromeContext}
|
|
49
|
+
* (epic Collapse Wiring Shells #2420, FACTORIES #2424 — breaking signature).
|
|
50
|
+
*
|
|
51
|
+
* Derives its old wide deps bag from the context: the URL/i18n helpers
|
|
52
|
+
* (`t`/`withBase`/`docsUrl`/…) and `locales`/`defaultLocale` are read directly;
|
|
53
|
+
* the nav data-prep builders + SearchWidget slot come from the shared
|
|
54
|
+
* `chrome/derive` helpers; `buildGitHubRepoUrl` is bound to `settings.githubUrl`.
|
|
76
55
|
*/
|
|
77
|
-
export declare function createHeaderWithDefaults(
|
|
56
|
+
export declare function createHeaderWithDefaults<S extends Settings = Settings>(ctx: ChromeContext<S>): (props: HeaderWithDefaultsProps) => JSX.Element;
|
|
@@ -7,24 +7,21 @@ import {
|
|
|
7
7
|
} from "../i18n-version/index.js";
|
|
8
8
|
import { ThemeToggle } from "../theme-toggle/index.js";
|
|
9
9
|
import { SidebarToggle } from "../sidebar-toggle-island/index.js";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
buildGitHubRepoUrl,
|
|
26
|
-
SearchWidget
|
|
27
|
-
} = deps;
|
|
10
|
+
import { buildGitHubRepoUrl as buildGitHubRepoUrlBase } from "../github-helpers/index.js";
|
|
11
|
+
import { deriveNavDataPrep, deriveSearchWidgetSlot } from "../chrome/derive.js";
|
|
12
|
+
function createHeaderWithDefaults(ctx) {
|
|
13
|
+
const settings = ctx.settings;
|
|
14
|
+
const defaultLocale = ctx.defaultLocale;
|
|
15
|
+
const locales = ctx.locales;
|
|
16
|
+
const t = ctx.t;
|
|
17
|
+
const withBase = ctx.withBase;
|
|
18
|
+
const stripBase = ctx.stripBase;
|
|
19
|
+
const docsUrl = ctx.docsUrl;
|
|
20
|
+
const navHref = ctx.navHref;
|
|
21
|
+
const versionedDocsUrl = ctx.versionedDocsUrl;
|
|
22
|
+
const { buildRootMenuItems, buildLocaleLinksForNav, buildSidebarNodes, getThemeDefaultMode } = deriveNavDataPrep(ctx);
|
|
23
|
+
const buildGitHubRepoUrl = () => buildGitHubRepoUrlBase(ctx.settings.githubUrl);
|
|
24
|
+
const SearchWidget = deriveSearchWidgetSlot(ctx);
|
|
28
25
|
function HeaderWithDefaults(props) {
|
|
29
26
|
const {
|
|
30
27
|
lang: langProp = defaultLocale,
|
|
@@ -36,12 +36,11 @@ generated: true
|
|
|
36
36
|
`;
|
|
37
37
|
fs.writeFileSync(path.join(outputDir, "index.mdx"), mdx);
|
|
38
38
|
}
|
|
39
|
-
function writeUnlistedSubPage(outputPath, title,
|
|
39
|
+
function writeUnlistedSubPage(outputPath, title, body) {
|
|
40
40
|
fs.writeFileSync(
|
|
41
41
|
outputPath,
|
|
42
42
|
`---
|
|
43
43
|
title: "${escapeTitle(title)}"
|
|
44
|
-
slug: "${slug}"
|
|
45
44
|
unlisted: true
|
|
46
45
|
generated: true
|
|
47
46
|
---
|
|
@@ -55,6 +54,46 @@ function assertNotIndexReserved(nameOrSlug, errorMessage) {
|
|
|
55
54
|
throw new Error(errorMessage);
|
|
56
55
|
}
|
|
57
56
|
}
|
|
57
|
+
function isRepoRelativeLink(url) {
|
|
58
|
+
const trimmed = url.trim();
|
|
59
|
+
if (trimmed === "") return false;
|
|
60
|
+
if (trimmed.startsWith("#")) return false;
|
|
61
|
+
if (trimmed.startsWith("/")) return false;
|
|
62
|
+
if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)) return false;
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
function downgradeRepoRelativeLinks(content) {
|
|
66
|
+
const blockPlaceholder = "\0CRLINK_BLOCK_";
|
|
67
|
+
const inlinePlaceholder = "\0CRLINK_INLINE_";
|
|
68
|
+
const codeBlocks = [];
|
|
69
|
+
const withBlocks = content.replace(/(`{3,}|~{3,})[^\n]*\n[\s\S]*?\1/g, (match) => {
|
|
70
|
+
codeBlocks.push(match);
|
|
71
|
+
return `${blockPlaceholder}${codeBlocks.length - 1}\0`;
|
|
72
|
+
});
|
|
73
|
+
const transformed = withBlocks.split(new RegExp(`(${blockPlaceholder}\\d+\0)`, "g")).map((part) => {
|
|
74
|
+
if (new RegExp(`^${blockPlaceholder}\\d+\0$`).test(part)) return part;
|
|
75
|
+
const inlineCodes = [];
|
|
76
|
+
const withInline = part.replace(
|
|
77
|
+
/(`{1,3})(?!`)([\s\S]*?[^`])\1(?!`)/g,
|
|
78
|
+
(match) => {
|
|
79
|
+
inlineCodes.push(match);
|
|
80
|
+
return `${inlinePlaceholder}${inlineCodes.length - 1}\0`;
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
const rewritten = withInline.replace(
|
|
84
|
+
/!?\[([^\]]*)\]\(([^)]+)\)/g,
|
|
85
|
+
(match, text, url) => isRepoRelativeLink(url) ? `\`${text}\`` : match
|
|
86
|
+
);
|
|
87
|
+
return rewritten.replace(
|
|
88
|
+
new RegExp(`${inlinePlaceholder}(\\d+)\0`, "g"),
|
|
89
|
+
(_, idx) => inlineCodes[Number(idx)] ?? ""
|
|
90
|
+
);
|
|
91
|
+
}).join("");
|
|
92
|
+
return transformed.replace(
|
|
93
|
+
new RegExp(`${blockPlaceholder}(\\d+)\0`, "g"),
|
|
94
|
+
(_, idx) => codeBlocks[Number(idx)] ?? ""
|
|
95
|
+
);
|
|
96
|
+
}
|
|
58
97
|
function findClaudeMdFiles(dir, excludeDirs) {
|
|
59
98
|
const results = [];
|
|
60
99
|
if (!fs.existsSync(dir)) return results;
|
|
@@ -133,7 +172,7 @@ generated: true
|
|
|
133
172
|
|
|
134
173
|
**Path:** \`${item.relPath}\`
|
|
135
174
|
|
|
136
|
-
${escapeForMdx(content.trim())}
|
|
175
|
+
${escapeForMdx(downgradeRepoRelativeLinks(content.trim()))}
|
|
137
176
|
`;
|
|
138
177
|
fs.writeFileSync(path.join(outputDir, `${item.slug}.mdx`), mdx);
|
|
139
178
|
});
|
|
@@ -297,13 +336,13 @@ generated: true
|
|
|
297
336
|
---
|
|
298
337
|
|
|
299
338
|
${body}`;
|
|
300
|
-
|
|
301
|
-
|
|
339
|
+
const skillDirOut = path.join(outputDir, dir);
|
|
340
|
+
ensureDir(skillDirOut);
|
|
341
|
+
fs.writeFileSync(path.join(skillDirOut, "index.mdx"), mdx);
|
|
302
342
|
for (const ref of references) {
|
|
303
343
|
writeUnlistedSubPage(
|
|
304
|
-
path.join(
|
|
344
|
+
path.join(skillDirOut, `ref-${ref.name}.mdx`),
|
|
305
345
|
ref.title,
|
|
306
|
-
`${skillSlugBase}/ref-${ref.name}`,
|
|
307
346
|
escapeForMdx(ref.content.trim())
|
|
308
347
|
);
|
|
309
348
|
}
|
|
@@ -316,9 +355,8 @@ ${body}`;
|
|
|
316
355
|
const h1Match = raw.match(/^#\s+(.+)$/m);
|
|
317
356
|
const title = h1Match?.[1] ?? slug;
|
|
318
357
|
writeUnlistedSubPage(
|
|
319
|
-
path.join(
|
|
358
|
+
path.join(skillDirOut, `script-${slug}.mdx`),
|
|
320
359
|
title,
|
|
321
|
-
`${skillSlugBase}/script-${slug}`,
|
|
322
360
|
escapeForMdx(raw.trim())
|
|
323
361
|
);
|
|
324
362
|
}
|
|
@@ -331,9 +369,8 @@ ${body}`;
|
|
|
331
369
|
const h1Match = raw.match(/^#\s+(.+)$/m);
|
|
332
370
|
const title = h1Match?.[1] ?? slug;
|
|
333
371
|
writeUnlistedSubPage(
|
|
334
|
-
path.join(
|
|
372
|
+
path.join(skillDirOut, `asset-${slug}.mdx`),
|
|
335
373
|
title,
|
|
336
|
-
`${skillSlugBase}/asset-${slug}`,
|
|
337
374
|
escapeForMdx(raw.trim())
|
|
338
375
|
);
|
|
339
376
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { CategoryMeta } from "../sidebar-tree/index.js";
|
|
2
2
|
import type { DocPageEntry } from "../doc-page-props/index.js";
|
|
3
|
+
import type { Settings } from "../settings.js";
|
|
3
4
|
export type { CategoryMeta, DocPageEntry };
|
|
4
5
|
export interface NavSourceDocs {
|
|
5
6
|
/** Full doc list (merged + draft-filtered; unlisted retained per options). */
|
|
@@ -41,58 +42,32 @@ export interface VersionConfigEntry {
|
|
|
41
42
|
}>;
|
|
42
43
|
}
|
|
43
44
|
/**
|
|
44
|
-
*
|
|
45
|
+
* Context slice `createNavSourceDocs` derives its bag from (epic Collapse
|
|
46
|
+
* Wiring Shells #2420, FACTORIES #2424 — breaking signature). This is a
|
|
47
|
+
* STRUCTURAL SUBSET of the unified `RouteContext`/`ChromeContext`, so callers
|
|
48
|
+
* pass the whole context: `docsDir`/`getVersions` are read off `settings`,
|
|
49
|
+
* `loadCategoryMeta` is imported from the package directly (it is a pure,
|
|
50
|
+
* `@/`-free helper), and the rest are reconstructed callables on the context.
|
|
45
51
|
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
52
|
+
* NB: `createRouteContext` builds the route context incrementally and calls
|
|
53
|
+
* this factory with the partial-but-sufficient base context — every field
|
|
54
|
+
* below is present before the nav-source resolvers are assembled.
|
|
49
55
|
*/
|
|
50
56
|
export interface NavSourceDocsContext {
|
|
51
|
-
/**
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
*/
|
|
57
|
+
/** The host's resolved settings object (reads `docsDir` + `versions`). */
|
|
58
|
+
settings: Settings;
|
|
59
|
+
/** Default locale code (un-prefixed `/docs/...` routes). E.g. `"en"`. */
|
|
55
60
|
defaultLocale: string;
|
|
56
|
-
/**
|
|
57
|
-
* The configured docs content directory (e.g. `"src/content/docs"`).
|
|
58
|
-
* Used as the base dir for `loadCategoryMeta`.
|
|
59
|
-
*/
|
|
60
|
-
docsDir: string;
|
|
61
|
-
/**
|
|
62
|
-
* Getter for the configured versions list (or false if versioning is not
|
|
63
|
-
* active). Called on every `resolveNavSource` invocation so test code that
|
|
64
|
-
* mutates `settings.versions` between calls sees the updated value.
|
|
65
|
-
* Structural equivalent of a getter for `settings.versions`.
|
|
66
|
-
*
|
|
67
|
-
* Pass `() => settings.versions` from the host stub.
|
|
68
|
-
*/
|
|
69
|
-
getVersions: () => VersionConfigEntry[] | false | undefined;
|
|
70
|
-
/**
|
|
71
|
-
* Look up locale-specific config (dir, etc.) for a locale code.
|
|
72
|
-
* Host passes `getLocaleConfig` from `@/config/i18n`.
|
|
73
|
-
*/
|
|
61
|
+
/** Per-locale config lookup (reconstructed on the context). */
|
|
74
62
|
getLocaleConfig: (lang: string) => LocaleConfig | undefined;
|
|
75
|
-
/**
|
|
76
|
-
* Load category metadata for a content dir.
|
|
77
|
-
* Host passes `loadCategoryMeta` from `@/utils/docs` (re-exported from
|
|
78
|
-
* `@takazudo/zudo-doc/sidebar-tree`).
|
|
79
|
-
*/
|
|
80
|
-
loadCategoryMeta: (dir: string) => Map<string, CategoryMeta>;
|
|
81
|
-
/**
|
|
82
|
-
* Filter predicate: true when a doc should appear in navigation.
|
|
83
|
-
* Host passes `isNavVisible` from `@/utils/docs`.
|
|
84
|
-
*/
|
|
63
|
+
/** Filter predicate: true when a doc should appear in navigation. */
|
|
85
64
|
isNavVisible: (doc: DocPageEntry) => boolean;
|
|
86
|
-
/**
|
|
87
|
-
* Returns true for paths that are only shown in the default locale.
|
|
88
|
-
* Host passes `isDefaultLocaleOnlyPath` from `@/utils/base`.
|
|
89
|
-
*/
|
|
65
|
+
/** Returns true for paths that are only shown in the default locale. */
|
|
90
66
|
isDefaultLocaleOnlyPath: (path: string) => boolean;
|
|
91
67
|
/**
|
|
92
|
-
* Identity-stable, draft-filtered docs array for a collection
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
* array instance is returned on every call within one build.
|
|
68
|
+
* Identity-stable, draft-filtered docs array for a collection (the
|
|
69
|
+
* content-bridge handle). Anchors memoization on the zfb snapshot so the
|
|
70
|
+
* SAME array instance is returned on every call within one build.
|
|
96
71
|
*/
|
|
97
72
|
stableDocs: (collectionName: string) => DocPageEntry[];
|
|
98
73
|
}
|
|
@@ -154,16 +129,7 @@ export interface NavSourceDocsAPI {
|
|
|
154
129
|
* loadNavSourceDocs,
|
|
155
130
|
* stableMergeCategoryMeta,
|
|
156
131
|
* stableNavDocs,
|
|
157
|
-
* } = createNavSourceDocs(
|
|
158
|
-
* defaultLocale,
|
|
159
|
-
* docsDir: settings.docsDir,
|
|
160
|
-
* getVersions: () => settings.versions,
|
|
161
|
-
* getLocaleConfig,
|
|
162
|
-
* loadCategoryMeta,
|
|
163
|
-
* isNavVisible,
|
|
164
|
-
* isDefaultLocaleOnlyPath,
|
|
165
|
-
* stableDocs,
|
|
166
|
-
* });
|
|
132
|
+
* } = createNavSourceDocs(routeContext);
|
|
167
133
|
* ```
|
|
168
134
|
*/
|
|
169
135
|
export declare function createNavSourceDocs(ctx: NavSourceDocsContext): NavSourceDocsAPI;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { loadCategoryMeta as loadCategoryMetaImpl } from "../sidebar-tree/index.js";
|
|
1
2
|
import { memoizeDerived } from "../nav-source-cache/index.js";
|
|
2
3
|
import { mergeLocaleDocs } from "../locale-merge/index.js";
|
|
3
4
|
function optionSig(o) {
|
|
@@ -5,16 +6,14 @@ function optionSig(o) {
|
|
|
5
6
|
}
|
|
6
7
|
const EMPTY_SLUG_SET = /* @__PURE__ */ new Set();
|
|
7
8
|
function createNavSourceDocs(ctx) {
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
stableDocs
|
|
17
|
-
} = ctx;
|
|
9
|
+
const defaultLocale = ctx.defaultLocale;
|
|
10
|
+
const docsDir = ctx.settings.docsDir;
|
|
11
|
+
const getVersions = () => ctx.settings.versions;
|
|
12
|
+
const getLocaleConfig = ctx.getLocaleConfig;
|
|
13
|
+
const loadCategoryMeta = loadCategoryMetaImpl;
|
|
14
|
+
const isNavVisible = ctx.isNavVisible;
|
|
15
|
+
const isDefaultLocaleOnlyPath = ctx.isDefaultLocaleOnlyPath;
|
|
16
|
+
const stableDocs = ctx.stableDocs;
|
|
18
17
|
const mergedCategoryMetaCache = /* @__PURE__ */ new Map();
|
|
19
18
|
function stableMergeCategoryMeta(baseDir, localeDir) {
|
|
20
19
|
const key = `${baseDir}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { RouteContext, RouteContextPayload } from "../factory-context/index.js";
|
|
2
|
+
import type { Settings } from "../settings.js";
|
|
3
|
+
import type { DocPageEntry } from "../doc-page-props/index.js";
|
|
4
|
+
export type { RouteContext, RouteContextPayload, TagInfo, } from "../factory-context/index.js";
|
|
5
|
+
/** A content-bridge handle: identity-stable, draft-filtered docs loader. */
|
|
6
|
+
export type ContentBridge = (collectionName: string) => DocPageEntry[];
|
|
7
|
+
export interface CreateRouteContextOptions {
|
|
8
|
+
/**
|
|
9
|
+
* The content-bridge handle (`stableDocs`). Default: the package
|
|
10
|
+
* `stableDocs` from `routes/_docs-helpers` (reads `@takazudo/zfb/content`,
|
|
11
|
+
* snapshot-anchored for per-build identity stability). The host may inject
|
|
12
|
+
* its own content loader here.
|
|
13
|
+
*/
|
|
14
|
+
stableDocs?: ContentBridge;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Reconstruct the full runtime route context from the serializable payload.
|
|
18
|
+
* Called ONCE per build (the route entrypoints share the returned singleton via
|
|
19
|
+
* the `routes/_context.ts` module), so the memoized closures inside
|
|
20
|
+
* (`createNavSourceDocs` / `createDocRouteEntries` / `createRouteEnumerators`)
|
|
21
|
+
* and the snapshot-anchored `stableDocs` keep array identity stable across all
|
|
22
|
+
* routes.
|
|
23
|
+
*/
|
|
24
|
+
export declare function createRouteContext<S extends Settings = Settings>(payload: RouteContextPayload<S>, options?: CreateRouteContextOptions): RouteContext<S>;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { makeUrlHelpers } from "../url-helpers/index.js";
|
|
2
|
+
import { loadCategoryMeta } from "../sidebar-tree/index.js";
|
|
3
|
+
import { extractHeadings as extractHeadingsBase } from "../extract-headings/index.js";
|
|
4
|
+
import { toRouteSlug, toSlugParams } from "../slug/index.js";
|
|
5
|
+
import { resolveTag } from "../tag-helpers/index.js";
|
|
6
|
+
import {
|
|
7
|
+
getCategoryOrder as getCategoryOrderBase,
|
|
8
|
+
getNavSectionForSlug as getNavSectionForSlugBase,
|
|
9
|
+
getNavSubtree as getNavSubtreeBase
|
|
10
|
+
} from "../nav-scope/index.js";
|
|
11
|
+
import { mergeLocaleDocs } from "../locale-merge/index.js";
|
|
12
|
+
import {
|
|
13
|
+
createNavSourceDocs
|
|
14
|
+
} from "../nav-source-docs/index.js";
|
|
15
|
+
import {
|
|
16
|
+
createDocRouteEntries
|
|
17
|
+
} from "../doc-route-entries/index.js";
|
|
18
|
+
import {
|
|
19
|
+
createRouteEnumerators
|
|
20
|
+
} from "../route-enumerators/index.js";
|
|
21
|
+
import {
|
|
22
|
+
stableDocs as defaultStableDocs,
|
|
23
|
+
isNavVisible,
|
|
24
|
+
buildNavTree,
|
|
25
|
+
buildBreadcrumbs,
|
|
26
|
+
collectAutoIndexNodes,
|
|
27
|
+
groupSatelliteNodes,
|
|
28
|
+
findNode,
|
|
29
|
+
firstRoutedHref
|
|
30
|
+
} from "../routes/_docs-helpers.js";
|
|
31
|
+
function createRouteContext(payload, options = {}) {
|
|
32
|
+
const settings = payload.settings;
|
|
33
|
+
const translations = payload.translations;
|
|
34
|
+
const tagVocabulary = payload.tagVocabulary;
|
|
35
|
+
const colorSchemes = payload.colorSchemes;
|
|
36
|
+
const stableDocs = options.stableDocs ?? defaultStableDocs;
|
|
37
|
+
const defaultLocale = settings.defaultLocale;
|
|
38
|
+
const locales = [
|
|
39
|
+
defaultLocale,
|
|
40
|
+
...Object.keys(settings.locales)
|
|
41
|
+
];
|
|
42
|
+
function getLocaleConfig(locale) {
|
|
43
|
+
return settings.locales[locale];
|
|
44
|
+
}
|
|
45
|
+
function getLocaleLabel(locale) {
|
|
46
|
+
if (locale === defaultLocale) return defaultLocale.toUpperCase();
|
|
47
|
+
return getLocaleConfig(locale)?.label ?? locale.toUpperCase();
|
|
48
|
+
}
|
|
49
|
+
function t(key, locale = defaultLocale) {
|
|
50
|
+
return translations[locale]?.[key] ?? translations[defaultLocale]?.[key] ?? key;
|
|
51
|
+
}
|
|
52
|
+
const i18n = { defaultLocale, locales, getLocaleLabel, t };
|
|
53
|
+
const urlHelpers = makeUrlHelpers(settings, i18n);
|
|
54
|
+
const { withBase, docsUrl, versionedDocsUrl, navHref, isDefaultLocaleOnlyPath } = urlHelpers;
|
|
55
|
+
function getCategoryOrder() {
|
|
56
|
+
return getCategoryOrderBase(settings.headerNav);
|
|
57
|
+
}
|
|
58
|
+
function getNavSectionForSlug(slug) {
|
|
59
|
+
return getNavSectionForSlugBase(slug, settings.headerNav);
|
|
60
|
+
}
|
|
61
|
+
function getNavSubtree(tree, categoryMatch) {
|
|
62
|
+
return getNavSubtreeBase(tree, categoryMatch, settings.headerNav);
|
|
63
|
+
}
|
|
64
|
+
function extractHeadings(body) {
|
|
65
|
+
return extractHeadingsBase(body, {
|
|
66
|
+
tocMinDepth: settings.tocMinDepth,
|
|
67
|
+
tocMaxDepth: settings.tocMaxDepth,
|
|
68
|
+
strategy: settings.headingIdStrategy
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function getVocab() {
|
|
72
|
+
return settings.tagVocabulary ? tagVocabulary : false;
|
|
73
|
+
}
|
|
74
|
+
function resolveTagBound(raw) {
|
|
75
|
+
return resolveTag(raw, getVocab(), settings.tagGovernance);
|
|
76
|
+
}
|
|
77
|
+
function collectTags(entries, slugFn) {
|
|
78
|
+
const tagMap = /* @__PURE__ */ new Map();
|
|
79
|
+
for (const entry of entries) {
|
|
80
|
+
const rawTags = entry.data.tags ?? [];
|
|
81
|
+
const slug = slugFn(entry.id, entry.data);
|
|
82
|
+
const seen = /* @__PURE__ */ new Set();
|
|
83
|
+
for (const raw of rawTags) {
|
|
84
|
+
const resolved = resolveTagBound(raw);
|
|
85
|
+
if (resolved.deprecated) continue;
|
|
86
|
+
if (seen.has(resolved.canonical)) continue;
|
|
87
|
+
seen.add(resolved.canonical);
|
|
88
|
+
if (!tagMap.has(resolved.canonical)) {
|
|
89
|
+
tagMap.set(resolved.canonical, {
|
|
90
|
+
tag: resolved.canonical,
|
|
91
|
+
count: 0,
|
|
92
|
+
docs: []
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
const info = tagMap.get(resolved.canonical);
|
|
96
|
+
info.count++;
|
|
97
|
+
info.docs.push({
|
|
98
|
+
slug,
|
|
99
|
+
title: entry.data.title ?? "",
|
|
100
|
+
description: entry.data.description
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return tagMap;
|
|
105
|
+
}
|
|
106
|
+
const base = {
|
|
107
|
+
settings,
|
|
108
|
+
colorSchemes,
|
|
109
|
+
i18n,
|
|
110
|
+
defaultLocale,
|
|
111
|
+
locales,
|
|
112
|
+
getLocaleConfig,
|
|
113
|
+
getLocaleLabel,
|
|
114
|
+
t,
|
|
115
|
+
urlHelpers,
|
|
116
|
+
...urlHelpers,
|
|
117
|
+
getCategoryOrder,
|
|
118
|
+
getNavSectionForSlug,
|
|
119
|
+
getNavSubtree,
|
|
120
|
+
extractHeadings,
|
|
121
|
+
resolveTagBound,
|
|
122
|
+
collectTags,
|
|
123
|
+
buildNavTree,
|
|
124
|
+
groupSatelliteNodes,
|
|
125
|
+
findNode,
|
|
126
|
+
firstRoutedHref,
|
|
127
|
+
collectAutoIndexNodes,
|
|
128
|
+
isNavVisible,
|
|
129
|
+
stableDocs,
|
|
130
|
+
toRouteSlug,
|
|
131
|
+
toSlugParams
|
|
132
|
+
};
|
|
133
|
+
const navSourceDocs = createNavSourceDocs(base);
|
|
134
|
+
const docRouteEntries = createDocRouteEntries(base);
|
|
135
|
+
const baseWithNav = { ...base, ...navSourceDocs };
|
|
136
|
+
const routeEnumerators = createRouteEnumerators(
|
|
137
|
+
baseWithNav
|
|
138
|
+
);
|
|
139
|
+
return {
|
|
140
|
+
...baseWithNav,
|
|
141
|
+
...docRouteEntries,
|
|
142
|
+
...routeEnumerators
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
export {
|
|
146
|
+
createRouteContext
|
|
147
|
+
};
|