mirror of
https://github.com/morluto/rea.git
synced 2026-11-05 22:36:08 +00:00
* 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
142 lines
5.9 KiB
TypeScript
142 lines
5.9 KiB
TypeScript
import { expect, it } from "vitest";
|
|
import * as t from "@babel/types";
|
|
|
|
import {
|
|
parseJavaScriptSource,
|
|
parseRecoveredJavaScript,
|
|
parserPluginsForPath,
|
|
javaScriptRuntimeContext,
|
|
javaScriptProgramStrictness,
|
|
javaScriptTopLevelThisMayBeGlobal,
|
|
} from "./javascriptSourceParser.js";
|
|
import { traverseJavaScriptAst } from "./javascriptSemanticTraversal.js";
|
|
import { analyzeParsedJavaScriptStaticSource } from "./javascriptStaticAnalysis.js";
|
|
|
|
it.each([
|
|
["class C extends (this.marker, Object) {}", true],
|
|
["class C { [this.marker]() {} }", true],
|
|
["class C { [this.marker] = 1 }", true],
|
|
["({[this.marker]() {}})", true],
|
|
["class C { value = this.marker }", false],
|
|
["class C { static value = this.marker }", false],
|
|
["class C { static { this.marker } }", false],
|
|
["class C { method() { this.marker } }", false],
|
|
["function f() { return class C extends (this.marker, Object) {} }", false],
|
|
["class C { value = class D { [this.marker]() {} } }", false],
|
|
["(() => class C { [this.marker]() {} })()", true],
|
|
] as const)(
|
|
"owns definition-time this separately from class bodies: %s",
|
|
(source, expected) => {
|
|
const parsed = parseJavaScriptSource(source);
|
|
if (parsed === null) throw new Error("Expected parsed fixture");
|
|
const parents = new WeakMap<t.Node, t.Node>();
|
|
let selected: t.ThisExpression | undefined;
|
|
traverseJavaScriptAst(parsed.program, {
|
|
enter(node, parent) {
|
|
if (parent !== null) parents.set(node, parent);
|
|
if (t.isThisExpression(node)) selected = node;
|
|
},
|
|
});
|
|
if (selected === undefined) throw new Error("Missing this fixture");
|
|
expect(
|
|
javaScriptTopLevelThisMayBeGlobal(selected, parsed.program, parents),
|
|
).toBe(expected);
|
|
},
|
|
);
|
|
|
|
it.each([
|
|
['import type {T} from "example";', "fixture.cts", "commonjs"],
|
|
['import type {T} from "example";', "fixture.mts", "module"],
|
|
['import type {T} from "example";', "fixture.ts", "unknown"],
|
|
['import cp = require("node:child_process");', "fixture.ts", "module"],
|
|
['import type cp = require("node:child_process");', "fixture.ts", "unknown"],
|
|
["const value=[]; export = value;", "fixture.ts", "commonjs"],
|
|
['export type {T} from "example";', "fixture.ts", "unknown"],
|
|
['import {type T} from "example";', "fixture.ts", "unknown"],
|
|
['export {type T} from "example";', "fixture.ts", "unknown"],
|
|
["export declare const value: unknown;", "fixture.ts", "unknown"],
|
|
["export default function f(): void;", "fixture.ts", "unknown"],
|
|
["export default interface I {}", "fixture.ts", "unknown"],
|
|
["export default function f() {}", "fixture.ts", "module"],
|
|
["export default class C {}", "fixture.ts", "module"],
|
|
['import {} from "example";', "fixture.js", "module"],
|
|
['import {} from "example";', "fixture.cjs", "commonjs"],
|
|
["export {};", "fixture.ts", "module"],
|
|
["const value = 1;", "fixture.mjs", "module"],
|
|
["const value = 1;", "fixture.js", "unknown"],
|
|
["const value = 1;", "fixture.cjs", "commonjs"],
|
|
["const value = 1;", "fixture.cts", "commonjs"],
|
|
["declare const value: unknown;", "fixture.d.cts", "unknown"],
|
|
] as const)(
|
|
"keeps runtime context consistent across parser entries: %s (%s)",
|
|
(source, path, context) => {
|
|
const parsed = parseJavaScriptSource(source, path);
|
|
if (parsed === null) throw new Error("Expected parsed source");
|
|
const recovered = parseRecoveredJavaScript(source, path, {
|
|
plugins: parserPluginsForPath(path),
|
|
}).file;
|
|
expect(javaScriptRuntimeContext(parsed.program)).toBe(context);
|
|
expect(javaScriptRuntimeContext(recovered.program)).toBe(context);
|
|
expect(javaScriptRuntimeContext(t.cloneNode(parsed.program, true))).toBe(
|
|
"unknown",
|
|
);
|
|
},
|
|
);
|
|
|
|
it.each([
|
|
["const args=[]; export = args;", "fixture.ts", "sloppy"],
|
|
['"use strict"; const args=[]; export = args;', "fixture.ts", "strict"],
|
|
['import type {T} from "example";', "fixture.ts", "unknown"],
|
|
["const args=[];", "fixture.mjs", "strict"],
|
|
["const args=[];", "fixture.cjs", "sloppy"],
|
|
] as const)(
|
|
"owns program strictness independently of parser syntax: %s (%s)",
|
|
(source, path, strictness) => {
|
|
const parsed = parseJavaScriptSource(source, path);
|
|
if (parsed === null) throw new Error("Expected parsed source");
|
|
expect(javaScriptProgramStrictness(parsed.program)).toBe(strictness);
|
|
const recovered = parseRecoveredJavaScript(source, path, {
|
|
plugins: parserPluginsForPath(path),
|
|
}).file;
|
|
expect(javaScriptProgramStrictness(recovered.program)).toBe(strictness);
|
|
},
|
|
);
|
|
|
|
const analyze = (source: string, path: string) => {
|
|
const parsed = parseJavaScriptSource(source, path);
|
|
return parsed === null
|
|
? null
|
|
: {
|
|
errors: parsed.errors.length,
|
|
facts: analyzeParsedJavaScriptStaticSource(source, parsed),
|
|
};
|
|
};
|
|
|
|
it("parses conditional arrow bodies in JavaScript sources with JavaScript grammar", () => {
|
|
// Bundlers emit this shape; TypeScript reads `):H=>` as a return type.
|
|
const source = `const {ipcMain}=require("electron");
|
|
const pick=n===0?H=>({start:H.startY}):H=>({start:H.startX});
|
|
ipcMain.handle("layout:ready",()=>pick);`;
|
|
for (const path of ["main.js", "main.cjs", "main.mjs", "main.jsx"]) {
|
|
const result = analyze(source, path);
|
|
expect(result?.errors).toBe(0);
|
|
expect(result?.facts.electron.ipc).toContainEqual(
|
|
expect.objectContaining({ channel: "layout:ready", operation: "handle" }),
|
|
);
|
|
}
|
|
});
|
|
|
|
it("keeps JavaScript comparison meaning for angle brackets in JavaScript sources", () => {
|
|
const source = `const a=fetch<limit>("/api/compare");`;
|
|
expect(analyze(source, "main.js")?.facts.endpoints).toEqual([]);
|
|
expect(analyze(source, "main.ts")?.facts.endpoints).toContainEqual(
|
|
expect.objectContaining({ value: "/api/compare" }),
|
|
);
|
|
});
|
|
|
|
it("keeps TypeScript syntax available for TypeScript and unnamed sources", () => {
|
|
const source = "let count: number = 1; export type Id = string;";
|
|
expect(parseJavaScriptSource(source, "value.ts")?.errors).toEqual([]);
|
|
expect(parseJavaScriptSource(source)?.errors).toEqual([]);
|
|
});
|