create-zudo-doc 0.2.21 → 1.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.
Files changed (92) hide show
  1. package/dist/compose.d.ts +6 -3
  2. package/dist/compose.js +6 -4
  3. package/dist/features/image-enlarge.d.ts +22 -12
  4. package/dist/features/image-enlarge.js +23 -191
  5. package/dist/scaffold.d.ts +11 -0
  6. package/dist/scaffold.js +51 -24
  7. package/dist/settings-gen.js +4 -0
  8. package/dist/zfb-config-gen.d.ts +16 -10
  9. package/dist/zfb-config-gen.js +34 -239
  10. package/package.json +1 -1
  11. package/templates/base/pages/_mdx-components.ts +64 -185
  12. package/templates/base/pages/index.tsx +1 -1
  13. package/templates/base/pages/lib/_body-end-islands.tsx +6 -13
  14. package/templates/base/pages/lib/_category-nav.tsx +30 -115
  15. package/templates/base/pages/lib/_category-tree-nav.tsx +38 -65
  16. package/templates/base/pages/lib/_compose-meta-title.ts +2 -6
  17. package/templates/base/pages/lib/_doc-body-end.tsx +3 -35
  18. package/templates/base/pages/lib/_doc-content-header.tsx +10 -111
  19. package/templates/base/pages/lib/_doc-history-area.tsx +19 -211
  20. package/templates/base/pages/lib/_doc-metainfo-area.tsx +10 -113
  21. package/templates/base/pages/lib/_doc-page-renderer.tsx +22 -183
  22. package/templates/base/pages/lib/_doc-page-shell.tsx +17 -251
  23. package/templates/base/pages/lib/_doc-pager.tsx +4 -74
  24. package/templates/base/pages/lib/_doc-route-entries.ts +43 -177
  25. package/templates/base/pages/lib/_doc-route-paths.ts +16 -101
  26. package/templates/base/pages/lib/_doc-tags-area.tsx +14 -77
  27. package/templates/base/pages/lib/_extract-headings.ts +21 -295
  28. package/templates/base/pages/lib/_footer-with-defaults.tsx +37 -225
  29. package/templates/base/pages/lib/_frontmatter-preview-data.ts +5 -31
  30. package/templates/base/pages/lib/_head-with-defaults.tsx +13 -138
  31. package/templates/base/pages/lib/_header-with-defaults.tsx +24 -324
  32. package/templates/base/pages/lib/_inline-version-switcher.tsx +16 -78
  33. package/templates/base/pages/lib/_math-block.tsx +4 -63
  34. package/templates/base/pages/lib/_nav-data-prep.ts +32 -51
  35. package/templates/base/pages/lib/_nav-source-cache.ts +12 -57
  36. package/templates/base/pages/lib/_nav-source-docs.ts +33 -233
  37. package/templates/base/pages/lib/_search-widget-script.ts +2 -470
  38. package/templates/base/pages/lib/_search-widget.tsx +9 -195
  39. package/templates/base/pages/lib/_sidebar-prepaint.tsx +6 -59
  40. package/templates/base/pages/lib/_sidebar-with-defaults.tsx +16 -118
  41. package/templates/base/pages/lib/_site-tree-nav.tsx +29 -80
  42. package/templates/base/pages/lib/doc-page-props.ts +26 -44
  43. package/templates/base/pages/lib/locale-merge.ts +32 -145
  44. package/templates/base/pages/lib/route-enumerators.ts +52 -286
  45. package/templates/base/src/components/ai-chat-modal.tsx +9 -8
  46. package/templates/base/src/components/content/code-group.tsx +3 -76
  47. package/templates/base/src/components/content/content-admonition.tsx +4 -56
  48. package/templates/base/src/components/doc-history.tsx +9 -8
  49. package/templates/base/src/components/image-enlarge.tsx +11 -8
  50. package/templates/base/src/components/sidebar-toggle.tsx +6 -170
  51. package/templates/base/src/components/sidebar-tree.tsx +6 -548
  52. package/templates/base/src/config/color-scheme-utils.ts +34 -158
  53. package/templates/base/src/config/i18n.ts +9 -0
  54. package/templates/base/src/config/settings-types.ts +34 -172
  55. package/templates/base/src/config/z-index-tokens.ts +5 -4
  56. package/templates/base/src/styles/global.css +40 -587
  57. package/templates/base/src/utils/base.ts +1 -1
  58. package/templates/base/src/utils/docs.ts +47 -16
  59. package/templates/base/src/utils/github.ts +12 -9
  60. package/templates/base/src/utils/nav-scope.ts +13 -42
  61. package/templates/base/src/utils/sidebar.ts +18 -86
  62. package/templates/base/src/utils/slug.ts +10 -53
  63. package/templates/base/src/utils/smart-break.tsx +12 -120
  64. package/templates/base/src/utils/tags.ts +25 -68
  65. package/templates/features/bodyFootUtil/files/src/utils/github.ts +12 -9
  66. package/templates/features/designTokenPanel/files/src/lib/design-token-panel-bootstrap.ts +13 -39
  67. package/templates/features/docHistory/files/src/components/doc-history.tsx +8 -636
  68. package/templates/features/docHistory/files/src/types/doc-history.ts +7 -23
  69. package/templates/features/docTags/files/pages/lib/_tag-pages.tsx +35 -201
  70. package/templates/features/i18n/files/pages/[locale]/index.tsx +1 -1
  71. package/templates/features/imageEnlarge/files/src/components/image-enlarge.tsx +8 -269
  72. package/templates/features/sidebarToggle/files/src/components/desktop-sidebar-toggle.tsx +6 -99
  73. package/templates/features/tagGovernance/files/scripts/tags-audit.ts +67 -515
  74. package/templates/features/versioning/files/pages/lib/_versions-page.tsx +21 -73
  75. package/templates/base/pages/404.tsx +0 -61
  76. package/templates/base/pages/robots.txt.tsx +0 -29
  77. package/templates/base/pages/sitemap.xml.tsx +0 -59
  78. package/templates/base/plugins/connect-adapter.mjs +0 -169
  79. package/templates/base/plugins/copy-public-plugin.mjs +0 -58
  80. package/templates/base/plugins/search-index-plugin.mjs +0 -66
  81. package/templates/base/scripts/gen-z-index.mjs +0 -157
  82. package/templates/base/src/components/mermaid-enlarge.tsx +0 -490
  83. package/templates/base/src/components/site-tree-nav.tsx +0 -220
  84. package/templates/features/claudeResources/files/plugins/claude-resources-plugin.mjs +0 -47
  85. package/templates/features/docHistory/files/plugins/doc-history-plugin.mjs +0 -111
  86. package/templates/features/docTags/files/pages/[locale]/docs/tags/[tag].tsx +0 -59
  87. package/templates/features/docTags/files/pages/[locale]/docs/tags/index.tsx +0 -39
  88. package/templates/features/docTags/files/pages/docs/tags/[tag].tsx +0 -43
  89. package/templates/features/docTags/files/pages/docs/tags/index.tsx +0 -20
  90. package/templates/features/llmsTxt/files/plugins/llms-txt-plugin.mjs +0 -93
  91. package/templates/features/versioning/files/pages/[locale]/docs/versions.tsx +0 -48
  92. package/templates/features/versioning/files/pages/docs/versions.tsx +0 -20
