import { expect, test } from "bun:test"; import { parse } from "../src/index.ts"; const page = (inner: string) => `page Repro { client { ${inner} } view {
x
} } `; test("parses a sectioned api block into request, response and error", () => { const ast = parse( page(` api searchUsers POST /api/users { request { body { name?: string age?: number } } response { return data.users } error { return [] } }`), ); const block = ast.dataApis[0]!; expect(block.name).toBe("searchUsers"); expect(block.method).toBe("POST"); expect(block.path).toBe("/api/users"); expect(block.sections?.body).toEqual([ { name: "name", optional: true, type: "string" }, { name: "age", optional: true, type: "number" }, ]); expect(block.sections?.response.trim()).toBe("return data.users"); expect(block.sections?.error.trim()).toBe("return []"); }); test("a bare body still parses as the legacy response body", () => { const ast = parse( page(` api legacyUsers GET /api/users { return users.length }`), ); const block = ast.dataApis[0]!; expect(block.sections).toBeUndefined(); expect(block.body.trim()).toBe("return users.length"); }); test("GET parameters are parsed as required when not marked optional", () => { const ast = parse( page(` api listUsers GET /api/users { request { parameters { team: string } } response { return data.users } }`), ); expect(ast.dataApis[0]!.sections?.parameters).toEqual([ { name: "team", optional: false, type: "string" }, ]); }); test("request inside an ssr block is rejected with a message naming the restriction", () => { const source = `page Repro { ssr { api ssrUsers GET /api/users { request { parameters { team: string } } response { return data.users } } } view {
x
} } `; expect(() => parse(source)).toThrow(/ssr[\s\S]*request/i); });