aboutsummaryrefslogtreecommitdiffstats
path: root/tools/feature-registry-check.js
blob: 9b7ac5e55fcc5792dfc18afa1e5a51952b409d00 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// Guard: src/features/index.js and build.js's ALL_FEATURES must agree.
// They drifted once (nwc was added to index.js only, so its i18n strings
// shipped but its code never did — the settings card silently never rendered,
// because build.js SWAPS OUT features/index.js for a generated module).
//   bun tools/feature-registry-check.js
import { readFileSync } from 'node:fs';

const idx = readFileSync(new URL('../src/features/index.js', import.meta.url), 'utf8');
const build = readFileSync(new URL('../build.js', import.meta.url), 'utf8');

const inIndex = [...idx.matchAll(/import \{ (\w+Feature) \} from '\.\/([\w-]+)\.js'/g)]
  .map((m) => ({ fn: m[1], name: m[2] }));
const registry = build.match(/const ALL_FEATURES = \{([^}]*)\}/s)?.[1] || '';
const inBuild = [...registry.matchAll(/(\w+):\s*'(\w+Feature)'/g)].map((m) => ({ name: m[1], fn: m[2] }));

let ok = true;
for (const f of inIndex) {
  if (!inBuild.find((b) => b.fn === f.fn)) {
    console.log(`x ${f.fn} (${f.name}.js) is in features/index.js but NOT in build.js ALL_FEATURES — it will not ship`);
    ok = false;
  }
}
for (const b of inBuild) {
  if (!inIndex.find((f) => f.fn === b.fn)) {
    console.log(`x ${b.fn} is in build.js ALL_FEATURES but not imported in features/index.js`);
    ok = false;
  }
}
// Compare the ORDER FEATURES ARE CONSTRUCTED IN (hook precedence depends on
// it), not the order they happen to be imported in.
const built = [...(idx.match(/return \[([^\]]*)\]/s)?.[1] || '')
  .matchAll(/(\w+Feature)\(ctx\)/g)].map((m) => m[1]);
const orderIdx = built.join(',');
const orderBuild = inBuild.map((b) => b.fn).join(',');
if (ok && orderIdx !== orderBuild) {
  console.log(`x feature ORDER differs (hook precedence depends on it)\n  index.js: ${orderIdx}\n  build.js: ${orderBuild}`);
  ok = false;
}
if (ok) console.log(`ok ${inIndex.length} features registered consistently`);
process.exit(ok ? 0 : 1);