create-zudo-doc 5.17.0 → 5.17.2

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 CHANGED
@@ -4,6 +4,19 @@ 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.17.2] - 2026-09-05
8
+
9
+ ### Bug Fixes
10
+
11
+ - Prevent generated documentation-skill setup scripts from overwriting real files or directories when creating symlinks (`559e7a1`)
12
+ - Detect locale settings inside spread `zudoDoc(...)` configurations when generating documentation skills (`c1658c9`)
13
+
14
+ ## [5.17.1] - 2026-09-04
15
+
16
+ ### Other Changes
17
+
18
+ - Newly generated projects now use the zfb 2.15.1 package family (`e54438e96`). This is a documentation-only upstream release with no behavior change — the shipped wasm artifacts are byte-size identical to 2.15.0 and a fresh scaffold needs no migration.
19
+
7
20
  ## [5.17.0] - 2026-09-04
8
21
 
9
22
  ### Features
@@ -31,5 +31,5 @@ export declare function deriveDocSkillName(projectName: string): string;
31
31
  *
32
32
  * Bumped in lockstep by scripts/release-create-zudo-doc.sh.
33
33
  */
34
- export declare const ZUDO_DOC_PIN = "^5.17.0";
34
+ export declare const ZUDO_DOC_PIN = "^5.17.2";
35
35
  export declare function scaffold(choices: UserChoices): Promise<void>;
