fix(javascript): resolve module-level Electron options in functions (#8960)

* fix(javascript): resolve module-level Electron options in functions

* fix(javascript): limit module option ancestry walk

* fix(javascript): preserve uncertain captured argument ordering

* fix(javascript): retain hoisted activation uncertainty

* fix(javascript): retain function ownership through loops

* fix(javascript): account for classic global activations

* fix(javascript): bind first activations to lexical identities

* fix(javascript): retain uncertain global activation timing

* fix(javascript): isolate receiver facts and share computed reads

* fix(javascript): retain projected and opaque global activations

* fix(javascript): refresh activation bounds as opaque effects grow

* fix(ci): format website watch directories without changing configuration

* fix(javascript): share source reads across opaque-effect updates

* fix(javascript): retain constructed-code global activation bounds

* fix(javascript): share runtime activation and receiver facts

* fix(javascript): reuse pattern reads and function positions

* fix(javascript): isolate copied paths and preserve runtime reads

* style(javascript): format migrated reference imports

* fix(javascript): normalize constructor activation and receiver effects

* fix(javascript): retain aliased receiver timing and lexical global this

* fix(javascript): preserve effect-free receiver identity across activations

* fix(javascript): retain outer activation and prototype effects

* fix(javascript): index implicit reads without deep path rescans

* fix(javascript): retain aliased prototype and parameter read uncertainty

* fix(javascript): index reflected reads through intrinsic invocation facts

* fix(javascript): retain unresolved global activation reads

* chore: refresh PR branch after review fix publication

* fix(javascript): retain projected receiver reads and cache method facts

* fix(javascript): retain inherited and implicit activation reads

* fix(javascript): retain caller-owned this uncertainty

* fix(javascript): retain reflected reads with unresolved spread arguments

* fix(javascript): preserve enclosing activation for decorators

* fix(javascript): track intrinsic literal prototype effects

* fix(javascript): retain catch activation from implicit reads

* perf(javascript): reuse effective keys for projected reads

* fix(javascript): retain possible caller-owned ambient effects
This commit is contained in:
ShuaixinHuang authored and GitHub committed 2026-11-05 16:52:19 +08:00
1 parent ce07d358cd
commit a2134b3a74
40 files changed
+2585 -191

No files matched your search

@@ -53,44 +53,68 @@ export const createSemanticOpaqueGlobalObserver = (
) => (
node: t.Node,
site: t.Node | undefined,
) => { paths: readonly (readonly (string | null)[])[] };
) => {
paths: readonly (readonly (string | null)[])[];
callerPaths: readonly (readonly (string | null)[])[];
};
createSemanticModuleInterop: (
state: JavaScriptSemanticAnalysisState,
options?: {
intrinsicPath: (node: t.Node) => readonly string[] | undefined;
},
) => {
intrinsicPath: (node: t.Node) => readonly string[] | undefined;
intrinsicInvocation: (
node: t.CallExpression | t.OptionalCallExpression,
node:
| t.CallExpression
| t.OptionalCallExpression
| t.NewExpression
| t.TaggedTemplateExpression,
) => { readonly path: readonly string[] } | undefined;
};
},
): ((node: t.Node) => void) | undefined => {
if (!state.opaqueEffects.mayReferenceGlobalEval) return undefined;
if (!state.opaqueEffects.mayReferenceGlobalCode) return undefined;
const ambientPaths = dependencies.createAmbientPathResolver(state, true);
let invocationSite: t.Node | undefined;
const interop = dependencies.createSemanticModuleInterop(state, {
intrinsicPath: (node) => {
const paths = ambientPaths(node, invocationSite).paths;
const path = paths.find((path) => path[1] === "eval") ?? paths[0];
const { paths, callerPaths } = ambientPaths(node, invocationSite);
const path =
paths.find((path) => path[1] === "eval" || path[1] === "Function") ??
callerPaths.find(
(path) => path[1] === "eval" || path[1] === "Function",
) ??
paths[0];
if (path?.[0] !== "global" || path.some((key) => key === null))
return undefined;
// Keep the global callable owner for generic call/apply/bind resolution.
return path[1] === "eval"
return path[1] === "eval" || path[1] === "Function"
? ["intrinsic", ...(path as readonly string[])]
: ["intrinsic", ...(path.slice(1) as readonly string[])];
},
});
return (node) => {
if (!t.isCallExpression(node) && !t.isOptionalCallExpression(node)) return;
if (
!t.isCallExpression(node) &&
!t.isOptionalCallExpression(node) &&
!t.isNewExpression(node) &&
!t.isTaggedTemplateExpression(node)
)
return;
invocationSite = node;
const invocation = interop.intrinsicInvocation(node);
if (invocation?.path.join(".") === "intrinsic.global.eval")
const path = interop.intrinsicInvocation(node)?.path;
// Constructed code may escape and activate a classic-script global. Keep
// its creation as a conservative timing bound, not proof of execution.
if (
path?.join(".") === "intrinsic.global.eval" ||
path?.join(".") === "intrinsic.global.Function"
)
state.opaqueEffects.globalSites.push(node);
};
};
/** Indirect eval can change globals, but cannot rebind its caller's locals. */
/** Global code can affect globals, but cannot rebind its caller's locals. */
export const semanticOpaqueGlobalMayHaveChanged = (
read: t.Node,
state: JavaScriptSemanticAnalysisState,