create-zudo-doc 0.1.0 → 0.2.0-next.1

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 (64) hide show
  1. package/dist/compose.d.ts +11 -9
  2. package/dist/compose.js +13 -11
  3. package/dist/features/design-token-panel.d.ts +6 -8
  4. package/dist/features/design-token-panel.js +6 -8
  5. package/dist/features/footer-taglist.d.ts +2 -2
  6. package/dist/features/footer-taglist.js +2 -2
  7. package/dist/features/image-enlarge.d.ts +11 -0
  8. package/dist/features/image-enlarge.js +188 -1
  9. package/dist/features/versioning.d.ts +5 -5
  10. package/dist/features/versioning.js +5 -5
  11. package/dist/index.js +8 -0
  12. package/dist/prompts.d.ts +2 -0
  13. package/dist/prompts.js +1 -0
  14. package/dist/scaffold.js +45 -11
  15. package/dist/settings-gen.js +13 -1
  16. package/dist/zfb-config-gen.js +57 -0
  17. package/package.json +4 -3
  18. package/templates/base/pages/404.tsx +1 -1
  19. package/templates/base/pages/_mdx-components.ts +34 -60
  20. package/templates/base/pages/docs/[...slug].tsx +4 -4
  21. package/templates/base/pages/index.tsx +13 -6
  22. package/templates/base/pages/lib/_category-nav.tsx +1 -1
  23. package/templates/base/pages/lib/_category-tree-nav.tsx +1 -1
  24. package/templates/base/pages/lib/_details.tsx +3 -4
  25. package/templates/base/pages/lib/_doc-history-area.tsx +3 -3
  26. package/templates/base/pages/lib/_doc-metainfo-area.tsx +3 -4
  27. package/templates/base/pages/lib/_doc-tags-area.tsx +3 -4
  28. package/templates/base/pages/lib/_footer-with-defaults.tsx +2 -5
  29. package/templates/base/pages/lib/_head-with-defaults.tsx +32 -15
  30. package/templates/base/pages/lib/_header-with-defaults.tsx +22 -24
  31. package/templates/base/pages/lib/_search-widget-script.ts +3 -5
  32. package/templates/base/pages/lib/_search-widget.tsx +1 -2
  33. package/templates/base/pages/lib/_sidebar-with-defaults.tsx +6 -7
  34. package/templates/base/pages/lib/_site-tree-nav.tsx +5 -10
  35. package/templates/base/pages/lib/locale-merge.ts +2 -3
  36. package/templates/base/pages/lib/route-enumerators.ts +3 -1
  37. package/templates/base/src/components/content/code-group.tsx +76 -0
  38. package/templates/base/src/components/content/content-admonition.tsx +56 -0
  39. package/templates/base/src/components/content/content-code.tsx +1 -1
  40. package/templates/base/src/components/sidebar-tree.tsx +3 -4
  41. package/templates/base/src/components/site-tree-nav.tsx +3 -4
  42. package/templates/base/src/plugins/rehype-heading-links.ts +3 -3
  43. package/templates/base/src/styles/global.css +70 -6
  44. package/templates/base/src/types/locale.ts +1 -1
  45. package/templates/base/src/utils/base.ts +2 -2
  46. package/templates/base/src/utils/content-files.ts +4 -0
  47. package/templates/base/src/utils/docs.ts +4 -2
  48. package/templates/features/designTokenPanel/files/src/config/design-token-panel-config.ts +205 -42
  49. package/templates/features/designTokenPanel/files/src/config/design-tokens-manifest.ts +48 -52
  50. package/templates/features/designTokenPanel/files/src/lib/design-token-panel-bootstrap.ts +18 -19
  51. package/templates/features/docTags/files/pages/[locale]/docs/tags/[tag].tsx +1 -1
  52. package/templates/features/docTags/files/pages/[locale]/docs/tags/index.tsx +4 -4
  53. package/templates/features/docTags/files/pages/docs/tags/[tag].tsx +1 -1
  54. package/templates/features/docTags/files/pages/docs/tags/index.tsx +2 -2
  55. package/templates/features/i18n/files/pages/[locale]/docs/[...slug].tsx +4 -4
  56. package/templates/features/i18n/files/pages/[locale]/index.tsx +12 -5
  57. package/templates/features/imageEnlarge/files/src/components/image-enlarge.tsx +8 -3
  58. package/templates/features/sidebarResizer/files/src/scripts/sidebar-resizer.ts +21 -8
  59. package/templates/features/tauri/files/src/components/find-in-page-init.tsx +1 -1
  60. package/templates/features/versioning/files/pages/[locale]/docs/versions.tsx +1 -1
  61. package/templates/features/versioning/files/pages/docs/versions.tsx +1 -1
  62. package/templates/features/versioning/files/pages/v/[version]/docs/[...slug].tsx +4 -4
  63. package/templates/features/versioning/files/pages/v/[version]/ja/docs/[...slug].tsx +3 -3
  64. package/templates/base/src/plugins/rehype-image-enlarge.ts +0 -113