@@ -1,263 +1,29 @@
1
1
  /** @jsxRuntime automatic */
2
2
  /** @jsxImportSource preact */
3
- // Shared render shell for all 4 doc-route page components.
4
- //
5
- // Extracted (#1917) from the near-verbatim render bodies of:
6
- // pages/docs/[[...slug]].tsx
7
- // pages/[locale]/docs/[[...slug]].tsx
8
- // pages/v/[version]/docs/[[...slug]].tsx
9
- // pages/v/[version]/[locale]/docs/[[...slug]].tsx
10
- //
11
- // This module is intentionally version- and i18n-AGNOSTIC: it imports no
12
- // VersionConfig and no versionedDocsUrl. Everything version/locale-specific
13
- // is threaded in as plain props or pre-built VNode slots, so the base EN
14
- // route (which ships in every scaffold, including barebones) can depend on
15
- // it without dragging in the versioning/i18n feature surface. The feature
16
- // route templates import this same module via the identical relative path,
17
- // keeping the create-zudo-doc template copies byte-identical to the host.
18
-
19
- import type { ComponentChildren, JSX, VNode } from "preact";
20
- import { Island } from "@takazudo/zfb";
3
+ // Host thin-stub see @takazudo/zudo-doc/doc-page-shell (epic #2344, S5).
21
4
  import { settings } from "@/config/settings";
22
- import type { NavNode } from "@/utils/docs";
23
- import { DocLayoutWithDefaults } from "@takazudo/zudo-doc/doclayout";
24
- import { Toc, MobileToc } from "@takazudo/zudo-doc/toc";
5
+ import { createDocPageShell } from "@takazudo/zudo-doc/doc-page-shell";
6
+ import { composeMetaTitle } from "./_compose-meta-title";
25
7
  import { getTocTitle } from "./_toc-title";
