release: WRNexusJS 0.6.0
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import { diagnose, parse } from "../src/index.ts";
|
||||
|
||||
const source = `import type { PublicUser } from "@/types/user.ts"
|
||||
import PublicLayout from "@/layouts/PublicLayout.wrn"
|
||||
|
||||
component ProfileCard {
|
||||
props {
|
||||
user: PublicUser
|
||||
title?: string
|
||||
open: boolean = false
|
||||
size: "small" | "medium" | "large" = "medium"
|
||||
}
|
||||
|
||||
state query: string = ""
|
||||
state {
|
||||
selected: PublicUser | null = null
|
||||
loading: boolean = false
|
||||
}
|
||||
client state { menuOpen: boolean = false }
|
||||
server state { sessionId: string | null = null }
|
||||
|
||||
computed ready: boolean = selected !== null
|
||||
computed { label: string = title || user.name }
|
||||
|
||||
outputs {
|
||||
confirm(payload: PublicUser)
|
||||
cancel()
|
||||
}
|
||||
|
||||
functions {
|
||||
client async function confirmed(payload: PublicUser): Promise<void> {
|
||||
const result = await server.confirmed(payload)
|
||||
output.confirm(result)
|
||||
}
|
||||
server async function confirmed(payload: PublicUser): Promise<PublicUser> {
|
||||
return payload
|
||||
}
|
||||
shared function normalize(value: string): string {
|
||||
return value.trim()
|
||||
}
|
||||
}
|
||||
|
||||
view { <button>{label}</button> }
|
||||
}`;
|
||||
|
||||
test("parses the WRNexusJS 0.6 language surface", () => {
|
||||
const ast = parse(source);
|
||||
expect(ast.structuredImports).toHaveLength(2);
|
||||
expect(ast.props.map((prop) => [prop.name, prop.required])).toEqual([
|
||||
["user", true],
|
||||
["title", false],
|
||||
["open", false],
|
||||
["size", false],
|
||||
]);
|
||||
expect(ast.states.map((state) => `${state.runtime}:${state.name}`)).toEqual([
|
||||
"shared:query",
|
||||
"shared:selected",
|
||||
"shared:loading",
|
||||
"client:menuOpen",
|
||||
"server:sessionId",
|
||||
]);
|
||||
expect(ast.outputs.map((output) => output.name)).toEqual(["confirm", "cancel"]);
|
||||
expect(ast.runtimeFunctions.map((fn) => `${fn.runtime}:${fn.name}`)).toEqual([
|
||||
"client:confirmed",
|
||||
"server:confirmed",
|
||||
"shared:normalize",
|
||||
]);
|
||||
});
|
||||
|
||||
test("supports global and page store roots", () => {
|
||||
const globalStore = parse(`global store UserStore {
|
||||
state { user: string | null = null }
|
||||
computed { authenticated: boolean = user !== null }
|
||||
persist { storage = "local" include = ["user"] version = 1 }
|
||||
lifecycle { serverInit {} clientInit {} hydrate {} dispose {} }
|
||||
functions { client function clear(): void { user = null } }
|
||||
}`);
|
||||
const pageStore = parse(`page store SearchStore { state { query: string = "" } }`);
|
||||
expect(globalStore.kind).toBe("global-store");
|
||||
expect(globalStore.persist?.storage).toBe("local");
|
||||
expect(globalStore.storeLifecycle).toEqual(
|
||||
expect.objectContaining({ serverInit: "", dispose: "" }),
|
||||
);
|
||||
expect(pageStore.kind).toBe("page-store");
|
||||
});
|
||||
|
||||
test("rejects duplicate implementations in the same runtime", () => {
|
||||
const diagnostics = diagnose(`component Invalid {
|
||||
functions {
|
||||
client function save(): void {}
|
||||
client function save(): void {}
|
||||
}
|
||||
view { <div></div> }
|
||||
}`);
|
||||
expect(diagnostics.some((diagnostic) => diagnostic.code === "WRN-FUNCTION-DUPLICATE")).toBe(true);
|
||||
});
|
||||
|
||||
test("readonly prop diagnostics ignore comparisons, strings, and shadowing parameters", () => {
|
||||
const diagnostics = diagnose(`component Valid {
|
||||
props { name: string = "field" mode: string = "exact" items: any[] = [] }
|
||||
functions {
|
||||
client function inspect(name, localItems) {
|
||||
if (mode === "exact") localItems = items.filter((item) => item.name === name)
|
||||
return document.querySelector("input[name='" + name + "']")
|
||||
}
|
||||
}
|
||||
view { <div></div> }
|
||||
}`);
|
||||
expect(diagnostics.some((diagnostic) => diagnostic.code === "WRN-PROP-READONLY")).toBe(false);
|
||||
});
|
||||
|
||||
test("readonly prop diagnostics still reject direct prop assignments", () => {
|
||||
const diagnostics = diagnose(`component Invalid {
|
||||
props { open: boolean = false }
|
||||
functions { client function mutate() { open = true } }
|
||||
view { <div></div> }
|
||||
}`);
|
||||
expect(diagnostics.some((diagnostic) => diagnostic.code === "WRN-PROP-READONLY")).toBe(true);
|
||||
});
|
||||
Reference in New Issue
Block a user