create-zudo-doc 0.1.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/LICENSE +21 -0
- package/README.md +146 -0
- package/bin/create-zudo-doc.js +2 -0
- package/dist/api.d.ts +20 -0
- package/dist/api.js +13 -0
- package/dist/claude-md-gen.d.ts +2 -0
- package/dist/claude-md-gen.js +113 -0
- package/dist/cli.d.ts +39 -0
- package/dist/cli.js +157 -0
- package/dist/compose.d.ts +95 -0
- package/dist/compose.js +206 -0
- package/dist/constants.d.ts +20 -0
- package/dist/constants.js +224 -0
- package/dist/features/body-foot-util.d.ts +10 -0
- package/dist/features/body-foot-util.js +12 -0
- package/dist/features/claude-resources.d.ts +2 -0
- package/dist/features/claude-resources.js +6 -0
- package/dist/features/design-token-panel.d.ts +14 -0
- package/dist/features/design-token-panel.js +27 -0
- package/dist/features/doc-history.d.ts +9 -0
- package/dist/features/doc-history.js +11 -0
- package/dist/features/doc-tags.d.ts +19 -0
- package/dist/features/doc-tags.js +33 -0
- package/dist/features/footer-taglist.d.ts +14 -0
- package/dist/features/footer-taglist.js +17 -0
- package/dist/features/footer.d.ts +8 -0
- package/dist/features/footer.js +10 -0
- package/dist/features/i18n.d.ts +22 -0
- package/dist/features/i18n.js +41 -0
- package/dist/features/image-enlarge.d.ts +11 -0
- package/dist/features/image-enlarge.js +13 -0
- package/dist/features/index.d.ts +15 -0
- package/dist/features/index.js +53 -0
- package/dist/features/llms-txt.d.ts +11 -0
- package/dist/features/llms-txt.js +13 -0
- package/dist/features/search.d.ts +9 -0
- package/dist/features/search.js +11 -0
- package/dist/features/sidebar-resizer.d.ts +14 -0
- package/dist/features/sidebar-resizer.js +16 -0
- package/dist/features/sidebar-toggle.d.ts +13 -0
- package/dist/features/sidebar-toggle.js +15 -0
- package/dist/features/tag-governance.d.ts +14 -0
- package/dist/features/tag-governance.js +16 -0
- package/dist/features/tauri-dev.d.ts +2 -0
- package/dist/features/tauri-dev.js +25 -0
- package/dist/features/tauri.d.ts +11 -0
- package/dist/features/tauri.js +52 -0
- package/dist/features/versioning.d.ts +27 -0
- package/dist/features/versioning.js +43 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +150 -0
- package/dist/preset.d.ts +37 -0
- package/dist/preset.js +156 -0
- package/dist/prompts.d.ts +32 -0
- package/dist/prompts.js +248 -0
- package/dist/scaffold.d.ts +4 -0
- package/dist/scaffold.js +344 -0
- package/dist/settings-gen.d.ts +2 -0
- package/dist/settings-gen.js +237 -0
- package/dist/utils.d.ts +8 -0
- package/dist/utils.js +34 -0
- package/dist/zfb-config-gen.d.ts +19 -0
- package/dist/zfb-config-gen.js +222 -0
- package/package.json +65 -0
- package/templates/base/.htmlvalidate.json +5 -0
- package/templates/base/.zfb/doc-history-meta.json +1 -0
- package/templates/base/pages/404.tsx +55 -0
- package/templates/base/pages/_data.ts +179 -0
- package/templates/base/pages/_mdx-components.ts +249 -0
- package/templates/base/pages/docs/[...slug].tsx +448 -0
- package/templates/base/pages/index.tsx +158 -0
- package/templates/base/pages/lib/_body-end-islands.tsx +201 -0
- package/templates/base/pages/lib/_category-nav.tsx +148 -0
- package/templates/base/pages/lib/_category-tree-nav.tsx +104 -0
- package/templates/base/pages/lib/_compose-meta-title.ts +29 -0
- package/templates/base/pages/lib/_details.tsx +30 -0
- package/templates/base/pages/lib/_doc-history-area.tsx +178 -0
- package/templates/base/pages/lib/_doc-metainfo-area.tsx +100 -0
- package/templates/base/pages/lib/_doc-tags-area.tsx +89 -0
- package/templates/base/pages/lib/_extract-headings.ts +81 -0
- package/templates/base/pages/lib/_footer-with-defaults.tsx +234 -0
- package/templates/base/pages/lib/_frontmatter-preview-data.ts +53 -0
- package/templates/base/pages/lib/_head-with-defaults.tsx +113 -0
- package/templates/base/pages/lib/_header-with-defaults.tsx +386 -0
- package/templates/base/pages/lib/_inline-version-switcher.tsx +84 -0
- package/templates/base/pages/lib/_math-block.tsx +63 -0
- package/templates/base/pages/lib/_nav-source-docs.ts +68 -0
- package/templates/base/pages/lib/_preset-generator.tsx +81 -0
- package/templates/base/pages/lib/_search-widget-script.ts +388 -0
- package/templates/base/pages/lib/_search-widget.tsx +196 -0
- package/templates/base/pages/lib/_sidebar-with-defaults.tsx +176 -0
- package/templates/base/pages/lib/_site-tree-nav.tsx +128 -0
- package/templates/base/pages/lib/locale-merge.ts +58 -0
- package/templates/base/pages/lib/route-enumerators.ts +302 -0
- package/templates/base/pages/sitemap.xml.tsx +51 -0
- package/templates/base/plugins/connect-adapter.mjs +144 -0
- package/templates/base/plugins/copy-public-plugin.mjs +50 -0
- package/templates/base/plugins/search-index-plugin.mjs +54 -0
- package/templates/base/scripts/run-b4push.sh +102 -0
- package/templates/base/src/components/ai-chat-modal.tsx +15 -0
- package/templates/base/src/components/client-router-bootstrap.tsx +14 -0
- package/templates/base/src/components/content/component-map.ts +25 -0
- package/templates/base/src/components/content/content-blockquote.tsx +16 -0
- package/templates/base/src/components/content/content-code.tsx +117 -0
- package/templates/base/src/components/content/content-link.tsx +83 -0
- package/templates/base/src/components/content/content-ol.tsx +19 -0
- package/templates/base/src/components/content/content-paragraph.tsx +10 -0
- package/templates/base/src/components/content/content-strong.tsx +16 -0
- package/templates/base/src/components/content/content-table.tsx +18 -0
- package/templates/base/src/components/content/content-ul.tsx +18 -0
- package/templates/base/src/components/content/heading-h2.tsx +26 -0
- package/templates/base/src/components/content/heading-h3.tsx +26 -0
- package/templates/base/src/components/content/heading-h4.tsx +26 -0
- package/templates/base/src/components/design-token-panel-bootstrap.tsx +15 -0
- package/templates/base/src/components/desktop-sidebar-toggle.tsx +15 -0
- package/templates/base/src/components/doc-history.tsx +18 -0
- package/templates/base/src/components/html-preview/highlighted-code.tsx +74 -0
- package/templates/base/src/components/html-preview/html-preview.tsx +108 -0
- package/templates/base/src/components/html-preview/preflight.ts +112 -0
- package/templates/base/src/components/html-preview/preview-base.tsx +159 -0
- package/templates/base/src/components/image-enlarge.tsx +19 -0
- package/templates/base/src/components/mobile-toc.tsx +94 -0
- package/templates/base/src/components/preset-generator.tsx +14 -0
- package/templates/base/src/components/sidebar-toggle.tsx +98 -0
- package/templates/base/src/components/sidebar-tree.tsx +543 -0
- package/templates/base/src/components/site-tree-nav.tsx +233 -0
- package/templates/base/src/components/theme-toggle.tsx +93 -0
- package/templates/base/src/components/toc.tsx +63 -0
- package/templates/base/src/components/tree-nav-shared.tsx +71 -0
- package/templates/base/src/config/color-scheme-utils.ts +182 -0
- package/templates/base/src/config/color-schemes.ts +128 -0
- package/templates/base/src/config/frontmatter-preview-defaults.ts +24 -0
- package/templates/base/src/config/frontmatter-preview-renderers.tsx +46 -0
- package/templates/base/src/config/i18n.ts +225 -0
- package/templates/base/src/config/settings-types.ts +162 -0
- package/templates/base/src/config/sidebars.ts +66 -0
- package/templates/base/src/config/tag-vocabulary-types.ts +39 -0
- package/templates/base/src/config/tag-vocabulary.ts +20 -0
- package/templates/base/src/hooks/use-active-heading.ts +133 -0
- package/templates/base/src/plugins/docs-source-map.ts +103 -0
- package/templates/base/src/plugins/hast-utils.ts +10 -0
- package/templates/base/src/plugins/rehype-code-title.ts +50 -0
- package/templates/base/src/plugins/rehype-heading-links.ts +53 -0
- package/templates/base/src/plugins/rehype-image-enlarge.ts +113 -0
- package/templates/base/src/plugins/rehype-mermaid.ts +41 -0
- package/templates/base/src/plugins/rehype-strip-md-extension.ts +58 -0
- package/templates/base/src/plugins/remark-admonitions.ts +99 -0
- package/templates/base/src/plugins/remark-resolve-markdown-links.ts +127 -0
- package/templates/base/src/plugins/url-utils.ts +4 -0
- package/templates/base/src/styles/global.css +1066 -0
- package/templates/base/src/types/docs-entry.ts +39 -0
- package/templates/base/src/types/heading.ts +5 -0
- package/templates/base/src/types/locale.ts +10 -0
- package/templates/base/src/utils/base.ts +139 -0
- package/templates/base/src/utils/content-files.ts +106 -0
- package/templates/base/src/utils/dedent.ts +24 -0
- package/templates/base/src/utils/docs.ts +335 -0
- package/templates/base/src/utils/git-info.ts +70 -0
- package/templates/base/src/utils/github.ts +19 -0
- package/templates/base/src/utils/header-right-items.ts +38 -0
- package/templates/base/src/utils/nav-scope.ts +63 -0
- package/templates/base/src/utils/sidebar.ts +104 -0
- package/templates/base/src/utils/slug.ts +10 -0
- package/templates/base/src/utils/smart-break.tsx +126 -0
- package/templates/base/src/utils/tags.ts +126 -0
- package/templates/base/tsconfig.json +36 -0
- package/templates/features/bodyFootUtil/files/src/utils/github.ts +19 -0
- package/templates/features/claudeResources/files/plugins/claude-resources-plugin.mjs +137 -0
- package/templates/features/claudeResources/files/src/integrations/claude-resources/__tests__/escape-for-mdx.test.ts +34 -0
- package/templates/features/claudeResources/files/src/integrations/claude-resources/__tests__/generate.test.ts +376 -0
- package/templates/features/claudeResources/files/src/integrations/claude-resources/escape-for-mdx.ts +93 -0
- package/templates/features/claudeResources/files/src/integrations/claude-resources/generate.ts +586 -0
- package/templates/features/designTokenPanel/files/src/components/design-token-panel-bootstrap.tsx +15 -0
- package/templates/features/designTokenPanel/files/src/config/design-token-panel-config.ts +99 -0
- package/templates/features/designTokenPanel/files/src/config/design-tokens-manifest.ts +177 -0
- package/templates/features/designTokenPanel/files/src/lib/design-token-panel-bootstrap.ts +50 -0
- package/templates/features/docHistory/files/plugins/doc-history-plugin.mjs +99 -0
- package/templates/features/docHistory/files/src/components/doc-history.tsx +598 -0
- package/templates/features/docHistory/files/src/types/doc-history.ts +23 -0
- package/templates/features/docHistory/files/src/utils/doc-history.ts +180 -0
- package/templates/features/docTags/files/pages/[locale]/docs/tags/[tag].tsx +116 -0
- package/templates/features/docTags/files/pages/[locale]/docs/tags/index.tsx +99 -0
- package/templates/features/docTags/files/pages/docs/tags/[tag].tsx +101 -0
- package/templates/features/docTags/files/pages/docs/tags/index.tsx +86 -0
- package/templates/features/i18n/files/pages/[locale]/docs/[...slug].tsx +467 -0
- package/templates/features/i18n/files/pages/[locale]/index.tsx +213 -0
- package/templates/features/imageEnlarge/files/src/components/image-enlarge.tsx +248 -0
- package/templates/features/llmsTxt/files/plugins/llms-txt-plugin.mjs +74 -0
- package/templates/features/sidebarResizer/files/src/scripts/sidebar-resizer.ts +185 -0
- package/templates/features/sidebarToggle/files/src/components/desktop-sidebar-toggle.tsx +126 -0
- package/templates/features/tagGovernance/files/scripts/tags-audit.ts +576 -0
- package/templates/features/tagGovernance/files/scripts/tags-suggest.ts +428 -0
- package/templates/features/tauri/files/src/components/find-bar.tsx +122 -0
- package/templates/features/tauri/files/src/components/find-in-page-init.tsx +53 -0
- package/templates/features/tauri/files/src/utils/find-in-page.ts +175 -0
- package/templates/features/tauri/files/src-tauri/Cargo.toml +14 -0
- package/templates/features/tauri/files/src-tauri/build.rs +3 -0
- package/templates/features/tauri/files/src-tauri/capabilities/default.json +11 -0
- package/templates/features/tauri/files/src-tauri/src/main.rs +250 -0
- package/templates/features/tauri/files/src-tauri/tauri.conf.json +25 -0
- package/templates/features/tauriDev/files/src-tauri-dev/Cargo.toml +15 -0
- package/templates/features/tauriDev/files/src-tauri-dev/build.rs +3 -0
- package/templates/features/tauriDev/files/src-tauri-dev/capabilities/default.json +7 -0
- package/templates/features/tauriDev/files/src-tauri-dev/frontend/index.html +187 -0
- package/templates/features/tauriDev/files/src-tauri-dev/icons/icon.png +0 -0
- package/templates/features/tauriDev/files/src-tauri-dev/src/main.rs +995 -0
- package/templates/features/tauriDev/files/src-tauri-dev/tauri.conf.json +22 -0
- package/templates/features/tauriDev/files/src-tauri-dev/test-launch.sh +65 -0
- package/templates/features/versioning/files/pages/[locale]/docs/versions.tsx +100 -0
- package/templates/features/versioning/files/pages/docs/versions.tsx +78 -0
- package/templates/features/versioning/files/pages/v/[version]/docs/[...slug].tsx +451 -0
- package/templates/features/versioning/files/pages/v/[version]/ja/docs/[...slug].tsx +490 -0
package/dist/scaffold.js
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { generateSettingsFile } from "./settings-gen.js";
|
|
5
|
+
import { generateZfbConfig } from "./zfb-config-gen.js";
|
|
6
|
+
import { generateCLAUDEFile } from "./claude-md-gen.js";
|
|
7
|
+
import { composeFeatures } from "./compose.js";
|
|
8
|
+
import { featureModules } from "./features/index.js";
|
|
9
|
+
import { capitalize, getSecondaryLang } from "./utils.js";
|
|
10
|
+
export { getSecondaryLang };
|
|
11
|
+
/**
|
|
12
|
+
* Files in `templates/base/**` that must never be copied into a generated
|
|
13
|
+
* project. Each entry is matched against the path relative to `templates/base/`
|
|
14
|
+
* (POSIX-style, forward slashes).
|
|
15
|
+
*
|
|
16
|
+
* W2 spec-lock Decision 5 (#1728) — `pages/api/**` is worker-only SSR
|
|
17
|
+
* (uses `@takazudo/zfb-adapter-cloudflare`, `prerender = false`) and is
|
|
18
|
+
* intentionally absent from `templates/base/pages/` already. This list
|
|
19
|
+
* is the explicit policy: future upstream-sync helpers that mirror more
|
|
20
|
+
* of `pages/` into `templates/base/` MUST honour these patterns.
|
|
21
|
+
*/
|
|
22
|
+
const EXCLUDE_FROM_MIRROR = [
|
|
23
|
+
/^pages\/api(\/|$)/,
|
|
24
|
+
];
|
|
25
|
+
/**
|
|
26
|
+
* `fs.copy` filter for the `templates/base/` → target-dir copy. Returns
|
|
27
|
+
* `false` for any path matching {@link EXCLUDE_FROM_MIRROR}. Directories
|
|
28
|
+
* matching an exclusion are skipped wholesale (fs.copy honours filter on
|
|
29
|
+
* directories).
|
|
30
|
+
*/
|
|
31
|
+
function shouldCopyBaseFile(srcAbs, baseDir) {
|
|
32
|
+
const rel = path.relative(baseDir, srcAbs).split(path.sep).join("/");
|
|
33
|
+
if (rel === "")
|
|
34
|
+
return true; // root — always include
|
|
35
|
+
for (const pattern of EXCLUDE_FROM_MIRROR) {
|
|
36
|
+
if (pattern.test(rel))
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
const STARTER_CONTENT_EN = (siteName) => `---
|
|
42
|
+
title: Welcome
|
|
43
|
+
sidebar_position: 1
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
# Welcome to ${siteName}
|
|
47
|
+
|
|
48
|
+
This documentation site was created with [zudo-doc](https://github.com/zudolab/zudo-doc).
|
|
49
|
+
|
|
50
|
+
## Getting Started
|
|
51
|
+
|
|
52
|
+
Edit the files in \`src/content/docs/\` to add your documentation.
|
|
53
|
+
`;
|
|
54
|
+
const STARTER_CONTENT_JA = () => `---
|
|
55
|
+
title: ようこそ
|
|
56
|
+
sidebar_position: 1
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
# ようこそ
|
|
60
|
+
|
|
61
|
+
このドキュメントサイトは [zudo-doc](https://github.com/zudolab/zudo-doc) で作成されました。
|
|
62
|
+
`;
|
|
63
|
+
const CHANGELOG_CONTENT_EN = () => `---
|
|
64
|
+
title: Changelog
|
|
65
|
+
sidebar_position: 99
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
# Changelog
|
|
69
|
+
|
|
70
|
+
## Unreleased
|
|
71
|
+
|
|
72
|
+
- Initial release
|
|
73
|
+
`;
|
|
74
|
+
const CHANGELOG_CONTENT_JA = () => `---
|
|
75
|
+
title: 変更履歴
|
|
76
|
+
sidebar_position: 99
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
# 変更履歴
|
|
80
|
+
|
|
81
|
+
## 未リリース
|
|
82
|
+
|
|
83
|
+
- 初回リリース
|
|
84
|
+
`;
|
|
85
|
+
export async function scaffold(choices) {
|
|
86
|
+
const targetDir = path.resolve(process.cwd(), choices.projectName);
|
|
87
|
+
if (await fs.pathExists(targetDir)) {
|
|
88
|
+
const contents = await fs.readdir(targetDir);
|
|
89
|
+
if (contents.length > 0) {
|
|
90
|
+
throw new Error(`Directory "${choices.projectName}" already exists and is not empty`);
|
|
91
|
+
}
|
|
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
|
|
95
|
+
// bodyFootUtil without docHistory would leave an unresolved import, so we
|
|
96
|
+
// silently co-enable docHistory.
|
|
97
|
+
if (choices.features.includes("bodyFootUtil") &&
|
|
98
|
+
!choices.features.includes("docHistory")) {
|
|
99
|
+
choices.features = [...choices.features, "docHistory"];
|
|
100
|
+
}
|
|
101
|
+
// Resolve template directories
|
|
102
|
+
const pkgRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
103
|
+
const templatesDir = path.join(pkgRoot, "templates");
|
|
104
|
+
const baseDir = path.join(templatesDir, "base");
|
|
105
|
+
const featuresDir = path.join(templatesDir, "features");
|
|
106
|
+
// For skillSymlinker, we still need the monorepo root for the script
|
|
107
|
+
const monorepoRoot = path.resolve(pkgRoot, "../..");
|
|
108
|
+
await fs.ensureDir(targetDir);
|
|
109
|
+
// 1. Copy base template
|
|
110
|
+
// Honour EXCLUDE_FROM_MIRROR so paths like `pages/api/**` (worker-only SSR
|
|
111
|
+
// endpoints) are never emitted into a generated project — see W2 spec-lock
|
|
112
|
+
// Decision 5 (#1728). Today templates/base/ does not contain any excluded
|
|
113
|
+
// paths, but the filter documents the policy in code that runs.
|
|
114
|
+
await fs.copy(baseDir, targetDir, {
|
|
115
|
+
filter: (src) => shouldCopyBaseFile(src, baseDir),
|
|
116
|
+
});
|
|
117
|
+
// 2. Copy skill symlinker script when enabled
|
|
118
|
+
if (choices.features.includes("skillSymlinker")) {
|
|
119
|
+
const scriptSrc = path.join(monorepoRoot, "scripts/setup-doc-skill.sh");
|
|
120
|
+
const scriptDest = path.join(targetDir, "scripts/setup-doc-skill.sh");
|
|
121
|
+
if (await fs.pathExists(scriptSrc)) {
|
|
122
|
+
await fs.copy(scriptSrc, scriptDest);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// 2b. Copy user-facing Claude Code skills when enabled
|
|
126
|
+
// Ships the curated zudo-doc-* skills (design-system, translate, version-bump)
|
|
127
|
+
// from the monorepo's .claude/skills/ into the user's .claude/skills/.
|
|
128
|
+
if (choices.features.includes("claudeSkills")) {
|
|
129
|
+
const userFacingSkills = [
|
|
130
|
+
"zudo-doc-design-system",
|
|
131
|
+
"zudo-doc-translate",
|
|
132
|
+
"zudo-doc-version-bump",
|
|
133
|
+
];
|
|
134
|
+
for (const skill of userFacingSkills) {
|
|
135
|
+
const skillSrc = path.join(monorepoRoot, ".claude/skills", skill);
|
|
136
|
+
const skillDest = path.join(targetDir, ".claude/skills", skill);
|
|
137
|
+
if (await fs.pathExists(skillSrc)) {
|
|
138
|
+
await fs.copy(skillSrc, skillDest);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const defaultLang = choices.defaultLang;
|
|
143
|
+
const escapedName = capitalize(choices.projectName.replace(/-/g, " "));
|
|
144
|
+
// Place primary content in src/content/docs/
|
|
145
|
+
const primaryContent = defaultLang === "ja"
|
|
146
|
+
? STARTER_CONTENT_JA()
|
|
147
|
+
: STARTER_CONTENT_EN(escapedName);
|
|
148
|
+
await fs.outputFile(path.join(targetDir, "src/content/docs/getting-started/index.mdx"), primaryContent);
|
|
149
|
+
// When i18n is ON, place secondary language content
|
|
150
|
+
if (choices.features.includes("i18n")) {
|
|
151
|
+
const secondaryLang = getSecondaryLang(defaultLang);
|
|
152
|
+
const secondaryDir = `src/content/docs-${secondaryLang}`;
|
|
153
|
+
await fs.ensureDir(path.join(targetDir, secondaryDir));
|
|
154
|
+
const secondaryContent = secondaryLang === "ja"
|
|
155
|
+
? STARTER_CONTENT_JA()
|
|
156
|
+
: STARTER_CONTENT_EN(escapedName);
|
|
157
|
+
await fs.outputFile(path.join(targetDir, `${secondaryDir}/getting-started/index.mdx`), secondaryContent);
|
|
158
|
+
}
|
|
159
|
+
// When changelog is ON, create a starter changelog page
|
|
160
|
+
if (choices.features.includes("changelog")) {
|
|
161
|
+
const changelogContent = defaultLang === "ja" ? CHANGELOG_CONTENT_JA() : CHANGELOG_CONTENT_EN();
|
|
162
|
+
await fs.outputFile(path.join(targetDir, "src/content/docs/changelog/index.mdx"), changelogContent);
|
|
163
|
+
if (choices.features.includes("i18n")) {
|
|
164
|
+
const secondaryLang = getSecondaryLang(defaultLang);
|
|
165
|
+
const secondaryChangelogContent = secondaryLang === "ja"
|
|
166
|
+
? CHANGELOG_CONTENT_JA()
|
|
167
|
+
: CHANGELOG_CONTENT_EN();
|
|
168
|
+
await fs.outputFile(path.join(targetDir, `src/content/docs-${secondaryLang}/changelog/index.mdx`), secondaryChangelogContent);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// 3. Generate programmatic files
|
|
172
|
+
const settingsContent = generateSettingsFile(choices);
|
|
173
|
+
await fs.outputFile(path.join(targetDir, "src/config/settings.ts"), settingsContent);
|
|
174
|
+
const zfbConfigContent = generateZfbConfig(choices);
|
|
175
|
+
await fs.outputFile(path.join(targetDir, "zfb.config.ts"), zfbConfigContent);
|
|
176
|
+
const pkg = generatePackageJson(choices);
|
|
177
|
+
await fs.outputFile(path.join(targetDir, "package.json"), JSON.stringify(pkg, null, 2) + "\n");
|
|
178
|
+
await fs.outputFile(path.join(targetDir, ".gitignore"), [
|
|
179
|
+
"# Build output",
|
|
180
|
+
"node_modules",
|
|
181
|
+
"dist",
|
|
182
|
+
".zfb",
|
|
183
|
+
"",
|
|
184
|
+
"# macOS",
|
|
185
|
+
".DS_Store",
|
|
186
|
+
"",
|
|
187
|
+
"# Environment",
|
|
188
|
+
".env",
|
|
189
|
+
".env.local",
|
|
190
|
+
".env.*.local",
|
|
191
|
+
"",
|
|
192
|
+
"# Logs",
|
|
193
|
+
"*.log",
|
|
194
|
+
"npm-debug.log*",
|
|
195
|
+
"yarn-debug.log*",
|
|
196
|
+
"pnpm-debug.log*",
|
|
197
|
+
"",
|
|
198
|
+
"# Cloudflare Wrangler",
|
|
199
|
+
".wrangler/",
|
|
200
|
+
"",
|
|
201
|
+
].join("\n"));
|
|
202
|
+
const claudeContent = generateCLAUDEFile(choices);
|
|
203
|
+
await fs.outputFile(path.join(targetDir, "CLAUDE.md"), claudeContent);
|
|
204
|
+
// 4. Compose features (copy feature files + inject into shared files)
|
|
205
|
+
await composeFeatures(targetDir, choices, featureModules, featuresDir);
|
|
206
|
+
// Ensure content directories exist
|
|
207
|
+
await fs.ensureDir(path.join(targetDir, "src/content/docs"));
|
|
208
|
+
}
|
|
209
|
+
function generatePackageJson(choices) {
|
|
210
|
+
// Intentionally absent from scaffolded deps:
|
|
211
|
+
// @takazudo/zudo-doc-md-plugins — zero references in generator templates/source
|
|
212
|
+
// @takazudo/zfb-adapter-cloudflare — zero references in generator templates/source
|
|
213
|
+
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.
|
|
218
|
+
// The two literals below must match root package.json's
|
|
219
|
+
// dependencies["@takazudo/zfb"] / ["@takazudo/zfb-runtime"] —
|
|
220
|
+
// 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
|
+
// @takazudo/zudo-doc — published from this monorepo via
|
|
224
|
+
// .github/workflows/publish-zudo-doc.yml. The pin here is bumped in
|
|
225
|
+
// lockstep by scripts/release-create-zudo-doc.sh whenever zudo-doc's
|
|
226
|
+
// version moves, so a fresh scaffold pulls the version we just published.
|
|
227
|
+
"@takazudo/zudo-doc": "^0.1.0",
|
|
228
|
+
// zod — used by the generated zfb.config.ts. zfb-config-gen emits
|
|
229
|
+
// `import { z } from "zod"` for the content-collection schema +
|
|
230
|
+
// `z.toJSONSchema(...)` conversion. Without this dep, the consumer
|
|
231
|
+
// fails at `zfb build` with esbuild "Could not resolve 'zod'" before
|
|
232
|
+
// any page compiles. The Astro→zfb retarget (3f0042f7) added the
|
|
233
|
+
// import without the runtime dep; W6B (#1735) consumer-build
|
|
234
|
+
// verification was the first to actually exercise it.
|
|
235
|
+
zod: "^4.0.0",
|
|
236
|
+
// ^10.29.1 floor satisfies @takazudo/zdtp's preact peer range so the app
|
|
237
|
+
// and zdtp resolve a single preact instance — a lower floor can split into
|
|
238
|
+
// two copies and crash hook-using SSR islands with "undefined reading __H".
|
|
239
|
+
preact: "^10.29.1",
|
|
240
|
+
// preact-render-to-string — zfb's emitted entry.mjs imports
|
|
241
|
+
// `renderToString` from this package as `__zfb_renderToString` to
|
|
242
|
+
// SSR each page. Without it, esbuild fails at the bundler step with
|
|
243
|
+
// "Could not resolve 'preact-render-to-string'" before any page
|
|
244
|
+
// compiles. Same pin as host. Caught by W6B (#1735) consumer-build
|
|
245
|
+
// verification.
|
|
246
|
+
"preact-render-to-string": "^6.6.6",
|
|
247
|
+
shiki: "^4.0.2",
|
|
248
|
+
"@shikijs/transformers": "^4.0.0",
|
|
249
|
+
clsx: "^2.1.0",
|
|
250
|
+
"gray-matter": "^4.0.0",
|
|
251
|
+
"github-slugger": "^2.0.0",
|
|
252
|
+
mermaid: "^11.12.3",
|
|
253
|
+
"remark-cjk-friendly": "^2.0.1",
|
|
254
|
+
"remark-directive": "^3.0.0",
|
|
255
|
+
"unist-util-visit": "^5.1.0",
|
|
256
|
+
// katex — server-side LaTeX renderer used by the always-on
|
|
257
|
+
// pages/lib/_math-block.tsx (called from pages/_mdx-components.ts
|
|
258
|
+
// for `$…$` and `$$…$$` math nodes). Caught by W6B (#1735)
|
|
259
|
+
// consumer-build verification — the import lives in the mirrored
|
|
260
|
+
// pages, not behind any feature gate. Same pin as host.
|
|
261
|
+
katex: "^0.16.38",
|
|
262
|
+
};
|
|
263
|
+
const devDeps = {
|
|
264
|
+
"@tailwindcss/vite": "^4.2.0",
|
|
265
|
+
tailwindcss: "^4.2.0",
|
|
266
|
+
typescript: "^5.9.0",
|
|
267
|
+
"@types/hast": "^3.0.4",
|
|
268
|
+
"@types/mdast": "^4.0.4",
|
|
269
|
+
"@types/node": "^22.0.0",
|
|
270
|
+
"@types/react": "^19.2.0", // needed for preact/compat type resolution
|
|
271
|
+
"html-validate": "^10.0.0",
|
|
272
|
+
};
|
|
273
|
+
if (choices.features.includes("search")) {
|
|
274
|
+
deps["minisearch"] = "^7.2.0";
|
|
275
|
+
devDeps["pagefind"] = "^1.4.0";
|
|
276
|
+
}
|
|
277
|
+
if (choices.features.includes("docHistory")) {
|
|
278
|
+
deps["diff"] = "^8.0.3";
|
|
279
|
+
// W7A (#1736): doc-history-plugin.mjs spawns `tsx -e <inline-script>` to
|
|
280
|
+
// run the v2 runtime in a TS-aware Node subprocess; without tsx the
|
|
281
|
+
// plugin's preBuild step exits with ENOENT before zfb finishes config
|
|
282
|
+
// load.
|
|
283
|
+
devDeps["tsx"] = "^4.21.0";
|
|
284
|
+
}
|
|
285
|
+
if (choices.features.includes("claudeResources")) {
|
|
286
|
+
// W7A (#1736): claude-resources-plugin.mjs spawns `tsx -e <inline-script>`
|
|
287
|
+
// for the same reason as doc-history (TS-aware Node subprocess wrapping
|
|
288
|
+
// the v2 runner).
|
|
289
|
+
devDeps["tsx"] = "^4.21.0";
|
|
290
|
+
}
|
|
291
|
+
if (choices.features.includes("designTokenPanel")) {
|
|
292
|
+
deps["@takazudo/zdtp"] = "0.1.0-next.1";
|
|
293
|
+
}
|
|
294
|
+
if (choices.features.includes("tagGovernance")) {
|
|
295
|
+
// gray-matter is already in `deps` unconditionally (base template uses it),
|
|
296
|
+
// so we only add the tooling deps specific to tags:audit / tags:suggest.
|
|
297
|
+
devDeps["string-similarity"] = "^4.0.4";
|
|
298
|
+
devDeps["@types/string-similarity"] = "^4.0.2";
|
|
299
|
+
devDeps["pluralize"] = "^8.0.0";
|
|
300
|
+
devDeps["@types/pluralize"] = "^0.0.33";
|
|
301
|
+
devDeps["picocolors"] = "^1.1.1";
|
|
302
|
+
devDeps["@inquirer/prompts"] = "^8.4.2";
|
|
303
|
+
devDeps["tsx"] = "^4.21.0";
|
|
304
|
+
}
|
|
305
|
+
const scripts = {
|
|
306
|
+
dev: "zfb dev",
|
|
307
|
+
build: "zfb build",
|
|
308
|
+
preview: "zfb preview",
|
|
309
|
+
check: "zfb check",
|
|
310
|
+
"check:html": "html-validate \"dist/**/*.html\"",
|
|
311
|
+
};
|
|
312
|
+
if (choices.features.includes("tagGovernance")) {
|
|
313
|
+
scripts["tags:audit"] = "tsx scripts/tags-audit.ts";
|
|
314
|
+
scripts["tags:suggest"] = "tsx scripts/tags-suggest.ts";
|
|
315
|
+
}
|
|
316
|
+
if (choices.features.includes("skillSymlinker")) {
|
|
317
|
+
scripts["setup:doc-skill"] = "bash scripts/setup-doc-skill.sh";
|
|
318
|
+
}
|
|
319
|
+
const runCmd = choices.packageManager === "npm" || choices.packageManager === "bun" ? `${choices.packageManager} run` : choices.packageManager;
|
|
320
|
+
// claudeSkills ships the zudo-doc-version-bump skill, whose release workflow
|
|
321
|
+
// calls `<pm> b4push`. Emit a minimal stub so the skill does not hit a
|
|
322
|
+
// "script not found" error on freshly scaffolded projects. Consumers are
|
|
323
|
+
// free to expand this into a richer pre-push pipeline later.
|
|
324
|
+
if (choices.features.includes("claudeSkills")) {
|
|
325
|
+
scripts["b4push"] = `${runCmd} check && ${runCmd} build`;
|
|
326
|
+
}
|
|
327
|
+
if (choices.features.includes("tauri")) {
|
|
328
|
+
scripts["dev:tauri"] = "cargo tauri dev";
|
|
329
|
+
scripts["build:tauri"] = `${runCmd} build && cargo tauri build`;
|
|
330
|
+
}
|
|
331
|
+
if (choices.features.includes("tauriDev")) {
|
|
332
|
+
scripts["dev:tauri-dev"] = "cd src-tauri-dev && cargo tauri dev";
|
|
333
|
+
scripts["build:tauri-dev"] = "cd src-tauri-dev && cargo tauri build";
|
|
334
|
+
}
|
|
335
|
+
return {
|
|
336
|
+
name: choices.projectName,
|
|
337
|
+
version: "0.0.1",
|
|
338
|
+
private: true,
|
|
339
|
+
type: "module",
|
|
340
|
+
scripts,
|
|
341
|
+
dependencies: deps,
|
|
342
|
+
devDependencies: devDeps,
|
|
343
|
+
};
|
|
344
|
+
}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { capitalize, getLangLabel, getSecondaryLang } from "./utils.js";
|
|
2
|
+
export function generateSettingsFile(choices) {
|
|
3
|
+
const lines = [];
|
|
4
|
+
// Import types from settings-types (copied from template src/config/)
|
|
5
|
+
lines.push(`export type {`);
|
|
6
|
+
lines.push(` HeaderNavChildItem,`);
|
|
7
|
+
lines.push(` HeaderNavItem,`);
|
|
8
|
+
lines.push(` HeaderRightItem,`);
|
|
9
|
+
lines.push(` ColorModeConfig,`);
|
|
10
|
+
lines.push(` HtmlPreviewConfig,`);
|
|
11
|
+
lines.push(` FrontmatterPreviewConfig,`);
|
|
12
|
+
lines.push(` LocaleConfig,`);
|
|
13
|
+
lines.push(` VersionConfig,`);
|
|
14
|
+
lines.push(` FooterConfig,`);
|
|
15
|
+
lines.push(` BodyFootUtilAreaConfig,`);
|
|
16
|
+
lines.push(` TagPlacement,`);
|
|
17
|
+
lines.push(` TagGovernanceMode,`);
|
|
18
|
+
lines.push(` TagVocabularyEntry,`);
|
|
19
|
+
lines.push(`} from "./settings-types";`);
|
|
20
|
+
lines.push(`import type {`);
|
|
21
|
+
lines.push(` HeaderNavItem,`);
|
|
22
|
+
lines.push(` HeaderRightItem,`);
|
|
23
|
+
lines.push(` ColorModeConfig,`);
|
|
24
|
+
lines.push(` HtmlPreviewConfig,`);
|
|
25
|
+
lines.push(` FrontmatterPreviewConfig,`);
|
|
26
|
+
lines.push(` LocaleConfig,`);
|
|
27
|
+
lines.push(` VersionConfig,`);
|
|
28
|
+
lines.push(` FooterConfig,`);
|
|
29
|
+
lines.push(` BodyFootUtilAreaConfig,`);
|
|
30
|
+
lines.push(` TagPlacement,`);
|
|
31
|
+
lines.push(` TagGovernanceMode,`);
|
|
32
|
+
lines.push(`} from "./settings-types";`);
|
|
33
|
+
lines.push(``);
|
|
34
|
+
lines.push(`export const settings = {`);
|
|
35
|
+
if (choices.colorSchemeMode === "single") {
|
|
36
|
+
lines.push(` colorScheme: ${JSON.stringify(choices.singleScheme ?? "Dracula")},`);
|
|
37
|
+
lines.push(` colorMode: false as ColorModeConfig | false,`);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
lines.push(` colorScheme: ${JSON.stringify(choices.darkScheme ?? "GitHub Dark")},`);
|
|
41
|
+
lines.push(` colorMode: {`);
|
|
42
|
+
lines.push(` defaultMode: ${JSON.stringify(choices.defaultMode ?? "dark")},`);
|
|
43
|
+
lines.push(` lightScheme: ${JSON.stringify(choices.lightScheme ?? "GitHub Light")},`);
|
|
44
|
+
lines.push(` darkScheme: ${JSON.stringify(choices.darkScheme ?? "GitHub Dark")},`);
|
|
45
|
+
lines.push(` respectPrefersColorScheme: ${choices.respectPrefersColorScheme ?? true},`);
|
|
46
|
+
lines.push(` } satisfies ColorModeConfig,`);
|
|
47
|
+
}
|
|
48
|
+
lines.push(` siteName: ${JSON.stringify(capitalize(choices.projectName.replace(/-/g, " ")))},`);
|
|
49
|
+
lines.push(` siteDescription: "" as string,`);
|
|
50
|
+
lines.push(` base: "/",`);
|
|
51
|
+
lines.push(` trailingSlash: false as boolean,`);
|
|
52
|
+
lines.push(` noindex: false as boolean,`);
|
|
53
|
+
lines.push(` editUrl: false as string | false,`);
|
|
54
|
+
const rawGithubUrl = (choices.githubUrl ?? "").trim();
|
|
55
|
+
if (rawGithubUrl) {
|
|
56
|
+
lines.push(` githubUrl: ${JSON.stringify(rawGithubUrl)} as string | false,`);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
lines.push(` githubUrl: false as string | false,`);
|
|
60
|
+
}
|
|
61
|
+
lines.push(` siteUrl: "" as string,`);
|
|
62
|
+
lines.push(` docsDir: "src/content/docs",`);
|
|
63
|
+
lines.push(` defaultLocale: ${JSON.stringify(choices.defaultLang ?? "en")} as string,`);
|
|
64
|
+
if (choices.features.includes("i18n")) {
|
|
65
|
+
const secondaryLang = getSecondaryLang(choices.defaultLang);
|
|
66
|
+
const secondaryLabel = getLangLabel(secondaryLang);
|
|
67
|
+
lines.push(` locales: {`);
|
|
68
|
+
lines.push(` ${secondaryLang}: { label: ${JSON.stringify(secondaryLabel)}, dir: "src/content/docs-${secondaryLang}" },`);
|
|
69
|
+
lines.push(` } as Record<string, LocaleConfig>,`);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
lines.push(` locales: {} as Record<string, LocaleConfig>,`);
|
|
73
|
+
}
|
|
74
|
+
lines.push(` mermaid: true,`);
|
|
75
|
+
lines.push(` sitemap: false,`);
|
|
76
|
+
lines.push(` docMetainfo: false,`);
|
|
77
|
+
lines.push(` docTags: false,`);
|
|
78
|
+
lines.push(` tagPlacement: "after-title" as TagPlacement,`);
|
|
79
|
+
if (choices.features.includes("tagGovernance")) {
|
|
80
|
+
lines.push(` tagGovernance: "warn" as TagGovernanceMode,`);
|
|
81
|
+
lines.push(` tagVocabulary: true as boolean,`);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
lines.push(` tagGovernance: "off" as TagGovernanceMode,`);
|
|
85
|
+
lines.push(` tagVocabulary: false as boolean,`);
|
|
86
|
+
}
|
|
87
|
+
lines.push(` frontmatterPreview: false as FrontmatterPreviewConfig | false,`);
|
|
88
|
+
if (choices.features.includes("llmsTxt")) {
|
|
89
|
+
lines.push(` llmsTxt: true,`);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
lines.push(` llmsTxt: false,`);
|
|
93
|
+
}
|
|
94
|
+
lines.push(` math: false,`);
|
|
95
|
+
lines.push(` cjkFriendly: ${choices.cjkFriendly ?? false} as boolean,`);
|
|
96
|
+
lines.push(` onBrokenMarkdownLinks: "warn" as "warn" | "error" | "ignore",`);
|
|
97
|
+
lines.push(` aiAssistant: false as boolean,`);
|
|
98
|
+
if (choices.features.includes("docHistory")) {
|
|
99
|
+
lines.push(` docHistory: true,`);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
lines.push(` docHistory: false,`);
|
|
103
|
+
}
|
|
104
|
+
if (choices.features.includes("bodyFootUtil")) {
|
|
105
|
+
lines.push(` bodyFootUtilArea: {`);
|
|
106
|
+
lines.push(` docHistory: ${choices.features.includes("docHistory")},`);
|
|
107
|
+
lines.push(` viewSourceLink: ${Boolean(rawGithubUrl)},`);
|
|
108
|
+
lines.push(` } satisfies BodyFootUtilAreaConfig as BodyFootUtilAreaConfig | false,`);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
lines.push(` bodyFootUtilArea: false as BodyFootUtilAreaConfig | false,`);
|
|
112
|
+
}
|
|
113
|
+
if (choices.features.includes("designTokenPanel")) {
|
|
114
|
+
lines.push(` designTokenPanel: true as boolean,`);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
lines.push(` designTokenPanel: false as boolean,`);
|
|
118
|
+
}
|
|
119
|
+
// Deprecated alias — kept for one release so existing user projects keep
|
|
120
|
+
// working. Prefer `designTokenPanel` above; when this alias is unset, only
|
|
121
|
+
// the new flag is consulted.
|
|
122
|
+
lines.push(` colorTweakPanel: undefined as boolean | undefined,`);
|
|
123
|
+
if (choices.features.includes("sidebarResizer")) {
|
|
124
|
+
lines.push(` sidebarResizer: true as boolean,`);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
lines.push(` sidebarResizer: false as boolean,`);
|
|
128
|
+
}
|
|
129
|
+
if (choices.features.includes("sidebarToggle")) {
|
|
130
|
+
lines.push(` sidebarToggle: true as boolean,`);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
lines.push(` sidebarToggle: false as boolean,`);
|
|
134
|
+
}
|
|
135
|
+
if (choices.features.includes("imageEnlarge")) {
|
|
136
|
+
lines.push(` imageEnlarge: true as boolean,`);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
lines.push(` imageEnlarge: false as boolean,`);
|
|
140
|
+
}
|
|
141
|
+
lines.push(` htmlPreview: undefined as HtmlPreviewConfig | undefined,`);
|
|
142
|
+
if (choices.features.includes("versioning")) {
|
|
143
|
+
lines.push(` versions: [] as VersionConfig[],`);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
lines.push(` versions: false as VersionConfig[] | false,`);
|
|
147
|
+
}
|
|
148
|
+
if (choices.features.includes("claudeResources")) {
|
|
149
|
+
lines.push(` claudeResources: {`);
|
|
150
|
+
lines.push(` claudeDir: ".claude",`);
|
|
151
|
+
lines.push(` } as { claudeDir: string; projectRoot?: string } | false,`);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
lines.push(` claudeResources: false as { claudeDir: string; projectRoot?: string } | false,`);
|
|
155
|
+
}
|
|
156
|
+
if (choices.features.includes("claudeResources")) {
|
|
157
|
+
lines.push(` defaultLocaleOnlyPrefixes: [`);
|
|
158
|
+
lines.push(` "/docs/claude-md/",`);
|
|
159
|
+
lines.push(` "/docs/claude-skills/",`);
|
|
160
|
+
lines.push(` "/docs/claude-agents/",`);
|
|
161
|
+
lines.push(` "/docs/claude-commands/",`);
|
|
162
|
+
lines.push(` ] as string[],`);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
lines.push(` defaultLocaleOnlyPrefixes: [] as string[],`);
|
|
166
|
+
}
|
|
167
|
+
if (choices.features.includes("footerNavGroup") ||
|
|
168
|
+
choices.features.includes("footerCopyright") ||
|
|
169
|
+
choices.features.includes("footerTaglist")) {
|
|
170
|
+
lines.push(` footer: {`);
|
|
171
|
+
if (choices.features.includes("footerNavGroup")) {
|
|
172
|
+
lines.push(` links: [`);
|
|
173
|
+
lines.push(` {`);
|
|
174
|
+
lines.push(` title: "Docs",`);
|
|
175
|
+
lines.push(` items: [`);
|
|
176
|
+
lines.push(` { label: "Getting Started", href: "/docs/getting-started" },`);
|
|
177
|
+
lines.push(` ],`);
|
|
178
|
+
lines.push(` },`);
|
|
179
|
+
lines.push(` ],`);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
lines.push(` links: [],`);
|
|
183
|
+
}
|
|
184
|
+
if (choices.features.includes("footerCopyright")) {
|
|
185
|
+
lines.push(` copyright: "Copyright © ${new Date().getFullYear()} Your Name. Built with zudo-doc.",`);
|
|
186
|
+
}
|
|
187
|
+
if (choices.features.includes("footerTaglist")) {
|
|
188
|
+
lines.push(` taglist: {`);
|
|
189
|
+
lines.push(` enabled: true,`);
|
|
190
|
+
lines.push(` groupBy: "group",`);
|
|
191
|
+
lines.push(` },`);
|
|
192
|
+
}
|
|
193
|
+
lines.push(` } satisfies FooterConfig as FooterConfig | false,`);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
lines.push(` footer: false as FooterConfig | false,`);
|
|
197
|
+
}
|
|
198
|
+
lines.push(` headerNav: [`);
|
|
199
|
+
lines.push(` { label: "Getting Started", path: "/docs/getting-started", categoryMatch: "getting-started" },`);
|
|
200
|
+
if (choices.features.includes("changelog")) {
|
|
201
|
+
lines.push(` { label: "Changelog", path: "/docs/changelog", categoryMatch: "changelog" },`);
|
|
202
|
+
}
|
|
203
|
+
lines.push(` ] as HeaderNavItem[],`);
|
|
204
|
+
lines.push(` headerRightItems: [`);
|
|
205
|
+
if (choices.headerRightItems !== undefined) {
|
|
206
|
+
// User-supplied override (including empty array): emit each entry verbatim,
|
|
207
|
+
// in the chosen order. An empty array means "no header-right items" — honor it.
|
|
208
|
+
// filterHeaderRightItems (src/utils/header-right-items.ts) handles runtime
|
|
209
|
+
// hiding of items whose feature is disabled — no need to gate emission
|
|
210
|
+
// here on choices.features.
|
|
211
|
+
for (const item of choices.headerRightItems) {
|
|
212
|
+
if (item.type === "trigger") {
|
|
213
|
+
lines.push(` { type: "trigger", trigger: ${JSON.stringify(item.trigger)} },`);
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
lines.push(` { type: "component", component: ${JSON.stringify(item.component)} },`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
// Default fallback: hardcoded order, gated on selected features.
|
|
222
|
+
if (choices.features.includes("designTokenPanel")) {
|
|
223
|
+
lines.push(` { type: "trigger", trigger: "design-token-panel" },`);
|
|
224
|
+
}
|
|
225
|
+
if (choices.features.includes("versioning")) {
|
|
226
|
+
lines.push(` { type: "component", component: "version-switcher" },`);
|
|
227
|
+
}
|
|
228
|
+
lines.push(` { type: "component", component: "github-link" },`);
|
|
229
|
+
lines.push(` { type: "component", component: "theme-toggle" },`);
|
|
230
|
+
if (choices.features.includes("i18n")) {
|
|
231
|
+
lines.push(` { type: "component", component: "language-switcher" },`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
lines.push(` ] as HeaderRightItem[],`);
|
|
235
|
+
lines.push(`};`);
|
|
236
|
+
return lines.join("\n") + "\n";
|
|
237
|
+
}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function installDependencies(dir: string, pm: string): void;
|
|
2
|
+
export declare function capitalize(str: string): string;
|
|
3
|
+
/** Get a short uppercase label for a language code (e.g. "en" → "EN", "zh-cn" → "ZH-CN"). */
|
|
4
|
+
export declare function getLangLabel(langCode: string): string;
|
|
5
|
+
/** Determine the secondary language code when i18n is enabled. */
|
|
6
|
+
export declare function getSecondaryLang(defaultLang: string): string;
|
|
7
|
+
/** Apply a list of regex replacements to a file (if it exists). */
|
|
8
|
+
export declare function patchFile(filePath: string, replacements: [RegExp, string][]): Promise<void>;
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
export function installDependencies(dir, pm) {
|
|
4
|
+
const commands = {
|
|
5
|
+
pnpm: "pnpm install",
|
|
6
|
+
npm: "npm install",
|
|
7
|
+
yarn: "yarn",
|
|
8
|
+
bun: "bun install",
|
|
9
|
+
};
|
|
10
|
+
const cmd = commands[pm] || "npm install";
|
|
11
|
+
// Use pipe to avoid garbled output when used alongside spinner
|
|
12
|
+
execSync(cmd, { cwd: dir, stdio: "pipe" });
|
|
13
|
+
}
|
|
14
|
+
export function capitalize(str) {
|
|
15
|
+
return str.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
16
|
+
}
|
|
17
|
+
/** Get a short uppercase label for a language code (e.g. "en" → "EN", "zh-cn" → "ZH-CN"). */
|
|
18
|
+
export function getLangLabel(langCode) {
|
|
19
|
+
return langCode.toUpperCase();
|
|
20
|
+
}
|
|
21
|
+
/** Determine the secondary language code when i18n is enabled. */
|
|
22
|
+
export function getSecondaryLang(defaultLang) {
|
|
23
|
+
return defaultLang === "en" ? "ja" : "en";
|
|
24
|
+
}
|
|
25
|
+
/** Apply a list of regex replacements to a file (if it exists). */
|
|
26
|
+
export async function patchFile(filePath, replacements) {
|
|
27
|
+
if (!(await fs.pathExists(filePath)))
|
|
28
|
+
return;
|
|
29
|
+
let content = await fs.readFile(filePath, "utf-8");
|
|
30
|
+
for (const [pattern, replacement] of replacements) {
|
|
31
|
+
content = content.replace(pattern, replacement);
|
|
32
|
+
}
|
|
33
|
+
await fs.writeFile(filePath, content);
|
|
34
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { UserChoices } from "./prompts.js";
|
|
2
|
+
/**
|
|
3
|
+
* Programmatically generate zfb.config.ts from user choices.
|
|
4
|
+
*
|
|
5
|
+
* W7A (#1736): emits zfb plugins in the host's INLINE-OBJECT shape —
|
|
6
|
+
* `{ name: "./plugins/<plugin>.mjs", options: {...} }` — not the
|
|
7
|
+
* pre-cutover factory-import pattern (`import { fooPlugin } from
|
|
8
|
+
* "./src/integrations/foo"`). Inline functions are not supported by zfb's
|
|
9
|
+
* plugin runtime (see `@takazudo/zfb/plugins` source); plugins MUST be
|
|
10
|
+
* authored as standalone `.mjs` modules referenced from `zfb.config.ts`
|
|
11
|
+
* by `name`. The plugin source files are shipped by the base/feature
|
|
12
|
+
* templates under `plugins/<plugin>.mjs` and `templates/features/<feature>/
|
|
13
|
+
* files/plugins/<plugin>.mjs`.
|
|
14
|
+
*
|
|
15
|
+
* Replaces the former astro-config-gen.ts + content-config-gen.ts pair.
|
|
16
|
+
* In the zfb world, content-collection schemas live inside zfb.config.ts
|
|
17
|
+
* itself — there is no separate content.config.ts.
|
|
18
|
+
*/
|
|
19
|
+
export declare function generateZfbConfig(choices: UserChoices): string;
|