fix(reference): preserve source scope and loader authority

Share parser-owned package and runtime facts across dependency consumers.
Preserve uncertain loader requests and explicit wrapper bindings without
inventing unbound require authority in known modules. Cover selected source
grammar through the public MCP boundary and retain ambient/type dependencies.

Open each selected directory before loading its scoped policy, retaining
partial directory failures and cleanup ownership. Preserve explicit caller
negation precedence and source diagnostics across inventory projections.

Clarify how version comparison retains container provenance without claiming
semantic drift. Use independent unknown source inputs to keep candidate-limit
fixtures meaningful as conditional branch evaluation becomes more precise.

Fixes #6891
Fixes #6882
Fixes #6883
Fixes #6859
This commit is contained in:
morluto
2026-10-24 05:49:57 +08:00
parent 52aeeee764
commit d5df7fd944
24 changed files with 813 additions and 143 deletions
@@ -347,7 +347,7 @@ describe("JavaScript semantic analysis: dataflow 2", () => {
});
});
it("fails closed on assignment ambiguity and alias cycles", () => {
it("preserves initializer uncertainty, assignment ambiguity and alias cycles", () => {
const ambiguous = analyzeJavaScriptSemantics(`
let current = "first";
current = "second";
@@ -358,7 +358,8 @@ describe("JavaScript semantic analysis: dataflow 2", () => {
status: "ambiguous",
});
expect(topLevelBinding(ambiguous, "left").value).toMatchObject({
status: "cycle",
status: "unknown",
reason: "Binding right has no proven initializer at this read.",
});
expect(topLevelBinding(ambiguous, "right").provenance).toMatchObject({
status: "cycle",
@@ -10,6 +10,7 @@ import * as t from "@babel/types";
import { traverseJavaScriptAst } from "./javascriptSemanticTraversal.js";
import { BUILTIN_RESOURCE_METHODS } from "./javascriptBuiltinResourceMethods.js";
import { javaScriptRuntimeContext } from "./javascriptSourceParser.js";
import type { JavaScriptModuleOrigin } from "./javascriptSemanticIr.js";
import {
resolveSemanticBindingState,
@@ -163,7 +164,11 @@ const requireLoaderValueAt = (
return "create-require";
if (loader.name !== "require") return "local";
if (binding === undefined) {
if (semanticResolutionBlocked(state, loader, "require")) return "unknown";
if (
javaScriptRuntimeContext(state.program) === "module" ||
semanticResolutionBlocked(state, loader, "require")
)
return "unknown";
return (state.ambientBindingWrites.get("require") ?? []).some(
(write) => semanticEffectTiming(node, write, state) !== "after",
)
@@ -1525,7 +1530,8 @@ export const semanticRequireOrigin = (
!isUnmodifiedCommonJsWrapperBinding(current.callee, "require", state) &&
!isWrapperRequireInitializerCall(requireBinding, current, state)) ||
(requireBinding === undefined &&
semanticResolutionBlocked(state, current.callee, "require")) ||
(javaScriptRuntimeContext(state.program) === "module" ||
semanticResolutionBlocked(state, current.callee, "require"))) ||
(state.ambientBindingWrites.get("require") ?? []).some(
(write) =>
!semanticTopLevelEffectFollowsCapture(
@@ -602,16 +602,13 @@ export const semanticBindingHasPriorValueWrite = (
);
};
/** Program `var` redeclarations retain wrapper identity until a source write. */
/** Explicit wrapper facts and program `var` redeclarations retain their lexical identity. */
export const commonJsWrapperBindingDeclaration = (
node: t.Node,
name: string,
state: JavaScriptSemanticAnalysisState,
): JavaScriptSemanticBindingState | undefined => {
// Parser sourceType separates explicit modules from script/CommonJS source;
// specifier resolution mode does not establish that distinction.
if (
state.program.sourceType !== "script" ||
!["module", "exports", "require", "__dirname", "__filename"].includes(
name,
) ||
@@ -621,9 +618,17 @@ export const commonJsWrapperBindingDeclaration = (
const binding = resolveSemanticBindingState(state, node, name);
if (binding === undefined) return undefined;
const scope = state.scopesById.get(binding.scopeId);
return scope?.kind === "program" &&
binding.declarationKinds.size > 0 &&
[...binding.declarationKinds].every((kind) => kind === "var")
if (
scope?.kind !== "program" ||
![...binding.declarationKinds].every((kind) => kind === "var")
)
return undefined;
// The index owns explicit wrapper parameters, including ones with no source
// redeclaration. Babel's module classification does not invalidate that fact.
if (binding.hostOrigin === "commonjs-wrapper") return binding;
// Without an explicit host fact, preserve the legacy script-var inference.
return state.program.sourceType === "script" &&
binding.declarationKinds.size > 0
? binding
: undefined;
};
+75 -26
View File
@@ -15,6 +15,13 @@ export type ParsedJavaScriptSource = ReturnType<typeof parse>;
// Babel's module classification includes erased TypeScript syntax. Keep the
// runtime proof separate, including explicit filename mode, for every parser entry.
type JavaScriptRuntimeContext = "module" | "commonjs" | "unknown";
/** Package scope observed inside a source inventory; missing scope is unknown. */
export type JavaScriptPackageType =
| "module"
| "commonjs"
| "unspecified"
| "unknown";
const runtimeContextByProgram = new WeakMap<
t.Program,
JavaScriptRuntimeContext
@@ -53,6 +60,7 @@ const parseWithRuntimeContext = (
source: string,
sourcePath: string | undefined,
options: ParserOptions,
packageContext?: JavaScriptPackageType,
): ParsedJavaScriptSource => {
const file = parse(source, options);
runtimeContextByProgram.set(
@@ -63,13 +71,19 @@ const parseWithRuntimeContext = (
: "commonjs"
: isExplicitModuleSourcePath(sourcePath)
? "module"
: file.program.body.some((node) => t.isTSExportAssignment(node))
? // CommonJS isolation does not establish strict ESM semantics.
"commonjs"
: file.program.sourceType === "module" &&
hasRuntimeModuleDeclaration(file.program)
? "module"
: "unknown",
: packageContext === "module" || packageContext === "commonjs"
? packageContext
: packageContext === "unspecified" && /\.js$/iu.test(sourcePath ?? "")
? file.program.sourceType === "module"
? "module"
: "commonjs"
: file.program.body.some((node) => t.isTSExportAssignment(node))
? // CommonJS isolation does not establish strict ESM semantics.
"commonjs"
: file.program.sourceType === "module" &&
hasRuntimeModuleDeclaration(file.program)
? "module"
: "unknown",
);
return file;
};
@@ -141,8 +155,25 @@ export const parseRecoveredJavaScript = (
source: string,
sourcePath: string | undefined,
options: Omit<ParserOptions, "sourceType" | "errorRecovery">,
observedPackageType?: JavaScriptPackageType,
): RecoveredJavaScriptParse => {
const sourceType = runtimeSourceTypeForPath(sourcePath);
const filenameType = runtimeSourceTypeForPath(sourcePath);
// Node package facts apply to .js/.ts sources, not explicit suffixes,
// declaration wrappers, or an unknown JSX compilation pipeline.
const packageContext =
/\.(?:js|ts)$/iu.test(sourcePath ?? "") &&
!/\.d\.ts$/iu.test(sourcePath ?? "")
? observedPackageType
: undefined;
// Retain TypeScript import syntax for later CommonJS compilation.
const sourceType =
filenameType !== "unambiguous"
? filenameType
: packageContext === "module"
? "module"
: packageContext === "commonjs" && /\.js$/iu.test(sourcePath ?? "")
? "commonjs"
: "unambiguous";
if (sourceType !== "unambiguous") {
const normalizedOptions = { ...options };
if (sourceType === "commonjs") {
@@ -153,32 +184,50 @@ export const parseRecoveredJavaScript = (
delete normalizedOptions.allowNewTargetOutsideFunction;
}
return {
file: parseWithRuntimeContext(source, sourcePath, {
...normalizedOptions,
sourceType,
errorRecovery: true,
}),
file: parseWithRuntimeContext(
source,
sourcePath,
{
...normalizedOptions,
sourceType,
errorRecovery: true,
},
packageContext,
),
moduleOnlyErrors: [],
};
}
const file = parseWithRuntimeContext(source, sourcePath, {
...options,
sourceType: "unambiguous",
errorRecovery: true,
});
const file = parseWithRuntimeContext(
source,
sourcePath,
{
...options,
sourceType: "unambiguous",
errorRecovery: true,
},
packageContext,
);
if (file.program.sourceType !== "script" || file.errors.length === 0)
return { file, moduleOnlyErrors: [] };
const script = parseWithRuntimeContext(source, sourcePath, {
...options,
sourceType: "script",
errorRecovery: true,
});
const script = parseWithRuntimeContext(
source,
sourcePath,
{
...options,
sourceType: "script",
errorRecovery: true,
},
packageContext,
);
const scriptErrors = new Set(script.errors.map((error) => error.message));
return {
file: script,
moduleOnlyErrors: file.errors
.map((error) => error.message)
.filter((message) => !scriptErrors.has(message)),
moduleOnlyErrors:
javaScriptRuntimeContext(script.program) === "commonjs"
? []
: file.errors
.map((error) => error.message)
.filter((message) => !scriptErrors.has(message)),
};
};
@@ -0,0 +1,124 @@
import { expect, it } from "vitest";
import * as t from "@babel/types";
import {
analyzeParsedJavaScriptSemantics,
indexJavaScriptBindingsWithReceiversSteps,
} from "./javascriptSemanticAnalysis.js";
import {
semanticRequireLoaderAt,
semanticRequireOrigin,
} from "./javascriptSemanticRequireOrigin.js";
import {
completeSemanticSteps,
traverseJavaScriptAst,
} from "./javascriptSemanticTraversal.js";
import { referenceSourceRequireCalls } from "../referenceSourceRequireBindings.js";
import {
javaScriptRuntimeContext,
parseRecoveredJavaScript,
parserPluginsForPath,
} from "./javascriptSourceParser.js";
it.each([
["entry.cjs", "module", "commonjs"],
["entry.cts", "module", "commonjs"],
["entry.mjs", "commonjs", "module"],
["entry.mts", "commonjs", "module"],
["entry.d.cts", "module", "unknown"],
["entry.d.ts", "commonjs", "unknown"],
["entry.d.mts", "commonjs", "module"],
["entry.jsx", "commonjs", "unknown"],
["entry.tsx", "commonjs", "unknown"],
["entry.js", "module", "module"],
["entry.ts", "commonjs", "commonjs"],
["entry.js", "unspecified", "commonjs"],
["entry.ts", "unspecified", "unknown"],
["entry.js", "unknown", "unknown"],
] as const)(
"preserves parser-owned %s context over an observed %s package type",
(path, observed, expected) => {
const parsed = parseRecoveredJavaScript(
"",
path,
{
plugins: parserPluginsForPath(path),
},
observed,
);
expect(parsed.file.errors).toEqual([]);
expect(parsed.moduleOnlyErrors).toEqual([]);
expect(javaScriptRuntimeContext(parsed.file.program)).toBe(expected);
},
);
it("does not derive factory authority from an ambient require in a proven module", () => {
const source = [
'const { createRequire } = require("node:module");',
'const load = createRequire(import.meta.url); load("./dep.cjs");',
].join("\n");
const { file } = parseRecoveredJavaScript(source, "entry.js", {}, "module");
expect(file.errors).toEqual([]);
expect(analyzeParsedJavaScriptSemantics(file).moduleLinks).toEqual([]);
expect([...referenceSourceRequireCalls(file, "entry.js")]).toEqual([]);
});
it.each([
["without source redeclarations", "", "", true],
["with a var redeclaration", "var require;\n", "", true],
["after a prior write", "require = custom;\n", "", false],
["before a later write", "", "\nrequire = custom;", true],
["behind a lexical declaration", "const require = custom;\n", "", false],
["behind a nested parameter", "function shadow(require) {\n", "\n}", false],
] as const)(
"uses the seeded wrapper fact consistently %s",
(_name, prefix, suffix, expected) => {
const source =
prefix +
[
'const { createRequire } = require("node:module");',
'const load = createRequire(import.meta.url); load("./dep.cjs");',
].join("\n") +
suffix;
const { file } = parseRecoveredJavaScript(source, "entry.js", {});
expect(file.errors).toEqual([]);
expect(file.program.sourceType).toBe("module");
expect(javaScriptRuntimeContext(file.program)).toBe("unknown");
const index = completeSemanticSteps(
indexJavaScriptBindingsWithReceiversSteps(
file.program,
"commonjs-wrapper",
),
);
completeSemanticSteps(index.indexMemberMutationFactsSteps());
let required: t.CallExpression | undefined;
let loaded: t.CallExpression | undefined;
traverseJavaScriptAst(file.program, {
enter: (node) => {
if (!t.isCallExpression(node)) return;
if (t.isIdentifier(node.callee, { name: "require" })) required = node;
if (t.isIdentifier(node.callee, { name: "load" })) loaded = node;
},
});
if (required === undefined || loaded === undefined)
throw new Error("Expected loader fixture calls");
expect(
semanticRequireOrigin(required, index.bindings)?.origin.specifier,
).toBe(expected ? "node:module" : undefined);
expect(semanticRequireLoaderAt(loaded, index.bindings, new Set())).toBe(
expected ? "create-require" : "local",
);
},
);
it("detects JavaScript module syntax within an observed unspecified package", () => {
const { file } = parseRecoveredJavaScript(
"void import.meta.url;",
"entry.js",
{},
"unspecified",
);
expect(file.errors).toEqual([]);
expect(javaScriptRuntimeContext(file.program)).toBe("module");
});