feat(cli): migrate api entries into the apis block
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import { migrateApisBlock } from "../src/migrations/apis-block.ts";
|
||||
|
||||
const SOURCE = `page Search {
|
||||
client {
|
||||
api searchUsers POST /api/users {
|
||||
request { body { name?: string } }
|
||||
response { return data.users }
|
||||
error { return [] }
|
||||
}
|
||||
}
|
||||
|
||||
view { <main>x</main> }
|
||||
}
|
||||
`;
|
||||
|
||||
test("a client api entry moves into an apis block", () => {
|
||||
const result = migrateApisBlock(SOURCE) as { source: string; changed: boolean };
|
||||
|
||||
expect(result.changed).toBe(true);
|
||||
expect(result.source).toContain("apis {");
|
||||
expect(result.source).toContain("searchUsers POST /api/users");
|
||||
expect(result.source).not.toContain("client {\n api");
|
||||
});
|
||||
|
||||
test("the sections survive unchanged", () => {
|
||||
const result = migrateApisBlock(SOURCE) as { source: string };
|
||||
|
||||
expect(result.source).toContain("return data.users");
|
||||
expect(result.source).toContain("return []");
|
||||
});
|
||||
|
||||
test("running it on migrated source changes nothing", () => {
|
||||
const once = (migrateApisBlock(SOURCE) as { source: string }).source;
|
||||
const twice = migrateApisBlock(once) as { source: string; changed: boolean };
|
||||
|
||||
expect(twice.changed).toBe(false);
|
||||
expect(twice.source).toBe(once);
|
||||
});
|
||||
|
||||
test("a name declared in both modes is skipped with a reason", () => {
|
||||
const clash = `page P {
|
||||
ssr { api dup GET /api/a { response { return data } } }
|
||||
client { api dup GET /api/a { response { return data } } }
|
||||
view { <main>x</main> }
|
||||
}
|
||||
`;
|
||||
const result = migrateApisBlock(clash) as { skip: string };
|
||||
|
||||
expect(result.skip).toContain("dup");
|
||||
});
|
||||
|
||||
test("a page with an existing apis block merges legacy entries instead of producing two apis blocks", () => {
|
||||
const source = `page P {
|
||||
apis {
|
||||
existing GET /api/existing {
|
||||
response { return data }
|
||||
}
|
||||
}
|
||||
|
||||
client {
|
||||
api added POST /api/added {
|
||||
response { return data.value }
|
||||
}
|
||||
}
|
||||
|
||||
view { <main>x</main> }
|
||||
}
|
||||
`;
|
||||
const result = migrateApisBlock(source) as { source: string; changed: boolean };
|
||||
|
||||
expect(result.changed).toBe(true);
|
||||
const apisCount = (result.source.match(/\bapis\s*\{/g) ?? []).length;
|
||||
expect(apisCount).toBe(1);
|
||||
expect(result.source).toContain("existing GET /api/existing");
|
||||
expect(result.source).toContain("added POST /api/added");
|
||||
expect(result.source).not.toContain("client {");
|
||||
});
|
||||
|
||||
test("a mode block mixing api entries with other content is skipped, not partially rewritten", () => {
|
||||
// A bare `ssr { … }` block is invalid syntax once api entries are removed
|
||||
// (only `state` and hydrate forms survive) -- leftover content such as
|
||||
// `functions { }` belongs to the move-mode-functions migration, so this
|
||||
// file cannot be completed by this migration alone.
|
||||
const source = `page P {
|
||||
ssr {
|
||||
api foo GET /api/foo {
|
||||
response { return data }
|
||||
}
|
||||
|
||||
functions {
|
||||
function helper() { return 1 }
|
||||
}
|
||||
}
|
||||
|
||||
view { <main>x</main> }
|
||||
}
|
||||
`;
|
||||
const result = migrateApisBlock(source) as { skip: string };
|
||||
|
||||
expect(result.skip).toContain("ssr");
|
||||
expect(result.skip).toContain("functions");
|
||||
});
|
||||
|
||||
test("a brace inside a string literal in a section body does not truncate the entry", () => {
|
||||
const source = `page P {
|
||||
client {
|
||||
api foo GET /api/foo {
|
||||
response { return { text: "a } b" } }
|
||||
}
|
||||
}
|
||||
|
||||
view { <main>x</main> }
|
||||
}
|
||||
`;
|
||||
const result = migrateApisBlock(source) as { source: string; changed: boolean };
|
||||
|
||||
expect(result.changed).toBe(true);
|
||||
expect(result.source).toContain('text: "a } b"');
|
||||
expect(result.source).toContain("apis {");
|
||||
});
|
||||
Reference in New Issue
Block a user