#!/usr/bin/env node // The kit declares exactly one contract version, in `template/module.json`'s // `coreApi` — the same field a reader copies. This asserts it still names the // version the pinned core actually exports. // // WHY EQUALITY AND NOT "SATISFIES": a range check is what CORE does at load time, // and it is right there — a module built against 1.4.0 should keep loading into // 1.5.0. It is the wrong question here. This kit's job is to be *current*: if core // moved to 1.5.0, `^1.4.0` still satisfies, the build stays green, and nobody ever // re-reads the chapters. Green would mean "the template still loads", when what we // need it to mean is "someone has looked at this since the contract changed". // // So the failure is deliberate and expected on every core bump, and the fix is a // human reading the book — not a version string. // // Usage: node scripts/checkCoreApi.js --core const fs = require('fs') const path = require('path') const ROOT = path.resolve(__dirname, '..') function arg(name) { const i = process.argv.indexOf(name) return i === -1 ? null : process.argv[i + 1] } const corePath = arg('--core') if (!corePath) { console.error('usage: node scripts/checkCoreApi.js --core ') process.exit(2) } const manifestPath = path.join(ROOT, 'template', 'module.json') if (!fs.existsSync(manifestPath)) { // Slice 0 landed this check before the template it checks. Not an error: the // workflow guards on the same file, and this message is what a local run says. console.log('checkCoreApi: no template/module.json yet — nothing to check') process.exit(0) } const versionFile = path.resolve(corePath, 'server/src/modules/version.js') if (!fs.existsSync(versionFile)) { console.error(`checkCoreApi: ${versionFile} does not exist.`) console.error(' Either --core does not point at a website checkout, or the pin in') console.error(' ci/core-ref.json names a ref with no module system in it (core `main`') console.error(' has none until the cutover — see that file).') process.exit(1) } // Core's version.js is a plain CommonJS module with no dependencies, so it can be // required straight out of an uninstalled checkout. const { MODULE_API_VERSION: core } = require(versionFile) const declared = String(JSON.parse(fs.readFileSync(manifestPath, 'utf8')).coreApi || '') // A `coreApi` is a RANGE (`^1.4.0`); the version it is built on is its base. const base = declared.replace(/^[\^~>=<\s]+/, '').trim() if (!base) { console.error(`checkCoreApi: template/module.json declares no coreApi (got ${JSON.stringify(declared)})`) process.exit(1) } if (base !== core) { console.error('checkCoreApi: the kit is written against a different core than it is pinned to.') console.error('') console.error(` template/module.json coreApi = ${declared} (base ${base})`) console.error(` pinned core MODULE_API_VERSION = ${core}`) console.error('') console.error(' This is the anti-rot check firing, not a broken build. Someone has to:') console.error(' 1. read MODULE_API.md §1.1 for what changed in the new version;') console.error(' 2. read the book and the template for anything that is now untrue;') console.error(' 3. update template/module.json and ci/core-ref.json together.') console.error('') console.error(' Bumping the two files without doing step 2 is the one way to make this') console.error(' check worthless.') process.exit(1) } console.log(`checkCoreApi: coreApi ${declared} matches the pinned core's ${core} — OK`)