fix(javascript): preserve loader authority for exact suffixes (#9477)

* fix(javascript): require exact loader suffix case

* fix(javascript): share exact loader mode across import resolution

* test(process): align symlink fixture with filesystem checkpoints

* test(javascript): normalize the module resolution oracle path separators

* test(frida): assert the CLI spawn Evidence contract

* test(mcp): use an unsupported analysis-view parent

* test(browser): separate source-location line bounds from parity

* fix(javascript): preserve uncertain loader provenance

* test(javascript): cover uncertain require resolution

* fix(javascript): retain conditional Electron evidence

* fix(javascript): preserve timed semantic provenance

* fix(javascript): retain conditional builtin effects

* test(javascript): distinguish bundled host authority

* fix(javascript): preserve nested loader invocation identity

* test(javascript): qualify Electron fixture authority

* fix(javascript): preserve loader invocation authority

* fix(javascript): respect source order for resolver escapes

* fix(javascript): check nested loader callable mutations

* fix(javascript): retain conditional constructor requests

* fix(reference): retain constructor loader relationships

* fix(reference): follow nested loader callable paths

* refactor(javascript): share callable mutation interpretation

* fix(javascript): require exact package loader suffixes

* refactor(javascript): unify conditional relation evidence

* refactor(javascript): unify conditional node evidence

* fix(javascript): retain unknown authority for mixed case sources

* fix(javascript): preserve loader uncertainty for dotfiles

* fix(reference): classify javascript suffix dotfiles

* test(reference): cover suffix dotfiles through cli

* fix(javascript): retain equivalent conditional built-in origins

* fix(javascript): preserve wrapped resolver operation

* fix(javascript): retain nested conditional built-in receivers

* test(javascript): declare CommonJS in native addon fixtures

* fix(javascript): retain wrapped resolver candidates

* style: format merged native command schema

* fix(javascript): preserve uncertain loader authority

* test(javascript): require candidate preload evidence

* test(javascript): cover reference loader member writes

---------

Co-authored-by: ShuaixinHuang <1836656514@qq.com>
This commit is contained in:
morlutoandShuaixinHuang authored and GitHub committed 2026-11-09 13:21:24 +08:00
1 parent 78a84d75c0
commit b46f4fcebd
112 files changed
+5156 -797

No files matched your search

@@ -8,6 +8,7 @@ import {
} from "./javascriptAstValues.js";
import {
resolveSemanticBindingState,
semanticResolutionBlocked,
type JavaScriptSemanticAnalysisState,
} from "./javascriptSemanticState.js";
import { isUnmodifiedGlobalReference } from "./javascriptSemanticAmbientWrites.js";
@@ -19,8 +20,10 @@ import type { JavaScriptSemanticPropertyPath } from "./javascriptSemanticPropert
import { semanticProjectedSourcesAtRead } from "./javascriptSemanticProjectedSources.js";
import {
isUnshadowedGlobal,
semanticBindingHasPriorValueWrite,
semanticEffectTiming,
} from "./javascriptSemanticMutationInitializers.js";
import { javaScriptRuntimeContext } from "./javascriptSourceParser.js";
import { SEMANTIC_ALIAS_SELECTION_LIMIT } from "./javascriptSemanticResourceLimits.js";
const exportInvocations = new WeakMap<
@@ -176,12 +179,37 @@ const copiedOwnFields = (
return { definite: common ?? new Set(), complete };
};
/** A possible wrapper export remains a candidate when its host is unknown. */
const isCommonJsExportReference = (
node: t.Node,
state: JavaScriptSemanticAnalysisState,
name: string,
): boolean => {
const context = javaScriptRuntimeContext(state.program);
if (context === "module") return false;
if (isUnshadowedGlobal(node, state, name)) return true;
if (
context !== "unknown" ||
!t.isIdentifier(node, { name }) ||
semanticResolutionBlocked(state, node, name)
)
return false;
const binding = resolveSemanticBindingState(state, node, name);
return (
binding !== undefined &&
state.scopesById.get(binding.scopeId)?.kind === "program" &&
binding.declarationKinds.size === 1 &&
binding.declarationKinds.has("var") &&
!semanticBindingHasPriorValueWrite(node, binding, state)
);
};
const isCommonJsModuleExports = (
node: t.Node,
state: JavaScriptSemanticAnalysisState,
): boolean =>
(t.isMemberExpression(node) || t.isOptionalMemberExpression(node)) &&
isUnshadowedGlobal(node.object, state, "module") &&
isCommonJsExportReference(node.object, state, "module") &&
semanticStaticPropertyKey(node.property, node.computed) === "exports";
/** One syntax owner for CJS export names and their receiver identities. */
@@ -193,7 +221,7 @@ export const commonJsExportName = (
return undefined;
const key = semanticStaticPropertyKey(node.property, node.computed);
if (
isUnshadowedGlobal(node.object, state, "exports") ||
isCommonJsExportReference(node.object, state, "exports") ||
isCommonJsModuleExports(node.object, state)
)
return key === null ? "*" : key;
@@ -230,7 +258,7 @@ export const commonJsDefinedExport = (
return undefined;
const receiver = unwrapJavaScriptExpression(target).node;
if (
(!isUnshadowedGlobal(receiver, state, "exports") &&
(!isCommonJsExportReference(receiver, state, "exports") &&
!isCommonJsModuleExports(receiver, state)) ||
!isUnmodifiedGlobalReference(node.callee, state, [
"Object",
@@ -272,7 +300,7 @@ const commonJsAssignedExports = (
if (!t.isExpression(target)) return undefined;
const receiver = unwrapJavaScriptExpression(target).node;
if (
!isUnshadowedGlobal(receiver, state, "exports") &&
!isCommonJsExportReference(receiver, state, "exports") &&
!isCommonJsModuleExports(receiver, state)
)
return undefined;
@@ -289,11 +317,8 @@ const commonJsAssignedExports = (
};
};
/** Runtime values published by the CommonJS syntax owner, before receiver applicability. */
export const commonJsRuntimeExportValues = (
node: t.Node,
state: JavaScriptSemanticAnalysisState,
): readonly {
interface CommonJsRuntimeExportValue {
readonly loaderAuthority?: "candidate";
readonly exportedName: string;
readonly value: t.Node | null;
/** Retained input to unresolved iteration; never a selected yielded value. */
@@ -301,7 +326,13 @@ export const commonJsRuntimeExportValues = (
/** Own enumerable fields copied at this source, after later-source overwrites. */
readonly projection?: JavaScriptSemanticPropertyPath;
readonly ownEnumerable?: true;
}[] => {
}
/** Runtime values published by the CommonJS syntax owner, before receiver applicability. */
const commonJsExportValues = (
node: t.Node,
state: JavaScriptSemanticAnalysisState,
): readonly CommonJsRuntimeExportValue[] => {
if (t.isAssignmentExpression(node)) {
const exportedName = commonJsExportName(node.left, state);
return exportedName === undefined
@@ -310,8 +341,7 @@ export const commonJsRuntimeExportValues = (
}
const assigned = commonJsAssignedExports(node, state);
if (assigned !== undefined) {
const exported: ReturnType<typeof commonJsRuntimeExportValues>[number][] =
[];
const exported: CommonJsRuntimeExportValue[] = [];
const overwritten = new Set<string>();
for (let index = assigned.sources.length - 1; index >= 0; index--) {
const { value, iterationSource } = assigned.sources[index]!;
@@ -359,6 +389,20 @@ export const commonJsRuntimeExportValues = (
];
};
/** Preserve potential exports without asserting an unobserved CommonJS wrapper. */
export const commonJsRuntimeExportValues = (
node: t.Node,
state: JavaScriptSemanticAnalysisState,
): readonly CommonJsRuntimeExportValue[] => {
const values = commonJsExportValues(node, state);
return javaScriptRuntimeContext(state.program) === "unknown"
? values.map((value) => ({
...value,
loaderAuthority: "candidate" as const,
}))
: values;
};
type Identity = t.Node | null;
type Execution = "ordered" | "conditional" | "deferred";
@@ -423,12 +467,12 @@ export function* indexCommonJsExportReceiversSteps(
target = unwrapJavaScriptExpression(target).node;
const possiblePublicWrite =
(t.isMemberExpression(target) || t.isOptionalMemberExpression(target)) &&
isUnshadowedGlobal(target.object, state, "module") &&
isCommonJsExportReference(target.object, state, "module") &&
semanticStaticPropertyKey(target.property, target.computed) === null;
const publicWrite =
isCommonJsModuleExports(target, state) || possiblePublicWrite;
const exportsWrite = isUnshadowedGlobal(target, state, "exports");
const moduleWrite = isUnshadowedGlobal(target, state, "module");
const exportsWrite = isCommonJsExportReference(target, state, "exports");
const moduleWrite = isCommonJsExportReference(target, state, "module");
if (!publicWrite && !exportsWrite && !moduleWrite) return;
if (mode === "deferred") {
// A source offset cannot order an invocation against module completion.
@@ -489,14 +533,14 @@ export function* indexCommonJsExportReceiversSteps(
mode !== "ordered"
? null
: receiver !== null &&
isUnshadowedGlobal(receiver, state, "exports")
isCommonJsExportReference(receiver, state, "exports")
? exportsIdentity
: publicIdentity,
);
}
const descriptor = commonJsDefinedExport(node, state);
if (descriptor !== undefined) {
const receiver = isUnshadowedGlobal(
const receiver = isCommonJsExportReference(
descriptor.receiver,
state,
"exports",
@@ -513,7 +557,7 @@ export function* indexCommonJsExportReceiversSteps(
node,
mode !== "ordered"
? null
: isUnshadowedGlobal(defined.receiver, state, "exports")
: isCommonJsExportReference(defined.receiver, state, "exports")
? exportsIdentity
: publicIdentity,
);
@@ -559,7 +603,7 @@ export function* indexCommonJsExportReceiversSteps(
(t.isMemberExpression(node.argument) ||
t.isOptionalMemberExpression(node.argument))
) {
const receiver = isUnshadowedGlobal(
const receiver = isCommonJsExportReference(
node.argument.object,
state,
"exports",
@@ -575,7 +619,7 @@ export function* indexCommonJsExportReceiversSteps(
}
}
write(node.argument, null, mode);
} else if (isUnshadowedGlobal(node, state, "exports")) {
} else if (isCommonJsExportReference(node, state, "exports")) {
values.set(node, exportsIdentity);
} else if (isCommonJsModuleExports(node, state)) {
values.set(node, publicIdentity);