Files
reverse-engineering-anything/src/application/javascript/JavaScriptArtifactPathResolution.test.ts
T
ShuaixinHuang e9fc8fb30c fix(javascript): preserve runtime path bytes and Electron ownership (#4941)
* fix(javascript): preserve literal percent runtime paths

* fix(javascript): ignore resolve prefixes before the final anchor

* fix(electron): retain application roots for loadFile declarations

* fix(electron): resolve loadFile from enclosing application package

* fix(electron): retain outer application root across package scopes

* fix(electron): derive application ownership from inventoried packages

* fix(electron): retain resolved package entrypoint ownership

* fix(electron): preserve competing application ownership

* fix(electron): retain invalid and omitted runtime ownership

* fix(electron): preserve omitted module ownership and runtime paths

* fix(electron): preserve proven roots before confining page paths

* fix(electron): retain possible owners behind missing imports

* fix(electron): distinguish absent imports and owned page candidates

* fix(electron): keep unavailable JSON out of owner gaps

* fix(electron): retain exact loader formats and default entry status

* fix(electron): retain unavailable entrypoint ownership candidates

* test(ghidra): preserve Windows Node probe prerequisites

* test(ghidra): assert cancellation during profile shutdown

* fix(electron): separate examined imports from frontend ownership

* fix(electron): retain unavailable directory entrypoint owners

* test(jeb): retain Linux ownership prerequisite in isolation

* fix(javascript): retain unchecked loader ownership and literal main paths

* fix(javascript): preserve runtime paths and call-site module aliases

* fix(javascript): bound module alias traversal and preserve projections

* fix(javascript): retain host module and nested artifact path boundaries

* fix(javascript): preserve ESM and archive module loader provenance

* test(javascript): distinguish unmapped containers from missing exports

* fix: retain default module aliases and Electron builtin imports

* fix: preserve host file URL and inward ASAR ownership

* fix: preserve CommonJS file URL classification in CI fixtures

* fix: retain bound module loaders and Windows entrypoint uncertainty

* fix: retain ASAR uncertainty and invalidate changed Electron app roots

* fix(javascript): retain ownership uncertainty across loader boundaries

* fix(javascript): preserve loader sources and bound alias queries

* fix(javascript): retain destructured loader sources

* fix(javascript): preserve loader uncertainty at resolution boundaries

* fix(javascript): preserve callable and package launch ownership

* fix(javascript): preserve captured values across member reads

* test(process): assert tagged filesystem cancellation failures

* fix(javascript): preserve inventory bases and invocation read timing

* fix(javascript): preserve ownership across indirect and unread loads

* test(javascript): order fixture directory creation on Windows

* test(javascript): share ordered filesystem fixture writer

* fix(javascript): unify loader provenance and package validation

* fix(javascript): preserve captured Node require loader values

* fix(javascript): preserve loader invocation authority

* fix(javascript): verify generic loader invocation authority

* fix(javascript): preserve conditional loader method alternatives

* fix(javascript): require proven factories for source association

* fix(javascript): honor replaced Electron app path setters

* fix(javascript): prove path and assignment source ownership

* fix(javascript): retain native delegate eligibility through shared writes

* fix(process): settle stale baseline errors after confirmed absence

* fix(javascript): preserve assignment and path boundary evidence

* fix(javascript): prove source-directory resolve anchors

* fix: preserve application path provenance and portable schemas

* fix(javascript): retain CommonJS exported setter effects

* fix: isolate Linux identity observations and retain native module exports

* fix(javascript): preserve published app and helper provenance

* fix(javascript): normalize typed stores and native path fixtures
2026-10-20 17:25:19 +08:00

4386 lines
127 KiB
TypeScript

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("Windows CommonJS request classification", () => {
it.each([
"..\\shared\\window.cjs",
".\\window.cjs",
"fixture\\window.cjs",
"C:shared\\window.cjs",
])(
"retains unknown Windows CommonJS request semantics for %s",
(declaredPath) => {
expect(
resolve({
declaredPath,
sourcePath: "app/main.cjs",
context: "module-specifier",
moduleKind: "require",
files: fileMap([
file("app/main.cjs", "root"),
file("app/window.cjs", "root"),
file("shared/window.cjs", "root"),
]),
}),
).toMatchObject({
declared_path: declaredPath,
resolution_status: "unavailable",
resolved_path: null,
});
},
);
it.each([
"node:\\fs",
"node:fs\\extra",
"https:\\example.invalid\\window.cjs",
])(
"does not treat the rejected scheme request %s as an unknown Windows path",
(declaredPath) => {
expect(
resolve({
declaredPath,
sourcePath: "app/main.cjs",
context: "module-specifier",
moduleKind: "require",
files: fileMap([file("app/main.cjs", "root")]),
}),
).toMatchObject({
declared_path: declaredPath,
resolution_status: "rejected",
resolved_path: null,
});
},
);
it("keeps rejected and URL-owned backslash requests distinct from CommonJS host syntax", () => {
const files = fileMap([
file("app/main.cjs", "root"),
file("app/window.cjs", "root"),
]);
for (const [declaredPath, moduleKind, status, resolvedPath] of [
[".\\window\0.cjs", "require", "rejected", null],
[".\\window.cjs", "import", "rejected", null],
["./window.cjs", "require", "resolved", "app/window.cjs"],
["node:fs", "require", "external", null],
] as const)
expect(
resolve({
declaredPath,
sourcePath: "app/main.cjs",
context: "module-specifier",
moduleKind,
files,
}),
).toMatchObject({
resolution_status: status,
resolved_path: resolvedPath,
});
});
});
describe("literal POSIX inventory base segments", () => {
it("validates the final URL after a parent reference removes the encoded base segment", () => {
expect(
resolve({
declaredPath: "../b.js",
sourcePath: "literal\\dir/a.mjs",
context: "module-specifier",
moduleKind: "import",
files: fileMap([file("b.js", "container")]),
}),
).toMatchObject({ resolution_status: "resolved", resolved_path: "b.js" });
});
it.each(
["literal\\dir", "resources/app.asar/literal\\dir"].flatMap((directory) =>
(["import", "require", "compiler-dependent"] as const).map(
(moduleKind) => ({ directory, moduleKind }),
),
),
)(
"preserves loader-specific admission from $directory with mode $moduleKind",
({ directory, moduleKind }) => {
const sourcePath = `${directory}/a.js`;
const target = `${directory}/b.js`;
const files = fileMap([
file(sourcePath, "container"),
file(target, "container"),
file(`${directory.replaceAll("\\", "/")}/b.js`, "container"),
]);
expect(
resolve({
declaredPath: "./b.js",
sourcePath,
context: "module-specifier",
moduleKind,
files,
}),
).toMatchObject({
resolution_status:
moduleKind === "require"
? "resolved"
: moduleKind === "import"
? "rejected"
: "unavailable",
resolved_path: moduleKind === "require" ? target : null,
...(moduleKind === "compiler-dependent"
? {
conditional_resolutions: [
expect.objectContaining({
mode: "import",
resolution_status: "rejected",
resolved_path: null,
}),
expect.objectContaining({
mode: "require",
resolution_status: "resolved",
resolved_path: target,
}),
],
}
: {}),
});
},
);
it.each([
"./bad%5Cb.js",
"./bad%2Fb.js",
"./bad%00b.js",
"./bad%xxb.js",
".\\b.js",
])(
"still rejects newly declared unsafe module URL syntax %s inside a literal inventory directory",
(declaredPath) => {
expect(
resolve({
declaredPath,
sourcePath: "literal\\dir/a.js",
context: "module-specifier",
moduleKind: "import",
files: fileMap([file("literal\\dir/b.js", "container")]),
}),
).toMatchObject({ resolution_status: "rejected", resolved_path: null });
},
);
it.each([
"./discard%5C/../b.js",
"./discard%2F/../b.js",
"./discard%00/../b.js",
"./discard%xx/../b.js",
])(
"still rejects inherited encoded separators after normalizing discarded request segments: %s",
(declaredPath) => {
expect(
resolve({
declaredPath,
sourcePath: "literal\\dir/a.js",
context: "module-specifier",
moduleKind: "import",
files: fileMap([file("literal\\dir/b.js", "container")]),
}),
).toMatchObject({
resolution_status: "rejected",
resolved_path: null,
});
},
);
});
describe("runtime host path classification", () => {
it.each([
"/discard%2F/../shared/window.cjs",
"/discard%5C/../shared/window.cjs",
"/discard%00/../shared/window.cjs",
"/discard%xx/../shared/window.cjs",
])(
"normalizes discarded absolute URL segments before pathname validation: %s",
(declaredPath) => {
expect(
resolve({
declaredPath,
sourcePath: "app/main.mjs",
context: "module-specifier",
moduleKind: "import",
files: new Map(),
}),
).toMatchObject({
resolution_status: "unavailable",
resolved_path: null,
});
},
);
it("normalizes discarded relative URL segments before pathname validation", () => {
expect(
resolve({
declaredPath: "./discard%2F/../window.cjs",
sourcePath: "app/main.mjs",
context: "module-specifier",
moduleKind: "import",
files: fileMap([file("app/window.cjs", "root")]),
}),
).toMatchObject({
resolution_status: "resolved",
resolved_path: "app/window.cjs",
});
});
it("retains unknown URL identity for an unpaired source directory segment", () => {
expect(
resolve({
declaredPath: "./window.cjs",
sourcePath: "app/\ud800/main.mjs",
context: "module-specifier",
moduleKind: "import",
files: new Map(),
}),
).toMatchObject({ resolution_status: "unavailable", resolved_path: null });
});
it.each([
"/shared%2Fwindow.mjs",
"/shared%5cwindow.mjs",
"/shared%00window.mjs",
"/shared%xxwindow.mjs",
])(
"rejects invalid absolute ESM URL path syntax before host lookup: %s",
(declaredPath) => {
expect(
resolve({
declaredPath,
sourcePath: "app/main.mjs",
context: "module-specifier",
moduleKind: "import",
files: new Map(),
}),
).toMatchObject({ resolution_status: "rejected", resolved_path: null });
expect(
resolve({
declaredPath,
sourcePath: "app/main.cjs",
context: "module-specifier",
moduleKind: "require",
files: new Map(),
}),
).toMatchObject({
resolution_status: "unavailable",
resolved_path: null,
});
},
);
it("keeps encoded query bytes outside ESM pathname admission", () => {
expect(
resolve({
declaredPath: "/shared/window.mjs?token=%2F#fragment",
sourcePath: "app/main.mjs",
context: "module-specifier",
moduleKind: "import",
files: new Map(),
}),
).toMatchObject({ resolution_status: "unavailable", resolved_path: null });
});
it.each(["exact-file", "application-file", "node-entrypoint"] as const)(
"keeps POSIX and Windows absolute %s paths unavailable before canonical admission",
(runtimePathKind) => {
for (const declaredPath of [
"/opt/app/main.cjs",
"C:/app/main.cjs",
"C:\\app\\main.cjs",
"\\\\server\\share\\main.cjs",
"//server/share/main.cjs",
"\\app\\main.cjs",
])
expect(
resolve({
declaredPath,
sourcePath: "app/package.json",
context: "filesystem-expression",
runtimePathKind,
files: fileMap([
file("opt/app/main.cjs", "root"),
file("app/main.cjs", "root"),
]),
}),
).toMatchObject({
resolution_status: "unavailable",
resolved_path: null,
declared_path: declaredPath,
});
expect(
resolve({
declaredPath: "C:/app/\0main.cjs",
sourcePath: "app/main.cjs",
context: "filesystem-expression",
runtimePathKind,
files: new Map(),
}),
).toMatchObject({ resolution_status: "rejected", resolved_path: null });
},
);
});
describe("artifact URI scheme classification", () => {
it.each(["entry:prod.cjs", "entry:prod%2Fname.cjs"])(
"retains package main filename bytes for %s without URI classification",
(declaredPath) => {
const files = fileMap([
file("app/package.json", "root"),
file(`app/${declaredPath}`, "root"),
]);
expect(
resolve({
declaredPath,
sourcePath: "app/package.json",
context: "package-entrypoint",
runtimePathKind: "node-entrypoint",
files,
}),
).toMatchObject({
declared_path: declaredPath,
resolution_status: "resolved",
resolved_path: `app/${declaredPath}`,
});
expect(
resolve({
declaredPath,
sourcePath: "app/package.json",
context: "module-specifier",
moduleKind: "require",
files,
}),
).toMatchObject({ resolution_status: "external", resolved_path: null });
expect(
resolve({
declaredPath,
sourcePath: "app/package.json",
context: "package-entrypoint",
runtimePathKind: "node-entrypoint",
files: fileMap([file("app/package.json", "root")]),
}),
).toMatchObject({
resolution_status: "not-found",
resolved_path: null,
candidate_path: `app/${declaredPath}`,
});
},
);
it.each(["require", "import"] as const)(
"resolves a colon-bearing dependency package main with the %s loader",
(moduleKind) => {
expect(
resolve({
declaredPath: "fixture",
sourcePath: "app/main.cjs",
context: "module-specifier",
moduleKind,
files: fileMap([
file("app/main.cjs", "root"),
file(
"app/node_modules/fixture/package.json",
"root",
'{"main":"entry:prod.cjs"}',
),
file("app/node_modules/fixture/entry:prod.cjs", "root"),
file("app/node_modules/fixture/index.js", "root"),
]),
}),
).toMatchObject({
resolution_status: "resolved",
resolved_path: "app/node_modules/fixture/entry:prod.cjs",
});
},
);
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("applies URL whitespace handling only to ESM lookup and retains declarations", () => {
const tab = "\t";
const files = fileMap([
file("app/entry.mjs", "root"),
file("app/feature.js", "root"),
file(`app/tab${tab}name.js`, "root"),
]);
for (const whitespace of ["\t", "\n", "\r"]) {
const raw = `./fea${whitespace}ture.js`;
expect(
resolve({
declaredPath: raw,
sourcePath: "app/entry.mjs",
context: "module-specifier",
moduleKind: "import",
files,
}),
).toMatchObject({ declared_path: raw, resolved_path: "app/feature.js" });
}
expect(
resolve({
declaredPath: `./tab${tab}name.js`,
sourcePath: "app/entry.mjs",
context: "module-specifier",
moduleKind: "import",
files,
}),
).toMatchObject({ resolved_path: null });
expect(
resolve({
declaredPath: `./tab${tab}name.js`,
sourcePath: "app/entry.cjs",
context: "module-specifier",
moduleKind: "require",
files,
}),
).toMatchObject({ resolved_path: "app/tab\tname.js" });
expect(
resolve({
declaredPath: "./tab%09name.js",
sourcePath: "app/entry.mjs",
context: "module-specifier",
moduleKind: "import",
files,
}),
).toMatchObject({ resolved_path: "app/tab\tname.js" });
});
});
describe("loader-specific module suffix 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: (path: string) =>
path === "app/core.jsc"
? {
...opaque.get(path)!,
container_sha256: "b".repeat(64),
}
: undefined,
},
}),
).toMatchObject({ resolution_status: "not-found", resolved_path: null });
});
});
describe("unavailable inventoried native add-ons", () => {
it("retains an inventoried native add-on whose bytes are unavailable", () => {
const unavailable = {
path: "app/addon.node",
container_sha256: file("app/entry.cjs", "root").container_sha256,
sha256: null,
bytes: 8192,
inventory_artifact_id: null,
inventory_occurrence_id: "missing-addon-occurrence",
kind: "native-addon" as const,
hash_status: "unavailable" as const,
limitations: ["unpacked companion is missing"],
};
const result = resolve({
declaredPath: "./addon.node",
sourcePath: "app/entry.cjs",
context: "module-specifier",
moduleKind: "require",
files: fileMap([file("app/entry.cjs", "root")]),
unanalyzedFiles: {
get: (path) => (path === unavailable.path ? unavailable : undefined),
hasDirectory: () => false,
},
});
expect(result).toMatchObject({
declared_path: "./addon.node",
resolution_status: "unavailable",
candidate_path: "app/addon.node",
limitations: [
"unpacked companion is missing",
expect.stringContaining("inventoried native-addon file"),
],
});
});
});
describe("unavailable package metadata", () => {
it("blocks directory fallback until same-container manifests are readable", () => {
const manifest = {
path: "app/relative/package.json",
container_sha256: file("app/main.cjs", "root").container_sha256,
sha256: null,
bytes: 28,
inventory_artifact_id: null,
inventory_occurrence_id: "missing-relative-manifest",
kind: "package-json" as const,
hash_status: "unavailable" as const,
limitations: ["unpacked manifest companion is missing"],
};
const files = fileMap([
file("app/main.cjs", "root"),
file("app/main.mjs", "root"),
file("app/relative/index.js", "root"),
]);
const requestedPaths: string[] = [];
const lookup = {
get: (path: string) => {
requestedPaths.push(path);
return path === manifest.path ? manifest : undefined;
},
hasDirectory: () => false,
};
const relativeRequire = resolve({
declaredPath: "./relative",
sourcePath: "app/main.cjs",
context: "module-specifier",
moduleKind: "require",
files,
unanalyzedFiles: lookup,
});
expect(requestedPaths).toContain(manifest.path);
expect(relativeRequire).toMatchObject({
resolution_status: "unavailable",
resolved_path: null,
limitations: ["unpacked manifest companion is missing"],
});
expect(
resolve({
declaredPath: "./relative",
sourcePath: "app/main.mjs",
context: "module-specifier",
moduleKind: "import",
files,
unanalyzedFiles: lookup,
}),
).toMatchObject({ resolution_status: "not-found", resolved_path: null });
const restoredFiles = fileMap([
...files.values(),
file("app/relative/package.json", "root", '{"main":"public.js"}'),
file("app/relative/public.js", "root"),
]);
expect(
resolve({
declaredPath: "./relative",
sourcePath: "app/main.cjs",
context: "module-specifier",
moduleKind: "require",
files: restoredFiles,
unanalyzedFiles: lookup,
}),
).toMatchObject({
resolution_status: "resolved",
resolved_path: "app/relative/public.js",
});
});
it("keeps bare package exports unknown while its manifest is unavailable", () => {
const containerSha256 = file("app/main.mjs", "root").container_sha256;
const manifest = {
path: "app/node_modules/fixture/package.json",
container_sha256: containerSha256,
sha256: null,
bytes: 47,
inventory_artifact_id: null,
kind: "package-json" as const,
hash_status: "unavailable" as const,
limitations: ["unpacked exports manifest is missing"],
};
const files = fileMap([
file("app/main.cjs", "root"),
file("app/main.mjs", "root"),
file("app/node_modules/fixture/index.js", "root"),
file("app/node_modules/fixture/import.js", "root"),
file("app/node_modules/fixture/require.js", "root"),
]);
const lookup = {
get: (path: string) => (path === manifest.path ? manifest : undefined),
hasDirectory: () => false,
};
for (const [sourcePath, moduleKind] of [
["app/main.cjs", "require"],
["app/main.mjs", "import"],
] as const)
expect(
resolve({
declaredPath: "fixture",
sourcePath,
context: "module-specifier",
moduleKind,
files,
unanalyzedFiles: lookup,
}),
).toMatchObject({
resolution_status: "unavailable",
resolved_path: null,
limitations: ["unpacked exports manifest is missing"],
});
const restoredFiles = fileMap([
...files.values(),
file(
manifest.path,
"root",
'{"exports":{"import":"./import.js","require":"./require.js"}}',
),
]);
for (const [sourcePath, moduleKind, target] of [
["app/main.cjs", "require", "app/node_modules/fixture/require.js"],
["app/main.mjs", "import", "app/node_modules/fixture/import.js"],
] as const)
expect(
resolve({
declaredPath: "fixture",
sourcePath,
context: "module-specifier",
moduleKind,
files: restoredFiles,
unanalyzedFiles: lookup,
}),
).toMatchObject({
resolution_status: "resolved",
resolved_path: target,
});
});
});
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.each(
["[]", "[{}]", "123", '"root"', "null", "false"].flatMap((text) =>
(["import", "require", "compiler-dependent"] as const).map(
(moduleKind) => ({ text, moduleKind }),
),
),
)(
"blocks index fallback for non-object package root $text in $moduleKind mode",
({ text, moduleKind }) => {
expect(
resolve({
declaredPath: "fixture",
sourcePath: "app/entry.js",
context: "module-specifier",
moduleKind,
files: fileMap([
file("app/entry.js", "root"),
file("app/node_modules/fixture/package.json", "root", text),
file("app/node_modules/fixture/index.js", "root"),
]),
}),
).toMatchObject({
resolution_status: "unavailable",
resolved_path: null,
limitations: expect.arrayContaining([
expect.stringContaining("not valid package JSON"),
]),
});
},
);
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("keeps absolute file URL modules unavailable without a host mapping", () => {
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: "unavailable",
resolved_path: null,
});
}
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: "unavailable", 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("scoped package directory and specifier resolution", () => {
it("resolves CommonJS bare scoped package directory to index or package main", () => {
const files = fileMap([
file("app/src/consumer.js", "root"),
file("app/node_modules/@scope/index.js", "root"),
file(
"app/node_modules/@scope-main/package.json",
"root",
JSON.stringify({ main: "entry.js" }),
),
file("app/node_modules/@scope-main/entry.js", "root"),
]);
expect(
resolve({
declaredPath: "@scope",
sourcePath: "app/src/consumer.js",
context: "module-specifier",
moduleKind: "require",
files,
}),
).toMatchObject({
resolution_status: "resolved",
resolved_path: "app/node_modules/@scope/index.js",
});
expect(
resolve({
declaredPath: "@scope/",
sourcePath: "app/src/consumer.js",
context: "module-specifier",
moduleKind: "require",
files,
}),
).toMatchObject({
resolution_status: "resolved",
resolved_path: "app/node_modules/@scope/index.js",
});
expect(
resolve({
declaredPath: "@scope-main",
sourcePath: "app/src/consumer.js",
context: "module-specifier",
moduleKind: "require",
files,
}),
).toMatchObject({
resolution_status: "resolved",
resolved_path: "app/node_modules/@scope-main/entry.js",
});
expect(
resolve({
declaredPath: "@scope-main/",
sourcePath: "app/src/consumer.js",
context: "module-specifier",
moduleKind: "require",
files,
}),
).toMatchObject({
resolution_status: "resolved",
resolved_path: "app/node_modules/@scope-main/entry.js",
});
});
it("distinguishes CommonJS scoped exports from ESM loader-owned export and specifier errors", () => {
const files = fileMap([
file("app/src/consumer.js", "root"),
file(
"app/node_modules/@scope/package.json",
"root",
JSON.stringify({
exports: {
".": "./selected.js",
},
}),
),
file("app/node_modules/@scope/selected.js", "root"),
file("app/node_modules/@scope/index.js", "root"),
]);
// CommonJS require("@scope") resolves root exports
expect(
resolve({
declaredPath: "@scope",
sourcePath: "app/src/consumer.js",
context: "module-specifier",
moduleKind: "require",
files,
}),
).toMatchObject({
resolution_status: "resolved",
resolved_path: "app/node_modules/@scope/selected.js",
});
// CommonJS require("@scope/") does not match "." subpath exports
expect(
resolve({
declaredPath: "@scope/",
sourcePath: "app/src/consumer.js",
context: "module-specifier",
moduleKind: "require",
files,
}),
).toMatchObject({
resolution_status: "external",
resolved_path: null,
});
// ESM import "@scope" without trailing slash is an invalid module specifier
expect(
resolve({
declaredPath: "@scope",
sourcePath: "app/src/consumer.js",
context: "module-specifier",
moduleKind: "import",
files,
}),
).toMatchObject({
resolution_status: "external",
resolved_path: null,
});
// ESM import "@scope/" with trailing slash resolves root exports
expect(
resolve({
declaredPath: "@scope/",
sourcePath: "app/src/consumer.js",
context: "module-specifier",
moduleKind: "import",
files,
}),
).toMatchObject({
resolution_status: "resolved",
resolved_path: "app/node_modules/@scope/selected.js",
});
// Truly invalid scoped specifiers stay external
expect(
resolve({
declaredPath: "@",
sourcePath: "app/src/consumer.js",
context: "module-specifier",
moduleKind: "require",
files,
}),
).toMatchObject({
resolution_status: "external",
resolved_path: null,
});
expect(
resolve({
declaredPath: "@/",
sourcePath: "app/src/consumer.js",
context: "module-specifier",
moduleKind: "require",
files,
}),
).toMatchObject({
resolution_status: "external",
resolved_path: null,
});
});
});
const packageExportPatternCases = [
{
name: "matching",
exports: { "./*": "./*.cjs" },
request: "fixture/window",
status: "unavailable",
},
{
name: "nonmatching",
exports: { "./other/*": "./*.cjs" },
request: "fixture/window",
status: "external",
},
{
name: "suffix mismatch",
exports: { "./*.js": "./*.cjs" },
request: "fixture/window.cjs",
status: "external",
},
{
name: "empty match",
exports: { "./*end": "./*.cjs" },
request: "fixture/end",
status: "external",
},
{
name: "multiple stars",
exports: { "./*/*": "./*.cjs" },
request: "fixture/deep/window",
status: "external",
},
{
name: "exact before pattern",
exports: { "./*": "./*.cjs", "./window": "./window.cjs" },
request: "fixture/window",
status: "resolved",
},
{
name: "exact null before pattern",
exports: { "./*": "./*.cjs", "./window": null },
request: "fixture/window",
status: "external",
},
{
name: "matching null",
exports: { "./*": null },
request: "fixture/window",
status: "external",
},
{
name: "overlapping null prefix",
exports: { "./*": "./*.cjs", "./private/*": null },
request: "fixture/private/window",
status: "external",
},
{
name: "overlapping null suffix",
exports: { "./*": "./*.cjs", "./*.hidden": null },
request: "fixture/window.hidden",
status: "external",
},
{
name: "overlapping value prefix",
exports: { "./*": null, "./public/*": "./*.cjs" },
request: "fixture/public/window",
status: "unavailable",
},
{
name: "inactive pattern condition",
exports: { "./*": { browser: "./*.cjs" } },
request: "fixture/window",
status: "external",
},
{
name: "conditional null",
exports: { "./*": { node: null, default: "./*.cjs" } },
request: "fixture/window",
status: "external",
},
];
describe("package exports subpath encapsulation", () => {
it.each(packageExportPatternCases)(
"keeps $name exports patterns distinct from deterministic encapsulation",
({ exports, request, status }) => {
for (const moduleKind of ["import", "require"] as const) {
expect(
resolve({
declaredPath: request,
sourcePath: "app/main.cjs",
context: "module-specifier",
moduleKind,
files: fileMap([
file("app/main.cjs", "root"),
file(
"app/node_modules/fixture/package.json",
"root",
JSON.stringify({ exports }),
),
file("app/node_modules/fixture/window.cjs", "root"),
]),
}),
).toMatchObject({
resolution_status: status,
resolved_path:
status === "resolved"
? "app/node_modules/fixture/window.cjs"
: null,
});
}
},
);
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: "unavailable",
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: "unavailable",
resolved_path: null,
});
expect(recursive.limitations.join(" ")).toMatch(/recursive/i);
expect(external).toMatchObject({
resolution_status: "unavailable",
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: "unavailable",
resolved_path: null,
});
expect(outcome.limitations.join(" ")).toContain("container boundary");
});
});
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";
import path, { dirname } from "node:path";
import { fileURLToPath } from "node:url";
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", null],
["./nested//../worker.js", "dist/nested/worker.js"],
])(
"keeps empty URL path segments significant: %s",
(declaredPath, resolvedPath) => {
// A dot segment removes the preceding empty segment, never `nested`.
expect(new URL(declaredPath, "file:///root/dist/app.mjs").pathname).toBe(
resolvedPath === null
? "/root/dist/nested//worker.js"
: `/root/${resolvedPath}`,
);
for (const context of ["url-reference", "html-reference"] as const)
expect(
resolve({
declaredPath,
sourcePath: "dist/app.mjs",
context,
files: fileMap([
file("dist/worker.js", "root"),
file("dist/nested/worker.js", "root"),
]),
}),
context,
).toMatchObject({ resolved_path: resolvedPath });
expect(
resolve({
declaredPath,
sourcePath: "dist/app.mjs",
context: "module-specifier",
moduleKind: "import",
files: fileMap([
file("dist/worker.js", "root"),
file("dist/nested/worker.js", "root"),
]),
}),
).toMatchObject({ resolved_path: resolvedPath });
// CommonJS keeps filesystem path semantics.
expect(
resolve({
declaredPath,
sourcePath: "dist/app.mjs",
context: "module-specifier",
moduleKind: "require",
files: fileMap([
file("dist/worker.js", "root"),
file("dist/nested/worker.js", "root"),
]),
}),
).toMatchObject({
resolved_path:
declaredPath === "./nested//worker.js"
? "dist/nested/worker.js"
: "dist/worker.js",
});
},
);
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,
});
});
});
describe("module-backed package main host paths", () => {
it.each([
["sub\\entry.cjs", "unavailable", null],
["sub/entry.cjs", "resolved", "app/node_modules/fixture/sub/entry.cjs"],
] as const)(
"preserves dependency main host semantics for %s",
(main, status, expected) => {
expect(
resolve({
declaredPath: "fixture",
sourcePath: "app/main.cjs",
context: "module-specifier",
moduleKind: "require",
files: fileMap([
file("app/main.cjs", "root"),
file(
"app/node_modules/fixture/package.json",
"root",
JSON.stringify({ main }),
),
file("app/node_modules/fixture/sub/entry.cjs", "root"),
file("app/node_modules/fixture/index.js", "root"),
]),
}),
).toMatchObject({ resolution_status: status, resolved_path: expected });
},
);
it.each(
[
"/shared/window.cjs",
"C:/shared/window.cjs",
"\\\\host\\share\\window.cjs",
].flatMap((main) => [true, false].map((direct) => ({ main, direct }))),
)(
"retains host main $main before logical lookup (direct=$direct)",
({ main, direct }) => {
expect(
resolve({
declaredPath: direct ? main : "fixture",
sourcePath: direct
? "app/node_modules/fixture/package.json"
: "app/main.cjs",
context: direct ? "package-entrypoint" : "module-specifier",
moduleKind: "require",
files: fileMap([
file("app/main.cjs", "root"),
file(
"app/node_modules/fixture/package.json",
"root",
JSON.stringify({ main }),
),
file("shared/window.cjs", "root"),
file("app/node_modules/fixture/index.js", "root"),
]),
}),
).toMatchObject({
declared_path: direct ? main : "fixture",
resolution_status: "unavailable",
resolved_path: null,
});
},
);
it.each(["entry.cjs", "./entry.cjs"])(
"preserves relative package main lookup for %s",
(main) => {
expect(
resolve({
declaredPath: "fixture",
sourcePath: "app/main.cjs",
context: "module-specifier",
moduleKind: "require",
files: fileMap([
file("app/main.cjs", "root"),
file(
"app/node_modules/fixture/package.json",
"root",
JSON.stringify({ main }),
),
file("app/node_modules/fixture/entry.cjs", "root"),
file("app/node_modules/fixture/index.js", "root"),
]),
}),
).toMatchObject({
resolution_status: "resolved",
resolved_path: "app/node_modules/fixture/entry.cjs",
});
},
);
it.each([true, false])(
"keeps NUL package mains rejected (direct=%s)",
(direct) => {
const main = "/shared/\0window.cjs";
expect(
resolve({
declaredPath: direct ? main : "fixture",
sourcePath: direct ? "app/package.json" : "app/main.cjs",
context: direct ? "package-entrypoint" : "module-specifier",
moduleKind: "require",
files: fileMap([
file("app/main.cjs", "root"),
file(
"app/node_modules/fixture/package.json",
"root",
JSON.stringify({ main }),
),
file("app/node_modules/fixture/index.js", "root"),
]),
}),
).toMatchObject({ resolution_status: "rejected", 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<Record<string, string | null>>,
): ReturnType<typeof fileMap> =>
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)(
"retains unknown Windows trailing-backslash package main semantics 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: "unavailable", resolved_path: null });
},
);
describe("literal-percent runtime path resolution", () => {
it.each([
["exact-file", "filesystem-expression"],
["exact-file", "module-specifier"],
["node-entrypoint", "filesystem-expression"],
] as const)(
"preserves literal percent bytes for %s in %s",
(runtimePathKind, context) => {
const declaredPath = "./preload%2F%5C%2E.cjs";
expect(
resolve({
declaredPath,
sourcePath: "app/main.cjs",
context,
runtimePathKind,
files: fileMap([
file("app/main.cjs", "root"),
file("app/preload%2F%5C%2E.cjs", "root"),
file("app/preload/entry.cjs", "root"),
]),
}),
).toMatchObject({
declared_path: declaredPath,
resolution_context: context,
resolution_status: "resolved",
resolved_path: "app/preload%2F%5C%2E.cjs",
limitations: [],
});
},
);
it("keeps a file URL's decoded percent bytes literal at runtime lookup", () => {
const analysis = analyzeJavaScriptStaticSource(`
import { BrowserWindow } from "electron";
import { fileURLToPath } from "node:url";
new BrowserWindow({ webPreferences: {
preload: fileURLToPath(new URL("./preload%252Fname.cjs", import.meta.url))
}});
`);
const preload = analysis.role_paths.find(({ role }) => role === "preload");
if (preload === undefined)
throw new Error("Expected a static preload path");
expect(analysis.parse_status).toBe("complete");
expect(preload).toMatchObject({
path: "./preload%2Fname.cjs",
resolution_context: "filesystem-expression",
});
expect(
resolve({
declaredPath: preload.path,
sourcePath: "app/main.mjs",
context: preload.resolution_context,
runtimePathKind: "exact-file",
files: fileMap([
file("app/main.mjs", "root"),
file("app/preload%2Fname.cjs", "root"),
file("app/preload/name.cjs", "root"),
file("app/preload%252Fname.cjs", "root"),
]),
}),
).toMatchObject({
declared_path: "./preload%2Fname.cjs",
resolution_status: "resolved",
resolved_path: "app/preload%2Fname.cjs",
limitations: [],
});
});
it.each(["exact-file", "node-entrypoint"] as const)(
"confines literal-percent filesystem paths for %s",
(runtimePathKind) => {
expect(
resolve({
declaredPath: "../../outside%2Fname.cjs",
sourcePath: "app/main.cjs",
context: "filesystem-expression",
runtimePathKind,
files: fileMap([
file("app/main.cjs", "root"),
file("outside%2Fname.cjs", "root"),
]),
}),
).toMatchObject({
resolution_status: "rejected",
resolved_path: null,
limitations: [
expect.stringContaining("escapes the canonical artifact root"),
],
});
},
);
it.each(["%2F", "%5C"])(
"keeps %s rejected in a URL-owned runtime resource",
(separator) => {
expect(
resolve({
declaredPath: `file:///app/preload${separator}name.cjs`,
sourcePath: "app/main.cjs",
context: "module-specifier",
runtimePathKind: "url-resource",
files: fileMap([
file("app/main.cjs", "root"),
file(`app/preload${separator}name.cjs`, "root"),
file("app/preload/name.cjs", "root"),
]),
}),
).toMatchObject({
resolution_status: "rejected",
resolved_path: null,
});
},
);
});
describe("application-root Electron loadFile resolution", () => {
it.each([
"sub\\index.html",
".\\index.html",
"C:index.html",
"C:sub\\index.html",
])(
"retains unknown Windows loadFile host semantics for %s",
(declaredPath) => {
expect(
resolve({
declaredPath,
sourcePath: "app/main.cjs",
context: "filesystem-expression",
runtimePathKind: "application-file",
applicationRootPath: "app",
files: fileMap([
file("app/main.cjs", "root"),
file("app/sub/index.html", "root"),
file("app/index.html", "root"),
]),
}),
).toMatchObject({
declared_path: declaredPath,
resolution_status: "unavailable",
resolved_path: null,
});
},
);
it.each([
["sub/index.html", "resolved", "app/sub/index.html"],
["sub\\index\0.html", "rejected", null],
] as const)(
"keeps loadFile admission controls for %s",
(declaredPath, status, path) => {
expect(
resolve({
declaredPath,
sourcePath: "app/main.cjs",
context: "filesystem-expression",
runtimePathKind: "application-file",
applicationRootPath: "app",
files: fileMap([
file("app/main.cjs", "root"),
file("app/sub/index.html", "root"),
]),
}),
).toMatchObject({ resolution_status: status, resolved_path: path });
},
);
it("confines a sibling path after applying a nested application root", () => {
expect(
resolve({
declaredPath: "../shared/index.html",
sourcePath: "app/main.cjs",
context: "filesystem-expression",
runtimePathKind: "application-file",
applicationRootPath: "app",
files: fileMap([
file("app/main.cjs", "root"),
file("shared/index.html", "root"),
]),
}),
).toMatchObject({
resolution_status: "resolved",
resolved_path: "shared/index.html",
});
});
it.each(["", "resources/app.asar"])(
"resolves loadFile within application root %j instead of the calling script",
(applicationRootPath) => {
const prefix =
applicationRootPath === "" ? "" : `${applicationRootPath}/`;
const files = fileMap([
file(`${prefix}sub/main.cjs`, "app"),
file(`${prefix}dist%2Findex.html`, "app"),
file(`${prefix}sub/dist%2Findex.html`, "app"),
file(`${prefix}sub/absent.html`, "app"),
file(`${prefix}fallback/index.html`, "app"),
file(`${prefix}foreign.html`, "other-container"),
file("outside.html", "other-container"),
]);
const loadFile = (declaredPath: string) =>
resolve({
declaredPath,
sourcePath: `${prefix}sub/main.cjs`,
context: "filesystem-expression",
runtimePathKind: "application-file",
applicationRootPath,
files,
});
expect(loadFile("dist%2Findex.html")).toMatchObject({
runtime_path_base: "application-root",
resolved_path: `${prefix}dist%2Findex.html`,
resolution_status: "resolved",
});
expect(loadFile("/dist%2Findex.html")).toMatchObject({
resolved_path: null,
resolution_status: "unavailable",
});
for (const path of ["absent.html", "fallback", "foreign.html"])
expect(loadFile(path)).toMatchObject({
resolved_path: null,
resolution_status: "not-found",
});
expect(loadFile("../../../../outside.html")).toMatchObject({
resolved_path: null,
resolution_status: "rejected",
});
},
);
});
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", "unavailable", 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 }),
});
});
describe("Node launch package main ownership", () => {
it.each(["index.js", "index.json", "index.cjs"])(
"uses the same package index producer for a default launch with %s",
(fallback) => {
expect(
resolve({
declaredPath: "",
sourcePath: "app/package.json",
context: "package-entrypoint",
runtimePathKind: "node-entrypoint",
files: fileMap([
file("app/package.json", "root"),
file(`app/${fallback}`, "root"),
file("app.js", "root"),
]),
}),
).toMatchObject({
resolution_status: fallback === "index.cjs" ? "not-found" : "resolved",
resolved_path: fallback === "index.cjs" ? null : `app/${fallback}`,
});
},
);
it("keeps unavailable main bytes ahead of a present package index", () => {
const source = file("app/package.json", "root");
expect(
resolve({
declaredPath: "declared.cjs",
sourcePath: source.path,
context: "package-entrypoint",
runtimePathKind: "node-entrypoint",
files: fileMap([source, file("app/index.js", "root")]),
unanalyzedFiles: {
get: (path) =>
path === "app/declared.cjs"
? {
path,
container_sha256: source.container_sha256,
sha256: null,
bytes: null,
inventory_artifact_id: null,
kind: "javascript",
hash_status: "unavailable",
limitations: ["main readback unavailable"],
}
: undefined,
hasDirectory: () => false,
},
}),
).toMatchObject({
resolution_status: "unavailable",
resolved_path: null,
candidate_path: "app/declared.cjs",
});
});
it.each([
["missing.cjs", "index.js", "app/index.js"],
["sub/missing", "index.json", "app/index.json"],
["directory", "index.js", "app/index.js"],
["declared.cjs", "index.js", "app/declared.cjs"],
["missing.cjs", "index.cjs", null],
] as const)(
"uses Node package main lookup for %s with %s",
(declaredPath, fallback, expected) => {
expect(
resolve({
declaredPath,
sourcePath: "app/package.json",
context: "package-entrypoint",
runtimePathKind: "node-entrypoint",
files: fileMap([
file("app/package.json", "root"),
file(`app/${fallback}`, "root"),
file("app/declared.cjs", "root"),
file("app/directory/package.json", "root", '{"main":"nested.cjs"}'),
file("app/directory/nested.cjs", "root"),
]),
}),
).toMatchObject({
resolution_status: expected === null ? "not-found" : "resolved",
resolved_path: expected,
});
},
);
it.each([
[
"app/package.json",
"../resources/CODE.ASAR/window.cjs",
"resources/CODE.ASAR/window.cjs",
"package-entrypoint",
],
[
"resources/APP.ASAR/package.json",
"../window.cjs",
"resources/window.cjs",
"package-entrypoint",
],
[
"main.cjs",
"./resources/CODE.ASAR/window.cjs",
"resources/CODE.ASAR/window.cjs",
"filesystem-expression",
],
] as const)(
"retains archive launch lookup for %s loading %s",
(sourcePath, declaredPath, target, context) => {
expect(
resolve({
sourcePath,
declaredPath,
context,
runtimePathKind: "node-entrypoint",
files: fileMap([file(sourcePath, "source"), file(target, "target")]),
}),
).toMatchObject({ resolution_status: "resolved", resolved_path: target });
},
);
it("does not use package fallback for a utility entrypoint or an unproven main container", () => {
for (const [context, declaredPath, status] of [
["filesystem-expression", "./missing.cjs", "not-found"],
["package-entrypoint", "declared.cjs", "unavailable"],
["package-entrypoint", "../../escape.cjs", "rejected"],
] as const)
expect(
resolve({
declaredPath,
sourcePath: "app/package.json",
context,
runtimePathKind: "node-entrypoint",
files: fileMap([
file("app/package.json", "source"),
file("app/index.js", "source"),
file("app/declared.cjs", "foreign"),
]),
}),
).toMatchObject({ resolution_status: status, resolved_path: null });
});
});
it.each(["sub\\main.cjs", ".\\main.cjs", "C:main.cjs"])(
"retains unknown host semantics for the Windows-relative entrypoint %s",
(declaredPath) => {
expect(
resolve({
declaredPath,
sourcePath: "app/package.json",
context: "filesystem-expression",
runtimePathKind: "node-entrypoint",
files: fileMap([
file("app/package.json", "root"),
file("app/main.cjs", "root"),
file("app/sub/main.cjs", "root"),
]),
}),
).toMatchObject({
declared_path: declaredPath,
resolution_status: "unavailable",
resolved_path: null,
});
},
);
describe("package metadata at archive module boundaries", () => {
it.each(["APP.ASAR", "app.AsAr"])(
"preserves archive component bytes while admitting %s runtime crossings",
(archive) => {
const directory = `resources/${archive}`;
const files = fileMap([
file("main.cjs", "outer"),
file(`${directory}/main.cjs`, "archive"),
file(
`${directory}/pkg/package.json`,
"archive",
'{"main":"actual.cjs"}',
),
file(`${directory}/pkg/actual.cjs`, "archive"),
file(`${directory}/pkg/index.js`, "archive"),
file("resources/pkg/package.json", "outer", '{"main":"actual.cjs"}'),
file("resources/pkg/actual.cjs", "outer"),
file("resources/pkg/index.js", "outer"),
]);
for (const [sourcePath, declaredPath, target] of [
["main.cjs", `./${directory}/pkg`, `${directory}/pkg/actual.cjs`],
[`${directory}/main.cjs`, "../pkg", "resources/pkg/actual.cjs"],
] as const)
expect(
resolve({
sourcePath,
declaredPath,
context: "module-specifier",
moduleKind: "require",
files,
}),
).toMatchObject({
resolution_status: "resolved",
resolved_path: target,
});
},
);
it("does not admit same-archive or similarly named foreign containers", () => {
for (const directory of ["resources/APP.ASAR", "resources/APP.ASAR-extra"])
expect(
resolve({
sourcePath: `${directory}/main.cjs`,
declaredPath: "./window.cjs",
context: "module-specifier",
moduleKind: "require",
files: fileMap([
file(`${directory}/main.cjs`, "source"),
file(`${directory}/window.cjs`, "foreign"),
]),
}),
).toMatchObject({
resolution_status: "unavailable",
resolved_path: null,
});
});
it.each([
["resources/app.asar/main.cjs", "../pkg", "resources/pkg"],
["app/main.cjs", "../resources/code.asar/pkg", "resources/code.asar/pkg"],
[
"resources/app.asar/main.cjs",
"fixture",
"resources/node_modules/fixture",
],
])(
"uses the selected package main for %s loading %s",
(sourcePath, declaredPath, directory) => {
expect(
resolve({
sourcePath,
declaredPath,
context: "module-specifier",
moduleKind: "require",
files: fileMap([
file(sourcePath, "source"),
file(
`${directory}/package.json`,
"target",
'{"main":"actual.cjs"}',
),
file(`${directory}/actual.cjs`, "target"),
file(`${directory}/index.js`, "target"),
]),
}),
).toMatchObject({
resolution_status: "resolved",
resolved_path: `${directory}/actual.cjs`,
});
},
);
it("keeps metadata-less ancestor package directories after an archive escape", () => {
expect(
resolve({
sourcePath: "resources/app.asar/main.cjs",
declaredPath: "fixture/parser",
context: "module-specifier",
moduleKind: "require",
files: fileMap([
file("resources/app.asar/main.cjs", "source"),
file("resources/node_modules/fixture/parser.js", "target"),
]),
}),
).toMatchObject({
resolution_status: "resolved",
resolved_path: "resources/node_modules/fixture/parser.js",
});
});
it.each(["resources/app.asar/main.cjs", "resources/main.cjs"])(
"keeps unread metadata blocking a decoy index for %s",
(sourcePath) => {
const path = "resources/pkg/package.json";
const target = file(path, "target", null);
const files = fileMap([
file(sourcePath, "source"),
file("resources/pkg/index.js", "source"),
]);
for (const opaque of [false, true]) {
expect(
resolve({
sourcePath,
declaredPath: sourcePath.includes(".asar/") ? "../pkg" : "./pkg",
context: "module-specifier",
moduleKind: "require",
files: opaque ? files : fileMap([...files.values(), target]),
unanalyzedFiles: {
get: (requested) =>
opaque && requested === path ? target : undefined,
hasDirectory: () => false,
},
}),
).toMatchObject({
resolution_status: "unavailable",
resolved_path: null,
});
}
},
);
});