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

@@ -17,6 +17,7 @@ import {
semanticResolutionBlocked,
semanticStableInitializer,
type JavaScriptSemanticAnalysisState,
type JavaScriptBindingIndex,
} from "./javascriptSemanticState.js";
import {
commonJsWrapperBindingDeclaration,
@@ -173,7 +174,7 @@ const requireLoaderValueAt = (
if (loader.name !== "require") return "local";
if (binding === undefined) {
if (
javaScriptRuntimeContext(state.program) === "module" ||
javaScriptRuntimeContext(state.program) !== "commonjs" ||
semanticResolutionBlocked(state, loader, "require")
)
return "unknown";
@@ -199,7 +200,10 @@ const requireLoaderValueAt = (
t.isNewExpression(node)) &&
isWrapperRequireInitializerCall(binding, node, state)
)
return commonJsLoaderAt(node, state);
return binding.hostOrigin === "commonjs-wrapper" ||
javaScriptRuntimeContext(state.program) === "commonjs"
? commonJsLoaderAt(node, state)
: "unknown";
const wrapperBinding = commonJsWrapperBindingDeclaration(
loader,
"require",
@@ -376,13 +380,14 @@ const selectedRequireSourcesAt = (
):
| Pick<
JavaScriptRequireCallFact,
"loader" | "sourceRelative" | "sourceRelativePath"
"loader" | "sourceRelative" | "sourceRelativePath" | "loaderAuthority"
>
| undefined => {
const pending: ModuleObjectSource[] = [{ node: root, path: [] }];
const seen = new WeakMap<t.Node, Set<string>>();
let count = 0;
let found = false;
let candidate = false;
let loaderBinding = false;
let selectedLoader: JavaScriptRequireLoaderFact | undefined;
let unknown = false;
@@ -432,6 +437,10 @@ const selectedRequireSourcesAt = (
? commonJsLoaderAt(site, state)
: captured;
found = true;
candidate ||=
invoked === "unknown" &&
t.isIdentifier(node, { name: "require" }) &&
isConditionalRequireAt(node, node, state);
unknown ||=
invoked === "unknown" ||
(selectedLoader !== undefined && selectedLoader !== invoked);
@@ -655,6 +664,7 @@ const selectedRequireSourcesAt = (
? (selectedLoader ?? "unknown")
: "local",
sourceRelative: found && sourceRelative && !unknown,
...(candidate ? { loaderAuthority: "candidate" as const } : {}),
...(found &&
!unknown &&
sourceRelative &&
@@ -701,23 +711,41 @@ export interface JavaScriptRequireCallFact {
| readonly t.CallExpression["arguments"][number][]
| undefined;
readonly sourceRelative: boolean;
readonly loaderAuthority?: "candidate";
readonly memberUnproven?: true;
/** A createRequire filename relative to the current source directory, when proven. */
readonly sourceRelativePath?: string;
}
/** A child-property write does not replace the selected callable itself. */
export const semanticSelectedMemberMayHaveChanged = (
index: JavaScriptBindingIndex,
site: t.Node,
member: t.Node,
): boolean => {
const effects = index.effectsForReferenceAt(site, member);
const targetDepth = semanticMemberChain(member)?.members.length;
return (
!effects.memberEffectsIndexed ||
effects.effects.some(
({ kind, timing, path }) =>
timing !== "after" &&
(kind === "escape" ||
(kind === "member-write" &&
(targetDepth === undefined ||
path === undefined ||
path.length <= targetDepth))),
)
);
};
/** Classify the selected loader and normalize invocation arguments once. */
export const semanticRequireCallAt = (
node: t.CallExpression | t.OptionalCallExpression | t.NewExpression,
state: JavaScriptSemanticAnalysisState,
factoryBindingIds: ReadonlySet<string>,
index?: JavaScriptBindingIndex,
): JavaScriptRequireCallFact | undefined => {
if (semanticModuleRequireCallAt(node, state))
return {
operation: "load",
loader: "unknown",
arguments: undefined,
sourceRelative: false,
};
const callee = unwrapJavaScriptExpression(node.callee).node;
if (
(t.isMemberExpression(callee) || t.isOptionalMemberExpression(callee)) &&
@@ -733,6 +761,59 @@ export const semanticRequireCallAt = (
arguments: undefined,
sourceRelative: false,
};
if (index !== undefined) {
let member = callee;
while (
t.isMemberExpression(member) ||
t.isOptionalMemberExpression(member)
) {
const key = semanticStaticPropertyKey(member.property, member.computed);
if (key === "call" || key === "apply" || key === "resolve") {
const loader = requireLoaderValueAt(
member.object,
node,
state,
factoryBindingIds,
);
const selected =
loader === "local"
? selectedRequireSourcesAt(
member.object,
node,
state,
factoryBindingIds,
)
: undefined;
if (
loader === "local" &&
(selected === undefined || selected.loader === "local")
) {
member = unwrapJavaScriptExpression(member.object).node;
continue;
}
if (semanticSelectedMemberMayHaveChanged(index, node, member))
return {
operation: "load",
loader: "unknown",
// A changed call/apply member has no trustworthy argument mapping.
arguments:
member === callee && key === "resolve"
? node.arguments
: undefined,
sourceRelative: false,
memberUnproven: true,
};
}
member = unwrapJavaScriptExpression(member.object).node;
}
}
if (semanticModuleRequireCallAt(node, state))
return {
operation: "load",
loader: "unknown",
arguments: undefined,
sourceRelative: false,
};
if (
(t.isMemberExpression(callee) || t.isOptionalMemberExpression(callee)) &&
semanticStaticPropertyKey(callee.property, callee.computed) === "resolve"
@@ -743,13 +824,19 @@ export const semanticRequireCallAt = (
state,
factoryBindingIds,
);
if (loader === "unknown")
if (loader === "unknown") {
const receiver = unwrapJavaScriptExpression(callee.object).node;
const candidate =
t.isIdentifier(receiver, { name: "require" }) &&
isConditionalRequireAt(receiver, node, state);
return {
operation: "load",
operation: "resolve",
loader,
arguments: undefined,
arguments: candidate ? node.arguments : undefined,
sourceRelative: false,
...(candidate ? { loaderAuthority: "candidate" as const } : {}),
};
}
// Bundler factory loaders can share the `require` shape, but their
// `.resolve` member is not Node's module resolver.
if (loader === "commonjs-loader" || loader === "create-require") {
@@ -790,6 +877,9 @@ export const semanticRequireCallAt = (
loader: selected?.loader ?? loader,
arguments: node.arguments,
sourceRelative: selected?.sourceRelative ?? loader !== "create-require",
...(selected?.loaderAuthority === "candidate"
? { loaderAuthority: "candidate" as const }
: {}),
...(selected?.sourceRelativePath === undefined
? {}
: { sourceRelativePath: selected.sourceRelativePath }),
@@ -804,8 +894,19 @@ export const semanticRequireCallAt = (
state,
factoryBindingIds,
);
if (loader !== "local" && loader !== "create-require")
return ["require-loader", loader, "relative"];
if (loader !== "local" && loader !== "create-require") {
const root = unwrapJavaScriptExpression(callee).node;
const candidate =
loader === "unknown" &&
t.isIdentifier(root, { name: "require" }) &&
isConditionalRequireAt(root, node, state);
return [
"require-loader",
loader,
"relative",
...(candidate ? ["candidate"] : []),
];
}
const selected = selectedRequireSourcesAt(
callee,
node,
@@ -817,6 +918,7 @@ export const semanticRequireCallAt = (
"require-loader",
selected.loader,
selected.sourceRelative ? "relative" : "unknown",
...(selected.loaderAuthority === "candidate" ? ["candidate"] : []),
];
return interop.intrinsicPath(callee);
});
@@ -836,6 +938,9 @@ export const semanticRequireCallAt = (
? "unknown"
: (invocation.path[1] as JavaScriptRequireLoaderFact),
arguments: invocation.arguments,
...(invocation.kind === "known" && invocation.path[3] === "candidate"
? { loaderAuthority: "candidate" as const }
: {}),
sourceRelative:
invocation.kind === "known" && invocation.path[2] === "relative",
...(selected?.sourceRelativePath === undefined
@@ -1267,6 +1372,18 @@ const hasCommonJsModuleSource = (
commonJsWrapperBindingDeclaration(value, "require", state) !==
undefined &&
!read.hasDefiniteInitializer;
// A top-level `var require` may refer to a host wrapper on an unknown
// runtime. Preserve a possible member-loader call without resolving it.
if (
includeUnknown &&
mainModulePath &&
javaScriptRuntimeContext(state.program) === "unknown" &&
state.scopesById.get(binding.scopeId)?.kind === "program" &&
binding.declarationKinds.size === 1 &&
binding.declarationKinds.has("var") &&
!read.hasDefiniteInitializer
)
return true;
if (
value.name === "module" &&
copyAdmitsModuleDelegate &&
@@ -1549,40 +1666,89 @@ export const semanticGlobalProcessPathOrigin = (
};
};
/** Check one unknown-host wrapper candidate at its source-ordered read. */
const isConditionalRequireAt = (
root: t.Identifier,
node: t.Node,
state: JavaScriptSemanticAnalysisState,
allowAmbientModule = false,
): boolean => {
const runtime = javaScriptRuntimeContext(state.program);
if (
(runtime !== "unknown" && !(allowAmbientModule && runtime === "module")) ||
semanticResolutionBlocked(state, root, "require") ||
commonJsDelegateChangedAt(node, state)
)
return false;
const binding = resolveSemanticBindingState(state, root, "require");
if (
binding !== undefined &&
(binding.hostOrigin === "commonjs-wrapper" ||
state.scopesById.get(binding.scopeId)?.kind !== "program" ||
binding.declarationKinds.size !== 1 ||
!binding.declarationKinds.has("var") ||
(semanticBindingHasPriorValueWrite(node, binding, state) &&
!(
(t.isCallExpression(node) ||
t.isOptionalCallExpression(node) ||
t.isNewExpression(node)) &&
isWrapperRequireInitializerCall(binding, node, state)
)))
)
return false;
return !(state.ambientBindingWrites.get("require") ?? []).some(
(write) =>
!semanticTopLevelEffectFollowsCapture(node, write, state.parentsByNode),
);
};
/** Recover an unshadowed literal require origin and its exact member path. */
export const semanticRequireOrigin = (
export const semanticRequireOriginCandidate = (
node: t.Node | null | undefined,
state: JavaScriptSemanticAnalysisState,
allowAmbientModule = false,
): JavaScriptRequireOrigin | undefined => {
const chain = semanticMemberChain(node);
const current = chain?.root;
if (
chain === undefined ||
!t.isCallExpression(current) ||
(!t.isCallExpression(current) && !t.isOptionalCallExpression(current)) ||
!t.isIdentifier(current.callee, { name: "require" })
)
return undefined;
if (commonJsDelegateChangedAt(current, state)) return undefined;
const requireBinding = resolveSemanticBindingState(
state,
current.callee,
"require",
);
const binding = resolveSemanticBindingState(state, current.callee, "require");
const runtime = javaScriptRuntimeContext(state.program);
const candidate =
(runtime === "unknown" ||
(allowAmbientModule && runtime === "module" && binding === undefined)) &&
binding?.hostOrigin !== "commonjs-wrapper";
if (
(requireBinding !== undefined &&
!isUnmodifiedCommonJsWrapperBinding(current.callee, "require", state) &&
!isWrapperRequireInitializerCall(requireBinding, current, state)) ||
(requireBinding === undefined &&
(javaScriptRuntimeContext(state.program) === "module" ||
semanticResolutionBlocked(state, current.callee, "require"))) ||
(state.ambientBindingWrites.get("require") ?? []).some(
(write) =>
!semanticTopLevelEffectFollowsCapture(
candidate
? !isConditionalRequireAt(
current.callee,
current,
write,
state.parentsByNode,
),
)
state,
allowAmbientModule,
)
: commonJsDelegateChangedAt(current, state) ||
(binding !== undefined &&
!isUnmodifiedCommonJsWrapperBinding(
current.callee,
"require",
state,
) &&
!isWrapperRequireInitializerCall(binding, current, state)) ||
(binding === undefined &&
(javaScriptRuntimeContext(state.program) === "module" ||
semanticResolutionBlocked(state, current.callee, "require"))) ||
(state.ambientBindingWrites.get("require") ?? []).some(
(write) =>
!semanticTopLevelEffectFollowsCapture(
current,
write,
state.parentsByNode,
),
)
)
return undefined;
const specifier = stringValue(current.arguments[0]);
@@ -1593,11 +1759,21 @@ export const semanticRequireOrigin = (
specifier,
importedPath: chain.members,
resolutionMode: "require",
...(candidate ? { loaderAuthority: "candidate" as const } : {}),
},
call: current,
};
};
/** Only a proven host loader may establish Node builtin identity. */
export const semanticRequireOrigin = (
node: t.Node | null | undefined,
state: JavaScriptSemanticAnalysisState,
): JavaScriptRequireOrigin | undefined => {
const result = semanticRequireOriginCandidate(node, state);
return result?.origin.loaderAuthority === "candidate" ? undefined : result;
};
/** Node's exported child objects retain their direct builtin-module identity. */
export const semanticRequireExportsIdentity = <Key>(
specifier: string,
@@ -1656,4 +1832,5 @@ export const semanticMutableBuiltinOrigin = <Key = never>(
};
semanticRequireOriginReaders.origin = semanticRequireOrigin;
semanticRequireOriginReaders.candidate = semanticRequireOriginCandidate;
semanticRequireOriginReaders.loader = semanticRequireLoaderAt;