tools/check-imports.mjs lists boundary hits and exits 1 only with --strict. The current hit is the Node data loader's node:fs, node:path and node:url. server/data.js stays allowed.
111 lines
3.9 KiB
JavaScript
111 lines
3.9 KiB
JavaScript
// Boundary checker: fixture rules, plus the real tree's current violation list.
|
|
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { spawnSync } from 'node:child_process';
|
|
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { dirname, join } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { findSpecifiers, scan } from '../tools/check-imports.mjs';
|
|
|
|
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
|
|
function fixture(files) {
|
|
const root = mkdtempSync(join(tmpdir(), 'sp-imp-'));
|
|
for (const [rel, body] of Object.entries(files)) {
|
|
const abs = join(root, rel);
|
|
mkdirSync(dirname(abs), { recursive: true });
|
|
writeFileSync(abs, body);
|
|
}
|
|
return root;
|
|
}
|
|
|
|
test('comments are not imports, and a multiline import is', () => {
|
|
const specs = findSpecifiers(`
|
|
// import fs from 'node:fs'
|
|
/* require('node:path') */
|
|
import {
|
|
a,
|
|
b,
|
|
} from './tier1.js';
|
|
export function fromThing() { return 1; }
|
|
`);
|
|
assert.deepEqual(specs.map((s) => s.spec), ['./tier1.js']);
|
|
});
|
|
|
|
test('sim and match rules on a fixture tree', () => {
|
|
const root = fixture({
|
|
'server/sim/clean.js': `
|
|
// import fs from 'node:fs'
|
|
import { a } from './other.js';
|
|
export function load() { return 1; }
|
|
export { a };
|
|
`,
|
|
'server/sim/bad.js': `
|
|
import '../match/Match.js';
|
|
import '../lobby.js';
|
|
import '../index.js';
|
|
import '../net.js';
|
|
import '../../public/js/main.js';
|
|
import fs from 'node:fs';
|
|
import 'fs';
|
|
export { z } from '../match/board.js';
|
|
const p = await import('node:path');
|
|
`,
|
|
'server/match/ok.js': `
|
|
import '../sim/rng.js';
|
|
import 'node:fs';
|
|
import '../data.js';
|
|
`,
|
|
'server/match/bad.js': `
|
|
import '../../public/js/main.js';
|
|
import 'node:http';
|
|
import 'ws';
|
|
import '../net.js';
|
|
import '../index.js';
|
|
`,
|
|
});
|
|
try {
|
|
const keys = scan(root).violations.map((v) => `${v.file} ${v.spec} ${v.code}`).sort();
|
|
assert.deepEqual(keys, [
|
|
'server/match/bad.js ../../public/js/main.js match-client',
|
|
'server/match/bad.js ../index.js match-http',
|
|
'server/match/bad.js ../net.js match-http',
|
|
'server/match/bad.js node:http match-http',
|
|
'server/match/bad.js ws match-http',
|
|
'server/sim/bad.js ../../public/js/main.js sim-client',
|
|
'server/sim/bad.js ../index.js sim-entry',
|
|
'server/sim/bad.js ../lobby.js sim-lobby',
|
|
'server/sim/bad.js ../match/Match.js sim-match',
|
|
'server/sim/bad.js ../match/board.js sim-match',
|
|
'server/sim/bad.js ../net.js sim-http',
|
|
'server/sim/bad.js fs sim-node',
|
|
'server/sim/bad.js node:fs sim-node',
|
|
'server/sim/bad.js node:path sim-node',
|
|
]);
|
|
assert.equal(scan(root).notes.length, 0);
|
|
} finally {
|
|
rmSync(root, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test('this repo: only the Node data loader crosses the sim boundary', () => {
|
|
const { violations, notes } = scan(ROOT);
|
|
assert.deepEqual(violations.map((v) => `${v.file}:${v.line}: ${v.spec} [${v.code}]`), [
|
|
'server/sim/nodeData.js:11: node:fs [sim-node]',
|
|
'server/sim/nodeData.js:12: node:path [sim-node]',
|
|
'server/sim/nodeData.js:13: node:url [sim-node]',
|
|
]);
|
|
assert.ok(notes.some((n) => n.file === 'server/sim/nodeData.js' && n.resolved === 'server/data.js'));
|
|
assert.ok(notes.every((n) => n.resolved === 'server/data.js'));
|
|
});
|
|
|
|
test('the CLI lists hits and fails only with --strict', () => {
|
|
const loose = spawnSync(process.execPath, ['tools/check-imports.mjs'], { cwd: ROOT, encoding: 'utf8' });
|
|
assert.equal(loose.status, 0);
|
|
assert.match(loose.stdout, /server\/sim\/nodeData\.js:11: node:fs \[sim-node\]/);
|
|
const strict = spawnSync(process.execPath, ['tools/check-imports.mjs', '--strict'], { cwd: ROOT, encoding: 'utf8' });
|
|
assert.equal(strict.status, 1);
|
|
assert.match(strict.stdout, /node:fs/);
|
|
});
|