Files
rea/src/domain/javascript/javascriptSemanticAnalysis.replaced_globals.test.ts
T
Kaoru0822andClaude Opus 5.5 3be45116ab fix(javascript): stop classifying replaced globals as built-in effects
Timer, request, coercion and JSON.parse effects recognized unbound globals
without consulting visible source-local writes, so `setTimeout = f` or
`self.fetch = f` still produced Node timer and fetch operations.

The ambient write owner now classifies a global reference as unmodified,
possibly replaced (a write under an unknown key, such as
`globalThis[k] = v`), or replaced (an exact visible write). Replaced globals
no longer produce built-in effects; possibly replaced ones keep the effect
with partial resolution instead of dropping it. The member-specific
`isUnmodifiedGlobalMember` helper is superseded and removed.

Fixes #3367

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 04:51:27 +00:00

58 lines
1.5 KiB
TypeScript

import { expect, it } from "vitest";
import { analyzeJavaScriptSemantics } from "./javascriptSemanticAnalysis.js";
const effects = (source: string) => {
const ir = analyzeJavaScriptSemantics(source);
return {
timers: ir.timerOperations.map(
({ method, resolution }) => `${method}:${resolution}`,
),
requests: ir.requestOperations
.filter(({ kind }) => kind === "request")
.map(({ method, resolution }) => `${method}:${resolution}`),
parses: ir.boundaryOperations
.filter(({ kind }) => kind === "parse")
.map(({ method, resolution }) => `${method}:${resolution}`),
};
};
const calls = `
function work() {}
setTimeout(work, 100);
fetch("https://example.invalid");
JSON.parse("null");
`;
it("does not classify calls to replaced globals as built-in effects", () => {
expect(
effects(`
setTimeout = () => null;
fetch = () => null;
JSON.parse = () => null;
${calls}
`),
).toEqual({ timers: [], requests: [], parses: ["parse:partial"] });
});
it("keeps built-in effects partial after a write under an unknown key", () => {
expect(
effects(`
globalThis[Symbol.for("registry")] = new Map();
${calls}
`),
).toEqual({
timers: ["setTimeout:partial"],
requests: ["fetch:partial"],
parses: ["JSON.parse:partial"],
});
});
it("keeps built-in effects for unmodified globals", () => {
expect(effects(calls)).toEqual({
timers: ["setTimeout:complete"],
requests: ["fetch:complete"],
parses: ["JSON.parse:complete"],
});
});