mirror of
https://github.com/morluto/rea
synced 2026-10-27 14:42:18 -04:00
fix(javascript): drop built-in effects for visibly replaced globals (#4565)
The semantic collectors admitted Node timers, fetch, WebSocket, JSON.parse and global coercions from the identifier spelling alone, so a source that replaced those globals (`setTimeout = () => null`) still produced resolved built-in effects. Require the existing isUnmodifiedGlobalReference guard, which the static analyzer already uses for fetch and WebSocket, before admitting these effects. The guard treats any visible possible write as a replacement without evaluating order or reachability, so computed global writes and guarded polyfills also remove the resolved effect. The workflow docs now say so. Fixes #3367
This commit is contained in:
@@ -37,6 +37,7 @@ import {
|
||||
traverseDataEffects as traverseWithContext,
|
||||
type DataEffectTraversalContext as TraversalContext,
|
||||
} from "./javascriptSemanticDataEffectHelpers.js";
|
||||
import { isUnmodifiedGlobalReference } from "./javascriptSemanticAmbientWrites.js";
|
||||
import { range } from "./javascriptStaticAnalysisHelpers.js";
|
||||
import { semanticPrimitiveSet } from "./javascriptSemanticPrimitives.js";
|
||||
import type { JavaScriptSemanticValue } from "./javascriptSemanticValueTypes.js";
|
||||
@@ -404,7 +405,10 @@ const boundaryDetails = (
|
||||
!semanticResolutionBlocked(state, node.callee, name);
|
||||
if (
|
||||
unbound &&
|
||||
["String", "Number", "Boolean", "parseInt", "parseFloat"].includes(name)
|
||||
["String", "Number", "Boolean", "parseInt", "parseFloat"].includes(
|
||||
name,
|
||||
) &&
|
||||
isUnmodifiedGlobalReference(node.callee, state, name)
|
||||
)
|
||||
return { kind: "coerce", method: name, resolution: "complete" };
|
||||
}
|
||||
@@ -415,7 +419,8 @@ const boundaryDetails = (
|
||||
method === "parse" &&
|
||||
t.isIdentifier(member.object, { name: "JSON" }) &&
|
||||
resolveSemanticBindingState(state, member.object, "JSON") === undefined &&
|
||||
!semanticResolutionBlocked(state, member.object, "JSON")
|
||||
!semanticResolutionBlocked(state, member.object, "JSON") &&
|
||||
isUnmodifiedGlobalReference(node.callee, state, ["JSON", "parse"])
|
||||
)
|
||||
return { kind: "parse", method: "JSON.parse", resolution: "complete" };
|
||||
if (method === "parse" || method === "safeParse")
|
||||
@@ -434,9 +439,13 @@ const requestMethod = (
|
||||
const unbound =
|
||||
resolveSemanticBindingState(state, node.callee, name) === undefined &&
|
||||
!semanticResolutionBlocked(state, node.callee, name);
|
||||
if (!t.isNewExpression(node) && unbound && name === "fetch") return "fetch";
|
||||
if (t.isNewExpression(node) && unbound && name === "WebSocket")
|
||||
return "WebSocket";
|
||||
const global = t.isNewExpression(node) ? "WebSocket" : "fetch";
|
||||
if (
|
||||
unbound &&
|
||||
name === global &&
|
||||
isUnmodifiedGlobalReference(node.callee, state, name)
|
||||
)
|
||||
return global;
|
||||
}
|
||||
const method = builtinMethod(node.callee, state, [
|
||||
"http",
|
||||
|
||||
Reference in New Issue
Block a user