@brandon_m_behring/book-scaffold-astro 3.7.0 → 3.7.1

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/dist/index.mjs CHANGED
@@ -787,9 +787,10 @@ function bookScaffoldIntegration(opts) {
787
787
  // src/config.ts
788
788
  async function defineBookConfig(opts) {
789
789
  const profile = resolvePreset(opts.preset, opts.profile);
790
+ const wantsKatex = PROFILES[profile]?.katex === true;
790
791
  const remarkPlugins = [];
791
792
  const rehypePlugins = [];
792
- if (profile === "academic") {
793
+ if (wantsKatex) {
793
794
  const { default: remarkMath } = await import(
794
795
  /* @vite-ignore */
795
796
  "remark-math"
@@ -862,7 +863,7 @@ async function defineBookConfig(opts) {
862
863
  void _extraStyles;
863
864
  void _markdown;
864
865
  void _katexMacros;
865
- const katexExternals = profile === "academic" ? [] : ["remark-math", "rehype-katex", "katex"];
866
+ const katexExternals = wantsKatex ? [] : ["remark-math", "rehype-katex", "katex"];
866
867
  const config = {
867
868
  ...rest,
868
869
  integrations,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@brandon_m_behring/book-scaffold-astro",
3
3
  "description": "Astro 6 + MDX toolkit for long-form technical books. Profile-aware (academic / tools / minimal); ships Tufte typography, KaTeX, BibTeX citations, Pagefind, Cloudflare Workers deploy. See PACKAGE_DESIGN.md for the API contract.",
4
- "version": "3.7.0",
4
+ "version": "3.7.1",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "author": "Brandon Behring",
@@ -26,9 +26,9 @@
26
26
  * Exit code = total failure count (0 = pass, >=1 = errors).
27
27
  */
28
28
  import { readFile, access } from 'node:fs/promises';
29
- import { glob } from 'node:fs/promises';
30
29
  import { existsSync, readFileSync } from 'node:fs';
31
30
  import { resolve, dirname, join } from 'node:path';
31
+ import { walkMdx } from './walk-mdx.mjs';
32
32
 
33
33
  /**
34
34
  * Best-effort .env reader. Mirrors `readEnvFile` in src/types.ts; kept inline
@@ -134,8 +134,13 @@ const refs = await loadJson(join(DATA_DIR, 'references.json'));
134
134
  const labels = await loadJson(join(DATA_DIR, 'labels.json'));
135
135
 
136
136
  // ===== Collect chapter files =====
137
+ // v3.7.1 (closes #52): walkMdx (in ./walk-mdx.mjs) is a recursive readdir
138
+ // walker that replaces the previous `glob` import from `node:fs/promises`.
139
+ // The `glob` API was added in Node 22 but consumer CI templates ship
140
+ // Node 20 — `npm run validate` crashed on every consumer's prebuild hook.
141
+ // Walker uses readdir + path only; works on Node 18+.
137
142
  const chapterFiles = [];
138
- for await (const f of glob('**/*.{md,mdx}', { cwd: CHAPTERS_DIR })) {
143
+ for await (const f of walkMdx(CHAPTERS_DIR)) {
139
144
  if (!f.split('/').pop().startsWith('_')) chapterFiles.push(f);
140
145
  }
141
146
 
@@ -0,0 +1,34 @@
1
+ /**
2
+ * scripts/walk-mdx.mjs — recursive .md/.mdx file walker for content trees.
3
+ *
4
+ * Extracted from scripts/validate.mjs in v3.7.1 (closes #52) so it can be
5
+ * unit-tested without running validate's side-effectful top-level await.
6
+ *
7
+ * Replaces the previous `glob` import from `node:fs/promises` (Node 22+
8
+ * only). The walker below uses `readdir` only — works on Node 18+ so
9
+ * consumer CIs running `node-version: '20'` no longer crash on the
10
+ * scaffold's prebuild validate hook.
11
+ *
12
+ * Output: relative paths in POSIX form ("subdir/file.mdx"), matching what
13
+ * the previous `glob('**\/*.{md,mdx}', { cwd })` produced.
14
+ */
15
+ import { readdir } from 'node:fs/promises';
16
+ import { join, relative } from 'node:path';
17
+
18
+ export async function* walkMdx(dir, baseDir = dir) {
19
+ let entries;
20
+ try {
21
+ entries = await readdir(dir, { withFileTypes: true });
22
+ } catch {
23
+ return; // dir missing or unreadable — treat as zero chapters
24
+ }
25
+ for (const entry of entries) {
26
+ const full = join(dir, entry.name);
27
+ if (entry.isDirectory()) {
28
+ yield* walkMdx(full, baseDir);
29
+ } else if (/\.(md|mdx)$/.test(entry.name)) {
30
+ // Normalize to forward slashes for cross-platform stability.
31
+ yield relative(baseDir, full).split(/[\\/]/).join('/');
32
+ }
33
+ }
34
+ }