@takazudo/zudo-doc 5.18.2 → 5.19.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 +6 -0
- package/bin/gen-component-tokens.mjs +44 -3
- package/bin/gen-z-index.mjs +39 -4
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@ All notable changes to `@takazudo/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.19.0] - 2026-09-07
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
- The `gen-z-index` and `gen-component-tokens` bins report a descriptive error instead of a raw Node stack trace. A missing input file now names the path and says which file it is, while `EACCES` / `EISDIR` keep their own message rather than collapsing into a misleading "not found", and a top-level handler prints the message to stderr and exits 1 for any deliberate throw. A non-`Error` throw prints its string form rather than a bare `undefined`. (83a4c6f7a, 134248eba)
|
|
12
|
+
|
|
7
13
|
## [5.18.2] - 2026-09-06
|
|
8
14
|
|
|
9
15
|
### Bug Fixes
|
|
@@ -45,6 +45,11 @@ const TOKENS_PATH = resolve(PKG_ROOT, "src/config/component-tokens.ts");
|
|
|
45
45
|
const CONTENT_CSS_PATH = resolve(PKG_ROOT, "src/content.css");
|
|
46
46
|
const FEATURES_CSS_PATH = resolve(PKG_ROOT, "src/features.css");
|
|
47
47
|
|
|
48
|
+
// Repo-relative label for TOKENS_PATH, matching the SURFACES table's relPath
|
|
49
|
+
// convention below — used only in the missing-file message so it never
|
|
50
|
+
// embeds this machine's absolute path.
|
|
51
|
+
const TOKENS_REL_PATH = "packages/zudo-doc/src/config/component-tokens.ts";
|
|
52
|
+
|
|
48
53
|
// Default marker pair = the content-surface block. Kept under the original
|
|
49
54
|
// names so buildBlock/replaceBlock default to the content block, preserving the
|
|
50
55
|
// byte-identical content.css output (and the existing unit-test call sites).
|
|
@@ -259,10 +264,30 @@ export function replaceBlock(
|
|
|
259
264
|
return css.slice(0, lineStart) + block + css.slice(lineEnd);
|
|
260
265
|
}
|
|
261
266
|
|
|
267
|
+
/**
|
|
268
|
+
* Reads a package-owned file, translating a missing file into a message that
|
|
269
|
+
* names both which file (`label`) and its repo-relative path (`relPath`) —
|
|
270
|
+
* these paths are absolute constants (see TOKENS_PATH/SURFACES above), so the
|
|
271
|
+
* relative label is what keeps the message free of a machine-specific path.
|
|
272
|
+
* Only ENOENT is translated: EACCES/EISDIR etc. are real, distinct failures
|
|
273
|
+
* (a permissions problem or "that's a directory") that a "not found" message
|
|
274
|
+
* would misreport, so they propagate unchanged with Node's own message.
|
|
275
|
+
*/
|
|
276
|
+
function readNamedFile(absPath, relPath, label) {
|
|
277
|
+
try {
|
|
278
|
+
return readFileSync(absPath, "utf8");
|
|
279
|
+
} catch (error) {
|
|
280
|
+
if (error.code === "ENOENT") {
|
|
281
|
+
throw new Error(`${label} file not found at ${relPath}`);
|
|
282
|
+
}
|
|
283
|
+
throw error;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
262
287
|
function main() {
|
|
263
288
|
const check = process.argv.includes("--check");
|
|
264
289
|
|
|
265
|
-
const tokensSrc =
|
|
290
|
+
const tokensSrc = readNamedFile(TOKENS_PATH, TOKENS_REL_PATH, "tokens");
|
|
266
291
|
const tokens = parseTokens(tokensSrc);
|
|
267
292
|
const routes = routeBySurface(tokens);
|
|
268
293
|
|
|
@@ -277,7 +302,7 @@ function main() {
|
|
|
277
302
|
`${target.surface}: ${surfaceTokens.length} token(s), ${selectorCount} selector(s)`,
|
|
278
303
|
);
|
|
279
304
|
|
|
280
|
-
const css =
|
|
305
|
+
const css = readNamedFile(target.cssPath, target.relPath, "css");
|
|
281
306
|
const block = buildBlock(surfaceTokens, target.beginMarker, target.endMarker);
|
|
282
307
|
const next = replaceBlock(
|
|
283
308
|
css,
|
|
@@ -344,5 +369,21 @@ function isDirectInvocation() {
|
|
|
344
369
|
}
|
|
345
370
|
|
|
346
371
|
if (isDirectInvocation()) {
|
|
347
|
-
|
|
372
|
+
// Turns any Error thrown by main() (the readNamedFile guard, the parser's
|
|
373
|
+
// loud-failure throws, or replaceBlock's missing-markers throw) into a
|
|
374
|
+
// single readable stderr line instead of a raw Node stack trace. This also
|
|
375
|
+
// hides the stack for a genuine *programming* error, not just a user-input
|
|
376
|
+
// one — an accepted CLI tradeoff, not an accident: the process still exits
|
|
377
|
+
// 1 and nothing is swallowed, but a future reader debugging an internal
|
|
378
|
+
// crash needs to call the exported `main()` directly (or temporarily
|
|
379
|
+
// remove this try/catch) to see the stack. Exit codes are unchanged:
|
|
380
|
+
// main()'s own return value (0 or 1) still flows through process.exit on
|
|
381
|
+
// the success path; only an uncaught throw is newly turned into exit(1)
|
|
382
|
+
// with a message.
|
|
383
|
+
try {
|
|
384
|
+
process.exit(main());
|
|
385
|
+
} catch (error) {
|
|
386
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
387
|
+
process.exit(1);
|
|
388
|
+
}
|
|
348
389
|
}
|
package/bin/gen-z-index.mjs
CHANGED
|
@@ -1023,6 +1023,26 @@ export function buildMdTable(tiers, options = {}) {
|
|
|
1023
1023
|
return lines.join("\n");
|
|
1024
1024
|
}
|
|
1025
1025
|
|
|
1026
|
+
/**
|
|
1027
|
+
* Reads a user-supplied file, translating a missing file into a message that
|
|
1028
|
+
* names both which file (`label`) and where it looked (`asGivenPath` — the
|
|
1029
|
+
* as-given path, never the resolved absolute one, matching the convention
|
|
1030
|
+
* documented on `main()` below). Only ENOENT is translated: EACCES/EISDIR
|
|
1031
|
+
* etc. are real, distinct failures (a permissions problem or "that's a
|
|
1032
|
+
* directory") that a "not found" message would misreport, so they propagate
|
|
1033
|
+
* unchanged with Node's own message.
|
|
1034
|
+
*/
|
|
1035
|
+
function readNamedFile(absPath, asGivenPath, label) {
|
|
1036
|
+
try {
|
|
1037
|
+
return readFileSync(absPath, "utf8");
|
|
1038
|
+
} catch (error) {
|
|
1039
|
+
if (error.code === "ENOENT") {
|
|
1040
|
+
throw new Error(`${label} file not found at ${asGivenPath}`);
|
|
1041
|
+
}
|
|
1042
|
+
throw error;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1026
1046
|
/**
|
|
1027
1047
|
* CLI entrypoint. `argv` defaults to the real process argv (minus the node/
|
|
1028
1048
|
* script prefix) so `isDirectInvocation()` below can call `main()` with no
|
|
@@ -1052,8 +1072,8 @@ export function main(argv = process.argv.slice(2)) {
|
|
|
1052
1072
|
const tokensAbsPath = resolve(root, tokensPath);
|
|
1053
1073
|
const cssAbsPath = resolve(root, cssPath);
|
|
1054
1074
|
|
|
1055
|
-
const tokensSrc =
|
|
1056
|
-
const css =
|
|
1075
|
+
const tokensSrc = readNamedFile(tokensAbsPath, tokensPath, "tokens");
|
|
1076
|
+
const css = readNamedFile(cssAbsPath, cssPath, "css");
|
|
1057
1077
|
|
|
1058
1078
|
const tiers = parseTiers(tokensSrc, tokensPath);
|
|
1059
1079
|
const block = buildBlock(tiers, { tokensPath, cssPath, themeWrapper });
|
|
@@ -1064,7 +1084,7 @@ export function main(argv = process.argv.slice(2)) {
|
|
|
1064
1084
|
let nextMd;
|
|
1065
1085
|
if (mdTablePath !== undefined) {
|
|
1066
1086
|
mdAbsPath = resolve(root, mdTablePath);
|
|
1067
|
-
mdSrc =
|
|
1087
|
+
mdSrc = readNamedFile(mdAbsPath, mdTablePath, "md-table");
|
|
1068
1088
|
const mdBlock = buildMdTable(tiers, { tokensPath });
|
|
1069
1089
|
nextMd = replaceBlock(
|
|
1070
1090
|
mdSrc,
|
|
@@ -1141,5 +1161,20 @@ function isDirectInvocation() {
|
|
|
1141
1161
|
}
|
|
1142
1162
|
|
|
1143
1163
|
if (isDirectInvocation()) {
|
|
1144
|
-
|
|
1164
|
+
// Turns any Error thrown by main() (there are ~17 deliberate `throw new
|
|
1165
|
+
// Error(...)` call sites above, plus the readNamedFile guard) into a single
|
|
1166
|
+
// readable stderr line instead of a raw Node stack trace. This also hides
|
|
1167
|
+
// the stack for a genuine *programming* error, not just a user-input one —
|
|
1168
|
+
// an accepted CLI tradeoff, not an accident: the process still exits 1 and
|
|
1169
|
+
// nothing is swallowed, but a future reader debugging an internal crash
|
|
1170
|
+
// needs to call the exported `main()` directly (or temporarily remove this
|
|
1171
|
+
// try/catch) to see the stack. Exit codes are unchanged: main()'s own
|
|
1172
|
+
// return value (0 or 1) still flows through process.exit on the success
|
|
1173
|
+
// path; only an uncaught throw is newly turned into exit(1) with a message.
|
|
1174
|
+
try {
|
|
1175
|
+
process.exit(main());
|
|
1176
|
+
} catch (error) {
|
|
1177
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
1178
|
+
process.exit(1);
|
|
1179
|
+
}
|
|
1145
1180
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@takazudo/zudo-doc",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.19.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "zudo-doc framework primitives layer that sits on top of zfb's engine — sidebar, theme, TOC, breadcrumb, layouts, head injection, View Transitions, SSR-skip wrappers (per ADR-003).",
|
|
6
6
|
"license": "MIT",
|
|
@@ -720,7 +720,7 @@
|
|
|
720
720
|
"typescript": "^5.0.0",
|
|
721
721
|
"vitest": "^4.1.0",
|
|
722
722
|
"zod": "^4.3.6",
|
|
723
|
-
"@takazudo/zudo-doc-history-server": "5.
|
|
723
|
+
"@takazudo/zudo-doc-history-server": "5.19.0"
|
|
724
724
|
},
|
|
725
725
|
"scripts": {
|
|
726
726
|
"gen:search-widget-script": "node scripts/gen-search-widget-script.mjs",
|