create-zudo-doc 5.13.1 → 5.15.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/CHANGELOG.md +29 -0
- package/README.md +41 -2
- package/dist/api.d.ts +3 -0
- package/dist/api.js +12 -1
- package/dist/claude-md-gen.d.ts +2 -1
- package/dist/claude-md-gen.js +40 -17
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +27 -0
- package/dist/compose.d.ts +5 -4
- package/dist/compose.js +6 -6
- package/dist/constants.js +8 -1
- package/dist/features/asset-viewer.d.ts +10 -0
- package/dist/features/asset-viewer.js +12 -0
- package/dist/features/claude-resources.d.ts +3 -2
- package/dist/features/claude-resources.js +3 -2
- package/dist/features/codex-resources.d.ts +3 -2
- package/dist/features/codex-resources.js +3 -2
- package/dist/features/doc-tags.d.ts +2 -2
- package/dist/features/doc-tags.js +2 -2
- package/dist/features/i18n.d.ts +4 -4
- package/dist/features/i18n.js +4 -4
- package/dist/features/index.js +2 -0
- package/dist/features/tag-governance.js +18 -9
- package/dist/features/versioning.d.ts +3 -6
- package/dist/features/versioning.js +3 -6
- package/dist/index.js +2 -1
- package/dist/locale-plan.d.ts +20 -0
- package/dist/locale-plan.js +58 -0
- package/dist/preset.d.ts +1 -0
- package/dist/preset.js +20 -0
- package/dist/prompts.d.ts +2 -0
- package/dist/prompts.js +14 -1
- package/dist/scaffold.d.ts +2 -3
- package/dist/scaffold.js +109 -77
- package/dist/utils.d.ts +7 -1
- package/dist/utils.js +9 -2
- package/dist/zfb-config-gen.d.ts +2 -1
- package/dist/zfb-config-gen.js +30 -17
- package/package.json +1 -1
- package/templates/base/pages/docs/[[...slug]].tsx +6 -8
- package/templates/base/scripts/check-links.js +80 -23
- package/templates/base/scripts/setup-doc-skill.sh +359 -21
- package/templates/features/claudeSkills/files/.claude/skills/zudo-doc-translate/SKILL.md +76 -53
- package/templates/features/claudeSkills/files/.claude/skills/zudo-doc-version-bump/SKILL.md +60 -36
- package/templates/features/claudeSkillsWriting/files/.claude/skills/zudo-doc-writing/SKILL.md +13 -3
- package/templates/features/i18n/files/pages/[locale]/docs/[[...slug]].tsx +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,35 @@ All notable changes to `create-zudo-doc` are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on Keep a Changelog, and release notes are generated from the changelog MDX pages.
|
|
6
6
|
|
|
7
|
+
## [5.15.0] - 2026-09-01
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
- Added one ordered locale-plan contract across the API, CLI, presets, prompts, scaffold output, and generated guidance, allowing new projects to select and emit any supported set of locales. (`10e34ca0`, `5a990248`, `c9543772`)
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
- Newly generated multi-locale projects now localize generated Claude/Codex resource routes by default instead of keeping them limited to the default locale. (`26ecad11`)
|
|
16
|
+
|
|
17
|
+
### Other Changes
|
|
18
|
+
|
|
19
|
+
- Updated newly generated projects to use the zfb 2.14.2 package family. (`1c1f8f26`)
|
|
20
|
+
|
|
21
|
+
## [5.14.0] - 2026-08-31
|
|
22
|
+
|
|
23
|
+
### Features
|
|
24
|
+
|
|
25
|
+
- Added the `--asset-viewer` feature flag. Generated projects now emit `assetViewer: true` in `zfb.config.ts`, enabling the package-owned viewer for files under `public/assets/` without adding a host route stub or extra template files. (`45dc50cdb`)
|
|
26
|
+
- Generated doc-history projects now use the package-owned `run-parallel` command for their concurrent development servers, removing `npm-run-all2` and reporting unsupported trailing arguments instead of silently ignoring them. (`9402ff157`, `3ebfa6e9c`)
|
|
27
|
+
|
|
28
|
+
### Bug Fixes
|
|
29
|
+
|
|
30
|
+
- Updated the generated link checker to recognize valid unquoted HTML attributes, decode character references, resolve percent-encoded routes, and avoid serialized-markup false positives. (`db9a07018`)
|
|
31
|
+
|
|
32
|
+
### Other Changes
|
|
33
|
+
|
|
34
|
+
- Updated newly generated projects to use the zfb 2.14.0 package family and `@takazudo/zdtp` 0.4.14. (`dbe8553c7`, `038870c94`)
|
|
35
|
+
|
|
7
36
|
## [5.13.1] - 2026-08-28
|
|
8
37
|
|
|
9
38
|
### Bug Fixes
|
package/README.md
CHANGED
|
@@ -35,13 +35,49 @@ pnpm create zudo-doc my-docs --yes
|
|
|
35
35
|
# Fully specified, non-interactive
|
|
36
36
|
pnpm create zudo-doc my-docs \
|
|
37
37
|
--lang ja \
|
|
38
|
+
--additional-langs en,de \
|
|
38
39
|
--scheme "Default Dark" \
|
|
39
|
-
--no-i18n \
|
|
40
40
|
--search \
|
|
41
41
|
--pm pnpm \
|
|
42
42
|
--install
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
+
### Locales and translations
|
|
46
|
+
|
|
47
|
+
`--lang` selects the primary locale. Its pages use the unprefixed
|
|
48
|
+
`/docs/...` routes and `src/content/docs/`. Add any number of additional
|
|
49
|
+
locales, in the order shown by the language switcher, with
|
|
50
|
+
`--additional-langs <code,...>`:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pnpm create zudo-doc my-docs \
|
|
54
|
+
--lang en \
|
|
55
|
+
--additional-langs ja,de \
|
|
56
|
+
--yes
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
An omitted or blank list creates a single-locale project. The same rule
|
|
60
|
+
applies to a preset that omits `additionalLangs`; an explicit non-empty list
|
|
61
|
+
is normalized to lowercase, validates each code for safe URL/path use, rejects
|
|
62
|
+
duplicates and the primary code, and creates `src/content/docs-<code>/` plus
|
|
63
|
+
the corresponding `/<code>/docs/...` routes. A legacy preset containing only
|
|
64
|
+
`i18n: true` keeps compatibility inference (`ja` for primary `en`, otherwise
|
|
65
|
+
`en`).
|
|
66
|
+
|
|
67
|
+
CLI locale flags replace the preset list rather than merging with it. An
|
|
68
|
+
explicit `--additional-langs` also enables i18n; if it overrides
|
|
69
|
+
`--no-i18n`, the CLI prints a warning so the precedence is visible.
|
|
70
|
+
|
|
71
|
+
The generated starter uses Japanese prose for `ja` and English placeholder
|
|
72
|
+
prose for every other additional locale. Translate those pages before
|
|
73
|
+
publishing. Labels are configuration-driven: the switcher uses each locale's
|
|
74
|
+
configured `label` and map order, so custom codes and labels are not tied to
|
|
75
|
+
hard-coded `JP` or `JA` links.
|
|
76
|
+
|
|
77
|
+
Built-in UI translations resolve in this order:
|
|
78
|
+
|
|
79
|
+
`requested locale → configured default locale → package English → raw UI-string key`
|
|
80
|
+
|
|
45
81
|
## Options
|
|
46
82
|
|
|
47
83
|
### Project basics
|
|
@@ -50,6 +86,7 @@ pnpm create zudo-doc my-docs \
|
|
|
50
86
|
|------|-------------|---------|
|
|
51
87
|
| `[project-name]` | Project name (positional arg or `--name`) | prompted |
|
|
52
88
|
| `--lang <code>` | Default language: `en`, `ja`, `zh-cn`, `zh-tw`, `ko`, `es`, `fr`, `de`, `pt` | `en` |
|
|
89
|
+
| `--additional-langs <a,b>` | Ordered additional locale codes; implies i18n and replaces a preset list | none |
|
|
53
90
|
| `--pm <manager>` | Package manager: `pnpm`, `npm`, `yarn`, `bun` | detected |
|
|
54
91
|
| `--[no-]install` | Install dependencies after scaffolding | prompted |
|
|
55
92
|
| `-y, --yes` | Use defaults for all unspecified options, skip prompts | — |
|
|
@@ -72,10 +109,11 @@ Each feature has a `--[no-]<flag>` form. Passing `--feature` enables it; `--no-f
|
|
|
72
109
|
|
|
73
110
|
| Flag | Description | Default |
|
|
74
111
|
|------|-------------|---------|
|
|
75
|
-
| `--[no-]i18n` |
|
|
112
|
+
| `--[no-]i18n` | Legacy multi-language toggle; with no explicit list, infers one additional locale | off |
|
|
76
113
|
| `--[no-]search` | Full-text search | on |
|
|
77
114
|
| `--[no-]sidebar-filter` | Real-time sidebar filter | on |
|
|
78
115
|
| `--[no-]image-enlarge` | Click-to-enlarge for oversized images | on |
|
|
116
|
+
| `--[no-]asset-viewer` | Viewer pages for files under `public/assets/` | off |
|
|
79
117
|
| `--[no-]tag-governance` | Vocabulary-aware tag audit + suggest scripts | off |
|
|
80
118
|
| `--[no-]claude-resources` | Auto-generate Claude Code docs from `.claude/` | off |
|
|
81
119
|
| `--[no-]codex-resources` | Auto-generate Codex docs from `.codex/` + `AGENTS.md` | off |
|
|
@@ -139,6 +177,7 @@ import { createZudoDoc } from "create-zudo-doc";
|
|
|
139
177
|
await createZudoDoc({
|
|
140
178
|
projectName: "my-docs",
|
|
141
179
|
defaultLang: "en",
|
|
180
|
+
additionalLangs: ["ja", "de"],
|
|
142
181
|
colorSchemeMode: "single",
|
|
143
182
|
singleScheme: "Default Dark",
|
|
144
183
|
features: ["search", "sidebarFilter", "tagGovernance"],
|
package/dist/api.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { PresetHeaderRightItem, PresetMetaTagsConfig } from "./preset.js";
|
|
2
|
+
export { resolveLocalePlan, type LocalePlan, type LocalePlanInput, } from "./locale-plan.js";
|
|
2
3
|
export type { UserChoices } from "./prompts.js";
|
|
3
4
|
export interface CreateOptions {
|
|
4
5
|
projectName: string;
|
|
5
6
|
/** Default language code (default: "en") */
|
|
6
7
|
defaultLang?: string;
|
|
8
|
+
/** Ordered additional locale codes. A non-empty list implies i18n. */
|
|
9
|
+
additionalLangs?: string[];
|
|
7
10
|
colorSchemeMode: "single" | "light-dark";
|
|
8
11
|
singleScheme?: string;
|
|
9
12
|
lightScheme?: string;
|
package/dist/api.js
CHANGED
|
@@ -3,6 +3,8 @@ import { SINGLE_SCHEMES, THEME_PACKS } from "./constants.js";
|
|
|
3
3
|
import { parseChangelogPackages, validateChangelogPackages, validateHeaderRightItems, validateMetaTags, } from "./preset.js";
|
|
4
4
|
import { scaffold } from "./scaffold.js";
|
|
5
5
|
import { initGitRepo, installDependencies, validateProjectName } from "./utils.js";
|
|
6
|
+
import { resolveLocalePlan } from "./locale-plan.js";
|
|
7
|
+
export { resolveLocalePlan, } from "./locale-plan.js";
|
|
6
8
|
export async function createZudoDoc(options) {
|
|
7
9
|
const { install = false, git = false, ...rest } = options;
|
|
8
10
|
const nameError = validateProjectName(rest.projectName);
|
|
@@ -52,9 +54,18 @@ export async function createZudoDoc(options) {
|
|
|
52
54
|
throw new Error(err);
|
|
53
55
|
changelogPackages = parseChangelogPackages(changelogPackages);
|
|
54
56
|
}
|
|
57
|
+
const localePlan = resolveLocalePlan({
|
|
58
|
+
defaultLang: rest.defaultLang ?? "en",
|
|
59
|
+
additionalLangs: rest.additionalLangs,
|
|
60
|
+
i18n: rest.features.includes("i18n"),
|
|
61
|
+
});
|
|
55
62
|
const choices = {
|
|
56
63
|
...rest,
|
|
57
|
-
defaultLang:
|
|
64
|
+
defaultLang: localePlan.defaultLang,
|
|
65
|
+
additionalLangs: rest.additionalLangs === undefined ? undefined : localePlan.additionalLangs,
|
|
66
|
+
features: localePlan.i18n
|
|
67
|
+
? [...new Set([...rest.features, "i18n"])]
|
|
68
|
+
: rest.features.filter((feature) => feature !== "i18n"),
|
|
58
69
|
changelogPackages,
|
|
59
70
|
};
|
|
60
71
|
await scaffold(choices);
|
package/dist/claude-md-gen.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { UserChoices } from "./prompts.js";
|
|
2
|
+
import type { LocalePlan } from "./locale-plan.js";
|
|
2
3
|
/**
|
|
3
4
|
* Generate the per-project `CLAUDE.md` (minimal-scaffold shape, epic
|
|
4
5
|
* zudolab/zudo-doc#2651, Wave 6 #2660). Rewritten from scratch — the old
|
|
@@ -7,4 +8,4 @@ import type { UserChoices } from "./prompts.js";
|
|
|
7
8
|
* longer exists. The scaffolded project is now ~13 files; almost
|
|
8
9
|
* everything referenced here lives in `node_modules/@takazudo/zudo-doc`.
|
|
9
10
|
*/
|
|
10
|
-
export declare function generateCLAUDEFile(choices: UserChoices): string;
|
|
11
|
+
export declare function generateCLAUDEFile(choices: UserChoices, localePlan?: LocalePlan): string;
|
package/dist/claude-md-gen.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveLocalePlan } from "./locale-plan.js";
|
|
2
|
+
import { capitalize, getLangLabel, pmRunCommand } from "./utils.js";
|
|
2
3
|
/**
|
|
3
4
|
* Generate the per-project `CLAUDE.md` (minimal-scaffold shape, epic
|
|
4
5
|
* zudolab/zudo-doc#2651, Wave 6 #2660). Rewritten from scratch — the old
|
|
@@ -7,9 +8,30 @@ import { capitalize, pmRunCommand } from "./utils.js";
|
|
|
7
8
|
* longer exists. The scaffolded project is now ~13 files; almost
|
|
8
9
|
* everything referenced here lives in `node_modules/@takazudo/zudo-doc`.
|
|
9
10
|
*/
|
|
10
|
-
export function generateCLAUDEFile(choices
|
|
11
|
+
export function generateCLAUDEFile(choices, localePlan = resolveLocalePlan({
|
|
12
|
+
defaultLang: choices.defaultLang,
|
|
13
|
+
additionalLangs: choices.additionalLangs,
|
|
14
|
+
i18n: choices.features.includes("i18n"),
|
|
15
|
+
i18nExplicitlyDisabled: choices.explicitlyDisabledFeatures?.includes("i18n"),
|
|
16
|
+
})) {
|
|
11
17
|
const siteName = capitalize(choices.projectName.replace(/-/g, " "));
|
|
12
18
|
const lines = [];
|
|
19
|
+
const localeDisplayName = (locale) => {
|
|
20
|
+
if (locale === "en")
|
|
21
|
+
return "English";
|
|
22
|
+
if (locale === "ja")
|
|
23
|
+
return "Japanese";
|
|
24
|
+
return getLangLabel(locale);
|
|
25
|
+
};
|
|
26
|
+
const localeStarterNote = (locale) => {
|
|
27
|
+
if (locale === "ja")
|
|
28
|
+
return "Japanese starter prose";
|
|
29
|
+
if (locale === "en")
|
|
30
|
+
return "English starter prose";
|
|
31
|
+
return "English placeholder prose pending translation";
|
|
32
|
+
};
|
|
33
|
+
const defaultLocaleLabel = localeDisplayName(localePlan.defaultLang);
|
|
34
|
+
const additionalLocales = localePlan.i18n ? localePlan.additionalLangs : [];
|
|
13
35
|
lines.push(`# ${siteName}`);
|
|
14
36
|
lines.push(``);
|
|
15
37
|
lines.push(`Documentation site built with [zudo-doc](https://github.com/zudolab/zudo-doc) — a zfb-based documentation framework with MDX, Tailwind CSS v4, and Preact islands. This project is intentionally minimal: one config file (\`zfb.config.ts\`) plus markdown content — layout, chrome, and islands all ship from \`@takazudo/zudo-doc\` in \`node_modules\`.`);
|
|
@@ -29,10 +51,10 @@ export function generateCLAUDEFile(choices) {
|
|
|
29
51
|
lines.push(``);
|
|
30
52
|
const pm = choices.packageManager;
|
|
31
53
|
if (choices.features.includes("docHistory")) {
|
|
32
|
-
lines.push(`- \`${pmRunCommand(pm, "dev")}\` — runs the zfb dev server (port 4321) and the doc-history API server (port 4322) concurrently via \`run-
|
|
54
|
+
lines.push(`- \`${pmRunCommand(pm, "dev")}\` — runs the zfb dev server (port 4321) and the doc-history API server (port 4322) concurrently via \`run-parallel\` (a bin from @takazudo/zudo-doc) (\`${pmRunCommand(pm, "dev:zfb")}\` / \`${pmRunCommand(pm, "dev:history")}\` individually)`);
|
|
33
55
|
lines.push(`- \`${pmRunCommand(pm, "dev:network")}\` — same, but zfb binds \`--host 0.0.0.0\` for LAN access (\`${pmRunCommand(pm, "dev:zfb:network")}\` individually); the doc-history server stays loopback-only and LAN clients reach it through zfb's \`/doc-history/*\` dev proxy`);
|
|
34
56
|
lines.push(`- **Trusted networks only:** this also serves your git doc-history — including UNPUBLISHED local commits — to anyone on the LAN via the \`/doc-history/*\` proxy`);
|
|
35
|
-
lines.push(`- \`run-
|
|
57
|
+
lines.push(`- \`run-parallel\` does not forward trailing args — it rejects them with an error rather than silently ignoring them, so pass other zfb flags directly instead: \`${pm} run dev:zfb -- <flags>\``);
|
|
36
58
|
}
|
|
37
59
|
else {
|
|
38
60
|
lines.push(`- \`${pmRunCommand(pm, "dev")}\` — zfb dev server (port 4321)`);
|
|
@@ -49,16 +71,17 @@ export function generateCLAUDEFile(choices) {
|
|
|
49
71
|
lines.push(`pages/`);
|
|
50
72
|
lines.push(`├── index.tsx # 1-line re-export of the package home route`);
|
|
51
73
|
lines.push(`└── docs/[[...slug]].tsx # self-contained doc-route stub (required for \`${pm} dev\`)`);
|
|
52
|
-
if (
|
|
74
|
+
if (localePlan.i18n) {
|
|
53
75
|
lines.push(` [locale]/docs/[[...slug]].tsx # same, for non-default locales`);
|
|
54
76
|
}
|
|
55
77
|
lines.push(`src/`);
|
|
56
78
|
lines.push(`├── chrome-bindings.tsx # optional typed primary chrome / named header / MDX bindings`);
|
|
57
79
|
lines.push(`├── content/`);
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
80
|
+
const defaultBranch = additionalLocales.length === 0 ? "└──" : "├──";
|
|
81
|
+
lines.push(`│ ${defaultBranch} docs/ # ${defaultLocaleLabel} (default) MDX content (routes at /docs/; ${localeStarterNote(localePlan.defaultLang)})`);
|
|
82
|
+
for (const [index, locale] of additionalLocales.entries()) {
|
|
83
|
+
const branch = index === additionalLocales.length - 1 ? "└──" : "├──";
|
|
84
|
+
lines.push(`│ ${branch} docs-${locale}/ # ${localeDisplayName(locale)} MDX content (routes at /${locale}/docs/; ${localeStarterNote(locale)})`);
|
|
62
85
|
}
|
|
63
86
|
lines.push(`└── styles/`);
|
|
64
87
|
lines.push(` └── global.css # @import chain + a token-override slot — that's it`);
|
|
@@ -105,16 +128,16 @@ export function generateCLAUDEFile(choices) {
|
|
|
105
128
|
lines.push(`Admonitions (above), tabbed content (\`<Tabs>\` / \`<TabItem>\`, \`<CodeGroup>\`), and block math (\`<MathBlock>\`) work the same way — no import. Full reference: https://zudo-doc.takazudomodular.com/docs/components/`);
|
|
106
129
|
lines.push(``);
|
|
107
130
|
// i18n section
|
|
108
|
-
if (
|
|
109
|
-
const secondaryLang = choices.defaultLang === "ja" ? "en" : "ja";
|
|
110
|
-
const defaultLabel = choices.defaultLang === "ja" ? "Japanese" : "English";
|
|
111
|
-
const secondaryLabel = secondaryLang === "ja" ? "Japanese" : "English";
|
|
131
|
+
if (localePlan.i18n) {
|
|
112
132
|
lines.push(`## i18n`);
|
|
113
133
|
lines.push(``);
|
|
114
|
-
lines.push(`- ${
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
134
|
+
lines.push(`- ${defaultLocaleLabel} (default, \`${localePlan.defaultLang}\`): \`/docs/...\` — content in \`src/content/docs/\` (${localeStarterNote(localePlan.defaultLang)})`);
|
|
135
|
+
for (const locale of additionalLocales) {
|
|
136
|
+
lines.push(`- ${localeDisplayName(locale)} (\`${locale}\`): \`/${locale}/docs/...\` — content in \`src/content/docs-${locale}/\` (${localeStarterNote(locale)})`);
|
|
137
|
+
}
|
|
138
|
+
lines.push(`- Every additional-locale directory should mirror the default directory structure`);
|
|
139
|
+
lines.push(`- The \`ja\` locale, when configured, receives Japanese starter prose and uses Japanese translation conventions. Other non-EN locale directories currently receive English placeholder prose pending translation; do not assume they are already translated.`);
|
|
140
|
+
lines.push(`- Both \`pages/docs/[[...slug]].tsx\` and \`pages/[locale]/docs/[[...slug]].tsx\` are self-contained doc-route stubs shipped by the generator as explicit host-owned seams. zfb 2.13.1 also renders package-injected dynamic routes in dev; keep these files so the generated project retains route ownership and customization.`);
|
|
118
141
|
lines.push(``);
|
|
119
142
|
}
|
|
120
143
|
// Enabled features
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export interface CliArgs {
|
|
2
2
|
name?: string;
|
|
3
3
|
lang?: string;
|
|
4
|
+
additionalLangs?: string[];
|
|
4
5
|
colorSchemeMode?: "single" | "light-dark";
|
|
5
6
|
scheme?: string;
|
|
6
7
|
lightScheme?: string;
|
|
@@ -43,6 +44,8 @@ export interface CliArgs {
|
|
|
43
44
|
yes?: boolean;
|
|
44
45
|
help?: boolean;
|
|
45
46
|
}
|
|
47
|
+
/** Presets are the base layer; an explicitly supplied CLI list replaces it. */
|
|
48
|
+
export declare function layerAdditionalLangs(presetValue: string[] | undefined, cliValue: string[] | undefined): string[] | undefined;
|
|
46
49
|
export declare function parseArgs(argv?: string[]): CliArgs;
|
|
47
50
|
export declare function printHelp(): void;
|
|
48
51
|
export declare function validateArgs(args: CliArgs): string | null;
|
package/dist/cli.js
CHANGED
|
@@ -3,11 +3,17 @@ import pc from "picocolors";
|
|
|
3
3
|
import { FEATURES, SINGLE_SCHEMES, SUPPORTED_LANGS, THEME_PACKS } from "./constants.js";
|
|
4
4
|
import { parseChangelogPackages, validateChangelogPackages, } from "./preset.js";
|
|
5
5
|
import { validateProjectName } from "./utils.js";
|
|
6
|
+
import { resolveLocalePlan } from "./locale-plan.js";
|
|
7
|
+
/** Presets are the base layer; an explicitly supplied CLI list replaces it. */
|
|
8
|
+
export function layerAdditionalLangs(presetValue, cliValue) {
|
|
9
|
+
return cliValue === undefined ? presetValue : cliValue;
|
|
10
|
+
}
|
|
6
11
|
export function parseArgs(argv = process.argv.slice(2)) {
|
|
7
12
|
const raw = minimist(argv, {
|
|
8
13
|
string: [
|
|
9
14
|
"name",
|
|
10
15
|
"lang",
|
|
16
|
+
"additional-langs",
|
|
11
17
|
"color-scheme-mode",
|
|
12
18
|
"scheme",
|
|
13
19
|
"light-scheme",
|
|
@@ -42,6 +48,10 @@ export function parseArgs(argv = process.argv.slice(2)) {
|
|
|
42
48
|
}
|
|
43
49
|
if (raw.lang)
|
|
44
50
|
args.lang = raw.lang;
|
|
51
|
+
if (raw["additional-langs"] !== undefined) {
|
|
52
|
+
const value = raw["additional-langs"];
|
|
53
|
+
args.additionalLangs = (typeof value === "string" ? value : String(value)).split(",");
|
|
54
|
+
}
|
|
45
55
|
if (raw["color-scheme-mode"])
|
|
46
56
|
args.colorSchemeMode = raw["color-scheme-mode"];
|
|
47
57
|
if (raw.scheme)
|
|
@@ -96,6 +106,7 @@ ${pc.bold("Options:")}
|
|
|
96
106
|
--name <name> Project name (or first positional arg)
|
|
97
107
|
--lang <code> Default language (${langList})
|
|
98
108
|
Default: en
|
|
109
|
+
--additional-langs <a,b> Additional locale codes (ordered; implies i18n)
|
|
99
110
|
--color-scheme-mode <mode> single | light-dark
|
|
100
111
|
--scheme <name> Color scheme (single mode)
|
|
101
112
|
--light-scheme <name> Light scheme (light-dark mode)
|
|
@@ -137,6 +148,22 @@ export function validateArgs(args) {
|
|
|
137
148
|
return `Invalid language "${args.lang}". Supported: ${validLangs.join(", ")}`;
|
|
138
149
|
}
|
|
139
150
|
}
|
|
151
|
+
// A preset may supply the primary locale, so defer cross-field validation
|
|
152
|
+
// until the layered choices reach runPrompts() when --lang is omitted.
|
|
153
|
+
if (args.additionalLangs !== undefined &&
|
|
154
|
+
(args.preset === undefined || args.lang !== undefined)) {
|
|
155
|
+
try {
|
|
156
|
+
resolveLocalePlan({
|
|
157
|
+
defaultLang: args.lang ?? "en",
|
|
158
|
+
additionalLangs: args.additionalLangs,
|
|
159
|
+
i18n: args.i18n ?? false,
|
|
160
|
+
i18nExplicitlyDisabled: args.i18n === false,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
return error instanceof Error ? error.message : String(error);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
140
167
|
if (args.colorSchemeMode && !["single", "light-dark"].includes(args.colorSchemeMode)) {
|
|
141
168
|
return `Invalid color-scheme-mode "${args.colorSchemeMode}". Must be "single" or "light-dark"`;
|
|
142
169
|
}
|
package/dist/compose.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { UserChoices } from "./prompts.js";
|
|
2
|
+
import type { LocalePlan } from "./locale-plan.js";
|
|
2
3
|
/** A single injection into a shared file at an anchor point. */
|
|
3
4
|
export interface Injection {
|
|
4
5
|
/** Target file path relative to project root */
|
|
@@ -29,13 +30,13 @@ export interface FeatureDefinition {
|
|
|
29
30
|
* Post-processing hook for complex transformations that cannot be expressed
|
|
30
31
|
* as simple file copies or anchor injections (e.g. i18n page patching).
|
|
31
32
|
*/
|
|
32
|
-
postProcess?: (targetDir: string, choices: UserChoices) => Promise<void>;
|
|
33
|
+
postProcess?: (targetDir: string, choices: UserChoices, localePlan?: LocalePlan) => Promise<void>;
|
|
33
34
|
}
|
|
34
35
|
/**
|
|
35
36
|
* A function that returns a FeatureDefinition based on user choices.
|
|
36
37
|
* This allows injections to be conditional on other choices.
|
|
37
38
|
*/
|
|
38
|
-
export type FeatureModule = (choices: UserChoices) => FeatureDefinition;
|
|
39
|
+
export type FeatureModule = (choices: UserChoices, localePlan?: LocalePlan) => FeatureDefinition;
|
|
39
40
|
/**
|
|
40
41
|
* Apply a list of injections to files in the target directory.
|
|
41
42
|
*
|
|
@@ -62,7 +63,7 @@ export declare function copyFeatureFiles(featureFilesDir: string, targetDir: str
|
|
|
62
63
|
* Resolve which features are selected based on UserChoices.
|
|
63
64
|
* Handles special cases like the footer pseudo-feature.
|
|
64
65
|
*/
|
|
65
|
-
export declare function resolveSelectedFeatures(choices: UserChoices, featureModules: Record<string, FeatureModule
|
|
66
|
+
export declare function resolveSelectedFeatures(choices: UserChoices, featureModules: Record<string, FeatureModule>, localePlan?: LocalePlan): FeatureDefinition[];
|
|
66
67
|
/**
|
|
67
68
|
* Validate that all feature dependencies are satisfied.
|
|
68
69
|
* Throws if a selected feature depends on one that isn't selected.
|
|
@@ -96,4 +97,4 @@ export declare const ANCHOR_FILES: string[];
|
|
|
96
97
|
* 5. Run post-processing hooks
|
|
97
98
|
* 6. Clean up unused anchors
|
|
98
99
|
*/
|
|
99
|
-
export declare function composeFeatures(targetDir: string, choices: UserChoices, featureModules: Record<string, FeatureModule>, featuresDir: string): Promise<void>;
|
|
100
|
+
export declare function composeFeatures(targetDir: string, choices: UserChoices, featureModules: Record<string, FeatureModule>, featuresDir: string, localePlan?: LocalePlan): Promise<void>;
|
package/dist/compose.js
CHANGED
|
@@ -120,7 +120,7 @@ export async function copyFeatureFiles(featureFilesDir, targetDir) {
|
|
|
120
120
|
* Resolve which features are selected based on UserChoices.
|
|
121
121
|
* Handles special cases like the footer pseudo-feature.
|
|
122
122
|
*/
|
|
123
|
-
export function resolveSelectedFeatures(choices, featureModules) {
|
|
123
|
+
export function resolveSelectedFeatures(choices, featureModules, localePlan) {
|
|
124
124
|
const selected = [];
|
|
125
125
|
for (const [name, moduleFn] of Object.entries(featureModules)) {
|
|
126
126
|
// Special case: footer is activated by footerNavGroup, footerCopyright,
|
|
@@ -129,12 +129,12 @@ export function resolveSelectedFeatures(choices, featureModules) {
|
|
|
129
129
|
if (choices.features.includes("footerNavGroup") ||
|
|
130
130
|
choices.features.includes("footerCopyright") ||
|
|
131
131
|
choices.features.includes("footerTaglist")) {
|
|
132
|
-
selected.push(moduleFn(choices));
|
|
132
|
+
selected.push(moduleFn(choices, localePlan));
|
|
133
133
|
}
|
|
134
134
|
continue;
|
|
135
135
|
}
|
|
136
136
|
if (choices.features.includes(name)) {
|
|
137
|
-
selected.push(moduleFn(choices));
|
|
137
|
+
selected.push(moduleFn(choices, localePlan));
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
return selected;
|
|
@@ -182,9 +182,9 @@ export const ANCHOR_FILES = [];
|
|
|
182
182
|
* 5. Run post-processing hooks
|
|
183
183
|
* 6. Clean up unused anchors
|
|
184
184
|
*/
|
|
185
|
-
export async function composeFeatures(targetDir, choices, featureModules, featuresDir) {
|
|
185
|
+
export async function composeFeatures(targetDir, choices, featureModules, featuresDir, localePlan) {
|
|
186
186
|
// 1. Resolve
|
|
187
|
-
const features = resolveSelectedFeatures(choices, featureModules);
|
|
187
|
+
const features = resolveSelectedFeatures(choices, featureModules, localePlan);
|
|
188
188
|
const selectedNames = new Set(features.map((f) => f.name));
|
|
189
189
|
// 2. Validate
|
|
190
190
|
validateDependencies(features, selectedNames);
|
|
@@ -202,7 +202,7 @@ export async function composeFeatures(targetDir, choices, featureModules, featur
|
|
|
202
202
|
// 5. Post-processing
|
|
203
203
|
for (const feature of features) {
|
|
204
204
|
if (feature.postProcess) {
|
|
205
|
-
await feature.postProcess(targetDir, choices);
|
|
205
|
+
await feature.postProcess(targetDir, choices, localePlan);
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
// 6. Clean up unused anchors
|
package/dist/constants.js
CHANGED
|
@@ -187,7 +187,7 @@ export const FEATURES = [
|
|
|
187
187
|
{
|
|
188
188
|
value: "i18n",
|
|
189
189
|
label: "i18n (multi-language)",
|
|
190
|
-
hint: "
|
|
190
|
+
hint: "Configure additional locales",
|
|
191
191
|
default: false,
|
|
192
192
|
cliFlag: "i18n",
|
|
193
193
|
},
|
|
@@ -331,6 +331,13 @@ export const FEATURES = [
|
|
|
331
331
|
default: true,
|
|
332
332
|
cliFlag: "image-enlarge",
|
|
333
333
|
},
|
|
334
|
+
{
|
|
335
|
+
value: "assetViewer",
|
|
336
|
+
label: "Asset viewer",
|
|
337
|
+
hint: "Viewer pages for files under public/assets",
|
|
338
|
+
default: false,
|
|
339
|
+
cliFlag: "asset-viewer",
|
|
340
|
+
},
|
|
334
341
|
{
|
|
335
342
|
value: "dynamicPageTransition",
|
|
336
343
|
label: "Dynamic page transition",
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FeatureModule } from "../compose.js";
|
|
2
|
+
/**
|
|
3
|
+
* Asset-viewer feature.
|
|
4
|
+
*
|
|
5
|
+
* Purely a `zudoDoc({ assetViewer: true })` field (see `zfb-config-gen.ts`).
|
|
6
|
+
* The scanner, viewer route, and all supporting UI are package-owned by
|
|
7
|
+
* `@takazudo/zudo-doc`; generated projects only need the config toggle.
|
|
8
|
+
* Nothing is injected or copied into the scaffold.
|
|
9
|
+
*/
|
|
10
|
+
export declare const assetViewerFeature: FeatureModule;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asset-viewer feature.
|
|
3
|
+
*
|
|
4
|
+
* Purely a `zudoDoc({ assetViewer: true })` field (see `zfb-config-gen.ts`).
|
|
5
|
+
* The scanner, viewer route, and all supporting UI are package-owned by
|
|
6
|
+
* `@takazudo/zudo-doc`; generated projects only need the config toggle.
|
|
7
|
+
* Nothing is injected or copied into the scaffold.
|
|
8
|
+
*/
|
|
9
|
+
export const assetViewerFeature = () => ({
|
|
10
|
+
name: "assetViewer",
|
|
11
|
+
injections: [],
|
|
12
|
+
});
|
|
@@ -5,7 +5,8 @@ import type { FeatureModule } from "../compose.js";
|
|
|
5
5
|
* Fully plugin-owned (`@takazudo/zudo-doc/plugins/claude-resources`,
|
|
6
6
|
* `zudoDocPreset()` wires it whenever `settings.claudeResources` is
|
|
7
7
|
* truthy). Generation is package-owned. This feature's touch points are now
|
|
8
|
-
* just
|
|
9
|
-
*
|
|
8
|
+
* just the `claudeResources` field (`zfb-config-gen.ts`). Resource routes are
|
|
9
|
+
* localized by default; projects can opt selected paths out through the
|
|
10
|
+
* general-purpose `defaultLocaleOnlyPrefixes` setting.
|
|
10
11
|
*/
|
|
11
12
|
export declare const claudeResourcesFeature: FeatureModule;
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* Fully plugin-owned (`@takazudo/zudo-doc/plugins/claude-resources`,
|
|
5
5
|
* `zudoDocPreset()` wires it whenever `settings.claudeResources` is
|
|
6
6
|
* truthy). Generation is package-owned. This feature's touch points are now
|
|
7
|
-
* just
|
|
8
|
-
*
|
|
7
|
+
* just the `claudeResources` field (`zfb-config-gen.ts`). Resource routes are
|
|
8
|
+
* localized by default; projects can opt selected paths out through the
|
|
9
|
+
* general-purpose `defaultLocaleOnlyPrefixes` setting.
|
|
9
10
|
*/
|
|
10
11
|
export const claudeResourcesFeature = () => ({
|
|
11
12
|
name: "claudeResources",
|
|
@@ -5,7 +5,8 @@ import type { FeatureModule } from "../compose.js";
|
|
|
5
5
|
* Fully plugin-owned (`@takazudo/zudo-doc/plugins/codex-resources`,
|
|
6
6
|
* `zudoDocPreset()` wires it whenever `settings.codexResources` is
|
|
7
7
|
* truthy). Generation is package-owned. This feature's touch points are now
|
|
8
|
-
* just
|
|
9
|
-
*
|
|
8
|
+
* just the `codexResources` field (`zfb-config-gen.ts`). Resource routes are
|
|
9
|
+
* localized by default; projects can opt selected paths out through the
|
|
10
|
+
* general-purpose `defaultLocaleOnlyPrefixes` setting.
|
|
10
11
|
*/
|
|
11
12
|
export declare const codexResourcesFeature: FeatureModule;
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* Fully plugin-owned (`@takazudo/zudo-doc/plugins/codex-resources`,
|
|
5
5
|
* `zudoDocPreset()` wires it whenever `settings.codexResources` is
|
|
6
6
|
* truthy). Generation is package-owned. This feature's touch points are now
|
|
7
|
-
* just
|
|
8
|
-
*
|
|
7
|
+
* just the `codexResources` field (`zfb-config-gen.ts`). Resource routes are
|
|
8
|
+
* localized by default; projects can opt selected paths out through the
|
|
9
|
+
* general-purpose `defaultLocaleOnlyPrefixes` setting.
|
|
9
10
|
*/
|
|
10
11
|
export const codexResourcesFeature = () => ({
|
|
11
12
|
name: "codexResources",
|
|
@@ -9,7 +9,7 @@ import type { FeatureModule } from "../compose.js";
|
|
|
9
9
|
* since the host catch-all stubs were retired in favor of package
|
|
10
10
|
* injection — there is nothing left to copy or postProcess.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* zfb 2.13.1 renders these injected tag routes in both dev and build. This
|
|
13
|
+
* feature has no host stubs because package injection owns the routes.
|
|
14
14
|
*/
|
|
15
15
|
export declare const docTagsFeature: FeatureModule;
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* since the host catch-all stubs were retired in favor of package
|
|
9
9
|
* injection — there is nothing left to copy or postProcess.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* zfb 2.13.1 renders these injected tag routes in both dev and build. This
|
|
12
|
+
* feature has no host stubs because package injection owns the routes.
|
|
13
13
|
*/
|
|
14
14
|
export const docTagsFeature = () => ({
|
|
15
15
|
name: "docTags",
|
package/dist/features/i18n.d.ts
CHANGED
|
@@ -3,9 +3,9 @@ import type { FeatureModule } from "../compose.js";
|
|
|
3
3
|
* i18n feature — gates the locale-prefixed page set.
|
|
4
4
|
*
|
|
5
5
|
* Locked manifest (#2653 Decision 4, i18n addendum): "i18n ON adds
|
|
6
|
-
* `pages/[locale]/docs/[[...slug]].tsx` (
|
|
7
|
-
* … No other pages." That ONE self-contained stub —
|
|
8
|
-
*
|
|
6
|
+
* `pages/[locale]/docs/[[...slug]].tsx` (the additional-locale doc route stub)
|
|
7
|
+
* … No other pages." That ONE self-contained stub — retained as an explicit
|
|
8
|
+
* host-owned route seam; zfb 2.13.1 also serves injected dynamic routes in dev —
|
|
9
9
|
* is shipped under `templates/features/i18n/files/pages/[locale]/docs/`
|
|
10
10
|
* and copied by `composeFeatures → copyFeatureFiles` whenever `i18n` is
|
|
11
11
|
* selected. The old `pages/[locale]/index.tsx` home-route template is GONE
|
|
@@ -15,7 +15,7 @@ import type { FeatureModule } from "../compose.js";
|
|
|
15
15
|
*
|
|
16
16
|
* No injections: the stub iterates `settings.locales` at build/request
|
|
17
17
|
* time, so no postProcess regex patching is required for non-default
|
|
18
|
-
*
|
|
18
|
+
* locales. Additional-locale content mirrors under
|
|
19
19
|
* `src/content/docs-<lang>/` are seeded by `scaffold.ts`.
|
|
20
20
|
*
|
|
21
21
|
* Loud-failure check: per spec-lock Decision 8 (#1737), abort scaffolding
|
package/dist/features/i18n.js
CHANGED
|
@@ -5,9 +5,9 @@ import { fileURLToPath } from "url";
|
|
|
5
5
|
* i18n feature — gates the locale-prefixed page set.
|
|
6
6
|
*
|
|
7
7
|
* Locked manifest (#2653 Decision 4, i18n addendum): "i18n ON adds
|
|
8
|
-
* `pages/[locale]/docs/[[...slug]].tsx` (
|
|
9
|
-
* … No other pages." That ONE self-contained stub —
|
|
10
|
-
*
|
|
8
|
+
* `pages/[locale]/docs/[[...slug]].tsx` (the additional-locale doc route stub)
|
|
9
|
+
* … No other pages." That ONE self-contained stub — retained as an explicit
|
|
10
|
+
* host-owned route seam; zfb 2.13.1 also serves injected dynamic routes in dev —
|
|
11
11
|
* is shipped under `templates/features/i18n/files/pages/[locale]/docs/`
|
|
12
12
|
* and copied by `composeFeatures → copyFeatureFiles` whenever `i18n` is
|
|
13
13
|
* selected. The old `pages/[locale]/index.tsx` home-route template is GONE
|
|
@@ -17,7 +17,7 @@ import { fileURLToPath } from "url";
|
|
|
17
17
|
*
|
|
18
18
|
* No injections: the stub iterates `settings.locales` at build/request
|
|
19
19
|
* time, so no postProcess regex patching is required for non-default
|
|
20
|
-
*
|
|
20
|
+
* locales. Additional-locale content mirrors under
|
|
21
21
|
* `src/content/docs-<lang>/` are seeded by `scaffold.ts`.
|
|
22
22
|
*
|
|
23
23
|
* Loud-failure check: per spec-lock Decision 8 (#1737), abort scaffolding
|
package/dist/features/index.js
CHANGED
|
@@ -22,6 +22,7 @@ import { versioningFeature } from "./versioning.js";
|
|
|
22
22
|
import { tauriFeature } from "./tauri.js";
|
|
23
23
|
import { tauriDevFeature } from "./tauri-dev.js";
|
|
24
24
|
import { imageEnlargeFeature } from "./image-enlarge.js";
|
|
25
|
+
import { assetViewerFeature } from "./asset-viewer.js";
|
|
25
26
|
import { dynamicPageTransitionFeature } from "./dynamic-page-transition.js";
|
|
26
27
|
import { tagGovernanceFeature } from "./tag-governance.js";
|
|
27
28
|
import { footerTaglistFeature } from "./footer-taglist.js";
|
|
@@ -50,6 +51,7 @@ export const featureModules = {
|
|
|
50
51
|
tauri: tauriFeature,
|
|
51
52
|
tauriDev: tauriDevFeature,
|
|
52
53
|
imageEnlarge: imageEnlargeFeature,
|
|
54
|
+
assetViewer: assetViewerFeature,
|
|
53
55
|
dynamicPageTransition: dynamicPageTransitionFeature,
|
|
54
56
|
// skillSymlinker — handled in scaffold.ts
|
|
55
57
|
// claudeSkills — handled in scaffold.ts (copies zudo-doc-* skills from monorepo)
|