@brandon_m_behring/book-scaffold-astro 3.3.0 → 3.5.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.
@@ -36,6 +36,26 @@
36
36
  import { readFile, writeFile, mkdir, readdir } from 'node:fs/promises';
37
37
  import { resolve, join, basename, dirname } from 'node:path';
38
38
 
39
+ // --help / -h: non-mutating (closes #14).
40
+ const USAGE = `Usage: book-scaffold build-labels
41
+
42
+ Emit src/data/labels.json for <XRef> resolution. Walks chapter MDX files,
43
+ extracts labelable components (Theorem, Figure, ...), assigns display strings
44
+ like "Theorem 4.2" matching LaTeX \\cref.
45
+
46
+ Env:
47
+ BOOK_CHAPTERS_DIR Override chapters dir (default: src/content/chapters).
48
+ BOOK_LABELS_OUT Override output path (default: src/data/labels.json).
49
+
50
+ Options:
51
+ --help, -h Print this message and exit (non-mutating).
52
+ `;
53
+
54
+ if (process.argv.includes('--help') || process.argv.includes('-h')) {
55
+ process.stdout.write(USAGE);
56
+ process.exit(0);
57
+ }
58
+
39
59
  const CHAPTERS_DIR = process.env.BOOK_CHAPTERS_DIR ?? 'src/content/chapters';
40
60
  const OUTPUT_PATH = process.env.BOOK_LABELS_OUT ?? 'src/data/labels.json';
41
61
 
@@ -35,6 +35,25 @@ import { dirname, resolve, basename } from 'node:path';
35
35
  import { fileURLToPath } from 'node:url';
36
36
  import { spawnSync } from 'node:child_process';
37
37
 
38
+ // --help / -h: non-mutating (closes #14).
39
+ const USAGE = `Usage: book-scaffold render-notebooks
40
+
41
+ Notebook pipeline. .ipynb -> standalone HTML via Jupyter nbconvert (--basic).
42
+ Walks notebooks/ (or BOOK_NOTEBOOKS_PATH), emits to public/notebooks/.
43
+ Graceful-skip if uv not on PATH.
44
+
45
+ Env:
46
+ BOOK_NOTEBOOKS_PATH Override notebooks source (default: notebooks/).
47
+
48
+ Options:
49
+ --help, -h Print this message and exit (non-mutating).
50
+ `;
51
+
52
+ if (process.argv.includes('--help') || process.argv.includes('-h')) {
53
+ process.stdout.write(USAGE);
54
+ process.exit(0);
55
+ }
56
+
38
57
  const __dirname = dirname(fileURLToPath(import.meta.url));
39
58
  const PROJECT_ROOT = process.cwd();
40
59
 
@@ -7,56 +7,70 @@
7
7
  * book so it's pre-commit-hook friendly.
8
8
  *
9
9
  * Checks performed (per Q14 in the v2.0 plan):
10
- *
11
10
  * 1. <Cite key="..." /> — key exists in src/data/references.json.
12
- * (Cite.astro already throws on unknown keys at build time; we
13
- * surface ALL bad keys at once instead of failing on the first.)
14
- *
15
- * 2. <XRef id="..." /> — id exists in src/data/labels.json. XRef
16
- * doesn't fail the build for unknown ids; without this check,
17
- * typos ship to readers as "[?label]" placeholders.
18
- *
19
- * 3. <Figure src="/path/..." /> — referenced file exists under
20
- * public/. Figure.astro renders a broken-image icon otherwise.
21
- *
22
- * 4. Internal markdown links [text](/foo) — target resolves to a
23
- * known chapter slug or a known top-level route. External (http*)
24
- * links are not checked (would need network IO).
11
+ * 2. <XRef id="..." /> id exists in src/data/labels.json.
12
+ * 3. <Figure src="/path/..." /> file exists under public/.
13
+ * 4. Internal markdown links [text](/foo) — target resolves.
14
+ * 5. <CodeRef path="..." line={N} /> — when BOOK_REPO_ROOT set,
15
+ * path exists + line in bounds.
25
16
  *