26
- import { Breadcrumb } from "@takazudo/zudo-doc/breadcrumb";
27
- import { NavCardGrid } from "@takazudo/zudo-doc/nav-indexing";
28
8
  import { HeadWithDefaults } from "./_head-with-defaults";
29
- import { composeMetaTitle } from "./_compose-meta-title";
30
9
  import { SidebarWithDefaults } from "./_sidebar-with-defaults";
31
10
  import { HeaderWithDefaults } from "./_header-with-defaults";
32
11
  import { FooterWithDefaults } from "./_footer-with-defaults";
33
12
  import { SidebarPrepaint } from "./_sidebar-prepaint";
34
13
  import { DocBodyEnd } from "./_doc-body-end";
35
14
  import { DocPager } from "./_doc-pager";
36
- import type { BreadcrumbItem } from "@/utils/docs";
37
- import type { VersionBannerLabels } from "@takazudo/zudo-doc/i18n-version";
38
- import type { Locale } from "@/config/i18n";
39
- import type { extractHeadings } from "./_extract-headings";
40
-
41
- /** Slots and parameters that vary between the 4 doc routes. */
42
- export interface DocPageShellProps {
43
- /** Discriminates the body: a real entry vs an auto-generated category index. */
44
- kind: "entry" | "autoIndex";
45
- /** Active locale string, e.g. "en", "ja". */
46
- locale: string;
47
- /** Canonical route slug for this page (no version/locale prefix). */
48
- slug: string;
49
- /** Page title (entry title or auto-index label). */
50
- title: string;
51
- /** Page description (may be undefined). */
52
- description?: string;
53
- /** Absolute canonical URL, or undefined when siteUrl is unset. */
54
- canonical?: string;
55
- /** Pre-resolved breadcrumb trail (hrefs already remapped per route). */
56
- breadcrumbs: BreadcrumbItem[];
57
- /** Pre-resolved prev/next nav nodes (hrefs already remapped per route). */
58
- prev: NavNode | null;
59
- next: NavNode | null;
60
- /** Depth-2/3/4 headings for the SSG TOC. */
61
- headings: ReturnType<typeof extractHeadings>;
62
-
63
- /** Sidebar/header nav-section key for this slug. */
64
- navSection: string | undefined;
65
- /** Per-page sidebar persist key (undefined when the sidebar is hidden). */
66
- sidebarPersistKey: string | undefined;
67
- /** Whether to hide the sidebar entirely (entry frontmatter). */
68
- hideSidebar?: boolean;
69
- /** Whether to hide the TOC (entry frontmatter). */
70
- hideToc?: boolean;
71
-
72
- /**
73
- * Path of THIS page used by Header/Sidebar to mark the active item.
74
- * Latest routes pass docsUrl(slug, locale); versioned routes pass
75
- * versionedDocsUrl(slug, version, locale).
76
- */
77
- currentPath: string;
78
- /** Version slug for Header/Sidebar active-state, or undefined on latest routes. */
79
- currentVersion?: string;
80
- /** Inline version switcher VNode for the breadcrumb right-slot (route-built). */
81
- versionSwitcher: ComponentChildren;
82
-
83
- /** Version banner type ("unmaintained" | "unreleased") or undefined on latest. */
84
- versionBanner?: "unmaintained" | "unreleased";
85
- /** URL of the latest equivalent page for the version banner link. */
86
- versionBannerLatestUrl?: string;
87
- /** Localized version-banner labels. */
88
- versionBannerLabels?: VersionBannerLabels;
89
-
90
- /** Auto-index branch: label heading text. */
91
- autoIndexLabel?: string;
92
- /** Auto-index branch: pre-filtered + href-remapped child cards. */
93
- autoIndexChildren?: NavNode[];
94
-
95
- /**
96
- * Auto-index branch slot: the build-time date block (DocMetainfoArea), or
97
- * null to omit it. Threaded in so the shell stays oblivious to which routes
98
- * render it.
99
- */
100
- metainfoSlot?: VNode | null;
101
-
102
- /**
103
- * Entry branch slot: the content header (h1 + meta + tags + description +
104
- * frontmatter preview), built per route (carries isFallback).
105
- */
106
- contentHeaderSlot?: VNode;
107
- /** Entry branch slot: the rendered MDX `<Content />`. */
108
- contentSlot?: VNode;
109
- /**
110
- * Entry branch slot: the document-utilities area (DocHistoryArea), or null
111
- * to omit it. Hidden on versioned pages (#1916 #5).
112
- */
113
- docHistorySlot?: VNode | null;
114
- }
115
-
116
- /**
117
- * Render shell shared by all 4 doc-route page components. The caller computes
118
- * every route-specific value (URLs, version switcher, slots) and passes it in;
119
- * this component only assembles the DocLayoutWithDefaults call and the two
120
- * body branches (auto-index vs entry).
121
- */
122
- export function DocPageShell(props: DocPageShellProps): JSX.Element {
123
- const {
124
- kind,
125
- locale,
126
- title,
127
- description,
128
- canonical,
129
- breadcrumbs,
130
- prev,
131
- next,
132
- headings,
133
- navSection,
134
- sidebarPersistKey,
135
- hideSidebar,
136
- hideToc,
137
- currentPath,
138
- currentVersion,
139
- versionSwitcher,
140
- versionBanner,
141
- versionBannerLatestUrl,
142
- versionBannerLabels,
143
- autoIndexLabel,
144
- autoIndexChildren,
145
- metainfoSlot,
146
- contentHeaderSlot,
147
- contentSlot,
148
- docHistorySlot,
149
- } = props;
150
-
151
- // TOC overrides: mount the package Toc/MobileToc with the host-resolved
152
- // locale-aware `tocTitle`. The gating mirrors the package's
153
- // `shouldRenderDefaultToc` exactly (`!hideToc && headings.length > 0`) so an
154
- // undefined override never silently falls back to the package default with a
155
- // different title. Each is wrapped in `<Island when="load">` here (the call
156
- // site), matching how the package wraps its own default. Hydrating these
157
- // npm-dist "use client" components requires zfb >= 0.1.0-next.39, whose
158
- // scanner registers node_modules islands (zfb#999/#1001) — the former
159
- // scanner-visible local shims (#2057) are gone; re-adding them would
160
- // recreate island marker-name collisions.
161
- const tocTitle = getTocTitle(locale);
162
- const shouldRenderToc = !hideToc && headings.length > 0;
163
- const tocOverride = shouldRenderToc
164
- ? (Island({
165
- when: "load",
166
- children: <Toc headings={headings} title={tocTitle} />,
167
- }) as unknown as VNode)
168
- : undefined;
169
- const mobileTocOverride = shouldRenderToc
170
- ? (Island({
171
- when: "load",
172
- children: <MobileToc headings={headings} title={tocTitle} />,
173
- }) as unknown as VNode)
174
- : undefined;
175
-
176
- return (
177
- <DocLayoutWithDefaults
178
- title={composeMetaTitle(title)}
179
- // Plain <meta name="description"> is emitted by DocLayout from this prop —
180
- // gate it here alongside the og:description gate inside HeadWithDefaults (#2078)
181
- description={settings.metaTags.description ? description : undefined}
182
- head={<HeadWithDefaults title={title} description={description} canonical={canonical} />}
183
- lang={locale}
184
- noindex={settings.noindex}
185
- hideSidebar={hideSidebar}
186
- hideToc={hideToc}
187
- headings={headings}
188
- canonical={canonical}
189
- sidebarPersistKey={sidebarPersistKey}
190
- versionBanner={versionBanner ?? false}
191
- versionBannerLatestUrl={versionBannerLatestUrl}
192
- versionBannerLabels={versionBannerLabels}
193
- headerOverride={
194
- <HeaderWithDefaults
195
- lang={locale as Locale}
196
- currentSlug={props.slug}
197
- navSection={navSection}
198
- currentVersion={currentVersion}
199
- currentPath={currentPath}
200
- />
201
- }
202
- breadcrumbOverride={
203
- breadcrumbs.length > 0 ? (
204
- <Breadcrumb items={breadcrumbs} rightSlot={versionSwitcher} />
205
- ) : undefined
206
- }
207
- sidebarOverride={
208
- <SidebarWithDefaults
209
- currentSlug={props.slug}
210
- lang={locale as Locale}
211
- navSection={navSection}
212
- currentVersion={currentVersion}
213
- currentPath={currentPath}
214
- />
215
- }
216
- tocOverride={tocOverride}
217
- mobileTocOverride={mobileTocOverride}
218
- afterSidebar={<SidebarPrepaint hideSidebar={hideSidebar} />}
219
- footerOverride={<FooterWithDefaults lang={locale} />}
220
- bodyEndComponents={<DocBodyEnd />}
221
- enableClientRouter={settings.dynamicPageTransition}
222
- >
223
- {kind === "autoIndex" ? (
224
- /* Auto-index page: category without an index.mdx.
225
- Fragment (not <div>) so children become direct children of
226
- <article class="zd-content">, picking up the flow-space rule
227
- (.zd-content > :where(* + *) { margin-top: var(--flow-space) }).
228
- Wrapping in <div> would make h1/description p children-of-children
229
- and the flow gap (~24px) would never apply — see #1460. */
230
- <>
231
- <h1 class="text-heading font-bold mb-vsp-xs">{autoIndexLabel}</h1>
232
-
233
- {/* Build-time date block — chrome parity (#1461). Threaded in via
234
- metainfoSlot so each route controls whether it renders. */}
235
- {metainfoSlot}
236
-
237
- {description && (
238
- <p class="mb-vsp-lg text-title text-muted">{description}</p>
239
- )}
240
- <NavCardGrid children={autoIndexChildren ?? []} />
241
- </>
242
- ) : (
243
- /* Regular doc page. Fragment (not <div>) for the same reason as
244
- the auto-index branch above — see #1460. */
245
- <>
246
- {contentHeaderSlot}
247
-
248
- {contentSlot}
249
-
250
- {/* Prev / Next pagination — placed before the document utilities
251
- section to match the Astro reference order: content → pager →
252
- view-source / history. Fixes #1535. */}
253
- <DocPager prev={prev} next={next} locale={locale} />
254
15
 
255
- {/* Document utilities (revision history + view-source link).
256
- Threaded in via docHistorySlot; null on versioned pages
257
- until versioned history is supported (#1916 #5). */}
258
- {docHistorySlot}
259
- </>
260
- )}
261
- </DocLayoutWithDefaults>
262
- );
263
- }
16
+ export type { DocPageShellProps } from "@takazudo/zudo-doc/doc-page-shell";
17
+
18
+ export const DocPageShell = createDocPageShell({
19
+ settings,
20
+ composeMetaTitle,
21
+ getTocTitle,
22
+ HeadWithDefaults,
23
+ SidebarWithDefaults,
24
+ HeaderWithDefaults,
25
+ FooterWithDefaults,
26
+ SidebarPrepaint,
27
+ DocBodyEnd,
28
+ DocPager,
29
+ });
@@ -1,79 +1,9 @@
1
1
  /** @jsxRuntime automatic */
