import assert from "node:assert/strict"; import { execFileSync } from "node:child_process"; import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { dirname, join } from "node:path"; import { describe, it } from "node:test"; import { listPackedJavaScriptImportIssues } from "./verify-packed-manifests.mjs"; describe("packed manifest verifier", () => { function withPackedFiles(files, packedFiles, callback) { const dir = mkdtempSync(join(tmpdir(), "hyperframes-pack-test-")); try { const packageDir = join(dir, "package"); mkdirSync(packageDir, { recursive: true }); for (const [file, source] of Object.entries(files)) { mkdirSync(dirname(join(packageDir, file)), { recursive: true }); writeFileSync(join(packageDir, file), source, "utf8"); } const tarball = join(dir, "package.tgz"); execFileSync("tar", ["-czf", tarball, "-C", dir, "package"]); callback(tarball, new Set(packedFiles)); } finally { rmSync(dir, { recursive: true, force: true }); } } it("passes explicit relative JavaScript imports whose target is packed", () => { withPackedFiles( { "dist/index.js": 'import { runtime } from "./generated/runtime-inline.js";\n', "dist/generated/runtime-inline.js": "export const runtime = 'ok';\n", }, ["dist/index.js", "dist/generated/runtime-inline.js"], (tarball, packedFiles) => { assert.deepEqual(listPackedJavaScriptImportIssues(tarball, packedFiles), []); }, ); }); it("reports explicit relative JavaScript imports whose target is missing from the tarball", () => { withPackedFiles( { "dist/index.js": 'import { runtime } from "./generated/runtime-inline.js";\n', }, ["dist/index.js"], (tarball, packedFiles) => { assert.deepEqual(listPackedJavaScriptImportIssues(tarball, packedFiles), [ "dist/index.js:1 imports missing ./generated/runtime-inline.js", ]); }, ); }); it("checks export-from, dynamic import, require, and mjs/cjs files", () => { withPackedFiles( { "dist/index.js": 'export * from "./generated/exports.js";\n', "dist/dynamic.mjs": 'await import("./generated/dynamic.js");\n', "dist/require.cjs": 'require("./generated/require.js");\n', }, ["dist/index.js", "dist/dynamic.mjs", "dist/require.cjs"], (tarball, packedFiles) => { assert.deepEqual(listPackedJavaScriptImportIssues(tarball, packedFiles), [ "dist/index.js:1 imports missing ./generated/exports.js", "dist/dynamic.mjs:1 imports missing ./generated/dynamic.js", "dist/require.cjs:1 imports missing ./generated/require.js", ]); }, ); }); it("reports extensionless relative imports", () => { withPackedFiles( { "dist/index.js": 'export {\n runtime\n} from "./generated/runtime-inline";\n', }, ["dist/index.js"], (tarball, packedFiles) => { assert.deepEqual(listPackedJavaScriptImportIssues(tarball, packedFiles), [ "dist/index.js:1 imports ./generated/runtime-inline", ]); }, ); }); it("reports side-effect imports whose target is missing from the tarball", () => { withPackedFiles( { "index.js": 'import "./missing.js";\n', }, ["index.js"], (tarball, packedFiles) => { assert.deepEqual(listPackedJavaScriptImportIssues(tarball, packedFiles), [ "index.js:1 imports missing ./missing.js", ]); }, ); }); });