// The bundle check, checked. // // `scripts/checkBundle.js` exists because of a failure this module has not had // and does not intend to: Module-uo's v1.0.0 shipped without `server/commands/` // and died at the register stage on the operator's box. A check written in // response to one bug is worth exactly as much as its coverage of that bug, so // the first two tests below are that bug, in both modes — a list that has stopped // covering what the entry point reaches, and a tarball with the file missing from // it — and the third pair is this module's own version of it, a runtime // dependency declared and not packed. // // **Every fixture is a template literal, and that is load-bearing** — the same // reason checkImports.test.js gives. `scripts/checkImports.js` scans this // directory too, so an ordinary quoted string holding a relative require would // make this file fail that check. Templates are blanked by the stripper. const test = require('node:test') const assert = require('node:assert') const fs = require('node:fs') const os = require('node:os') const path = require('node:path') const { reachable, resolveFile, checkDeclaration, checkBundle, declaredServerPaths, runtimeDependencies, } = require('../scripts/checkBundle') /** * Write a throwaway module tree: `files` under server/, `bundle` as its * ci/bundle.json, `pkg` as its server/package.json. Returns the module root. */ function fixture(files, bundle = { server: ['index.js'] }, pkg = null) { const root = fs.mkdtempSync(path.join(os.tmpdir(), 'module-rust-bundle-')) for (const [name, source] of Object.entries(files)) { const file = path.join(root, 'server', name) fs.mkdirSync(path.dirname(file), { recursive: true }) fs.writeFileSync(file, source) } fs.mkdirSync(path.join(root, 'ci'), { recursive: true }) fs.writeFileSync(path.join(root, 'ci', 'bundle.json'), JSON.stringify(bundle)) if (pkg) { fs.mkdirSync(path.join(root, 'server'), { recursive: true }) fs.writeFileSync(path.join(root, 'server', 'package.json'), JSON.stringify(pkg)) } return root } const cleanup = (root) => fs.rmSync(root, { recursive: true, force: true }) // ── The regression this script was written for ───────────────────────────── test('--check catches a directory the include list has stopped covering', () => { const root = fixture( { 'index.js': `const r = require('./router/public/rust.router')`, 'router/public/rust.router.js': `module.exports = {}`, }, { server: ['index.js'] }, // `router` missing — exactly Module-uo's v1.0.0 ) try { const { uncovered } = checkDeclaration(root) assert.strictEqual(uncovered.size, 1) assert.ok(uncovered.has('server/router')) } finally { cleanup(root) } }) test('--bundle catches the file missing from an assembled tarball', () => { const root = fixture({ 'index.js': `require('./router/public/rust.router')` }) try { const { missing } = checkBundle(root) assert.strictEqual(missing.length, 1) assert.strictEqual(missing[0].specifier, './router/public/rust.router') } finally { cleanup(root) } }) // ── This module's own version of that failure ────────────────────────────── // // The release packs no node_modules because the shipped half declares no // dependencies (org lead, phase 2). The value of that decision is entirely in // the day it stops being true being a LOUD day, so both modes ask. test('--check reports a runtime dependency the release would not pack', () => { const root = fixture({ 'index.js': `module.exports = 1` }, { server: ['index.js'] }, { name: 'x', dependencies: { ws: '^8.21.0' }, }) try { assert.deepStrictEqual(checkDeclaration(root).dependencies, ['ws']) } finally { cleanup(root) } }) test('--bundle reports a dependency the assembled bundle declares and does not carry', () => { const root = fixture({ 'index.js': `module.exports = 1` }, { server: ['index.js'] }, { name: 'x', dependencies: { ws: '^8.21.0' }, }) try { assert.deepStrictEqual(checkBundle(root).dependencies, ['ws']) } finally { cleanup(root) } }) test('devDependencies are not runtime dependencies', () => { // express, express-validator and swagger-autogen are all here and none of them // ships: the shipped half is handed express on `ctx` (§2.3). A check that // confused the two would fail on a correct repo, which is the one way to make // everyone stop reading it. const root = fixture({ 'index.js': `module.exports = 1` }, { server: ['index.js'] }, { name: 'x', devDependencies: { express: '^4.19.2' }, }) try { assert.deepStrictEqual(runtimeDependencies(root), []) } finally { cleanup(root) } }) // ── It has to reach requires that are not at the top level ───────────────── test('follows requires written inside a function', () => { // index.js requires inside `register()` because require order is load-bearing: // `core.init(ctx)` has to run before anything under router/ is required. A // check that only saw file-scope requires would miss every router this module // has. const root = fixture( { 'index.js': `module.exports = function register(ctx) { const r = require('./router/a') }`, 'router/a.js': `module.exports = {}`, }, { server: ['index.js', 'router'] }, ) try { assert.strictEqual(checkDeclaration(root).uncovered.size, 0) assert.strictEqual(checkBundle(root).missing.length, 0) } finally { cleanup(root) } }) test('follows requires transitively, not just one hop', () => { const root = fixture( { 'index.js': `require('./a')`, 'a.js': `require('./b')`, 'b.js': `require('./deep/c')`, 'deep/c.js': `module.exports = {}`, }, { server: ['index.js', 'a.js', 'b.js'] }, // `deep` missing ) try { assert.ok(checkDeclaration(root).uncovered.has('server/deep')) } finally { cleanup(root) } }) // ── Resolution has to match Node's, or it invents failures ───────────────── test('resolves a directory to its index.js', () => { const root = fixture( { 'index.js': `require('./boot')`, 'boot/index.js': `module.exports = {}` }, { server: ['index.js', 'boot'] }, ) try { assert.strictEqual(checkDeclaration(root).uncovered.size, 0) } finally { cleanup(root) } }) test('resolves a .json dependency, and does not try to parse it for requires', () => { // server/index.js's last line requires ../module.json, which is why this case // is not hypothetical and why `generated` is in the declared list at all. const root = fixture( { 'index.js': `require('./data/atlas.json')`, 'data/atlas.json': `{"a":1}` }, { server: ['index.js', 'data'] }, ) try { const { uncovered, missing } = checkDeclaration(root) assert.strictEqual(missing.length, 0) assert.strictEqual(uncovered.size, 0) } finally { cleanup(root) } }) test('survives a require cycle', () => { const root = fixture( { 'index.js': `require('./a')`, 'a.js': `require('./index')` }, { server: ['index.js', 'a.js'] }, ) try { assert.strictEqual(checkDeclaration(root).uncovered.size, 0) } finally { cleanup(root) } }) test('a specifier that resolves to nothing is reported, not thrown', () => { const root = fixture({ 'index.js': `require('./gone')` }) try { const { missing } = checkDeclaration(root) assert.strictEqual(missing.length, 1) assert.strictEqual(missing[0].specifier, './gone') } finally { cleanup(root) } }) test('prose describing a require is not a require', () => { // The failure mode checkImports.js hit the first time it ran: index.js's own // header explains why it must never require express, and comments in this repo // name module paths constantly. const root = fixture( { 'index.js': `// this file used to require('./router/gone')\nmodule.exports = 1` }, { server: ['index.js'] }, ) try { assert.strictEqual(checkDeclaration(root).missing.length, 0) } finally { cleanup(root) } }) test("node_modules inside a bundle is npm's business, not this check's", () => { // Nothing ships one today. The skip stays so that the day a dependency does // arrive, this is not also the thing that breaks. const root = fixture({ 'index.js': `module.exports = 1`, 'node_modules/ws/index.js': `require('./lib/that-npm-owns')`, }) try { assert.strictEqual(checkBundle(root).missing.length, 0) } finally { cleanup(root) } }) // ── And the real repo, which is the check that actually gates a release ──── test('the real ci/bundle.json covers everything the real entry point reaches', () => { const { uncovered, missing, reached, dependencies } = checkDeclaration() assert.deepStrictEqual([...uncovered.keys()], []) assert.deepStrictEqual(missing, []) assert.deepStrictEqual(dependencies, []) assert.ok(reached > 1, 'the walk should reach more than the entry point itself') }) test('every path ci/bundle.json declares exists', () => { // A list naming a path that has moved packs nothing and says nothing — `cp` in // the release would fail, but only after the tag had been pushed. for (const p of declaredServerPaths()) { assert.ok(fs.existsSync(p), `ci/bundle.json names ${p}, which does not exist`) } }) test('the entry point is reachable from the declared list', () => { const entry = path.resolve(__dirname, '..', 'index.js') assert.ok(reachable(entry).files.includes(entry)) assert.ok(resolveFile(path.dirname(entry), './core')) })