package/dist/scaffold.js CHANGED
@@ -47,7 +47,7 @@ export function deriveDocSkillName(projectName) {
47
47
  *
48
48
  * Bumped in lockstep by scripts/release-create-zudo-doc.sh.
49
49
  */
50
- export const ZUDO_DOC_PIN = "^5.17.0";
50
+ export const ZUDO_DOC_PIN = "^5.17.2";
51
51
  /**
52
52
  * Files in `templates/base/**` that must not be copied by the unconditional
53
53
  * base mirror. Each entry is matched against the path relative to
@@ -754,9 +754,14 @@ function generatePackageJson(choices, localePlan) {
754
754
  // build after upgrading re-renders cached content under the new grammar
755
755
  // set. Token classes stay on the same semantic-role vocabulary, so themes
756
756
  // need no new rules and a fresh scaffold needs no migration.
757
- "@takazudo/zfb": "2.15.0",
758
- "@takazudo/zfb-runtime": "2.15.0",
759
- "@takazudo/zfb-md-wasm": "2.15.0",
757
+ // 2.15.1: documentation-only upstream release — the md-wasm README gained a
758
+ // note about the artifact-size repair sequence's compression tolerance. The
759
+ // four shipped wasm binaries are byte-size identical to 2.15.0 (rebuild
760
+ // noise only), and no public API, export, config default, or engine
761
+ // requirement moves, so a fresh scaffold needs no migration.
762
+ "@takazudo/zfb": "2.15.1",
763
+ "@takazudo/zfb-runtime": "2.15.1",
764
+ "@takazudo/zfb-md-wasm": "2.15.1",
760
765
  // @takazudo/zudo-doc — published from this monorepo via
761
766
  // .github/workflows/publish-zudo-doc.yml. The pin here is bumped in
762
767
  // lockstep by scripts/release-create-zudo-doc.sh whenever zudo-doc's
@@ -884,7 +889,7 @@ function generatePackageJson(choices, localePlan) {
884
889
  // `/exclude` at module scope from the always-bundled chrome graph; #3110
885
890
  // moved compileExclude into @takazudo/zudo-doc, so projects with both
886
891
  // docHistory and assetViewer off no longer need the package at all.
887
- deps["@takazudo/zudo-doc-history-server"] = "^5.17.0";
892
+ deps["@takazudo/zudo-doc-history-server"] = "^5.17.2";
888
893
  // tsx is no longer needed here: the relocated package plugin imports the
889
894
  // runner directly (no `tsx -e` spawn) since the package ships compiled
890
895
  // dist/ — package-first migration #2321 (#2337).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-zudo-doc",
3
- "version": "5.17.0",
3
+ "version": "5.17.2",
4
4
  "description": "Create a new zudo-doc documentation site",
5
5
  "license": "MIT",
6
6
  "author": "Takeshi Takatsudo",
@@ -298,15 +298,38 @@ function matchingBrace(masked, open) {
298
298
  return -1;
299
299
  }
300
300
 
301
+ function spreadZudoDocObjectRanges(masked, depths) {
302
+ const ranges = [];
303
+ const spreadPattern = /\.\.\.\s*zudoDoc\s*\(\s*/g;
304
+ let match;
305
+ while ((match = spreadPattern.exec(masked)) !== null) {
306
+ const open = match.index + match[0].length;
307
+ if (masked[open] !== "{") continue;
308
+ const close = matchingBrace(masked, open);
309
+ if (close < 0) continue;
310
+ ranges.push({ open, close, propertyDepth: depths[open] + 1 });
311
+ }
312
+ return ranges;
313
+ }
314
+
315
+ function isTopLevelSetting(index, depths, spreadRanges) {
316
+ if (depths[index] === 1) return true;
317
+ return spreadRanges.some(
318
+ ({ open, close, propertyDepth }) =>
319
+ index > open && index < close && depths[index] === propertyDepth,
320
+ );
321
+ }
322
+
301
323
  function topLevelObject(source, property) {
302
324
  const masked = maskSource(source);
303
325
  const depths = braceDepths(masked);
326
+ const spreadRanges = spreadZudoDocObjectRanges(masked, depths);
304
327
  const propertyPattern = new RegExp(`\\b${property}\\s*:`, "g");
305
328
  let match;
306
329
  while ((match = propertyPattern.exec(masked)) !== null) {
307
- // Direct fields of the settings/zudoDoc object are at depth 1. Nested
308
- // `versions[].locales` and nav-label locales are intentionally ignored.
309
- if (depths[match.index] !== 1) continue;
330
+ // Direct settings objects use depth 1; spread zudoDoc settings use their
331
+ // explicitly identified object depth. Nested locale maps stay ignored.
332
+ if (!isTopLevelSetting(match.index, depths, spreadRanges)) continue;
310
333
  let open = match.index + match[0].length;
311
334
  while (/\s/.test(masked[open] ?? "")) open += 1;
312
335
  if (masked[open] !== "{") continue;
@@ -320,10 +343,11 @@ function topLevelObject(source, property) {
320
343
  function topLevelString(source, property) {
321
344
  const masked = maskSource(source);
322
345
  const depths = braceDepths(masked);
346
+ const spreadRanges = spreadZudoDocObjectRanges(masked, depths);
323
347
  const propertyPattern = new RegExp(`\\b${property}\\s*:`, "g");
324
348
  let match;
325
349
  while ((match = propertyPattern.exec(masked)) !== null) {
326
- if (depths[match.index] !== 1) continue;
350
+ if (!isTopLevelSetting(match.index, depths, spreadRanges)) continue;
327
351
  const tail = source.slice(match.index + match[0].length).trimStart();
328
352
  const quote = tail[0];
329
353
  if (quote !== "\"" && quote !== "'") continue;
@@ -407,6 +431,12 @@ for (const { source } of sources) {
407
431
  if (localeObject === null) localeObject = topLevelObject(source, "locales");
408
432
  }
409
433
 
434
+ if (defaultLocale === null && docsDir === null && localeObject === null) {
435
+ console.error(
436
+ "no explicit locale settings found in zfb.config.ts; assuming defaults (en, src/content/docs, no additional locales)",
437
+ );
438
+ }
439
+
410
440
  console.log(`default\t${defaultLocale ?? "en"}`);
411
441
  console.log(`docs\t${docsDir ?? "src/content/docs"}`);
412
442
  if (localeObject) {
@@ -470,12 +500,15 @@ physical_dir() {
470
500
  fi
471
501
  }
472
502
 
473
- # Helper: replace a symlink or file at the given path
503
+ # Helper: replace a symlink at the given path; refuse to remove real files or directories
474
504
  ensure_symlink() {
475
505
  local link_path="$1"
476
506
  local target="$2"
477
- if [ -L "$link_path" ] || [ -e "$link_path" ]; then
478
- rm -rf "$link_path"
507
+ if [ -L "$link_path" ]; then
508
+ rm "$link_path"
509
+ elif [ -e "$link_path" ]; then
510
+ echo "Error: '$link_path' already exists and is not a symlink. Move or remove it and rerun setup:doc-skill." >&2
511
+ exit 1
479
512
  fi
480
513
  ln -s "$target" "$link_path"
481
514
  }