import { describe, expect, it } from "vitest"; import { analyzeJavaScriptSemantics } from "./javascriptSemanticAnalysis.js"; const observe = (source: string) => { const ir = analyzeJavaScriptSemantics(source); return { binding: ir.bindings.find((item) => item.name === "x")?.value, returned: ir.callables.find((item) => item.name === "read")?.returnSites[0] ?.value, }; }; describe("JavaScript semantic analysis: logical assignment", () => { it.each(["||=", "??=", "&&="])( "keeps a parameter uncertain after %s", (operator) => { const { binding, returned } = observe( `function read(x) { x ${operator} 2; return x; }`, ); expect(binding?.status).toBe("unknown"); expect(returned?.status).toBe("unknown"); }, ); it.each(["||=", "??=", "&&="])( "keeps a destructured parameter uncertain after %s", (operator) => { const { binding, returned } = observe( `function read({ x }) { x ${operator} 2; return x; }`, ); expect(binding?.status).toBe("unknown"); expect(returned?.status).toBe("unknown"); }, ); it.each(["||=", "??=", "&&="])( "keeps a catch binding uncertain after %s", (operator) => { const { binding, returned } = observe( `function read() { try { run(); } catch (x) { x ${operator} 2; return x; } }`, ); expect(binding?.status).toBe("unknown"); expect(returned?.status).toBe("unknown"); }, ); it.each([ ["let", "||="], ["let", "??="], ["var", "||="], ["var", "??="], ])( "keeps an uninitialized %s local exact after %s", (declaration, operator) => { const { binding, returned } = observe( `function read() { ${declaration} x; x ${operator} 2; return x; }`, ); expect(binding).toEqual({ status: "literal", value: 2 }); expect(returned).toEqual({ status: "literal", value: 2 }); }, ); it("keeps an unconditional parameter assignment exact", () => { const { binding, returned } = observe( "function read(x) { x = 2; return x; }", ); expect(binding).toEqual({ status: "literal", value: 2 }); expect(returned).toEqual({ status: "literal", value: 2 }); }); it("keeps an unchanged parameter unknown", () => { expect(observe("function read(x) { return x; }").returned?.status).toBe( "unknown", ); }); });