feat: replace the ssr/client data blocks with apis blocks

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-20 07:59:37 +05:30
co-authored by Claude Opus 5
parent de99a2c2e0
commit 890d6106b3
14 changed files with 135 additions and 1421 deletions
+8 -53
View File
@@ -1,10 +1,5 @@
import { WRN_RUNTIME_TARGETS } from "./spec.ts";
import {
parseApiSections,
parseApiEntries,
hasRequestSection,
type ApiSections,
} from "./api-sections.ts";
import { parseApiEntries, type ApiSections } from "./api-sections.ts";
/**
* Recursive-descent parser for `.wrn`, producing a small AST.
@@ -147,7 +142,7 @@ export interface ApiBlock {
export type SeoBlock = Record<string, string>;
export type DataMode = "ssr" | "client" | "any";
export type DataMode = "any";
export interface DataApiBlock {
mode: DataMode;
@@ -669,7 +664,6 @@ export function parse(source: string): PageAst {
case "client":
case "server": {
const rawMode = kw.value;
const mode: DataMode = rawMode === "client" ? "client" : "ssr";
lx.next();
if (
(rawMode === "client" || rawMode === "server") &&
@@ -684,56 +678,17 @@ export function parse(source: string): PageAst {
);
break;
}
if (mode === "client" && lx.peek().type === "eq") {
if (rawMode === "client" && lx.peek().type === "eq") {
lx.next();
hydrate = expect("string").value;
break;
}
expect("lbrace");
while (lx.peek().type !== "rbrace") {
const member = lx.peek();
if (member.type === "eof") {
throw new ParseError(`Unexpected end of input inside ${mode} block`);
}
if (member.type !== "ident") {
throw new ParseError(`Expected a ${mode} member keyword at offset ${member.pos}`);
}
switch (member.value) {
case "api": {
lx.next();
const name = expect("ident").value;
const method = expect("ident").value.toUpperCase();
const path = lx.readPath();
const body = lx.readBalancedBraces();
const sections = parseApiSections(body);
if (sections && mode !== "client" && hasRequestSection(body)) {
throw new ParseError(
`An ssr api block cannot declare "request": there is no caller at render time to supply it. Use a client block, or a server function.`,
);
}
dataApis.push({
mode,
name,
method,
path,
body: sections ? "" : body,
...(sections ? { sections } : {}),
});
break;
}
case "functions": {
lx.next();
modeFunctions.push({ mode, body: lx.readBalancedBraces() });
break;
}
default:
throw new ParseError(
`Unknown ${mode} member '${member.value}' at offset ${member.pos}`,
);
}
if (lx.peek().type === "lbrace") {
throw new ParseError(
`"${rawMode} { … }" data blocks were removed. Declare API calls in a page-level "apis { }" block, and move mode-scoped helpers into "functions { shared function … }".`,
);
}
expect("rbrace");
break;
throw new ParseError(`Expected a ${rawMode} state block or hydrate assignment`);
}
case "shared": {
lx.next();