2
2
  /** @jsxImportSource preact */
3
- // Shared prev/next pager <nav> for doc pages.
4
- //
5
- // Extracted from the four doc-route render bodies (pages/docs/[...slug].tsx,
6
- // pages/[locale]/docs/[...slug].tsx, pages/v/[version]/docs/[...slug].tsx,
7
- // pages/v/[version]/[locale]/docs/[...slug].tsx) where the block was
8
- // duplicated verbatim.
9
- //
10
- // Uses ChevronLeft / ChevronRight from the shared icon module
11
- // (@takazudo/zudo-doc/icons) rather than hand-written SVG paths, absorbing
12
- // the last inline chevron occurrences in the route files (see #1880 item 4).
13
-
14
- import type { JSX } from "preact";
3
+ // Host thin-stub — see @takazudo/zudo-doc/doc-pager (epic #2344, S7).
15
4
  import { t } from "@/config/i18n";
16
- import { ChevronLeft, ChevronRight } from "@takazudo/zudo-doc/icons";
17
-
18
- // NavNode is a superset; we only need the fields the pager uses.
19
- interface PagerNode {
20
- href?: string;
21
- label: string;
22
- }
5
+ import { createDocPager } from "@takazudo/zudo-doc/doc-pager";
23
6
 
24
- interface DocPagerProps {
25
- /** Previous page node (null = no previous page → renders placeholder). */
26
- prev: PagerNode | null;
27
- /** Next page node (null = no next page → renders placeholder). */
28
- next: PagerNode | null;
29
- /** Active locale for translated "Previous" / "Next" labels. */
30
- locale: string;
31
- }
7
+ export type { DocPagerProps } from "@takazudo/zudo-doc/doc-pager";
32
8
 