package/dist/compose.d.ts CHANGED
@@ -70,15 +70,17 @@ export declare function resolveSelectedFeatures(choices: UserChoices, featureMod
70
70
  export declare function validateDependencies(features: FeatureDefinition[], allSelectedNames: Set<string>): void;
71
71
  /** Files that may contain injection anchors and need cleaning.
72
72
  *
73
- * W7A (#1736): the two `.astro` entries were dropped — those files no
74
- * longer exist in generated projects after the post-cutover .tsx
75
- * migration. The only surviving anchor target is `global.css`, where
76
- * `design-token-panel.ts` injects `@import "@takazudo/zdtp/styles.css";`
77
- * at `@slot:global-css:feature-styles`. The sibling
78
- * `@slot:global-css:theme-tokens` anchor in the same file is consumed
79
- * by the color-scheme palette generator and must remain. The .tsx
80
- * anchor form is still supported in `ANCHOR_LINE_RE` for forward
81
- * compatibility, but no current feature uses it.
73
+ * The anchor targets today are:
74
+ * - `global.css` design-token-panel.ts injects
75
+ * `@import "@takazudo/zdtp/styles.css";` at `@slot:global-css:feature-styles`.
76
+ * The sibling `@slot:global-css:theme-tokens` anchor is consumed by the
77
+ * color-scheme palette generator and must remain.
78
+ * - `pages/_mdx-components.ts` image-enlarge.ts injects the
79
+ * EnlargeableParagraph p-override (ENLARGE_SVG, EnlargeableParagraph def,
80
+ * `p:` map entry) when imageEnlarge is enabled.
81
+ *
82
+ * The .tsx anchor form is still supported in `ANCHOR_LINE_RE` for forward
83
+ * compatibility.
82
84
  */
83
85
  export declare const ANCHOR_FILES: string[];
84
86
  /**
package/dist/compose.js CHANGED
@@ -10,7 +10,7 @@ import path from "path";
10
10
  * - `// @slot:…` — TypeScript/JS line comment (module scope)
11
11
  * - `/* @slot:… *\/` — block comment
12
12
  * - `{/* @slot:… *\/}` — JSX expression comment (body region in .tsx)
13
- * - `<!-- @slot:… -->` — HTML comment (legacy .astro body region)
13
+ * - `<!-- @slot:… -->` — HTML comment (supported in case future template files use HTML comments)
14
14
  * - `# @slot:…` — shell / YAML comment
15
15
  */
16
16
  const ANCHOR_LINE_RE = /^[ \t]*(?:\{\/\*|\/\/|\/\*|<!--|#)\s*@slot:[^\n]*(?:\*\/\}|\*\/|-->)?[ \t]*\r?\n?$/gm;
@@ -156,17 +156,19 @@ export function validateDependencies(features, allSelectedNames) {
156
156
  }
157
157
  /** Files that may contain injection anchors and need cleaning.
158
158
  *
159
- * W7A (#1736): the two `.astro` entries were dropped — those files no
160
- * longer exist in generated projects after the post-cutover .tsx
161
- * migration. The only surviving anchor target is `global.css`, where
162
- * `design-token-panel.ts` injects `@import "@takazudo/zdtp/styles.css";`
163
- * at `@slot:global-css:feature-styles`. The sibling
164
- * `@slot:global-css:theme-tokens` anchor in the same file is consumed
165
- * by the color-scheme palette generator and must remain. The .tsx
166
- * anchor form is still supported in `ANCHOR_LINE_RE` for forward
167
- * compatibility, but no current feature uses it.
159
+ * The anchor targets today are:
160
+ * - `global.css` design-token-panel.ts injects
161
+ * `@import "@takazudo/zdtp/styles.css";` at `@slot:global-css:feature-styles`.
162
+ * The sibling `@slot:global-css:theme-tokens` anchor is consumed by the
163
+ * color-scheme palette generator and must remain.
164
+ * - `pages/_mdx-components.ts` image-enlarge.ts injects the
165
+ * EnlargeableParagraph p-override (ENLARGE_SVG, EnlargeableParagraph def,
166
+ * `p:` map entry) when imageEnlarge is enabled.
167
+ *
168
+ * The .tsx anchor form is still supported in `ANCHOR_LINE_RE` for forward
169
+ * compatibility.
168
170
  */
169
- export const ANCHOR_FILES = ["src/styles/global.css"];
171
+ export const ANCHOR_FILES = ["src/styles/global.css", "pages/_mdx-components.ts"];
170
172
  /**
171
173
  * Main composition entry point. Orchestrates the full feature composition
172
174
  * pipeline for a generated project.
@@ -2,13 +2,11 @@ import type { FeatureModule } from "../compose.js";
2
2
  /**
3
3
  * Design-token-panel (zdtp) feature.
4
4
  *
5
- * W7A (#1736): keeps the single surviving inject() — the zdtp CSS @import
6
- * at `@slot:global-css:feature-styles`. The two dead .astro injections
7
- * (doc-layout bootstrap import + header trigger button) are dropped:
8
- * the bootstrap is loaded by `pages/lib/design-token-panel-bootstrap`-side
9
- * effect when the feature is enabled, and the header trigger is now
10
- * rendered by `pages/lib/_header-with-defaults.tsx` from the
11
- * `settings.headerRightItems` entry `{ type: "trigger", trigger:
12
- * "design-token-panel" }`.
5
+ * Injects the zdtp CSS @import at `@slot:global-css:feature-styles` in
6
+ * `src/styles/global.css`. The bootstrap is loaded by
7
+ * `pages/lib/design-token-panel-bootstrap` as a side effect when the
8
+ * feature is enabled, and the header trigger is rendered by
9
+ * `pages/lib/_header-with-defaults.tsx` from the `settings.headerRightItems`
10
+ * entry `{ type: "trigger", trigger: "design-token-panel" }`.
13
11
  */
14
12
  export declare const designTokenPanelFeature: FeatureModule;
@@ -1,14 +1,12 @@
1
1
  /**
2
2
  * Design-token-panel (zdtp) feature.
3
3
  *
4
- * W7A (#1736): keeps the single surviving inject() — the zdtp CSS @import
5
- * at `@slot:global-css:feature-styles`. The two dead .astro injections
6
- * (doc-layout bootstrap import + header trigger button) are dropped:
7
- * the bootstrap is loaded by `pages/lib/design-token-panel-bootstrap`-side
8
- * effect when the feature is enabled, and the header trigger is now
9
- * rendered by `pages/lib/_header-with-defaults.tsx` from the
10
- * `settings.headerRightItems` entry `{ type: "trigger", trigger:
11
- * "design-token-panel" }`.
4
+ * Injects the zdtp CSS @import at `@slot:global-css:feature-styles` in
5
+ * `src/styles/global.css`. The bootstrap is loaded by
6
+ * `pages/lib/design-token-panel-bootstrap` as a side effect when the
7
+ * feature is enabled, and the header trigger is rendered by
8
+ * `pages/lib/_header-with-defaults.tsx` from the `settings.headerRightItems`
9
+ * entry `{ type: "trigger", trigger: "design-token-panel" }`.
12
10
  */
13
11
  export const designTokenPanelFeature = () => ({
14
12
  name: "designTokenPanel",
@@ -4,10 +4,10 @@ import type { FeatureModule } from "../compose.js";
4
4
  *
5
5
  * Purely a settings toggle: `settings-gen.ts` emits
6
6
  * `footer.taglist = { enabled: true, groupBy: "group" }` when selected,
7
- * and the existing `footer.astro` (part of the footer pseudo-feature) reads
7
+ * and the footer component (part of the footer pseudo-feature) reads
8
8
  * `settings.footer.taglist` to decide whether to render the column(s).
9
9
  *
10
- * `footer.astro` is only installed by the footer pseudo-feature, so
10
+ * The footer component is only installed by the footer pseudo-feature, so
11
11
  * `resolveSelectedFeatures` treats `footerTaglist` as one of the triggers
12
12
  * for that feature.
13
13
  */
@@ -3,10 +3,10 @@
3
3
  *
4
4
  * Purely a settings toggle: `settings-gen.ts` emits
5
5
  * `footer.taglist = { enabled: true, groupBy: "group" }` when selected,
6
- * and the existing `footer.astro` (part of the footer pseudo-feature) reads
6
+ * and the footer component (part of the footer pseudo-feature) reads
7
7
  * `settings.footer.taglist` to decide whether to render the column(s).
8
8
  *
9
- * `footer.astro` is only installed by the footer pseudo-feature, so
9
+ * The footer component is only installed by the footer pseudo-feature, so
10
10
  * `resolveSelectedFeatures` treats `footerTaglist` as one of the triggers
11
11
  * for that feature.
12
12
  */
@@ -7,5 +7,16 @@ import type { FeatureModule } from "../compose.js";
7
7
  * always-loaded stub-or-real ImageEnlarge component). Image-enlarge CSS
8
8
  * lives unconditionally in `templates/base/src/styles/global.css` — the
9
9
  * selectors only activate when the runtime mounts the .zd-enlarge-btn.
10
+ *
11
+ * S2 (#1825): after zfb next.18 removed the built-in imageEnlarge Rust
12
+ * feature, the server-side figure/button emission is re-implemented via an
13
+ * MDX paragraph (p) component override in pages/_mdx-components.ts. When
14
+ * imageEnlarge is enabled, three injections into the template file install:
15
+ * 1. Additional imports: toChildArray + VNode from preact, settings.
16
+ * 2. ENLARGE_SVG const + EnlargeableParagraph function definition.
17
+ * 3. `p: EnlargeableParagraph` entry in the createMdxComponents return map.
18
+ * When imageEnlarge is OFF, none of these are injected, so the override is
19
+ * absent and paragraphs render plain (the Rust built-in is gone — "off" must
20
+ * mean no wrapping at all).
10
21
  */
11
22
  export declare const imageEnlargeFeature: FeatureModule;
@@ -6,8 +6,195 @@
6
6
  * always-loaded stub-or-real ImageEnlarge component). Image-enlarge CSS
7
7
  * lives unconditionally in `templates/base/src/styles/global.css` — the
8
8
  * selectors only activate when the runtime mounts the .zd-enlarge-btn.
9
+ *
10
+ * S2 (#1825): after zfb next.18 removed the built-in imageEnlarge Rust
11
+ * feature, the server-side figure/button emission is re-implemented via an
12
+ * MDX paragraph (p) component override in pages/_mdx-components.ts. When
13
+ * imageEnlarge is enabled, three injections into the template file install:
14
+ * 1. Additional imports: toChildArray + VNode from preact, settings.
15
+ * 2. ENLARGE_SVG const + EnlargeableParagraph function definition.
16
+ * 3. `p: EnlargeableParagraph` entry in the createMdxComponents return map.
17
+ * When imageEnlarge is OFF, none of these are injected, so the override is
18
+ * absent and paragraphs render plain (the Rust built-in is gone — "off" must
19
+ * mean no wrapping at all).
9
20
  */
10
21
  export const imageEnlargeFeature = () => ({
11
22
  name: "imageEnlarge",
12
- injections: [],
23
+ injections: [
24
+ // 1. Import additions: toChildArray + VNode from preact, settings.
25
+ // Inserted AFTER the `// @slot:mdx-components:enlarge-imports` anchor.
26
+ {
27
+ file: "pages/_mdx-components.ts",
28
+ anchor: "// @slot:mdx-components:enlarge-imports",
29
+ position: "after",
30
+ content: `import { toChildArray } from "preact";
31
+ import type { VNode } from "preact";
32
+ import { settings } from "@/config/settings";`,
33
+ },
34
+ // 2. ENLARGE_SVG const + EnlargeableParagraph function.
35
+ // Inserted AFTER the `// @slot:mdx-components:enlarge-defs` anchor
36
+ // (which sits just before the `createMdxComponents` JSDoc comment).
37
+ // Markup is ported verbatim from rehype-image-enlarge.ts makeEnlargeButton()
38
+ // so the island's eligibility/[hidden] logic and CSS keep working identically.
39
+ {
40
+ file: "pages/_mdx-components.ts",
41
+ anchor: "// @slot:mdx-components:enlarge-defs",
42
+ position: "after",
43
+ content: `/**
44
+ * SVG icon for the image-enlarge button (4-corner-arrows).
45
+ *
46
+ * Ported verbatim from
47
+ * packages/create-zudo-doc/templates/base/src/plugins/rehype-image-enlarge.ts
48
+ * makeEnlargeButton() — this is the same icon the old Rust plugin emitted.
49
+ * Must match exactly so the existing .zd-enlarge-btn CSS and the
50
+ * image-enlarge island (src/components/image-enlarge.tsx) keep working.
51
+ *
52
+ * Attribute spellings: HTML/Preact conventions — \`focusable\` stays a string
53
+ * ("false") because Preact's preact-render-to-string drops boolean false;
54
+ * \`aria-hidden\` is the HTML attribute name (not ariaHidden).
55
+ */
56
+ const ENLARGE_SVG = {
57
+ type: "svg",
58
+ props: {
59
+ viewBox: "0 0 38.99 38.99",
60
+ fill: "currentColor",
61
+ focusable: "false",
62
+ "aria-hidden": "true",
63
+ children: [
64
+ {
65
+ type: "polygon",
66
+ props: {
67
+ points:
68
+ "16.2 13.74 5.92 3.47 11.2 3.47 11.2 0 3.47 0 0 0 0 3.47 0 11.2 3.47 11.2 3.47 5.92 13.74 16.2 16.2 13.74",
69
+ },
70
+ key: null,
71
+ constructor: undefined,
72
+ },
73
+ {
74
+ type: "polygon",
75
+ props: {
76
+ points:
77
+ "25.24 16.2 35.52 5.92 35.52 11.2 38.99 11.2 38.99 3.47 38.99 0 35.52 0 27.79 0 27.79 3.47 33.07 3.47 22.79 13.74 25.24 16.2",
78
+ },
79
+ key: null,
80
+ constructor: undefined,
81
+ },
82
+ {
83
+ type: "polygon",
84
+ props: {
85
+ points:
86
+ "22.79 25.24 33.07 35.52 27.79 35.52 27.79 38.99 35.52 38.99 38.99 38.99 38.99 35.52 38.99 27.79 35.52 27.79 35.52 33.07 25.24 22.79 22.79 25.24",
87
+ },
88
+ key: null,
89
+ constructor: undefined,
90
+ },
91
+ {
92
+ type: "polygon",
93
+ props: {
94
+ points:
95
+ "13.74 22.79 3.47 33.07 3.47 27.79 0 27.79 0 35.52 0 38.99 3.47 38.99 11.2 38.99 11.2 35.52 5.92 35.52 16.2 25.24 13.74 22.79",
96
+ },
97
+ key: null,
98
+ constructor: undefined,
99
+ },
100
+ ],
101
+ },
102
+ key: null,
103
+ constructor: undefined,
104
+ };
105
+
106
+ /**
107
+ * Enlarge-aware MDX paragraph override.
108
+ *
109
+ * When \`settings.imageEnlarge\` is enabled and a paragraph contains exactly
110
+ * one non-whitespace child that is a block-level image VNode (type ===
111
+ * ContentImg or "img"), this wraps the image in:
112
+ * <figure class="zd-enlargeable">
113
+ * <img ...>
114
+ * <button type="button" class="zd-enlarge-btn" hidden aria-label="Enlarge image">
115
+ * <svg ...>…</svg>
116
+ * </button>
117
+ * </figure>
118
+ *
119
+ * The \`title="no-enlarge"\` opt-out is read from the un-rendered VNode
120
+ * (Preact's h() is lazy — child.type is still the ContentImg function, not
121
+ * yet called). ContentImg strips the sentinel from the rendered img DOM.
122
+ *
123
+ * All other paragraphs delegate to htmlOverrides.p (ContentParagraph passthrough).
124
+ */
125
+ function EnlargeableParagraph(props: {
126
+ children?: ComponentChildren;
127
+ [key: string]: unknown;
128
+ }): unknown {
129
+ const { children, ...rest } = props;
130
+ // Collect children and drop whitespace-only text nodes.
131
+ const kids = toChildArray(children).filter((child) => {
132
+ if (typeof child === "string" || typeof child === "number") {
133
+ return String(child).trim() !== "";
134
+ }
135
+ return true;
136
+ });
137
+
138
+ // Check for a single-image block paragraph eligible for enlarge wrapping.
139
+ if (settings.imageEnlarge && kids.length === 1) {
140
+ const kid = kids[0];
141
+ // VNode type guard: must be an object with a \`type\` property.
142
+ if (
143
+ kid !== null &&
144
+ typeof kid === "object" &&
145
+ "type" in kid &&
146
+ "props" in kid
147
+ ) {
148
+ const vnode = kid as VNode<Record<string, unknown>>;
149
+ if (vnode.type === ContentImg || vnode.type === "img") {
150
+ const imgProps = (vnode.props ?? {}) as Record<string, unknown>;
151
+ // Opt-out: title="no-enlarge" — render plain paragraph (ContentImg
152
+ // will strip the sentinel title from the actual img DOM).
153
+ if (imgProps.title !== "no-enlarge") {
154
+ // Wrap in figure.zd-enlargeable with the enlarge button.
155
+ const enlargeBtn = {
156
+ type: "button",
157
+ props: {
158
+ type: "button",
159
+ class: "zd-enlarge-btn",
160
+ hidden: true,
161
+ "aria-label": "Enlarge image",
162
+ children: ENLARGE_SVG,
163
+ },
164
+ key: null,
165
+ constructor: undefined,
166
+ };
167
+ return {
168
+ type: "figure",
169
+ props: {
170
+ class: "zd-enlargeable",
171
+ children: [vnode, enlargeBtn],
172
+ },
173
+ key: null,
174
+ constructor: undefined,
175
+ };
176
+ }
177
+ }
178
+ }
179
+ }
180
+
181
+ // Fallback: delegate to the standard ContentParagraph passthrough.
182
+ return (htmlOverrides.p as (props: unknown) => unknown)(props);
183
+ }
184
+ `,
185
+ },
186
+ // 3. p: EnlargeableParagraph entry in createMdxComponents return map.
187
+ // Inserted AFTER the `// @slot:mdx-components:enlarge-p-entry` anchor
188
+ // (which sits between `img: ContentImg,` and `HtmlPreview:`).
189
+ // Must come AFTER the ...htmlOverrides spread to override ContentParagraph.
190
+ {
191
+ file: "pages/_mdx-components.ts",
192
+ anchor: "// @slot:mdx-components:enlarge-p-entry",
193
+ position: "after",
194
+ content: ` // p override: wraps block-level images in <figure class="zd-enlargeable">
195
+ // with an enlarge button when settings.imageEnlarge is enabled.
196
+ // Must come AFTER the ...htmlOverrides spread to override ContentParagraph.
197
+ p: EnlargeableParagraph,`,
198
+ },
199
+ ],
13
200
  });
@@ -2,11 +2,11 @@ import type { FeatureModule } from "../compose.js";
2
2
  /**
3
3
  * Versioning feature.
4
4
  *
5
- * W7A (#1736): post-cutover, the pages/lib wrappers gate `VersionSwitcher`
6
- * and `VersionBanner` on `settings.versions`. Doc-layout flow is handled by
7
- * route enumerators + `_inline-version-switcher.tsx`. The .astro inject
8
- * calls that used to wire this in have been retired (they targeted dead
9
- * `src/layouts/doc-layout.astro` + `src/components/header.astro` anchors).
5
+ * The pages/lib wrappers gate `VersionSwitcher` and `VersionBanner` on
6
+ * `settings.versions`. Doc-layout flow is handled by route enumerators +
7
+ * `_inline-version-switcher.tsx`. This feature copies versioning page
8
+ * templates from `templates/features/versioning/files/` via
9
+ * `copyFeatureFiles` (compose.ts), and injects nothing into `global.css`.
10
10
  *
11
11
  * W7C (#1738): the versioning feature ships pages under
12
12
  * `templates/features/versioning/files/pages/`:
@@ -3,11 +3,11 @@ import path from "path";
3
3
  /**
4
4
  * Versioning feature.
5
5
  *
6
- * W7A (#1736): post-cutover, the pages/lib wrappers gate `VersionSwitcher`
7
- * and `VersionBanner` on `settings.versions`. Doc-layout flow is handled by
8
- * route enumerators + `_inline-version-switcher.tsx`. The .astro inject
9
- * calls that used to wire this in have been retired (they targeted dead
10
- * `src/layouts/doc-layout.astro` + `src/components/header.astro` anchors).
6
+ * The pages/lib wrappers gate `VersionSwitcher` and `VersionBanner` on
7
+ * `settings.versions`. Doc-layout flow is handled by route enumerators +
8
+ * `_inline-version-switcher.tsx`. This feature copies versioning page
9
+ * templates from `templates/features/versioning/files/` via
10
+ * `copyFeatureFiles` (compose.ts), and injects nothing into `global.css`.
11
11
  *
12
12
  * W7C (#1738): the versioning feature ships pages under
13
13
  * `templates/features/versioning/files/pages/`:
package/dist/index.js CHANGED
@@ -69,6 +69,14 @@ async function main() {
69
69
  if (Object.keys(featureFlags).length > 0) {
70
70
  prefilled.features = { ...prefilled.features, ...featureFlags };
71
71
  }
72
+ // Record which features were explicitly disabled via --no-<flag> so
73
+ // scaffold.ts can warn when an auto-enable overrides that explicit choice.
74
+ const explicitlyDisabled = Object.entries(featureFlags)
75
+ .filter(([, v]) => v === false)
76
+ .map(([k]) => k);
77
+ if (explicitlyDisabled.length > 0) {
78
+ prefilled.explicitlyDisabledFeatures = explicitlyDisabled;
79
+ }
72
80
  // With --yes or --preset: fill all unspecified options with defaults
73
81
  if (args.yes || args.preset) {
74
82
  prefilled.projectName ??= "my-docs";
package/dist/prompts.d.ts CHANGED
@@ -9,6 +9,7 @@ export interface UserChoices {
9
9
  respectPrefersColorScheme?: boolean;
10
10
  defaultMode?: "light" | "dark";
11
11
  features: string[];
12
+ explicitlyDisabledFeatures?: string[];
12
13
  githubUrl?: string;
13
14
  cjkFriendly?: boolean;
14
15
  packageManager: "pnpm" | "npm" | "yarn" | "bun";
@@ -24,6 +25,7 @@ export interface PartialChoices {
24
25
  respectPrefersColorScheme?: boolean;
25
26
  defaultMode?: "light" | "dark";
26
27
  features?: Partial<Record<string, boolean>>;
28
+ explicitlyDisabledFeatures?: string[];
27
29
  githubUrl?: string;
28
30
  cjkFriendly?: boolean;
29
31
  packageManager?: "pnpm" | "npm" | "yarn" | "bun";
package/dist/prompts.js CHANGED
@@ -240,6 +240,7 @@ export async function runPrompts(prefilled = {}) {
240
240
  respectPrefersColorScheme,
241
241
  defaultMode,
242
242
  features,
243
+ explicitlyDisabledFeatures: prefilled.explicitlyDisabledFeatures,
243
244
  githubUrl,
244
245
  cjkFriendly: prefilled.cjkFriendly,
245
246
  packageManager,
package/dist/scaffold.js CHANGED
@@ -90,12 +90,15 @@ export async function scaffold(choices) {
90
90
  throw new Error(`Directory "${choices.projectName}" already exists and is not empty`);
91
91
  }
92
92
  }
93
- // body-foot-util-area.astro ships the DocHistory component inline (byte-
94
- // identical to main/src/components/body-foot-util-area.astro). Selecting
93
+ // body-foot-util-area.tsx ships the DocHistory component inline (byte-
94
+ // identical to main/src/components/body-foot-util-area.tsx). Selecting
95
95
  // bodyFootUtil without docHistory would leave an unresolved import, so we
96
- // silently co-enable docHistory.
96
+ // co-enable docHistory. Warn when this overrides an explicit --no-doc-history.
97
97
  if (choices.features.includes("bodyFootUtil") &&
98
98
  !choices.features.includes("docHistory")) {
99
+ if (choices.explicitlyDisabledFeatures?.includes("docHistory")) {
100
+ console.warn("body-foot-util requires doc-history; enabling it despite --no-doc-history");
101
+ }
99
102
  choices.features = [...choices.features, "docHistory"];
100
103
  }
101
104
  // Resolve template directories
@@ -211,20 +214,44 @@ function generatePackageJson(choices) {
211
214
  // @takazudo/zudo-doc-md-plugins — zero references in generator templates/source
212
215
  // @takazudo/zfb-adapter-cloudflare — zero references in generator templates/source
213
216
  const deps = {
214
- // zfb engine — replaces astro/@astrojs/* now that the cutover (#500 S5)
215
- // has retired the legacy Astro pipeline. Distributed as published npm
216
- // packages (the prebuilt binary ships via an optionalDependency of
217
- // @takazudo/zfb); pinned to the pre-release the scaffold targets.
217
+ // zfb engine — distributed as published npm packages (the prebuilt binary
218
+ // ships via an optionalDependency of @takazudo/zfb-<platform>); pinned to
219
+ // the pre-release the scaffold targets (per #500).
218
220
  // The two literals below must match root package.json's
219
221
  // dependencies["@takazudo/zfb"] / ["@takazudo/zfb-runtime"] —
220
222
  // enforced by scripts/check-pin-parity.mjs (W4A — #1732).
221
- "@takazudo/zfb": "0.1.0-next.6",
222
- "@takazudo/zfb-runtime": "0.1.0-next.6",
223
+ // Bumped to next.13 in S6 (#1808) — absorbs the next.12 breaking change
224
+ // (4 former-Core features moved to opt-in markdown.features block).
225
+ // Bumped to next.14 (#1817) — fixes the ruby SSR-500 (#1815) and the
226
+ // tocExport indented-export build break (#1814), letting both features
227
+ // be re-enabled in the showcase markdown.features block.
228
+ // Bumped to next.19 (#1824) — next.18 hard-removed the built-in
229
+ // imageEnlarge markdown feature (now re-implemented in userland via an MDX
230
+ // p-override); next.19 adds the islands esbuild react/jsx-runtime→preact
231
+ // alias fix (Takazudo/zudo-front-builder#633) that next.18 lacked.
232
+ // Bumped to next.21 — next.20/next.21 are Rust-engine-internal robustness
233
+ // releases (no SDK API change): dev cold-boot 200, dev watch-ADD discovery
234
+ // of newly-added content files, and bounded waits fixing build/dev hangs.
235
+ // Bumped to next.22 — additive bundler/markdown migration-parity release (no
236
+ // breaking config change): Vite import.meta.glob eager transform, bundle.exclude
237
+ // glob knob, opt-in markdown hardBreaks (default false), and config-eval V8
238
+ // web polyfills + tsconfig path-alias composition fixes.
239
+ // Bumped to next.23 — zfb/config ambient type improvements (BundleConfig +
240
+ // bundle field in ZfbConfig; fixes Takazudo/zudo-front-builder#678).
241
+ // Bumped to next.25 — BREAKING: removes `admonitionsPreset` (configs
242
+ // still setting it hard-error at load). Replaced by the generic
243
+ // `markdown.features.directives` map; host zfb.config.ts migrated
244
+ // in zudolab/zudo-doc#1840.
245
+ "@takazudo/zfb": "0.1.0-next.25",
246
+ "@takazudo/zfb-runtime": "0.1.0-next.25",
247
+ // zfb-adapter-cloudflare — required for any route with `prerender = false`.
248
+ // Pinned in lockstep with @takazudo/zfb.
249
+ "@takazudo/zfb-adapter-cloudflare": "0.1.0-next.25",
223
250
  // @takazudo/zudo-doc — published from this monorepo via
224
251
  // .github/workflows/publish-zudo-doc.yml. The pin here is bumped in
225
252
  // lockstep by scripts/release-create-zudo-doc.sh whenever zudo-doc's
226
253
  // version moves, so a fresh scaffold pulls the version we just published.
227
- "@takazudo/zudo-doc": "^0.1.0",
254
+ "@takazudo/zudo-doc": "^0.2.0-next.1",
228
255
  // zod — used by the generated zfb.config.ts. zfb-config-gen emits
229
256
  // `import { z } from "zod"` for the content-collection schema +
230
257
  // `z.toJSONSchema(...)` conversion. Without this dep, the consumer
@@ -276,6 +303,13 @@ function generatePackageJson(choices) {
276
303
  }
277
304
  if (choices.features.includes("docHistory")) {
278
305
  deps["diff"] = "^8.0.3";
306
+ // @takazudo/zudo-doc has @takazudo/zudo-doc-history-server as an optional
307
+ // peer dep. When docHistory is selected the zfb plugin
308
+ // (plugins/doc-history-plugin.mjs) eagerly imports
309
+ // @takazudo/zudo-doc/integrations/doc-history which in turn imports
310
+ // @takazudo/zudo-doc-history-server/git-history. Without this dep the
311
+ // plugin host fails at init with ERR_MODULE_NOT_FOUND — W8A (#1739).
312
+ deps["@takazudo/zudo-doc-history-server"] = "^0.2.0-next.1";
279
313
  // W7A (#1736): doc-history-plugin.mjs spawns `tsx -e <inline-script>` to
280
314
  // run the v2 runtime in a TS-aware Node subprocess; without tsx the
281
315
  // plugin's preBuild step exits with ENOENT before zfb finishes config
@@ -289,7 +323,7 @@ function generatePackageJson(choices) {
289
323
  devDeps["tsx"] = "^4.21.0";
290
324
  }
291
325
  if (choices.features.includes("designTokenPanel")) {
292
- deps["@takazudo/zdtp"] = "0.1.0-next.1";
326
+ deps["@takazudo/zdtp"] = "0.2.0-next.2";
293
327
  }
294
328
  if (choices.features.includes("tagGovernance")) {
295
329
  // gray-matter is already in `deps` unconditionally (base template uses it),
@@ -71,10 +71,14 @@ export function generateSettingsFile(choices) {
71
71
  else {
72
72
  lines.push(` locales: {} as Record<string, LocaleConfig>,`);
73
73
  }
74
+ // mermaid is controlled by the markdown.features block in zfb.config.ts
75
+ // (zfb next.12+). This field is retained for compatibility with framework
76
+ // components that still read settings.mermaid. See the markdown.features
77
+ // block in the generated zfb.config.ts for the canonical opt-in.
74
78
  lines.push(` mermaid: true,`);
75
79
  lines.push(` sitemap: false,`);
76
80
  lines.push(` docMetainfo: false,`);
77
- lines.push(` docTags: false,`);
81
+ lines.push(` docTags: ${choices.features.includes("docTags")},`);
78
82
  lines.push(` tagPlacement: "after-title" as TagPlacement,`);
79
83
  if (choices.features.includes("tagGovernance")) {
80
84
  lines.push(` tagGovernance: "warn" as TagGovernanceMode,`);
@@ -95,6 +99,14 @@ export function generateSettingsFile(choices) {
95
99
  lines.push(` cjkFriendly: ${choices.cjkFriendly ?? false} as boolean,`);
96
100
  lines.push(` onBrokenMarkdownLinks: "warn" as "warn" | "error" | "ignore",`);
97
101
  lines.push(` aiAssistant: false as boolean,`);
102
+ // When the user wires up `pages/api/ai-chat.tsx` (not shipped in any
103
+ // scaffold variant — W6A spec-lock Decision 5), this toggle short-circuits
104
+ // the endpoint with a fixed "disabled" reply. Default `false` here — the
105
+ // showcase ships with `true` because it deploys without an Anthropic key,
106
+ // but a fresh scaffold has `aiAssistant: false` and the user only enables
107
+ // the chat once they're wiring up a real `ANTHROPIC_API_KEY`. Defaulting
108
+ // demo mode off avoids silently disabling chat for them.
109
+ lines.push(` aiChatDemoMode: false as boolean,`);
98
110
  if (choices.features.includes("docHistory")) {
99
111
  lines.push(` docHistory: true,`);
100
112
  }
@@ -216,6 +216,63 @@ export function generateZfbConfig(choices) {
216
216
  lines.push(` },`);
217
217
  lines.push(` base: settings.base,`);
218
218
  lines.push(` trailingSlash: settings.trailingSlash,`);
219
+ // markdown.features block — mirrors the zfb next.13 opt-in model.
220
+ //
221
+ // Value-shape rule (empirically verified against the next.13 Rust loader):
222
+ // object-typed features (githubAutolinks, codeEnrichment, imageDimensions,
223
+ // linkValidation) REJECT the `true` shorthand and must be given an options
224
+ // object (`{}` or fields). Boolean-OR-object features (githubAlerts,
225
+ // readingTime, codeTabs, mermaid, headingMarkerToc) accept `true`.
226
+ // (directives is object-typed — it takes a `name → component` map, not `true`.)
227
+ // Note: imageEnlarge was formerly a Boolean-OR-object feature here, but
228
+ // next.18 hard-removed it from the Rust config schema — it is now
229
+ // re-implemented in userland via an MDX p-override in pages/_mdx-components.ts
230
+ // (gated on settings.imageEnlarge). Do NOT add imageEnlarge back here.
231
+ //
232
+ // Intentionally omitted features (known-blocked at zfb next.13):
233
+ // - tocExport: injects indented `export const toc = [...]` that MDX
234
+ // parses as content, breaking esbuild with "Expected }" across the
235
+ // whole corpus. Re-enable when the upstream Rust pass emits the
236
+ // export at column 0. (Filed as zudolab/zudo-doc#1814.)
237
+ // - ruby: the `^{...}` annotation syntax 500s the SSR render at next.13.
238
+ // A registered stub cannot fix it — the error is inside zfb's Rust
239
+ // ruby pass. Re-enable when the upstream crate is fixed. (#1815.)
240
+ // - transclude: `:::include{file="..."}` 500s SSR (no registered
241
+ // <include> renderer); `![[...]]` wikilink form is a no-op.
242
+ // Re-enable when a transclude renderer is wired.
243
+ //
244
+ // githubAutolinks is omitted intentionally: the showcase hardcodes
245
+ // `repo: "zudolab/zudo-doc"` but a scaffolded project belongs to a
246
+ // different repo. Users can add `githubAutolinks: { repo: "owner/repo" }`
247
+ // to their zfb.config.ts after scaffolding.
248
+ lines.push(` markdown: {`);
249
+ lines.push(` features: {`);
250
+ lines.push(` // Former-Core features (were always-on before zfb next.12).`);
251
+ lines.push(` // imageEnlarge was a former-Core feature but was hard-removed in zfb`);
252
+ lines.push(` // next.18 — it is now re-implemented via an MDX p-override.`);
253
+ lines.push(` // Admonitions recipe: register the :::name directive vocabulary`);
254
+ lines.push(` // (note/tip/info/warning/danger/caution/details) → components.`);
255
+ lines.push(` directives: {`);
256
+ lines.push(` note: "Note",`);
257
+ lines.push(` tip: "Tip",`);
258
+ lines.push(` info: "Info",`);
259
+ lines.push(` warning: "Warning",`);
260
+ lines.push(` danger: "Danger",`);
261
+ lines.push(` caution: "Caution",`);
262
+ lines.push(` details: "Details", // collapsible — routes to DetailsWrapper`);
263
+ lines.push(` },`);
264
+ lines.push(` mermaid: true,`);
265
+ lines.push(` headingMarkerToc: true,`);
266
+ lines.push(` // Safe opt-in features.`);
267
+ lines.push(` githubAlerts: true,`);
268
+ lines.push(` readingTime: true,`);
269
+ lines.push(` codeEnrichment: {},`);
270
+ lines.push(` codeTabs: true,`);
271
+ lines.push(` imageDimensions: {},`);
272
+ lines.push(` // warn-only link validation — failOnBroken: false never fails the build.`);
273
+ lines.push(` linkValidation: { failOnBroken: false },`);
274
+ lines.push(` },`);
275
+ lines.push(` },`);
219
276
  lines.push(` plugins: integrationPlugins,`);
220
277
  lines.push(`});`);
221
278
  return lines.join("\n") + "\n";