mirror of
https://github.com/morluto/rea.git
synced 2026-10-29 02:45:58 +00:00
Reuse semantic module provenance for aliases and keep property path segments intact through Electron matching. Reject shadowed names and nested or dotted lookalikes. Reassigned and conditionally initialized module origins remain ambiguous, with their source origins retained. Add a compiled CLI/stdio MCP regression for windows, preloads, context bridges, IPC operations, pairing, and source ranges. Validate 771 JavaScript domain tests, seven composition tests, the public acceptance workflow, build, and check:fast. Fixes #1656
170 lines
6.2 KiB
TypeScript
170 lines
6.2 KiB
TypeScript
import { expect, it } from "vitest";
|
|
|
|
import {
|
|
analyzeParsedJavaScriptSemantics,
|
|
analyzeParsedJavaScriptSemanticsSteps,
|
|
classifyParsedJavaScriptElectronBindings,
|
|
classifyParsedJavaScriptElectronBindingsSteps,
|
|
classifyParsedJavaScriptOpenReceivers,
|
|
classifyParsedJavaScriptOpenReceiversSteps,
|
|
} from "./javascriptSemanticAnalysis.js";
|
|
import { parseJavaScriptSource } from "./javascriptSourceParser.js";
|
|
import {
|
|
traverseJavaScriptAst,
|
|
traverseJavaScriptAstSteps,
|
|
} from "./javascriptSemanticTraversal.js";
|
|
|
|
const source = `
|
|
import { readFile } from "node:fs";
|
|
const shared = { token: "TOKEN" };
|
|
export function load(path) {
|
|
return new Promise((resolve) => setTimeout(() => resolve(readFile(path)), 1));
|
|
}
|
|
export const box = { get() { return shared; } };
|
|
box.get().value = process.env.MODE ?? "default";
|
|
`;
|
|
|
|
it("yields between semantic phases and returns the synchronous result (#1462)", () => {
|
|
const parsed = parseJavaScriptSource(source, "main.js");
|
|
if (parsed === null) throw new Error("Expected parsed source");
|
|
const steps = analyzeParsedJavaScriptSemanticsSteps(parsed);
|
|
let yields = 0;
|
|
let step = steps.next();
|
|
while (step.done !== true) {
|
|
yields += 1;
|
|
step = steps.next();
|
|
}
|
|
expect(yields).toBeGreaterThan(0);
|
|
const reparsed = parseJavaScriptSource(source, "main.js");
|
|
if (reparsed === null) throw new Error("Expected parsed source");
|
|
expect(step.value).toEqual(analyzeParsedJavaScriptSemantics(reparsed));
|
|
});
|
|
|
|
it("traverses a large tree in steps with the synchronous visit order (#1462)", () => {
|
|
const parsed = parseJavaScriptSource(
|
|
Array.from(
|
|
{ length: 400 },
|
|
(_, index) => `const v${index} = [${index}];`,
|
|
).join("\n"),
|
|
"large.js",
|
|
);
|
|
if (parsed === null) throw new Error("Expected parsed source");
|
|
const visits = (record: string[]) => ({
|
|
enter: (node: { readonly type: string }) => record.push(`+${node.type}`),
|
|
exit: (node: { readonly type: string }) => record.push(`-${node.type}`),
|
|
});
|
|
const synchronous: string[] = [];
|
|
traverseJavaScriptAst(parsed.program, visits(synchronous));
|
|
const stepped: string[] = [];
|
|
const steps = traverseJavaScriptAstSteps(parsed.program, visits(stepped));
|
|
let yields = 0;
|
|
while (steps.next().done !== true) yields += 1;
|
|
expect(yields).toBeGreaterThan(0);
|
|
expect(stepped).toEqual(synchronous);
|
|
});
|
|
|
|
it("preserves receiver and Electron alias scope across traversal pauses (#1462)", () => {
|
|
const padding = Array.from(
|
|
{ length: 400 },
|
|
(_, index) => `const v${index} = [${index}];`,
|
|
).join("\n");
|
|
const text = `
|
|
import { BrowserWindow as NativeWindow } from "electron";
|
|
const ambient = window;
|
|
export function local(ambient, NativeWindow) {
|
|
${padding}
|
|
ambient.open("/local");
|
|
new NativeWindow();
|
|
}
|
|
ambient.open("/global");
|
|
new NativeWindow();
|
|
`;
|
|
const parsed = parseJavaScriptSource(text, "receivers.js");
|
|
if (parsed === null) throw new Error("Expected parsed source");
|
|
const openSteps = classifyParsedJavaScriptOpenReceiversSteps(parsed);
|
|
let openStep = openSteps.next();
|
|
expect(openStep.done).toBe(false);
|
|
while (openStep.done !== true) openStep = openSteps.next();
|
|
expect([...openStep.value]).toEqual([
|
|
[text.indexOf('ambient.open("/local")'), "local"],
|
|
[text.indexOf('ambient.open("/global")'), "window"],
|
|
]);
|
|
expect(openStep.value).toEqual(classifyParsedJavaScriptOpenReceivers(parsed));
|
|
|
|
const electronSteps = classifyParsedJavaScriptElectronBindingsSteps(parsed);
|
|
let electronStep = electronSteps.next();
|
|
expect(electronStep.done).toBe(false);
|
|
while (electronStep.done !== true) electronStep = electronSteps.next();
|
|
expect([...electronStep.value]).toEqual([
|
|
[text.lastIndexOf("NativeWindow()"), ["BrowserWindow"]],
|
|
]);
|
|
expect(electronStep.value).toEqual(
|
|
classifyParsedJavaScriptElectronBindings(parsed),
|
|
);
|
|
});
|
|
|
|
it("resolves Electron APIs through proven immutable aliases", () => {
|
|
const text = `
|
|
const {
|
|
BrowserWindow: ImportedWindow,
|
|
contextBridge: ImportedBridge,
|
|
ipcMain: ImportedMain,
|
|
ipcRenderer: ImportedRenderer,
|
|
} = require("electron");
|
|
const Win = ImportedWindow;
|
|
const bridge = ImportedBridge;
|
|
const ipc = ImportedMain;
|
|
const renderer = ImportedRenderer;
|
|
new Win({ webPreferences: { preload: "./preload.js" } });
|
|
bridge.exposeInMainWorld("api", {});
|
|
ipc.handle("main:ping", () => "pong");
|
|
renderer.invoke("main:ping");
|
|
|
|
const electron = require("electron");
|
|
const namespace = electron;
|
|
const directMember = electron.ipcMain;
|
|
directMember.handle("direct-namespace:ping", () => "pong");
|
|
const member = namespace.ipcMain;
|
|
member.handle("namespace:ping", () => "pong");
|
|
require("electron").ipcMain.handle("direct-require:ping", () => "pong");
|
|
require("electron").notAnApi.ipcMain.handle("nested-lookalike", () => "local");
|
|
require("electron")["ipcMain.handle"]("dotted-lookalike", () => "local");
|
|
|
|
function shadow(ipc) {
|
|
ipc.handle("shadowed:ping", () => "local");
|
|
}
|
|
const fakeElectron = require("./fake-electron");
|
|
const fakeIpc = fakeElectron.ipcMain;
|
|
fakeIpc.handle("lookalike:ping", () => "local");
|
|
let reassigned = ImportedMain;
|
|
reassigned = fakeIpc;
|
|
reassigned.handle("reassigned:ping", () => "local");
|
|
let { ipcMain: reassignedImport } = require("electron");
|
|
reassignedImport = fakeIpc;
|
|
reassignedImport.handle("reassigned-import:ping", () => "local");
|
|
let transitive = ImportedMain;
|
|
transitive = fakeIpc;
|
|
const reassignedAlias = transitive;
|
|
reassignedAlias.handle("transitive-reassigned:ping", () => "local");
|
|
if (globalThis.register) {
|
|
var conditional = require("electron").ipcMain;
|
|
}
|
|
const conditionalAlias = conditional;
|
|
conditionalAlias.handle("conditional-alias:ping", () => "local");
|
|
`;
|
|
const parsed = parseJavaScriptSource(text, "aliases.js");
|
|
if (parsed === null) throw new Error("Expected parsed source");
|
|
|
|
expect([...classifyParsedJavaScriptElectronBindings(parsed)]).toEqual([
|
|
[text.indexOf("Win({"), ["BrowserWindow"]],
|
|
[text.indexOf("bridge.exposeInMainWorld"), ["contextBridge"]],
|
|
[text.indexOf('ipc.handle("main:ping"'), ["ipcMain"]],
|
|
[text.indexOf("renderer.invoke"), ["ipcRenderer"]],
|
|
[text.indexOf("directMember.handle"), ["ipcMain"]],
|
|
[text.indexOf("member.handle"), ["ipcMain"]],
|
|
[text.indexOf('require("electron").ipcMain.handle'), []],
|
|
[text.indexOf('require("electron").notAnApi.ipcMain.handle'), []],
|
|
[text.indexOf('require("electron")["ipcMain.handle"]'), []],
|
|
]);
|
|
});
|