feat(wrn): support native structured prop expressions

This commit is contained in:
2026-07-29 16:46:18 +05:30
parent 6afe32f63f
commit 8fc6f15402
68 changed files with 210 additions and 118 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@wrnexus/syntax",
"version": "0.5.0",
"version": "0.5.1",
"type": "module",
"main": "src/index.ts",
"exports": {
+27 -4
View File
@@ -712,13 +712,30 @@ export function parseHtmlView(src: string, pos: number): { nodes: ViewNode[]; en
while (i < src.length && isWs(src[i]!)) i++;
};
/** Read a `{...}` interpolation (brace-balanced), braces included. */
/** Read a `{...}` interpolation (brace-balanced and quote-aware), braces included. */
const readInterpolation = (): string => {
const start = i;
let depth = 0;
let quote: string | null = null;
for (; i < src.length; i++) {
if (src[i] === "{") depth++;
else if (src[i] === "}" && --depth === 0) {
const char = src[i]!;
if (quote) {
if (char === "\\" && i + 1 < src.length) {
i++;
continue;
}
if (char === quote) quote = null;
continue;
}
if (char === '"' || char === "'" || char === "`") {
quote = char;
continue;
}
if (char === "{") depth++;
else if (char === "}" && --depth === 0) {
i++;
return src.slice(start, i);
}
@@ -819,7 +836,13 @@ export function parseHtmlView(src: string, pos: number): { nodes: ViewNode[]; en
if (src[i] === "=") {
i++;
skipWs();
attrs.push({ name, value: readQuoted(), event: false });
const value =
src[i] === '"' || src[i] === "'"
? readQuoted()
: src[i] === "{"
? readInterpolation()
: fail(`Expected a quoted value or {...} expression after '${name}='`);
attrs.push({ name, value, event: false });
} else {
attrs.push({ name, value: "", event: false, boolean: true });
}
+29
View File
@@ -1,6 +1,35 @@
import { expect, test } from "bun:test";
import { diagnose, formatDiagnostic, parse } from "../src/index.ts";
test("parses native array and object literals in state and component props", () => {
const ast = parse(`
component Navigation {
state items = [{"label":"Home","href":"/"}]
state options = {"dense":true,"nested":{"label":"A {brace}"}}
view {
<Navbar items={items} />
<Sidebar items={[{"label":"Cases","href":"/cases"}]} options={{"dense":true}} />
}
}
`);
expect(ast.states[0]?.expr).toBe('[{"label":"Home","href":"/"}]');
expect(ast.states[1]?.expr).toBe('{"dense":true,"nested":{"label":"A {brace}"}}');
const elements = ast.view.filter((node) => node.type === "element");
const navbar = elements[0];
const sidebar = elements[1];
expect(navbar?.type).toBe("element");
expect(sidebar?.type).toBe("element");
if (navbar?.type !== "element" || sidebar?.type !== "element") return;
expect(navbar.attrs.find((attr) => attr.name === "items")?.value).toBe("{items}");
expect(sidebar.attrs.find((attr) => attr.name === "items")?.value).toBe(
'{[{"label":"Cases","href":"/cases"}]}',
);
expect(sidebar.attrs.find((attr) => attr.name === "options")?.value).toBe('{{"dense":true}}');
});
test("parses WRN 0.3 execution, data, security, and reactivity blocks", () => {
const ast = parse(`page Dashboard {
runtime = "universal"