33
- /**
34
- * Prev/next pagination nav shared by all four doc-route page components.
35
- *
36
- * Renders a two-column grid: prev card on the left, next card on the right.
37
- * When a node is absent its slot is filled with an empty `<div>` to maintain
38
- * the two-column layout. Placement: immediately after MDX content, before
39
- * `DocHistoryArea` (Astro reference order — content → pager → utilities,
40
- * per #1535).
41
- */
42
- export function DocPager({ prev, next, locale }: DocPagerProps): JSX.Element {
43
- return (
44
- <nav class="mt-vsp-2xl grid grid-cols-2 gap-hsp-xl">
45
- {prev ? (
46
- <a
47
- href={prev.href}
48
- class="group border border-muted rounded-lg p-hsp-lg hover:border-accent"
49
- >
50
- <div class="flex items-center gap-hsp-xs text-caption text-muted mb-vsp-2xs">
51
- <ChevronLeft className="h-[1.125rem] w-[1.125rem]" />
52
- <span class="no-underline">{t("nav.previous", locale)}</span>
53
- </div>
54
- <p class="text-small font-semibold underline group-hover:text-accent">
55
- {prev.label}
56
- </p>
57
- </a>
58
- ) : (
59
- <div />
60
- )}
61
- {next ? (
62
- <a
63
- href={next.href}
64
- class="group border border-muted rounded-lg p-hsp-lg hover:border-accent text-right"
65
- >
66
- <div class="flex items-center justify-end gap-hsp-xs text-caption text-muted mb-vsp-2xs">
67
- <span class="no-underline">{t("nav.next", locale)}</span>
68
- <ChevronRight className="h-[1.125rem] w-[1.125rem]" />
69
- </div>
70
- <p class="text-small font-semibold underline group-hover:text-accent">
71
- {next.label}
72
- </p>
73
- </a>
74
- ) : (
75
- <div />
76
- )}
77
- </nav>
78
- );
79
- }
9
+ export const DocPager = createDocPager({ t });
@@ -1,188 +1,54 @@
1
- // Shared, memoized route-entry builder for the 4 doc catch-all routes.
2
- //
3
- // Extracted (#2010) from the ~85%-duplicated paths() bodies of:
4
- // pages/docs/[[...slug]].tsx
5
- // pages/[locale]/docs/[[...slug]].tsx
6
- // pages/v/[version]/docs/[[...slug]].tsx
7
- // pages/v/[version]/[locale]/docs/[[...slug]].tsx
8
- //
9
- // Each route resolves its own identity-stable nav source (resolveNavSource /
10
- // resolveVersionedLocaleSource) and URL closure, then delegates the per-entry
11
- // derived-data work here. The result is memoized with the #1902 WeakMap
12
- // pattern (memoizeDerived keyed on the identity-stable `source.docs` array +
13
- // a per-route signature), so the expensive per-entry work — extractHeadings,
14
- // buildBreadcrumbs, prev/next resolution — runs ONCE per entry per build,
15
- // not once per entry per page (zfb re-invokes paths() once per built page).
16
- //
17
- // Versioned-vs-latest behavior is keyed on the presence of `urlFor` (#1916):
18
- // - `urlFor` set (versioned routes): breadcrumbs resolve against the NAV
19
- // tree (unlisted excluded) with crumbs remapped to the versioned URL
20
- // space; prev/next hrefs are rewritten through the closure; auto-index
21
- // child-card hrefs are ALWAYS remapped to the versioned URL.
22
- // - `urlFor` unset (latest routes): breadcrumbs resolve against the FULL
23
- // tree (unlisted included, for accurate crumbs); prev/next and child
24
- // hrefs keep the latest `docsUrl` already baked into the nav nodes.
25
- // These two behaviors travel together by construction: only versioned routes
26
- // own a versioned URL closure (see _doc-route-paths.ts for the #1916
27
- // rationale on why latest routes must never receive one).
28
-
1
+ // Thin stub — doc-route-entries moved to the package (epic #2344, S6).
2
+ // Calls `createDocRouteEntries(ctx)` from @takazudo/zudo-doc/doc-route-entries
3
+ // with the host utilities injected, then re-exports the resulting builder
4
+ // function so all existing call sites continue to work unchanged.
5
+
6
+ import { createDocRouteEntries } from "@takazudo/zudo-doc/doc-route-entries";
7
+ import type {
8
+ DocPageEntry,
9
+ DocNavNode,
10
+ BreadcrumbItem,
11
+ } from "@takazudo/zudo-doc/doc-route-entries";
12
+ export type { DocRouteEntry, BuildDocRouteEntriesArgs } from "@takazudo/zudo-doc/doc-route-entries";
29
13
  import {
30
14
  buildNavTree,
31
15
  buildBreadcrumbs,
32
16
  collectAutoIndexNodes,
33
17
  type NavNode,
18
+ type CategoryMeta,
34
19
  } from "@/utils/docs";
