import test from 'node:test'; import assert from 'node:assert/strict'; import {createHash} from 'node:crypto'; import {buildDeclaredModule} from './build_declared_module.mjs'; import {buildGraphPlan} from './build_graph_plan.mjs'; function fixture(source){ const raw={'rollup.config.js':`const pkg=require('./package.json');export default {input:'src/core.js',output:{file:pkg.module,format:'es'}}`, 'package.json':JSON.stringify({module:'dist/core.js',scripts:{sync:'cp dist/core.js web/core.js'}}), 'src/core.js':source,'web/main.js':`import {twice} from './core'; export const answer=twice(21);`}; return {digest:'a'.repeat(64),repository:{files:Object.fromEntries(Object.entries(raw).map(([p,s])=>{const b=Buffer.from(s);return[p,{base64:b.toString('base64'),bytes:b.length,sha256:createHash('sha256').update(b).digest('hex')}];}))}}; } test('bundles declared generated alias using captured bytes only',async()=>{ const p=fixture('export const twice=x=>x*2;');const before=JSON.stringify(p); const r=await buildDeclaredModule(p,'web/main.js','modern-esm-bundle-v1'); assert.equal(r.used['web/core.js'].source,'src/core.js'); assert.equal(r.status,'UNVERIFIED_CANDIDATE');assert.equal(JSON.stringify(p),before); assert.ok(r.bytes>0); }); test('external and dynamic module acquisition refuse',async()=>{ await assert.rejects(()=>buildDeclaredModule(fixture(`import x from 'https://example.com/a.js';export const twice=x;`),'web/main.js','modern-esm-bundle-v1')); await assert.rejects(()=>buildDeclaredModule(fixture(`export const twice=()=>import('./later.js');`),'web/main.js','modern-esm-bundle-v1')); }); test('graph readiness detects transitive gaps without executing source',()=>{ const p=fixture(`throw Error('must not execute');export {twice} from './helper';`); const r=buildGraphPlan(p,'web/main.js'); assert.deepEqual(r.graph.missing_paths,['src/helper']); assert.equal(r.graph.status,'CAPTURE_REQUIRED'); assert.equal(r.graph.verified_application,false); for(const source of [`import x from 'external';`, `import('./later.js');`, `import '../../../escape.js';`]) assert.throws(()=>buildGraphPlan(fixture(source),'web/main.js')); }); test('graph readiness terminates cycles and checks source bytes',()=>{ const p=fixture(`import '../web/main.js';export const twice=x=>x*2;`); assert.equal(buildGraphPlan(p,'web/main.js').graph.status,'READY'); p.repository.files['src/core.js'].sha256='0'.repeat(64); assert.throws(()=>buildGraphPlan(p,'web/main.js'),/SOURCE_BINDING/); });