import { describe, expect, it } from "vitest"; import { resolveArtifactPathByContext, type ResolveArtifactPathInput, } from "./JavaScriptArtifactPathResolution.js"; import type { JavaScriptArtifactFile } from "../../domain/javascript/javascriptArtifactFiles.js"; import { artifactLocalIdentity } from "./JavaScriptArtifactGraphContext.js"; import { applicationNodeIdentitySchema } from "../../domain/javascript/javascriptApplicationEvidenceSchemas.js"; import { analyzeJavaScriptStaticSource } from "../../domain/javascript/javascriptStaticAnalysis.js"; describe("artifact URI scheme classification", () => { it.each(["html-reference", "module-specifier", "url-reference"] as const)( "keeps digit-bearing schemes external in %s even when a local file matches", (context) => { const files = fileMap([ file("index.html", "root"), file("web3:app.js", "root"), ]); expect( resolve({ declaredPath: "web3:app.js", sourcePath: "index.html", context, files, }), ).toMatchObject({ resolution_status: "external", resolved_path: null }); }, ); it("keeps references under a digit-bearing external base href external", () => { const files = fileMap([ file("index.html", "root"), file("web3:assets/app.js", "root"), ]); expect( resolve({ declaredPath: "app.js", sourcePath: "index.html", context: "html-reference", htmlBaseHref: "web3:assets/", files, }), ).toMatchObject({ resolution_status: "external", resolved_path: null }); }); }); describe("artifact-local graph identity", () => { it("preserves complete long namespace and key values", () => { const digest = "a".repeat(64); const namespacePrefix = "n".repeat(512); const keyPrefix = "k".repeat(4_096); const first = artifactLocalIdentity( digest, `${namespacePrefix}a`, `${keyPrefix}a`, ); const second = artifactLocalIdentity( digest, `${namespacePrefix}b`, `${keyPrefix}b`, ); expect(applicationNodeIdentitySchema.parse(first)).toEqual(first); expect(applicationNodeIdentitySchema.parse(second)).toEqual(second); expect(first).not.toEqual(second); }); }); describe("loader-owned path lookup", () => { it("keeps relative ESM imports exact", () => { const files = fileMap([ file("app/entry.mjs", "root"), file("app/feature.js", "root"), file("app/directory/index.js", "root"), file("app/feature.js.js", "root"), ]); for (const declaredPath of ["./feature", "./directory"]) { expect( resolve({ declaredPath, sourcePath: "app/entry.mjs", context: "module-specifier", moduleKind: "import", files, }), ).toMatchObject({ resolution_status: "not-found", resolved_path: null }); } expect( resolve({ declaredPath: "./feature.js", sourcePath: "app/entry.mjs", context: "module-specifier", moduleKind: "import", files, }), ).toMatchObject({ resolved_path: "app/feature.js" }); }); it("does not use .cjs as an extensionless CommonJS probe", () => { const files = fileMap([ file("app/entry.cjs", "root"), file("app/feature.cjs", "root"), ]); expect( resolve({ declaredPath: "./feature", sourcePath: "app/entry.cjs", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "not-found", resolved_path: null }); expect( resolve({ declaredPath: "./feature.cjs", sourcePath: "app/entry.cjs", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolved_path: "app/feature.cjs" }); }); it("keeps present opaque inventory files distinct from missing module targets", () => { const opaque = new Map([ [ "app/core.jsc", { path: "app/core.jsc", container_sha256: file("app/entry.cjs", "root").container_sha256, sha256: "a".repeat(64), bytes: 7, inventory_artifact_id: "opaque-core", }, ], ]); const files = fileMap([file("app/entry.cjs", "root")]); const unanalyzedFiles = { get: (path: string) => opaque.get(path), hasDirectory: () => false, }; expect( resolve({ declaredPath: "./core.jsc", sourcePath: "app/entry.cjs", context: "module-specifier", moduleKind: "require", files, unanalyzedFiles, }), ).toMatchObject({ resolution_status: "unavailable", resolved_path: null, candidate_path: "app/core.jsc", limitations: [ expect.stringContaining(`sha256 ${"a".repeat(64)}, 7 bytes`), ], }); expect( resolve({ declaredPath: "./missing.jsc", sourcePath: "app/entry.cjs", context: "module-specifier", moduleKind: "require", files, unanalyzedFiles, }), ).toMatchObject({ resolution_status: "not-found", resolved_path: null }); expect( resolve({ declaredPath: "./core.jsc", sourcePath: "app/entry.cjs", context: "module-specifier", moduleKind: "require", files, unanalyzedFiles: { ...unanalyzedFiles, get: () => ({ ...opaque.get("app/core.jsc")!, container_sha256: "b".repeat(64), }), }, }), ).toMatchObject({ resolution_status: "not-found", resolved_path: null }); }); }); describe("bare package root file lookup", () => { it("uses loader-specific bare package roots when only a sibling .js file exists", () => { const absentDirectory = fileMap([ file("app/entry.mjs", "root"), file("app/node_modules/fixture.js", "root"), ]); expect( resolve({ declaredPath: "fixture", sourcePath: "app/entry.mjs", context: "module-specifier", moduleKind: "import", files: absentDirectory, }), ).toMatchObject({ resolution_status: "external", resolved_path: null }); expect( resolve({ declaredPath: "fixture", sourcePath: "app/entry.mjs", context: "module-specifier", moduleKind: "require", files: absentDirectory, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "app/node_modules/fixture.js", }); const packageDirectory = fileMap([ file("app/entry.mjs", "root"), file("app/node_modules/fixture.js", "root"), file("app/node_modules/fixture/package.json", "root", "{}"), ]); expect( resolve({ declaredPath: "fixture", sourcePath: "app/entry.mjs", context: "module-specifier", moduleKind: "import", files: packageDirectory, }), ).toMatchObject({ resolution_status: "not-found", resolved_path: null }); expect( resolve({ declaredPath: "fixture", sourcePath: "app/entry.mjs", context: "module-specifier", moduleKind: "require", files: packageDirectory, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "app/node_modules/fixture.js", }); }); }); describe("legacy package main lookup", () => { it("treats an empty package main as absent and resolves the root index", () => { const files = fileMap([ file("app/src/entry.cjs", "root"), file("app/node_modules/fixture/package.json", "root", '{"main":""}'), file("app/node_modules/fixture/index.js", "root"), ]); expect( resolve({ declaredPath: "fixture", sourcePath: "app/src/entry.cjs", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "app/node_modules/fixture/index.js", }); }); it.each(["import", "require"] as const)( "limits %s package-main probes to Node's file extensions", (moduleKind) => { const files = fileMap([ file("app/src/entry.js", "root"), file( "app/node_modules/fixture/package.json", "root", '{"main":"main"}', ), file("app/node_modules/fixture/main.cjs", "root"), file("app/node_modules/fixture/index.mjs", "root"), ]); expect( resolve({ declaredPath: "fixture", sourcePath: "app/src/entry.js", context: "module-specifier", moduleKind, files, }), ).toMatchObject({ resolution_status: "not-found", resolved_path: null }); }, ); it("retains inventoried directories during legacy ESM main finalization", () => { const files = fileMap([ file("app/src/entry.mjs", "root"), file( "app/node_modules/fixture/package.json", "root", '{"main":"./lib/"}', ), file("app/node_modules/fixture/lib.js", "root"), ]); expect( resolve({ declaredPath: "fixture", sourcePath: "app/src/entry.mjs", context: "module-specifier", moduleKind: "import", files, directoryPaths: new Set(["app/node_modules/fixture/lib/.js"]), }), ).toMatchObject({ resolution_status: "rejected", resolved_path: null, candidate_path: "app/node_modules/fixture/lib/.js", }); }); it.each(["import", "require"] as const)( "does not recursively resolve a nested package from a %s package main", (moduleKind) => { const files = fileMap([ file("app/src/entry.js", "root"), file("app/node_modules/fixture/package.json", "root", '{"main":"sub"}'), file( "app/node_modules/fixture/sub/package.json", "root", '{"main":"other"}', ), file("app/node_modules/fixture/sub/other.js", "root"), ]); expect( resolve({ declaredPath: "fixture", sourcePath: "app/src/entry.js", context: "module-specifier", moduleKind, files, }), ).toMatchObject({ resolution_status: "not-found", resolved_path: null }); }, ); }); describe("legacy package main metadata validation and fallback", () => { it("still rejects non-string package main metadata", () => { expect( resolve({ declaredPath: "./package", sourcePath: "app/entry.js", context: "filesystem-expression", files: fileMap([ file("app/entry.js", "root"), file("app/package/package.json", "root", '{"main":false}'), file("app/package/index.js", "root"), ]), }), ).toMatchObject({ resolution_status: "unavailable", resolved_path: null }); }); it.each(["import", "require"] as const)( "uses Node's index fallback for a non-string %s package main", (moduleKind) => { const files = fileMap([ file("app/src/entry.js", "root"), file("app/node_modules/fixture/package.json", "root", '{"main":42}'), file("app/node_modules/fixture/index.js", "root"), ]); expect( resolve({ declaredPath: "fixture", sourcePath: "app/src/entry.js", context: "module-specifier", moduleKind, files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "app/node_modules/fixture/index.js", }); }, ); it.each(["import", "require"] as const)( "does not treat a root-pointing %s package main as a dotfile module", (moduleKind) => { const files = fileMap([ file("src/entry.js", "root"), file("node_modules/fixture/package.json", "root", '{"main":"../.."}'), file("index.js", "root"), file(".js", "root"), file(".json", "root"), ]); expect( resolve({ declaredPath: "fixture", sourcePath: "src/entry.js", context: "module-specifier", moduleKind, files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "index.js", }); }, ); }); describe("CommonJS bare package ancestor lookup", () => { it.each([ ["absent metadata", undefined, true], ["empty metadata", "{}", true], ["empty main", '{"main":""}', true], ["truthy missing main", '{"main":"missing"}', false], ] as const)( "handles %s before an ancestor package for both loaders", (_name, packageJson, commonJsUsesAncestor) => { const files = fileMap([ file("app/src/entry.js", "root"), file("app/src/node_modules/fixture/placeholder.js", "root"), ...(packageJson === undefined ? [] : [ file( "app/src/node_modules/fixture/package.json", "root", packageJson, ), ]), file("app/node_modules/fixture/index.js", "root"), ]); for (const moduleKind of ["import", "require"] as const) { const resolution = resolve({ declaredPath: "fixture", sourcePath: "app/src/entry.js", context: "module-specifier", moduleKind, files, }); if (moduleKind === "require" && commonJsUsesAncestor) { expect(resolution).toMatchObject({ resolution_status: "resolved", resolved_path: "app/node_modules/fixture/index.js", }); } else { expect(resolution).toMatchObject({ resolution_status: "not-found", resolved_path: null, }); } } }, ); }); describe("CommonJS bare package subpath ancestor lookup", () => { it.each([ ["absent subpath", undefined, true], ["empty subpath metadata", "{}", true], ["truthy missing subpath main", '{"main":"missing"}', false], ] as const)( "handles %s before an ancestor package for both loaders", (_name, packageJson, commonJsUsesAncestor) => { const files = fileMap([ file("app/src/entry.js", "root"), file("app/src/node_modules/fixture/placeholder.js", "root"), ...(packageJson === undefined ? [] : [ file( "app/src/node_modules/fixture/parser/package.json", "root", packageJson, ), file( "app/src/node_modules/fixture/parser/placeholder.js", "root", ), ]), file("app/node_modules/fixture/parser.js", "root"), ]); const commonJsResolution = resolve({ declaredPath: "fixture/parser", sourcePath: "app/src/entry.js", context: "module-specifier", moduleKind: "require", files, }); expect(commonJsResolution).toMatchObject({ resolved_path: commonJsUsesAncestor ? "app/node_modules/fixture/parser.js" : null, }); const esmResolution = resolve({ declaredPath: "fixture/parser", sourcePath: "app/src/entry.js", context: "module-specifier", moduleKind: "import", files, }); expect(esmResolution.resolved_path).toBeNull(); }, ); }); describe("CommonJS bare package exhausted lookup", () => { it.each([ ["empty main", "fixture", '{"main":""}', "app/src/node_modules/fixture"], [ "missing subpath", "fixture/parser", "{}", "app/src/node_modules/fixture/parser", ], ] as const)( "preserves not-found for an exhausted %s lookup", (_name, declaredPath, packageJson, packageDirectory) => { const files = fileMap([ file("app/src/entry.js", "root"), file("app/src/node_modules/fixture/package.json", "root", packageJson), file(`${packageDirectory}/placeholder.js`, "root"), ]); expect( resolve({ declaredPath, sourcePath: "app/src/entry.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "not-found", resolved_path: null }); }, ); }); describe("logical path identity", () => { it("resolves an NFD relative import to the NFC inventory path and rejects a root escape", () => { const nfc = "caf\u00e9".normalize("NFC"); const nfd = nfc.normalize("NFD"); const files = fileMap([ file("dir/index.js", "root"), file(`dir/${nfc}.js`, "root"), ]); expect( resolve({ declaredPath: `./${nfd}.js`, sourcePath: "dir/index.js", context: "module-specifier", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: `dir/${nfc}.js`, }); expect( resolve({ declaredPath: "../escape.js", sourcePath: "index.js", context: "module-specifier", files, }), ).toMatchObject({ resolution_status: "rejected", resolved_path: null }); }); }); describe("contextual JavaScript artifact path resolution", () => { it.each([ ["main.js", "app/main.js"], ["./main.js", "app/main.js"], ["src/main", "app/src/main.cjs"], ["entry", "app/entry/start.mjs"], ["fallback", "app/fallback/index.ts"], ])("resolves package entrypoint %s", (declaredPath, expected) => { const files = fileMap([ file("app/package.json", "root"), file("app/main.js", "root"), file("app/src/main.cjs", "root"), file("app/entry/package.json", "root", '{"main":"start"}'), file("app/entry/start.mjs", "root"), file("app/fallback/index.ts", "root"), ]); expect( resolve({ declaredPath, sourcePath: "app/package.json", context: "package-entrypoint", files, }), ).toMatchObject({ resolution_context: "package-entrypoint", resolution_status: "resolved", resolved_path: expected, limitations: [], }); }); it("resolves dirname-derived bare paths but keeps bare module specifiers external", () => { const files = fileMap([ file("app/main.js", "root"), file("app/preload.js", "root"), ]); const base = { declaredPath: "preload.js", sourcePath: "app/main.js", files, } as const; expect( resolve({ ...base, context: "filesystem-expression" }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "app/preload.js", }); expect(resolve({ ...base, context: "module-specifier" })).toMatchObject({ resolution_status: "external", resolved_path: null, }); }); it("applies document and base-href semantics to HTML references", () => { const files = fileMap([ file("renderer/index.html", "root"), file("assets/app.js", "root"), file("renderer/local.js", "root"), ]); expect( resolve({ declaredPath: "app.js?v=1", sourcePath: "renderer/index.html", context: "html-reference", htmlBaseHref: "/assets/", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "assets/app.js", }); expect( resolve({ declaredPath: "./local.js", sourcePath: "renderer/index.html", context: "html-reference", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "renderer/local.js", }); }); it.each(["node:fs", "electron", "../../escape.js", "%2e%2e/escape.js"])( "fails closed for unsafe or external module declaration %s", (declaredPath) => { const result = resolve({ declaredPath, sourcePath: "app/main.js", context: "module-specifier", files: fileMap([file("app/main.js", "root")]), }); expect(result.resolved_path).toBeNull(); expect(["external", "rejected"]).toContain(result.resolution_status); expect(result.limitations.length).toBeGreaterThan(0); }, ); it("does not cross nested ASAR container identities", () => { const files = fileMap([ file("app.asar/main.js", "asar-a"), file("app.asar/preload.js", "asar-b"), ]); expect( resolve({ declaredPath: "preload.js", sourcePath: "app.asar/main.js", context: "filesystem-expression", files, }), ).toMatchObject({ resolution_status: "not-found", resolved_path: null }); }); it("resolves inventoried paths longer than the former character ceiling", () => { const declaredPath = `./${"a".repeat(5_000)}.js`; const expectedPath = `app/${declaredPath.slice(2)}`; const files = fileMap([ file("app/consumer.js", "root"), file(expectedPath, "root"), ]); expect( resolve({ declaredPath, sourcePath: "app/consumer.js", context: "module-specifier", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: expectedPath, limitations: [], }); }); }); describe("ESM module URL path decoding", () => { it.each([ ["./a%2eb.mjs", "app/esm/a.b.mjs"], ["./sub/%2e%2e/x.mjs", "app/esm/x.mjs"], ])( "decodes confined URL path %s before artifact lookup", (declaredPath, target) => { expect( resolve({ declaredPath, sourcePath: "app/esm/entry.mjs", context: "module-specifier", moduleKind: "import", files: fileMap([ file("app/esm/entry.mjs", "root"), file("app/esm/a.b.mjs", "root"), file("app/esm/x.mjs", "root"), ]), }), ).toMatchObject({ resolved_path: target, resolution_status: "resolved", }); }, ); it("rejects encoded separators and paths escaping the artifact root", () => { const files = fileMap([ file("app/esm/entry.mjs", "root"), file("app/esm/x.mjs", "root"), ]); for (const declaredPath of ["./sub%2fx.mjs", "../../../escape.mjs"]) { expect( resolve({ declaredPath, sourcePath: "app/esm/entry.mjs", context: "module-specifier", moduleKind: "import", files, }), ).toMatchObject({ resolved_path: null, resolution_status: "rejected", }); } }); }); describe("JavaScript file URL resolution", () => { it("resolves file URL paths without interpreting query bytes as path syntax", () => { const files = fileMap([file("assets/app.js", "root")]); for (const declaredPath of [ "file:///assets/app.js#entry", "FILE:///assets/app.js?token=%2F#entry", ]) { expect( resolve({ declaredPath, sourcePath: "main.js", context: "module-specifier", moduleKind: "import", files, }), ).toMatchObject({ declared_path: declaredPath, resolution_status: "resolved", resolved_path: "assets/app.js", }); } for (const declaredPath of [ "file:///assets%2Fapp.js", "file:///assets%2\nFapp.js", ]) { expect( resolve({ declaredPath, sourcePath: "main.js", context: "module-specifier", moduleKind: "import", files, }), ).toMatchObject({ resolution_status: "rejected", resolved_path: null }); } expect( resolve({ declaredPath: "file:/assets/app.js", sourcePath: "main.js", context: "module-specifier", moduleKind: "import", files, }), ).toMatchObject({ resolution_status: "external", resolved_path: null }); }); }); describe("contextual JavaScript package path resolution", () => { it("follows package entrypoints beyond the former recursion ceiling", () => { const files = fileMap([ file("app/consumer.js", "root"), file( "app/node_modules/pkg-1/package.json", "root", '{"main":"../pkg-2"}', ), file( "app/node_modules/pkg-2/package.json", "root", '{"main":"../pkg-3"}', ), file( "app/node_modules/pkg-3/package.json", "root", '{"main":"../pkg-4"}', ), file( "app/node_modules/pkg-4/package.json", "root", '{"main":"../pkg-5"}', ), file( "app/node_modules/pkg-5/package.json", "root", '{"main":"../pkg-6"}', ), file( "app/node_modules/pkg-6/package.json", "root", '{"main":"entry.js"}', ), file("app/node_modules/pkg-6/entry.js", "root"), ]); expect( resolve({ declaredPath: "pkg-1", sourcePath: "app/consumer.js", context: "module-specifier", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "app/node_modules/pkg-6/entry.js", limitations: [], }); }); it("keeps an inventoried but unreadable directory package unavailable", () => { const files = fileMap([ file("app/package.json", "root"), file("app/entry/package.json", "root", null), ]); expect( resolve({ declaredPath: "entry", sourcePath: "app/package.json", context: "package-entrypoint", files, }), ).toMatchObject({ resolution_status: "unavailable", resolved_path: null, limitations: [expect.stringContaining("text is unavailable")], }); }); it("resolves nearest inventoried bare packages with import/require conditions", () => { const files = fileMap([ file("app/src/consumer.js", "root"), file( "app/node_modules/fixture/package.json", "root", JSON.stringify({ exports: { ".": { import: "./esm.mjs", require: "./cjs.cjs", default: "./fallback.js", }, }, }), ), file("app/node_modules/fixture/esm.mjs", "root"), file("app/node_modules/fixture/cjs.cjs", "root"), file("app/node_modules/fixture/fallback.js", "root"), file("app/node_modules/fixture/hidden.js", "root"), file("app/node_modules/fs/index.js", "root"), ]); expect( resolve({ declaredPath: "fixture", sourcePath: "app/src/consumer.js", context: "module-specifier", moduleKind: "import", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "app/node_modules/fixture/esm.mjs", }); expect( resolve({ declaredPath: "fixture", sourcePath: "app/src/consumer.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "app/node_modules/fixture/cjs.cjs", }); expect( resolve({ declaredPath: "fs", sourcePath: "app/src/consumer.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "external", resolved_path: null }); expect( resolve({ declaredPath: "fixture/hidden.js", sourcePath: "app/src/consumer.js", context: "module-specifier", moduleKind: "import", files, }), ).toMatchObject({ resolution_status: "external", resolved_path: null, limitations: [ expect.stringContaining("declares no exports target for subpath"), ], }); }); }); describe("package exports subpath resolution", () => { it("resolves exact subpath keys through import and require conditions", () => { const files = fileMap([ file("app/src/consumer.js", "root"), file( "app/node_modules/fixture/package.json", "root", JSON.stringify({ exports: { ".": "./index.cjs", "./parser": { import: "./parser.mjs", require: "./parser.cjs", default: "./fallback.js", }, }, }), ), file("app/node_modules/fixture/index.cjs", "root"), file("app/node_modules/fixture/parser.mjs", "root"), file("app/node_modules/fixture/parser.cjs", "root"), file("app/node_modules/fixture/fallback.js", "root"), ]); expect( resolve({ declaredPath: "fixture/parser", sourcePath: "app/src/consumer.js", context: "module-specifier", moduleKind: "import", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "app/node_modules/fixture/parser.mjs", }); expect( resolve({ declaredPath: "fixture/parser", sourcePath: "app/src/consumer.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "app/node_modules/fixture/parser.cjs", }); }); it("resolves array subpath targets at their first string entry", () => { const files = fileMap([ file("app/src/consumer.js", "root"), file( "app/node_modules/fixture/package.json", "root", JSON.stringify({ exports: { "./parser": [{ import: "./parser.mjs" }, "./parser.cjs"], }, }), ), file("app/node_modules/fixture/parser.cjs", "root"), ]); expect( resolve({ declaredPath: "fixture/parser", sourcePath: "app/src/consumer.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "app/node_modules/fixture/parser.cjs", }); }); it("resolves subpaths of scoped packages", () => { const files = fileMap([ file("app/src/consumer.js", "root"), file( "app/node_modules/@scope/fixture/package.json", "root", JSON.stringify({ exports: { "./parser": "./parser.cjs" }, }), ), file("app/node_modules/@scope/fixture/parser.cjs", "root"), ]); expect( resolve({ declaredPath: "@scope/fixture/parser", sourcePath: "app/src/consumer.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "app/node_modules/@scope/fixture/parser.cjs", }); }); }); describe("package exports subpath encapsulation", () => { it("keeps subpaths encapsulated when only a root target is exported", () => { const files = fileMap([ file("app/src/consumer.js", "root"), file( "app/node_modules/fixture/package.json", "root", JSON.stringify({ exports: "./index.cjs" }), ), file("app/node_modules/fixture/index.cjs", "root"), file("app/node_modules/fixture/parser.cjs", "root"), ]); expect( resolve({ declaredPath: "fixture/parser", sourcePath: "app/src/consumer.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "external", resolved_path: null, limitations: [expect.stringContaining("a root target only")], }); }); it("blocks subpaths with an explicit null target", () => { const files = fileMap([ file("app/src/consumer.js", "root"), file( "app/node_modules/fixture/package.json", "root", JSON.stringify({ exports: { ".": "./index.cjs", "./parser": null }, }), ), file("app/node_modules/fixture/index.cjs", "root"), ]); expect( resolve({ declaredPath: "fixture/parser", sourcePath: "app/src/consumer.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "external", resolved_path: null, limitations: [expect.stringContaining("explicit null exports target")], }); }); it("reports a missing selected subpath target without index fallback", () => { const files = fileMap([ file("app/src/consumer.js", "root"), file( "app/node_modules/fixture/package.json", "root", JSON.stringify({ exports: { "./parser": "./parser.cjs" }, }), ), file("app/node_modules/fixture/parser/index.js", "root"), ]); expect( resolve({ declaredPath: "fixture/parser", sourcePath: "app/src/consumer.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "not-found", resolved_path: null, limitations: [expect.stringContaining("exports targets are exact files")], }); }); }); describe("package subpath directory ownership", () => { it.each(["root", "other"])( "selects metadata-less package directories only in the %s container", (container) => { const files = fileMap([ file("app/src/consumer.js", "root"), file("app/src/node_modules/fixture/parser.js", container), file("app/node_modules/fixture/package.json", "root", "{}"), file("app/node_modules/fixture/parser.js", "root"), ]); expect( resolve({ declaredPath: "fixture/parser", sourcePath: "app/src/consumer.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ declared_path: "fixture/parser", resolution_context: "module-specifier", resolution_status: "resolved", resolved_path: container === "root" ? "app/src/node_modules/fixture/parser.js" : "app/node_modules/fixture/parser.js", }); }, ); it("does not mistake a package-name file or sibling prefix for a nearer directory", () => { const files = fileMap([ file("app/src/consumer.js", "root"), file("app/src/node_modules/fixture.js", "root"), file("app/src/node_modules/fixture-extra/parser.js", "root"), file("app/node_modules/fixture/parser.js", "root"), ]); expect( resolve({ declaredPath: "fixture/parser", sourcePath: "app/src/consumer.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolved_path: "app/node_modules/fixture/parser.js", resolution_status: "resolved", }); }); it.each([ ["malformed", "{", "not valid package JSON"], ["unavailable", null, "text is unavailable"], ])("preserves %s nested directory failures", (_name, text, reason) => { const files = fileMap([ file("app/consumer.js", "root"), file("app/node_modules/fixture/package.json", "root", "{}"), file("app/node_modules/fixture/parser/package.json", "root", text), ]); expect( resolve({ declaredPath: "fixture/parser", sourcePath: "app/consumer.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ declared_path: "fixture/parser", resolution_context: "module-specifier", resolved_path: null, resolution_status: "unavailable", limitations: [expect.stringContaining(reason)], }); }); it("does not recurse through a cyclic nested main during CommonJS lookup", () => { const files = fileMap([ file("app/consumer.js", "root"), file("app/node_modules/fixture/package.json", "root", "{}"), file( "app/node_modules/fixture/parser/package.json", "root", '{"main":"."}', ), ]); expect( resolve({ declaredPath: "fixture/parser", sourcePath: "app/consumer.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "not-found", resolved_path: null, }); }); }); describe("package subpath legacy lookup and metadata failures", () => { it("resolves CommonJS legacy subpath files and indexes without exports", () => { const files = fileMap([ file("app/src/consumer.js", "root"), file( "app/node_modules/fixture/package.json", "root", '{"main":"./index.cjs"}', ), file("app/node_modules/fixture/direct.js", "root"), file("app/node_modules/fixture/explicit.cjs", "root"), file("app/node_modules/fixture/folder/index.js", "root"), ]); expect( resolve({ declaredPath: "fixture/direct", sourcePath: "app/src/consumer.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "app/node_modules/fixture/direct.js", }); expect( resolve({ declaredPath: "fixture/explicit.cjs", sourcePath: "app/src/consumer.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "app/node_modules/fixture/explicit.cjs", }); expect( resolve({ declaredPath: "fixture/folder", sourcePath: "app/src/consumer.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "app/node_modules/fixture/folder/index.js", }); }); it("rejects subpath metadata that mixes subpath and condition keys", () => { const files = fileMap([ file("app/src/consumer.js", "root"), file( "app/node_modules/fixture/package.json", "root", JSON.stringify({ exports: { "./parser": "./parser.cjs", node: "./index.cjs" }, }), ), file("app/node_modules/fixture/parser.cjs", "root"), ]); expect( resolve({ declaredPath: "fixture/parser", sourcePath: "app/src/consumer.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "rejected", resolved_path: null, limitations: [expect.stringContaining("mixes subpath keys")], }); }); it("reports malformed subpath package metadata as unavailable", () => { const files = fileMap([ file("app/src/consumer.js", "root"), file("app/node_modules/fixture/package.json", "root", "{"), file("app/node_modules/fixture/parser.cjs", "root"), ]); expect( resolve({ declaredPath: "fixture/parser", sourcePath: "app/src/consumer.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "unavailable", resolved_path: null, limitations: [expect.stringContaining("not valid package JSON")], }); }); it("reports unavailable metadata text for subpath resolution", () => { const files = fileMap([ file("app/src/consumer.js", "root"), file("app/node_modules/fixture/package.json", "root", null), file("app/node_modules/fixture/parser.cjs", "root"), ]); expect( resolve({ declaredPath: "fixture/parser", sourcePath: "app/src/consumer.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "unavailable", resolved_path: null, limitations: [expect.stringContaining("text is unavailable")], }); }); }); describe("generic package entry heuristics", () => { it.each([ ['{"main":"actual.cjs","module":"bundler.mjs"}', "actual.cjs"], ['{"module":"bundler.mjs"}', "bundler.mjs"], ])( "preserves generic entry heuristics without a module kind for %s", (metadata, entry) => { const files = fileMap([ file("app/consumer.js", "root"), file("app/node_modules/fixture/package.json", "root", metadata), file("app/node_modules/fixture/actual.cjs", "root"), file("app/node_modules/fixture/bundler.mjs", "root"), file("app/node_modules/fixture/index.js", "root"), ]); expect( resolve({ declaredPath: "fixture", sourcePath: "app/consumer.js", context: "module-specifier", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: `app/node_modules/fixture/${entry}`, }); }, ); }); describe("package exports exact targets", () => { it.each([ ["./file", "app/node_modules/fixture/file.js"], ["./folder", "app/node_modules/fixture/folder/index.js"], ])( "resolves exports target %s only to that exact file", (target, nearMiss) => { const files = fileMap([ file("app/consumer.js", "root"), file( "app/node_modules/fixture/package.json", "root", JSON.stringify({ exports: target }), ), file(nearMiss, "root"), ]); for (const moduleKind of ["import", "require"] as const) { const resolution = resolve({ declaredPath: "fixture", sourcePath: "app/consumer.js", context: "module-specifier", moduleKind, files, }); expect(resolution).toMatchObject({ resolution_status: "not-found", resolved_path: null, }); expect(resolution.limitations.join(" ")).toContain( "exports targets are exact files", ); } }, ); it("keeps extension and index fallbacks for a legacy main entry", () => { for (const [main, target] of [ ["./file", "app/node_modules/fixture/file.js"], ["./folder", "app/node_modules/fixture/folder/index.js"], ] as const) { const files = fileMap([ file("app/consumer.js", "root"), file( "app/node_modules/fixture/package.json", "root", JSON.stringify({ main }), ), file(target, "root"), ]); expect( resolve({ declaredPath: "fixture", sourcePath: "app/consumer.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: target }); } }); }); describe("package import alias resolution", () => { it.each(["import", "require"] as const)( "resolves an exact #%s alias from the enclosing package imports map", (moduleKind) => { const files = aliasFiles({ "package.json": JSON.stringify({ imports: { "#config": "./config.cjs" }, }), "main.js": "", "config.cjs": "", }); expect( resolve({ declaredPath: "#config", sourcePath: "main.js", context: "module-specifier", moduleKind, files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "config.cjs", declared_path: "#config", }); }, ); it("resolves an alias from a nested file through the enclosing package root", () => { const files = aliasFiles({ "package.json": JSON.stringify({ imports: { "#config": "./config.cjs" }, }), "src/main.js": "", "config.cjs": "", }); expect( resolve({ declaredPath: "#config", sourcePath: "src/main.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "config.cjs", }); }); it("keeps package import aliases available for runtime entrypoints", () => { const files = aliasFiles({ "package.json": JSON.stringify({ imports: { "#worker": "./worker.js" }, }), "main.cjs": "", "worker.js": "", }); expect( resolve({ declaredPath: "#worker", sourcePath: "main.cjs", context: "module-specifier", files, runtimePathKind: "exact-file", }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "worker.js", declared_path: "#worker", }); }); it("uses a nested package imports map rather than the application root", () => { const files = aliasFiles({ "package.json": JSON.stringify({ imports: { "#config": "./root.cjs" }, }), "root.cjs": "", "node_modules/fixture/package.json": JSON.stringify({ imports: { "#config": "./local.cjs" }, }), "node_modules/fixture/index.js": "", "node_modules/fixture/local.cjs": "", }); expect( resolve({ declaredPath: "#config", sourcePath: "node_modules/fixture/index.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "node_modules/fixture/local.cjs", }); }); it("does not inherit an ancestor imports map across a nested package.json", () => { const files = aliasFiles({ "package.json": JSON.stringify({ imports: { "#config": "./root.cjs" }, }), "root.cjs": "", "node_modules/fixture/package.json": "{}", "node_modules/fixture/index.js": "", }); const outcome = resolve({ declaredPath: "#config", sourcePath: "node_modules/fixture/index.js", context: "module-specifier", moduleKind: "require", files, }); expect(outcome).toMatchObject({ resolution_status: "external", resolved_path: null, }); expect(outcome.limitations.join(" ")).toContain( "node_modules/fixture/package.json", ); expect(outcome.limitations.join(" ")).not.toContain("root.cjs"); }); it("does not apply a nested package map to the application root importer", () => { const files = aliasFiles({ "package.json": JSON.stringify({ imports: { "#config": "./root.cjs" }, }), "main.js": "", "root.cjs": "", "node_modules/fixture/package.json": JSON.stringify({ imports: { "#config": "./local.cjs" }, }), "node_modules/fixture/local.cjs": "", }); expect( resolve({ declaredPath: "#config", sourcePath: "main.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "root.cjs", }); }); }); describe("package import alias target selection", () => { it("selects import and require conditions from an imports target", () => { const files = aliasFiles({ "package.json": JSON.stringify({ imports: { "#config": { import: "./config.mjs", require: "./config.cjs", default: "./fallback.js", }, }, }), "main.js": "", "config.mjs": "", "config.cjs": "", "fallback.js": "", }); expect( resolve({ declaredPath: "#config", sourcePath: "main.js", context: "module-specifier", moduleKind: "import", files, }).resolved_path, ).toBe("config.mjs"); expect( resolve({ declaredPath: "#config", sourcePath: "main.js", context: "module-specifier", moduleKind: "require", files, }).resolved_path, ).toBe("config.cjs"); }); it("resolves array import targets at their first string entry", () => { const files = aliasFiles({ "package.json": JSON.stringify({ imports: { "#config": [{ import: "./missing.mjs" }, "./config.cjs"] }, }), "main.js": "", "config.cjs": "", }); expect( resolve({ declaredPath: "#config", sourcePath: "main.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "config.cjs", }); }); it("does not add an extension or index to a selected import target", () => { const files = aliasFiles({ "package.json": JSON.stringify({ imports: { "#config": "./config" }, }), "main.js": "", "config.cjs": "", "config/index.js": "", }); const outcome = resolve({ declaredPath: "#config", sourcePath: "main.js", context: "module-specifier", moduleKind: "require", files, }); expect(outcome).toMatchObject({ resolution_status: "not-found", resolved_path: null, }); expect(outcome.limitations.join(" ")).toContain( "import targets are exact files", ); }); }); describe("package import alias refusals", () => { it("reports a missing exact alias without looking in another package", () => { const files = aliasFiles({ "package.json": JSON.stringify({ imports: { "#config": "./config.cjs" }, }), "main.js": "", "config.cjs": "", }); const outcome = resolve({ declaredPath: "#other", sourcePath: "main.js", context: "module-specifier", moduleKind: "require", files, }); expect(outcome).toMatchObject({ resolution_status: "external", resolved_path: null, }); expect(outcome.limitations.join(" ")).toContain("#other"); expect(outcome.limitations.join(" ")).toContain("#config"); }); it("reports an explicit null import target as blocked", () => { const files = aliasFiles({ "package.json": JSON.stringify({ imports: { "#config": null }, }), "main.js": "", "config.cjs": "", }); const outcome = resolve({ declaredPath: "#config", sourcePath: "main.js", context: "module-specifier", moduleKind: "require", files, }); expect(outcome).toMatchObject({ resolution_status: "external", resolved_path: null, }); expect(outcome.limitations.join(" ")).toContain("explicit null"); }); it("leaves wildcard import aliases unresolved", () => { const files = aliasFiles({ "package.json": JSON.stringify({ imports: { "#internal/*": "./src/*.js" }, }), "main.js": "", "src/util.js": "", }); const outcome = resolve({ declaredPath: "#internal/util", sourcePath: "main.js", context: "module-specifier", moduleKind: "import", files, }); expect(outcome).toMatchObject({ resolution_status: "external", resolved_path: null, }); expect(outcome.limitations.join(" ")).toMatch(/wildcard/i); }); it("leaves recursive and external-package import targets unresolved", () => { const files = aliasFiles({ "package.json": JSON.stringify({ imports: { "#loop": "#config", "#dep": "fixture" }, }), "main.js": "", "node_modules/fixture/index.js": "", }); const recursive = resolve({ declaredPath: "#loop", sourcePath: "main.js", context: "module-specifier", moduleKind: "require", files, }); const external = resolve({ declaredPath: "#dep", sourcePath: "main.js", context: "module-specifier", moduleKind: "require", files, }); expect(recursive).toMatchObject({ resolution_status: "external", resolved_path: null, }); expect(recursive.limitations.join(" ")).toMatch(/recursive/i); expect(external).toMatchObject({ resolution_status: "external", resolved_path: null, }); expect(external.limitations.join(" ")).toMatch(/external-package/i); }); it("rejects reserved hash specifiers", () => { const files = aliasFiles({ "package.json": JSON.stringify({ imports: { "#config": "./config.cjs" }, }), "main.js": "", "config.cjs": "", }); expect( resolve({ declaredPath: "#", sourcePath: "main.js", context: "module-specifier", moduleKind: "import", files, }), ).toMatchObject({ resolution_status: "rejected", resolved_path: null }); }); it("does not use a foreign-container enclosing package.json", () => { const files = fileMap([ file( "package.json", "other", JSON.stringify({ imports: { "#config": "./config.cjs" } }), ), file("main.js", "root"), file("config.cjs", "root"), ]); const outcome = resolve({ declaredPath: "#config", sourcePath: "main.js", context: "module-specifier", moduleKind: "require", files, }); expect(outcome).toMatchObject({ resolution_status: "external", resolved_path: null, }); expect(outcome.limitations.join(" ")).toContain("package scopes"); }); }); describe("directory package entrypoint precedence", () => { it.each([ ["require", '{"main":"actual.cjs"}', "actual.cjs"], ["require", '{"exports":{"require":"./actual.cjs"}}', "actual.cjs"], ["import", '{"exports":{"import":"./actual.mjs"}}', "actual.mjs"], ] as const)( "prefers declared %s entrypoints over index files", (moduleKind, metadata, entry) => { const files = fileMap([ file("app/consumer.js", "root"), file("app/node_modules/fixture/package.json", "root", metadata), file(`app/node_modules/fixture/${entry}`, "root"), file("app/node_modules/fixture/index.js", "root"), ]); expect( resolve({ declaredPath: "fixture", sourcePath: "app/consumer.js", context: "module-specifier", moduleKind, files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: `app/node_modules/fixture/${entry}`, }); }, ); it.each(["{}", '{"main":"."}'])( "preserves index fallback for package metadata %s", (metadata) => { const files = fileMap([ file("app/consumer.js", "root"), file("app/entry/package.json", "root", metadata), file("app/entry/index.js", "root"), ]); expect( resolve({ declaredPath: "./entry", sourcePath: "app/consumer.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "app/entry/index.js", }); }, ); it.each([null, "{"])( "keeps unreadable or invalid metadata explicit even when an index exists", (metadata) => { const files = fileMap([ file("app/consumer.js", "root"), file("app/entry/package.json", "root", metadata), file("app/entry/index.js", "root"), ]); expect( resolve({ declaredPath: "./entry", sourcePath: "app/consumer.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "unavailable", resolved_path: null, }); }, ); it("does not replace a missing exports target with an index", () => { const files = fileMap([ file("app/consumer.js", "root"), file( "app/node_modules/fixture/package.json", "root", '{"exports":"./missing.js"}', ), file("app/node_modules/fixture/index.js", "root"), ]); expect( resolve({ declaredPath: "fixture", sourcePath: "app/consumer.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "not-found", resolved_path: null, }); }); it("keeps direct files ahead of a relative directory package", () => { const files = fileMap([ file("app/consumer.js", "root"), file("app/entry.js", "root"), file("app/entry/package.json", "root", '{"main":"actual.js"}'), file("app/entry/actual.js", "root"), file("app/entry/index.js", "root"), ]); expect( resolve({ declaredPath: "./entry", sourcePath: "app/consumer.js", context: "module-specifier", moduleKind: "require", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "app/entry.js", }); }); it("retains cycle diagnostics for generic package-entrypoint inference", () => { const files = fileMap([ file("app/package.json", "root"), file("app/a/package.json", "root", '{"main":"../b"}'), file("app/b/package.json", "root", '{"main":"../a"}'), ]); expect( resolve({ declaredPath: "./a", sourcePath: "app/package.json", context: "package-entrypoint", files, }), ).toMatchObject({ resolution_status: "unavailable", resolved_path: null, limitations: [expect.stringContaining("cycle")], }); }); }); describe("contextual JavaScript module identity", () => { it("retains CommonJS and ESM file-base identity during inert extraction", () => { const analysis = analyzeJavaScriptStaticSource( ` import { BrowserWindow } from "electron"; new BrowserWindow({ webPreferences: { preload: path.resolve("ignored", __dirname, "preload.cjs") }}); new BrowserWindow({ webPreferences: { preload: fileURLToPath(new URL("./preload.mjs", import.meta.url)) }}); new BrowserWindow({ webPreferences: { preload: path.join(path.dirname(__filename), "legacy-preload.js") }}); new BrowserWindow({ webPreferences: { preload: path.posix.resolve("/ignored", dirname(fileURLToPath(import.meta.url)), "esm-preload.js") }}); new BrowserWindow({ webPreferences: { preload: path.posix.resolve(__dirname, "/shared", "absolute-preload.js/") }}); new BrowserWindow({ webPreferences: { preload: path.posix.resolve(\`/templates\`, "template-preload.js") }}); new BrowserWindow({ webPreferences: { preload: new URL("./remote-base.js", location.href) }}); window.loadURL("file:///renderer/index.html"); `, ); expect(analysis.role_paths).toEqual( expect.arrayContaining([ expect.objectContaining({ path: "preload.cjs", resolution_context: "filesystem-expression", }), expect.objectContaining({ path: "./preload.mjs", resolution_context: "filesystem-expression", }), expect.objectContaining({ path: "legacy-preload.js", resolution_context: "filesystem-expression", }), expect.objectContaining({ path: "esm-preload.js", resolution_context: "filesystem-expression", }), expect.objectContaining({ path: "/shared/absolute-preload.js", resolution_context: "filesystem-expression", }), expect.objectContaining({ path: "/templates/template-preload.js", resolution_context: "filesystem-expression", }), expect.objectContaining({ path: "file:///renderer/index.html", resolution_context: "module-specifier", }), ]), ); expect(analysis.electron.browser_windows).toEqual( expect.arrayContaining([ expect.objectContaining({ preload_path: "preload.cjs", preload_resolution_context: "filesystem-expression", }), expect.objectContaining({ preload_path: "./preload.mjs", preload_resolution_context: "filesystem-expression", }), expect.objectContaining({ preload_path: "esm-preload.js", preload_resolution_context: "filesystem-expression", }), expect.objectContaining({ preload_path: "/shared/absolute-preload.js", preload_resolution_context: "filesystem-expression", }), expect.objectContaining({ preload_path: "/templates/template-preload.js", preload_resolution_context: "filesystem-expression", }), ]), ); expect(analysis.role_paths).not.toEqual( expect.arrayContaining([ expect.objectContaining({ path: "./remote-base.js" }), ]), ); }); }); describe("TypeScript NodeNext emitted-extension resolution", () => { const container = "container"; it.each([ ["./dep.js", "src/dep.ts"], ["./ui/Button.js", "src/ui/Button.tsx"], ["./cfg.mjs", "src/cfg.mts"], ["./legacy.cjs", "src/legacy.cts"], ] as const)( "resolves %s to its TypeScript source counterpart", (specifier, target) => { const files = fileMap([ file("src/main.ts", container), file(target, container, "export const value = 1;"), ]); expect( resolve({ declaredPath: specifier, sourcePath: "src/main.ts", context: "module-specifier", moduleKind: "import", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: target }); }, ); }); describe("TypeScript declaration fallback ownership", () => { const container = "container"; it.each([ ["./dep.js", "src/dep.d.ts"], ["./cfg.mjs", "src/cfg.d.mts"], ["./legacy.cjs", "src/legacy.d.cts"], ] as const)( "retains %s as compile-time evidence without inventing a runtime target", (specifier, target) => { const files = fileMap([ file("src/main.ts", container), file(target, container, "export const value = 1;"), ]); for (const moduleKind of ["import", "require"] as const) { expect( resolve({ declaredPath: specifier, sourcePath: "src/main.ts", context: "module-specifier", moduleKind, files, }), ).toMatchObject({ resolution_status: "unavailable", resolved_path: null, candidate_path: target, }); } expect( resolve({ declaredPath: "./" + target.slice(4), sourcePath: "src/main.ts", context: "module-specifier", moduleKind: "import", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: target }); }, ); it("prefers a present runtime file and keeps the fallback off for JS callers", () => { const files = fileMap([ file("src/main.ts", container), file("src/dep.js", container), file("src/dep.ts", container), file("src/js-main.js", container), ]); expect( resolve({ declaredPath: "./dep.js", sourcePath: "src/main.ts", context: "module-specifier", moduleKind: "import", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "src/dep.js", }); expect( resolve({ declaredPath: "./dep.js", sourcePath: "src/js-main.js", context: "module-specifier", moduleKind: "import", files: fileMap([ file("src/js-main.js", container), file("src/dep.ts", container), ]), }), ).toMatchObject({ resolution_status: "not-found", resolved_path: null }); }); it("does not apply the mapping to URL resources or package export targets", () => { const urlFiles = fileMap([ file("src/main.ts", container), file("src/asset.ts", container), ]); expect( resolve({ declaredPath: "asset.js", sourcePath: "src/main.ts", context: "url-reference", files: urlFiles, }), ).toMatchObject({ resolution_status: "not-found", resolved_path: null }); const packageFiles = fileMap([ file("src/main.ts", container), file( "src/node_modules/fixture/package.json", container, '{"exports":"./dep.js"}', ), file("src/node_modules/fixture/dep.ts", container), ]); expect( resolve({ declaredPath: "fixture", sourcePath: "src/main.ts", context: "module-specifier", moduleKind: "import", files: packageFiles, }), ).toMatchObject({ resolution_status: "not-found", resolved_path: null }); }); it("does not substitute source counterparts for directory or index resolution", () => { const files = fileMap([ file("src/main.ts", container), file("src/lib/index.ts", container), ]); expect( resolve({ declaredPath: "./lib.js", sourcePath: "src/main.ts", context: "module-specifier", moduleKind: "import", files, }), ).toMatchObject({ resolution_status: "not-found", resolved_path: null }); }); it("resolves an emitted dotfile name within its own directory", () => { const files = fileMap([ file("src/main.ts", container), file("src/.ts", container), ]); expect( resolve({ declaredPath: "./.js", sourcePath: "src/main.ts", context: "module-specifier", moduleKind: "import", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "src/.ts", }); }); }); describe("url-reference directory and empty-segment semantics", () => { it.each([ "./worker.js/.", "./worker.js/child/..", "./worker.js/", "/dist/worker.js/.", "./worker.js/.?cache=1#entry", ])("keeps directory-form URLs distinct from files: %s", (declaredPath) => { expect( resolve({ declaredPath, sourcePath: "dist/app.mjs", context: "url-reference", files: fileMap([file("dist/worker.js", "root")]), }), ).toMatchObject({ declared_path: declaredPath, resolution_status: "not-found", resolved_path: null, }); }); it.each(["./nested//worker.js", "./nested//../worker.js"])( "does not collapse empty URL path segments: %s", (declaredPath) => { expect( resolve({ declaredPath, sourcePath: "dist/app.mjs", context: "url-reference", files: fileMap([ file("dist/worker.js", "root"), file("dist/nested/worker.js", "root"), ]), }), ).toMatchObject({ resolved_path: null }); }, ); it.each([ ["./nested/.././worker.js?cache=1#entry", "dist/worker.js"], ["./.worker.js", "dist/.worker.js"], ])("resolves exact file URLs with dots: %s", (declaredPath, resolvedPath) => { expect( resolve({ declaredPath, sourcePath: "dist/app.mjs", context: "url-reference", files: fileMap([file(resolvedPath, "root")]), }), ).toMatchObject({ resolution_status: "resolved", resolved_path: resolvedPath, }); }); }); describe("suffix-only non-runtime URL references", () => { it.each(["", "?cache=1", "#worker"])( "rejects URL reference %s without a path or known base document", (declaredPath) => { expect( resolve({ declaredPath, sourcePath: "dist/app.mjs", context: "url-reference", files: fileMap([file("dist/app.mjs", "root")]), }), ).toMatchObject({ declared_path: declaredPath, resolution_status: "rejected", resolved_path: null, }); }, ); }); describe("url-reference JavaScript artifact path resolution", () => { it.each([ ["C|?cache=1#entry", "dist/C|"], ["/c:/worker.js", "c:/worker.js"], ["/./c|/worker.js", "c|/worker.js"], ["../c|/worker.js", "c|/worker.js"], ["/nested/../c|/worker.js", "c|/worker.js"], ["c|/../worker.js", "dist/worker.js"], ])("leaves drive-letter URL paths unresolved: %s", (declaredPath, decoy) => { const resolution = resolve({ declaredPath, sourcePath: "dist/app.mjs", context: "url-reference", files: fileMap([file(decoy, "root")]), }); expect(resolution).toMatchObject({ declared_path: declaredPath, resolution_status: "unavailable", resolved_path: null, }); expect(resolution.limitations.length).toBeGreaterThan(0); }); it.each([ ["./c|/worker.js", "dist/c|/worker.js"], ["c|name/worker.js", "dist/c|name/worker.js"], ["/%63|/worker.js", "c|/worker.js"], ["/c%3A/worker.js", "c:/worker.js"], ])( "retains non-drive URL path identities: %s", (declaredPath, resolvedPath) => { expect( resolve({ declaredPath, sourcePath: "dist/app.mjs", context: "url-reference", files: fileMap([file(resolvedPath, "root")]), }), ).toMatchObject({ declared_path: declaredPath, resolution_status: "resolved", resolved_path: resolvedPath, }); }, ); it.each(["?value=", "#value="])( "admits the pathname independently of its %s suffix", (suffix) => { for (const value of ["%2F", "%2E", "%5C", "%00", "%FF", "\\", "\0"]) { const declaredPath = `./worker.js${suffix}${value}`; expect( resolve({ declaredPath, sourcePath: "dist/app.js", context: "url-reference", files: fileMap([file("dist/worker.js", "root")]), }), declaredPath, ).toMatchObject({ declared_path: declaredPath, resolution_status: "resolved", resolved_path: "dist/worker.js", }); } }, ); it.each([ "app\0.js.map?valid=1", "nested\\worker.js#valid", "app%00.js.map", "app%FF.js.map", "app%C0%AF.js.map", "app%2ejs.map", "nested%2fworker.js", "nested%5cworker.js", "h\nttp://[", "../../outside.js.map", "../../outside/.", ])("rejects an inadmissible URL path: %s", (declaredPath) => { const resolution = resolve({ declaredPath, sourcePath: "dist/app.js", context: "url-reference", files: fileMap([ file("dist/app.js.map", "root"), file("dist/nested/worker.js", "root"), ]), }); expect(resolution).toMatchObject({ declared_path: declaredPath, resolution_context: "url-reference", resolution_status: "rejected", resolved_path: null, }); expect(resolution.limitations.length).toBeGreaterThan(0); }); it("resolves sibling paths and rejects external URL forms", () => { const files = fileMap([ file("dist/app.js", "root"), file("dist/app.js.map", "root"), file("dist/worker.js", "root"), ]); expect( resolve({ declaredPath: "app.js.map", sourcePath: "dist/app.js", context: "url-reference", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "dist/app.js.map", }); expect( resolve({ declaredPath: "app.js.map?v=1#section", sourcePath: "dist/app.js", context: "url-reference", files, }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "dist/app.js.map", }); expect( resolve({ declaredPath: "//cdn.example.com/app.js.map", sourcePath: "dist/app.js", context: "url-reference", files, }), ).toMatchObject({ resolution_status: "external", resolved_path: null, }); expect( resolve({ declaredPath: "https://cdn.example.com/app.js.map", sourcePath: "dist/app.js", context: "url-reference", files, }), ).toMatchObject({ resolution_status: "external", resolved_path: null, }); }); }); const resolve = (input: ResolveArtifactPathInput) => resolveArtifactPathByContext(input); const fileMap = (files: readonly JavaScriptArtifactFile[]) => new Map(files.map((value) => [value.path, value])); const file = ( path: string, container: string, text: string | null = "", ): JavaScriptArtifactFile => ({ path, container_sha256: container.padEnd(64, "0").slice(0, 64), sha256: path.padEnd(64, "0").slice(0, 64), bytes: text?.length ?? 0, inventory_artifact_id: `artifact-${path}`, kind: path.endsWith("package.json") ? "package-json" : "javascript", unpacked: false, text: text === null ? { included: false, reason: "invalid-utf8" } : { included: true, value: text }, }); const aliasFiles = ( entries: Readonly>, ): ReturnType => fileMap( Object.entries(entries).map(([path, text]) => file(path, "root", text ?? ""), ), ); describe("exact HTML resource resolution", () => { it.each([ ["extension", ["app.js"]], ["directory index", ["app/index.js"]], ["directory package", ["app/package.json", "app/entry.js"]], ] as const)("does not infer a file from %s fallback", (_name, paths) => { const files = fileMap([ file("index.html", "root"), ...paths.map((path) => file( path, "root", path.endsWith("package.json") ? '{"main":"entry.js"}' : "", ), ), ]); expect( resolve({ declaredPath: "./app", sourcePath: "index.html", context: "html-reference", files, }), ).toMatchObject({ resolution_status: "not-found", resolved_path: null }); }); it("prefers an exact extensionless resource and retains URL suffix handling", () => { const files = fileMap([ file("renderer/index.html", "root"), file("assets/app", "root"), file("assets/app.js", "root"), file("assets/app/index.js", "root"), ]); expect( resolve({ declaredPath: "./app?cache=1#v2", sourcePath: "renderer/index.html", context: "html-reference", htmlBaseHref: "/assets/", files, }), ).toMatchObject({ declared_path: "./app?cache=1#v2", resolution_status: "resolved", resolved_path: "assets/app", }); }); }); it.each(["require", "import"] as const)( "rejects a literal trailing backslash package main before %s probing", (moduleKind) => { const files = fileMap([ file("entry.js", "root"), file( "node_modules/p/package.json", "root", JSON.stringify({ main: "lib\\" }), ), file("node_modules/p/lib", "root"), ]); expect( resolve({ declaredPath: "p", sourcePath: "entry.js", context: "module-specifier", moduleKind, files, }), ).toMatchObject({ resolution_status: "rejected", resolved_path: null }); }, ); describe("exact Electron runtime entrypoint resolution", () => { it("requires a protocol for Electron URL resources", () => { const files = fileMap([ file("app/main.cjs", "root"), file("app/renderer", "root"), file("app/renderer.js", "root"), ]); expect( resolve({ declaredPath: "./renderer", sourcePath: "app/main.cjs", context: "module-specifier", files, runtimePathKind: "url-resource", }), ).toMatchObject({ resolution_status: "unavailable", resolved_path: null, limitations: [expect.stringContaining("requires a URL protocol")], }); expect( resolve({ declaredPath: "file:///app/renderer", sourcePath: "app/main.cjs", context: "module-specifier", files, runtimePathKind: "url-resource", }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "app/renderer", }); }); it("checks local paths exactly while preserving bare package lookup", () => { const files = fileMap([ file("app/main.cjs", "root"), file("app/worker.js", "root"), file("app/worker", "root"), file("app/worker#v1.js", "root"), file( "node_modules/exported/package.json", "root", '{"exports":{"./parser":"./parser.cjs"}}', ), file("node_modules/exported/parser.cjs", "root"), file("app/fallback/index.js", "root"), ]); expect( resolve({ declaredPath: "./worker.js", sourcePath: "app/main.cjs", context: "module-specifier", files, runtimePathKind: "exact-file", }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "app/worker.js", }); expect( resolve({ declaredPath: "exported/parser", sourcePath: "app/main.cjs", context: "module-specifier", files, runtimePathKind: "exact-file", }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "node_modules/exported/parser.cjs", }); expect( resolve({ declaredPath: "./worker#v1.js", sourcePath: "app/main.cjs", context: "module-specifier", files, runtimePathKind: "exact-file", }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "app/worker#v1.js", }); expect( resolve({ declaredPath: "./fallback", sourcePath: "app/main.cjs", context: "module-specifier", files, runtimePathKind: "exact-file", }), ).toMatchObject({ resolution_status: "not-found", resolved_path: null, }); }); it("accepts an exact extensionless file but not a directory index", () => { const files = fileMap([ file("app/main.cjs", "root"), file("app/preload", "root"), file("app/preload.js", "root"), file("app/fallback/index.js", "root"), ]); expect( resolve({ declaredPath: "./preload", sourcePath: "app/main.cjs", context: "module-specifier", files, runtimePathKind: "exact-file", }), ).toMatchObject({ resolution_status: "resolved", resolved_path: "app/preload", }); expect( resolve({ declaredPath: "./fallback", sourcePath: "app/main.cjs", context: "module-specifier", files, runtimePathKind: "exact-file", }), ).toMatchObject({ resolution_status: "not-found", resolved_path: null, }); }); }); it.each(["#home", "?theme=dark", ""])( "does not invent a document base for runtime URL %s", (declaredPath) => { expect( resolve({ declaredPath, sourcePath: "main.cjs", context: "url-reference", runtimePathKind: "url-resource", files: fileMap([file("main.cjs", "root")]), }), ).toMatchObject({ declared_path: declaredPath, resolution_status: "unavailable", resolved_path: null, }); }, ); it("resolves Node runtime entrypoints without substituting emitted TypeScript sources", () => { const files = fileMap([ file("main.ts", "root"), file("worker.ts", "root"), file("worker.js", "other-container"), file("runtime.js", "root"), file("directory/index.js", "root"), ]); for (const [declaredPath, status, path, candidatePath] of [ ["./worker.js", "not-found", null, "worker.js"], ["./runtime", "resolved", "runtime.js", undefined], ["./directory", "resolved", "directory/index.js", undefined], ] as const) expect( resolve({ declaredPath, sourcePath: "main.ts", context: "module-specifier", files, runtimePathKind: "node-entrypoint", }), ).toMatchObject({ resolution_status: status, resolved_path: path, ...(candidatePath === undefined ? {} : { candidate_path: candidatePath }), }); });