// package-shape.test.mjs // Step 10 (A1): package.json-kontrakten for det bevisste zero-dep-bruddet. // Verifiserer at dep-laget er EXACT-pinnet (ingen ^/~/*), at engines-gulvet er // satt (unpdf krever node >= 22), at pakken er ESM (type: module), at versjonen // er 1.8.1 (patch-lane: okf_layout-migrasjon) paa ALLE shippede flater, og at .npmrc slaar av // install-scripts (Shai-Hulud / supply-chain). Zero npm deps i selve testen. // Moenster: tests/frontmatter.test.mjs (les fil, assert struktur). import { test } from 'node:test'; import assert from 'node:assert/strict'; import { readFileSync, existsSync } from 'node:fs'; import { join, dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..'); const PKG = join(ROOT, 'package.json'); const NPMRC = join(ROOT, '.npmrc'); const LOCK = join(ROOT, 'package-lock.json'); // De fire pure-JS-konverterings-deps fra A0 pre-flight (audit 0 vulnerabilities). const EXPECTED_DEPS = ['mammoth', 'turndown', 'postal-mime', 'unpdf']; function readPkg() { return JSON.parse(readFileSync(PKG, 'utf8')); } test('package.json: type module + version 1.8.1 (patch-lane)', () => { const pkg = readPkg(); assert.equal(pkg.type, 'module'); assert.equal(pkg.version, '1.8.1'); }); test('package.json: engines.node-gulv satt (unpdf krever >= 22)', () => { const pkg = readPkg(); assert.ok(pkg.engines && pkg.engines.node, 'engines.node mangler'); assert.equal(pkg.engines.node, '>=22'); }); test('package.json: alle dependencies EXACT-pinnet (ingen ^/~/*)', () => { const pkg = readPkg(); assert.ok(pkg.dependencies, 'dependencies mangler'); for (const dep of EXPECTED_DEPS) { assert.ok(pkg.dependencies[dep], `dep mangler: ${dep}`); } for (const [name, version] of Object.entries(pkg.dependencies)) { assert.match( version, /^\d+\.\d+\.\d+$/, `dep ${name} er ikke exact-pinnet: ${version}`, ); } }); test('.npmrc: install-scripts avslaatt (supply-chain-vern)', () => { const npmrc = readFileSync(NPMRC, 'utf8'); assert.match(npmrc, /^ignore-scripts\s*=\s*true$/m); }); test('package-lock.json: finnes og pinner transitive deps med integrity', () => { assert.ok(existsSync(LOCK), 'package-lock.json mangler'); const lock = JSON.parse(readFileSync(LOCK, 'utf8')); const entries = Object.entries(lock.packages ?? {}).filter(([k]) => k !== ''); assert.ok(entries.length >= EXPECTED_DEPS.length, 'lockfile uten pakke-oppfoeringer'); for (const [name, meta] of entries) { if (meta.link) continue; assert.ok(meta.integrity, `lockfile-oppfoering uten integrity: ${name}`); assert.match(meta.version ?? '', /^\d/, `lockfile-oppfoering uten versjon: ${name}`); } }); // R3 (review.md 5e61ae0d): package.json er `private: true` og shipper ALDRI -- versjons- // assertet over voktet dermed den ene flaten brukeren aldri ser. Polyrepo-ritualet // (katalog-ref pinnet til release-tag) forutsetter at alle flater bumpes SAMTIDIG, saa en // delvis bump skal bli ROED. Forventet versjon utledes fra package.json (ett sted aa endre). const VERSION_SURFACES = [ { file: '.claude-plugin/plugin.json', re: /"version":\s*"([^"]+)"/ }, { file: 'README.md', re: /img\.shields\.io\/badge\/version-(\d+\.\d+\.\d+)-/ }, { file: 'skills/okr-offentlig-sektor/SKILL.md', re: /^version:\s*"?([^"\s]+)"?\s*$/m }, { file: 'skills/okr-second-brain-search/SKILL.md', re: /^version:\s*"?([^"\s]+)"?\s*$/m }, ]; test('versjonssync: alle shippede flater baerer package.json-versjonen', () => { const expected = readPkg().version; const drift = []; for (const { file, re } of VERSION_SURFACES) { const m = re.exec(readFileSync(join(ROOT, file), 'utf8')); if (!m) { drift.push(`${file}: fant ingen versjon (flaten flyttet? oppdater regexen)`); continue; } if (m[1] !== expected) drift.push(`${file}: ${m[1]} != ${expected}`); } assert.deepEqual(drift, [], `delvis versjonsbump (forventet ${expected}):\n${drift.join('\n')}`); });