26
- * 5. <CodeRef path="..." line={N} /> when run inside a repo
27
- * whose root is BOOK_REPO_ROOT, the path exists and the line
28
- * number is within file bounds. Skipped when BOOK_REPO_ROOT
29
- * isn't set (the scaffold default; only meaningful for academic
30
- * books that paired with an experiments/ subtree).
31
- *
32
- * What this DOESN'T do (and why):
33
- * - frontmatter Zod validation — already done by astro build's
34
- * content-collection sync.
35
- * - MDX renders — same; astro build will fail.
36
- * - KaTeX strict-mode — covered by rehype-katex when academic
37
- * profile is active; undefined macros become build errors.
17
+ * Run from the consumer's project root. Closes #8 (was resolving paths
18
+ * from the package's own directory inside node_modules false negatives
19
+ * across all reference consumers).
38
20
  *
39
21
  * Usage:
40
- * node scripts/validate.mjs
41
- * BOOK_REPO_ROOT=/abs/path/to/code/repo node scripts/validate.mjs
42
- *
43
- * Exit code = total failure count (0 = pass, ≥1 = errors).
22
+ * book-scaffold validate
23
+ * book-scaffold validate --preset academic
24
+ * BOOK_REPO_ROOT=/abs/path npx book-scaffold validate
44
25
  *
45
- * Wire into:
46
- * - package.json scripts: "validate": "node scripts/validate.mjs"
47
- * - pre-commit hook: .pre-commit-config.yaml
48
- * - CI build pipeline: run before `astro build`
26
+ * Exit code = total failure count (0 = pass, >=1 = errors).
49
27
  */
50
28
  import { readFile, access } from 'node:fs/promises';
51
29
  import { glob } from 'node:fs/promises';
52
30
  import { resolve, dirname, join } from 'node:path';
53
- import { fileURLToPath } from 'node:url';
54
31
 
55
- const ROOT = resolve(fileURLToPath(import.meta.url), '../..');
32
+ // --help / -h: non-mutating (closes #14).
33
+ const USAGE = `Usage: book-scaffold validate [--preset <name>]
34
+
35
+ Pre-flight content validator. Checks Cite keys, XRef ids, Figure srcs,
36
+ internal markdown links, and (when BOOK_REPO_ROOT is set) CodeRef paths.
37
+
38
+ Options:
39
+ --preset <name> academic | tools | minimal | course-notes
40
+ (overrides BOOK_PRESET / BOOK_PROFILE env)
41
+ --help, -h Print this message and exit (non-mutating).
42
+
43
+ Env:
44
+ BOOK_PRESET Preset name (preferred over BOOK_PROFILE).
45
+ BOOK_PROFILE Backward-compat alias for BOOK_PRESET.
46
+ BOOK_REPO_ROOT Absolute path to a sibling code repo for CodeRef checks.
47
+
48
+ Exit code = total failure count.
49
+ `;
50
+
51
+ if (process.argv.includes('--help') || process.argv.includes('-h')) {
52
+ process.stdout.write(USAGE);
53
+ process.exit(0);
54
+ }
55
+
56
+ // --preset <name> CLI flag (closes #9 — single source of truth across
57
+ // defineBookConfig + validate).
58
+ const argv = process.argv.slice(2);
59
+ const presetFlagIdx = argv.findIndex((a) => a === '--preset');
60
+ const presetFromFlag = presetFlagIdx >= 0 ? argv[presetFlagIdx + 1] : undefined;
61
+
62
+ // v3.4.0: ROOT is the consumer's CWD, not the package's own dir.
63
+ // Resolves issue #8 — three reference consumers reported "0 chapter(s) checked"
64
+ // because ROOT was the package directory inside node_modules.
65
+ const ROOT = process.cwd();
56
66
  const CHAPTERS_DIR = resolve(ROOT, 'src/content/chapters');
57
67
  const PUBLIC_DIR = resolve(ROOT, 'public');
58
68
  const DATA_DIR = resolve(ROOT, 'src/data');
59
- const PROFILE = process.env.BOOK_PROFILE ?? 'minimal';
69
+
70
+ // Preset resolution: --preset flag > BOOK_PRESET env > BOOK_PROFILE env > 'minimal'.
71
+ const PRESET = presetFromFlag ?? process.env.BOOK_PRESET ?? process.env.BOOK_PROFILE ?? 'minimal';
72
+ // Alias kept for downstream message text only; the resolution above is canonical.
73
+ const PROFILE = PRESET;
60
74
  const REPO_ROOT = process.env.BOOK_REPO_ROOT ?? null;
61
75
 
62
76
  const errors = [];