35
20
  import { getNavSectionForSlug, getNavSubtree } from "@/utils/nav-scope";
36
21
  import { toRouteSlug, toSlugParams } from "@/utils/slug";
22
+ import type { DocsEntry } from "@/types/docs-entry";
37
23
  import type { Locale } from "@/config/i18n";
38
24
  import { extractHeadings } from "./_extract-headings";
39
- import type { AutoIndexNode, DocPageBaseProps } from "./doc-page-props";
40
- import { memoizeDerived } from "./_nav-source-cache";
41
- import type { NavSourceDocs } from "./_nav-source-docs";
42
- import {
43
- resolveDocPrevNext,
44
- flattenSubtree,
45
- rewriteNavHref,
46
- remapNavChildHrefs,
47
- } from "./_doc-route-paths";
48
-
49
- // ---------------------------------------------------------------------------
50
- // Types
51
- // ---------------------------------------------------------------------------
52
-
53
- /** One enumerated doc route: a content entry or an auto-generated category
54
- * index, with all per-page derived data pre-computed. */
55
- export interface DocRouteEntry {
56
- /** Canonical route slug ("" for the docs root index — #1891). */
57
- slug: string;
58
- /** Optional-catchall params array — `toSlugParams(slug)` ([] for the root). */
59
- slugParams: string[];
60
- /**
61
- * True when the entry came from the base collection rather than the locale
62
- * collection (`!localeSlugSet.has(slug)`). Only meaningful on routes whose
63
- * nav source performs a locale merge — routes without one (default-locale /
64
- * versioned-EN, where `localeSlugSet` is empty) must ignore this field.
65
- * Always false for autoIndex items.
66
- */
67
- isFallback: boolean;
68
- /** Shared page props (kind/entry/autoIndex/breadcrumbs/prev/next/headings). */
69
- props: DocPageBaseProps;
70
- }
71
-
72
- export interface BuildDocRouteEntriesArgs {
73
- /** Identity-stable nav source for this route's (locale, version) context —
74
- * from resolveNavSource / resolveVersionedLocaleSource. The memo is keyed
75
- * on `source.docs` identity, so the source MUST come from those resolvers
76
- * (a fresh array defeats the memo — harmless, but recomputes per call). */
77
- source: NavSourceDocs;
78
- /** Active locale for nav-tree labels and breadcrumbs. */
79
- locale: Locale;
80
- /**
81
- * Unique memo signature for this route context. Each route file passes its
82
- * own prefix plus the loop variables (version slug / locale), e.g.
83
- * "docs;en", "locale-docs;ja", "v-docs;1.0", "v-locale-docs;1.0;ja" —
84
- * call sites that share a docs array identity must never collide on a key.
85
- */
86
- routeSig: string;
87
- /** Versioned URL closure bound to the route's version (+ locale). Presence
88
- * switches the versioned behaviors documented in the module header. */
89
- urlFor?: (slug: string) => string;
90
- }
91
-
92
- // ---------------------------------------------------------------------------
93
- // buildDocRouteEntries
94
- // ---------------------------------------------------------------------------
95
-
96
- /**
97
- * Enumerate all doc routes (content entries + auto-index pages) for one
98
- * (locale, version) context, with per-entry derived data pre-computed.
99
- *
100
- * Memoized per build on the identity-stable `source.docs` array (#1902), so
101
- * repeated paths() invocations across the route's many pages return the SAME
102
- * array instance without redoing the per-entry work. In the no-snapshot
103
- * fallback path (unit tests / direct Node runs) `source.docs` is a fresh
104
- * array per call, so the memo misses and this computes fresh — matching the
105
- * deliberate no-memo policy in _nav-source-cache.ts.
106
- */
107
- export function buildDocRouteEntries(
108
- args: BuildDocRouteEntriesArgs,
109
- ): DocRouteEntry[] {
110
- const { source, locale, routeSig, urlFor } = args;
111
-
112
- return memoizeDerived([source.docs], `docRouteEntries;${routeSig}`, () => {
113
- const { docs, navDocs, categoryMeta, localeSlugSet } = source;
114
-
115
- // Nav docs: exclude unlisted (for sidebar/prev-next) but keep for breadcrumbs
116
- const tree = buildNavTree(navDocs, locale, categoryMeta);
117
- // Breadcrumb tree: latest routes use the full tree (including unlisted)
118
- // for accurate crumbs; versioned routes resolve crumbs against the nav
119
- // tree itself (#1916 #1).
120
- const breadcrumbTree = urlFor ? tree : buildNavTree(docs, locale, categoryMeta);
121
-
122
- const result: DocRouteEntry[] = [];
123
-
124
- // Regular doc pages
125
- for (const entry of docs) {
126
- // A `category_no_page` index.mdx carries category metadata only — keep
127
- // it in the nav tree (built above, used for breadcrumbs) but emit NO
128
- // route for it. zfb's walker retains every .mdx as a collection entry,
129
- // so without this explicit skip the metadata file would silently add a
130
- // route.
131
- if (entry.data.category_no_page === true) continue;
132
- // Canonical route slug via the one shared rule (@/utils/slug) — yields
133
- // "" for a root index (URL /docs/ — #1891).
134
- const slug = entry.data.slug ?? toRouteSlug(entry.slug);
135
- const navSection = getNavSectionForSlug(slug);
136
- const subtree = getNavSubtree(tree, navSection);
137
-
138
- // Prev/next + frontmatter pagination overrides resolved against THIS
139
- // route's own `tree`; versioned routes then rewrite the hrefs through
140
- // their urlFor closure (latest routes pass it through unchanged).
141
- const { prev: prevNode, next: nextNode } = resolveDocPrevNext(
142
- tree,
143
- flattenSubtree(subtree),
144
- slug,
145
- entry.data,
146
- );
147
-
148
- result.push({
149
- slug,
150
- slugParams: toSlugParams(slug),
151
- isFallback: !localeSlugSet.has(slug),
152
- props: {
153
- kind: "entry",
154
- entry,
155
- breadcrumbs: buildBreadcrumbs(breadcrumbTree, slug, locale, urlFor),
156
- prev: rewriteNavHref(prevNode, urlFor),
157
- next: rewriteNavHref(nextNode, urlFor),
158
- headings: extractHeadings(entry.body ?? ""),
159
- },
160
- });
161
- }
162
-
163
- // Auto-generated index pages for categories without index.mdx
164
- for (const node of collectAutoIndexNodes(tree)) {
165
- result.push({
166
- slug: node.slug,
167
- slugParams: toSlugParams(node.slug),
168
- isFallback: false,
169
- props: {
170
- kind: "autoIndex",
171
- autoIndex: urlFor
172
- ? // #1916 #2: child-card hrefs ALWAYS resolve to the versioned URL.
173
- ({
174
- ...node,
175
- children: remapNavChildHrefs(node.children, urlFor) as NavNode[],
176
- } as AutoIndexNode)
177
- : (node as AutoIndexNode),
178
- breadcrumbs: buildBreadcrumbs(breadcrumbTree, node.slug, locale, urlFor),
179
- prev: null,
180
- next: null,
181
- headings: [],
182
- },
183
- });
184
- }
185
25
 
186
- return result;
187
- });
188
- }
26
+ export const { buildDocRouteEntries } = createDocRouteEntries({
27
+ // The factory describes its injected nav builders with the package's own
28
+ // structural counterparts (DocPageEntry / DocNavNode / Map<string, unknown>)
29
+ // and a plain `locale: string`. The host's buildNavTree / buildBreadcrumbs
30
+ // are typed against the concrete project types (DocsEntry / NavNode / the
31
+ // Locale union / Map<string, CategoryMeta>). They are runtime-identical, so
32
+ // the stub adapts them with thin wrappers that cast at the injection boundary
33
+ // where the host owns the type knowledge.
34
+ buildNavTree: (docs: DocPageEntry[], locale: string, categoryMeta: Map<string, unknown>) =>
35
+ buildNavTree(
36
+ docs as unknown as DocsEntry[],
37
+ locale as Locale,
38
+ categoryMeta as Map<string, CategoryMeta>,
39
+ ) as DocNavNode[],
40
+ buildBreadcrumbs: (
41
+ tree: DocNavNode[],
42
+ slug: string,
43
+ locale: string,
44
+ urlFor?: (slug: string) => string,
45
+ ): BreadcrumbItem[] =>
46
+ buildBreadcrumbs(tree as NavNode[], slug, locale as Locale, urlFor),
47
+ collectAutoIndexNodes: (tree: DocNavNode[]) =>
48
+ collectAutoIndexNodes(tree as NavNode[]) as DocNavNode[],
49
+ getNavSectionForSlug,
50
+ getNavSubtree,
51
+ toRouteSlug,
52
+ toSlugParams,
53
+ extractHeadings,
54
+ });