import { expect, test } from "bun:test"; import { parse } from "@wrnexus/syntax"; import { generateTargets } from "../src/targets.ts"; const withCalls = (calls: string) => `page Probe { apis { used POST /api/used { request { body { name?: string } } response { return data.users } } unused GET /api/unused { response { return data.secretShape } } } functions { client async function go(): Promise { ${calls} } } view {
} } `; test("a block the client calls is emitted into the browser module", () => { const browser = generateTargets(parse(withCalls(` await api.used({ name: "a" })`))).browser; expect(browser).toContain("used"); expect(browser).toContain('"/api/used"'); }); test("a block the client never calls is NOT emitted into the browser module", () => { // Server-only transforms must not ship. This is the point of usage-driven emission. const browser = generateTargets(parse(withCalls(` await api.used({ name: "a" })`))).browser; expect(browser).not.toContain("secretShape"); expect(browser).not.toContain('"/api/unused"'); }); test("no api object at all when the client calls none", () => { const browser = generateTargets(parse(withCalls(` console.log("nothing")`))).browser; expect(browser).not.toContain("const api ="); }); test("the emitted browser module is valid JavaScript", () => { const browser = generateTargets(parse(withCalls(` await api.used({ name: "a" })`))).browser; expect(() => { new Function(browser.replace(/^\s*import[^\n]*$/gm, "").replace(/\bexport\s+/g, "")); }).not.toThrow(); }); test("declared field types never reach the browser module", () => { const browser = generateTargets(parse(withCalls(` await api.used({ name: "a" })`))).browser; expect(browser).not.toContain("name?: string"); }); test("dynamic bracket access on api is a compile error naming the construct", () => { expect(() => generateTargets(parse(withCalls(` await api["used"]({ name: "a" })`)))).toThrow( /api/, ); }); test("passing api to a helper is a compile error", () => { expect(() => generateTargets(parse(withCalls(` callHelper(api)`)))).toThrow(/api/); }); test("a plain api.name(...) call still compiles", () => { expect(() => generateTargets(parse(withCalls(` await api.used({ name: "a" })`))), ).not.toThrow(); }); test("an identifier that merely contains 'api' does not trigger the dynamic-access error", () => { expect(() => generateTargets( parse( withCalls( ` const rapidCheck = 1; this.apiary = rapidCheck; await api.used({ name: "a" })`, ), ), ), ).not.toThrow(); }); test("the word 'api' inside a comment or string literal does not trigger the dynamic-access error", () => { expect(() => generateTargets( parse( withCalls( ` // this mentions api in a comment\n const note = "the api is great";\n await api.used({ name: "a" })`, ), ), ), ).not.toThrow(); });