feat(javascript): resolve exact package import aliases (#1862)

* feat(javascript): resolve exact package import aliases

Resolve exact #alias specifiers against the importer's enclosing
package.json imports map using the shared condition, array, and null
target selection. Nested packages keep their own maps; missing keys,
explicit nulls, and out-of-scope aliases report a precise reason.
Wildcard, recursive, and external-package import targets remain
unresolved.

* fix(javascript): keep nested import aliases in CLI graphs

Bound nested #alias requires produce application-graph require edges
from the enclosing package. Node reports MODULE_NOT_FOUND when a nested
package.json has no imports field, without inheriting the ancestor map.

* fix(javascript): resolve literal package import keys before path admission

* fix(javascript): preserve import keys and invalid-target fallback

* fix(javascript): preserve unmatched package target arrays

* fix(javascript): retain package target refusal evidence

* test(browser): match real verifier startup budget

---------

Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
This commit is contained in:
Matt Van Hornandmorluto authored and GitHub committed 2026-10-12 01:17:58 +08:00
1 parent e8491e023a
commit d28b41ea4e
10 files changed
+1838 -83

No files matched your search

@@ -742,6 +742,30 @@ describe("nested and array package export targets", () => {
);
});
describe("unmatched package export conditions", () => {
it.each([
[[{ browser: "./default.cjs" }], "browser"],
[
[[{ browser: "./default.cjs" }, { "rea-inactive": "./node.cjs" }]],
"browser, rea-inactive",
],
[{ node: [{ browser: "./default.cjs" }] }, "node, browser"],
] as const)(
"preserves condition names in unmatched target %j",
async (target, declared) => {
for (const moduleKind of ["import", "require"] as const) {
const { node_error, outcome } = await compareWithNode(
target,
moduleKind,
);
expect(node_error).toBe("ERR_PACKAGE_PATH_NOT_EXPORTED");
expect(outcome).toMatchObject({
resolution_status: "external",
resolved_path: null,
});
expect(outcome.limitations[0]).toContain(`It declares ${declared}.`);
}
},
);
it.each(["import", "require"] as const)(
"names the declared conditions for %s",
async (moduleKind) => {
@@ -769,6 +793,31 @@ describe("unmatched package export conditions", () => {
});
});
describe("blocked package export provenance", () => {
it.each([
[[], "an empty exports target array"],
[{ node: [] }, "an empty exports target array"],
[[null, []], "an empty exports target array"],
[[[], null], "an explicit null exports target"],
] as const)(
"preserves the blocking source value in %j",
async (target, limitation) => {
for (const moduleKind of ["import", "require"] as const) {
const { node_error, outcome } = await compareWithNode(
target,
moduleKind,
);
expect(node_error).toBe("ERR_PACKAGE_PATH_NOT_EXPORTED");
expect(outcome).toMatchObject({
resolution_status: "external",
resolved_path: null,
});
expect(outcome.limitations[0]).toContain(limitation);
}
},
);
});
describe("package exports fallback refusal reasons", () => {
it.each([
[{ import: [42, 7] }, "ERR_INVALID_PACKAGE_TARGET", "rejected"],