288 lines
8.3 KiB
Plaintext
288 lines
8.3 KiB
Plaintext
// Bun Snapshot v1, https://bun.sh/docs/test/snapshots
|
|
|
|
exports[`compiler output remains snapshot-compatible for the canonical component contract 1`] = `
|
|
{
|
|
"code":
|
|
"// compiled from .wrn
|
|
import Button from "@wrnexus/ui/components/Button.wrn";
|
|
|
|
import { Buffer as __WrnexusBuffer } from "node:buffer";
|
|
|
|
export const __wrnexusComponent = "Counter";
|
|
|
|
export const __wrnexusRuntime = "universal";
|
|
|
|
export const __wrnexusRender = "hybrid";
|
|
|
|
export const __wrnexusHydrate = "load";
|
|
|
|
export const __wrnexusHydrationId = "Counter:1skggk6";
|
|
|
|
export const __wrnexusBehavior = {
|
|
"functions": "function increment(){\\n count = count + 1\\n output.change(count)\\n }",
|
|
"outputs": [
|
|
{
|
|
"name": "change",
|
|
"payload": {
|
|
"name": "value",
|
|
"valueType": "number",
|
|
"optional": false
|
|
}
|
|
}
|
|
],
|
|
"computed": [],
|
|
"effects": [],
|
|
"lifecycle": {},
|
|
"watches": []
|
|
};
|
|
|
|
export interface CounterProps {
|
|
[attribute: string]: unknown;
|
|
"label"?: string;
|
|
}
|
|
|
|
export interface CounterOutputs {
|
|
"change"(value: number): void;
|
|
}
|
|
|
|
function __coerce(v: unknown, def: unknown, declared: string = "unknown", propName: string = "prop"): unknown {
|
|
if (v === undefined || v === null) {
|
|
return def;
|
|
}
|
|
|
|
if (declared === "number" || typeof def === "number") {
|
|
const parsed = Number(v);
|
|
if (!Number.isFinite(parsed)) throw new TypeError("Expected a finite number prop");
|
|
return parsed;
|
|
}
|
|
|
|
if (declared === "boolean" || typeof def === "boolean") {
|
|
if (v === true || v === "" || v === "true" || v === 1 || v === "1") return true;
|
|
if (v === false || v === "false" || v === 0 || v === "0") return false;
|
|
throw new TypeError("Expected a boolean prop");
|
|
}
|
|
|
|
if (declared === "array" || Array.isArray(def)) {
|
|
if (Array.isArray(v)) {
|
|
return v;
|
|
}
|
|
|
|
if (typeof v === "string") {
|
|
try {
|
|
const parsed = JSON.parse(v);
|
|
if (!Array.isArray(parsed)) throw new TypeError("Expected an array prop '" + propName + "'");
|
|
return parsed;
|
|
} catch {
|
|
throw new TypeError("Expected an array prop '" + propName + "'");
|
|
}
|
|
}
|
|
|
|
throw new TypeError("Expected an array prop '" + propName + "'");
|
|
}
|
|
|
|
if (declared === "object" || (def !== null && typeof def === "object")) {
|
|
if (
|
|
v !== null &&
|
|
typeof v === "object" &&
|
|
!Array.isArray(v)
|
|
) {
|
|
return v;
|
|
}
|
|
|
|
if (typeof v === "string") {
|
|
try {
|
|
const parsed = JSON.parse(v);
|
|
|
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
throw new TypeError("Expected an object prop '" + propName + "'");
|
|
}
|
|
return parsed;
|
|
} catch {
|
|
throw new TypeError("Expected an object prop '" + propName + "'");
|
|
}
|
|
}
|
|
|
|
throw new TypeError("Expected an object prop '" + propName + "'");
|
|
}
|
|
|
|
if (declared === "bigint") return BigInt(v as string | number | bigint | boolean);
|
|
if (declared === "function" && typeof v !== "function") {
|
|
throw new TypeError("Expected a function prop");
|
|
}
|
|
return declared === "unknown" && def === undefined ? v : String(v);
|
|
}
|
|
|
|
function __restProps(
|
|
props: Record<string, unknown>,
|
|
declared: Set<string>,
|
|
): Record<string, unknown> {
|
|
return Object.fromEntries(
|
|
Object.entries(props).filter(([name]) => !declared.has(name)),
|
|
);
|
|
}
|
|
|
|
function __wrnHtml(v: unknown): string {
|
|
return String(v == null ? "" : v).replace(
|
|
/[&<>]/g,
|
|
(c) =>
|
|
c === "&"
|
|
? "&"
|
|
: c === "<"
|
|
? "<"
|
|
: ">",
|
|
);
|
|
}
|
|
|
|
function __wrnOptionalAttr(name: string, value: string): string {
|
|
return value === "" ? "" : " " + name + '="' + value + '"';
|
|
}
|
|
|
|
function __wrnAttr(v: unknown): string {
|
|
return String(v == null ? "" : v).replace(
|
|
/[&<>"]/g,
|
|
(c) =>
|
|
c === "&"
|
|
? "&"
|
|
: c === "<"
|
|
? "<"
|
|
: c === ">"
|
|
? ">"
|
|
: """,
|
|
);
|
|
}
|
|
|
|
function __wrnBooleanAttr(name: string, value: unknown): string {
|
|
return value === true ||
|
|
value === "true" ||
|
|
value === "" ||
|
|
value === 1 ||
|
|
value === "1" ||
|
|
value === name
|
|
? " " + name
|
|
: "";
|
|
}
|
|
|
|
function __wrnSpreadAttrs(value: unknown): string {
|
|
if (value === null || typeof value !== "object" || Array.isArray(value)) return "";
|
|
|
|
const booleanAttributes = new Set(["allowfullscreen","async","autofocus","autoplay","checked","controls","default","defer","disabled","formnovalidate","hidden","inert","ismap","itemscope","loop","multiple","muted","nomodule","novalidate","open","playsinline","readonly","required","reversed","selected"]);
|
|
const attributes: string[] = [];
|
|
|
|
for (const [name, raw] of Object.entries(value)) {
|
|
const lowerName = name.toLowerCase();
|
|
if (
|
|
!/^[A-Za-z_:][A-Za-z0-9_.:-]*$/.test(name) ||
|
|
lowerName.startsWith("on") ||
|
|
lowerName === "style" ||
|
|
lowerName === "slot" ||
|
|
lowerName === "data-component" ||
|
|
// Internal markers must not leak through a spread. Parent-owned output
|
|
// and prop bindings ride from the mount onto the
|
|
// rendered child root so the mounting scope can bind them there.
|
|
(lowerName.startsWith("data-wrn") &&
|
|
!lowerName.startsWith("data-wrn-out-") &&
|
|
!lowerName.startsWith("data-wrn-prop-bind-"))
|
|
) {
|
|
continue;
|
|
}
|
|
|
|
if (booleanAttributes.has(lowerName)) {
|
|
attributes.push(__wrnBooleanAttr(name, raw));
|
|
continue;
|
|
}
|
|
|
|
if (raw === false || raw === null || raw === undefined) continue;
|
|
attributes.push(" " + name + '="' + __wrnAttr(raw) + '"');
|
|
}
|
|
|
|
return attributes.join("");
|
|
}
|
|
|
|
function __wrnProp(v: unknown): string {
|
|
const value =
|
|
v !== null && typeof v === "object"
|
|
? JSON.stringify(v)
|
|
: String(v == null ? "" : v);
|
|
|
|
return __wrnAttr(value);
|
|
}
|
|
|
|
function __wrnRaw(v: unknown): string {
|
|
return String(v == null ? "" : v);
|
|
}
|
|
|
|
function __wrnexusEncodeControl(value: unknown): string {
|
|
return __WrnexusBuffer.from(JSON.stringify(value), "utf8").toString("base64");
|
|
}
|
|
|
|
function __wrnexusSerializeScopeValue(value: unknown): string {
|
|
if (value === undefined) {
|
|
return "undefined";
|
|
}
|
|
|
|
if (value === null) {
|
|
return "null";
|
|
}
|
|
|
|
if (typeof value === "number") {
|
|
return Number.isFinite(value)
|
|
? String(value)
|
|
: "null";
|
|
}
|
|
|
|
if (typeof value === "boolean") {
|
|
return value ? "true" : "false";
|
|
}
|
|
|
|
if (typeof value === "string") {
|
|
return JSON.stringify(value);
|
|
}
|
|
|
|
try {
|
|
const serialized = JSON.stringify(value);
|
|
|
|
return serialized === undefined
|
|
? "undefined"
|
|
: serialized;
|
|
} catch {
|
|
return "null";
|
|
}
|
|
}
|
|
|
|
function __wrnexusScopeDecl(obj: Record<string, unknown>): string {
|
|
return Object.keys(obj)
|
|
.map(
|
|
(key) =>
|
|
key +
|
|
": " +
|
|
__wrnexusSerializeScopeValue(
|
|
obj[key],
|
|
),
|
|
)
|
|
.join(", ")
|
|
.replace(/&/g, "&")
|
|
.replace(/"/g, """)
|
|
.replace(/</g, "<")
|
|
.replace(/>/g, ">");
|
|
}
|
|
|
|
export function render(props: CounterProps = {} as CounterProps): string {
|
|
const __p = props || {};
|
|
const label: string = __coerce(__p["label"], ("Count"), "string", "label") as string;
|
|
const __attrs = __restProps(__p, new Set(["label"]));
|
|
let count = (0);
|
|
const __scopeState = { "label": label, "count": count };
|
|
const __scope = __wrnexusScopeDecl(__scopeState);
|
|
const __scopePayload = __WrnexusBuffer.from(JSON.stringify(__scopeState), "utf8").toString("base64");
|
|
return \`<div data-scope="\${__scope}" data-wrn-scope="\${__scopePayload}" data-wrn-behavior="eyJmdW5jdGlvbnMiOiJmdW5jdGlvbiBpbmNyZW1lbnQoKXtcbiAgICAgIGNvdW50ID0gY291bnQgKyAxXG4gICAgICBvdXRwdXQuY2hhbmdlKGNvdW50KVxuICAgIH0iLCJvdXRwdXRzIjpbeyJuYW1lIjoiY2hhbmdlIiwicGF5bG9hZCI6eyJuYW1lIjoidmFsdWUiLCJ2YWx1ZVR5cGUiOiJudW1iZXIiLCJvcHRpb25hbCI6ZmFsc2V9fV0sImNvbXB1dGVkIjpbXSwiZWZmZWN0cyI6W10sImxpZmVjeWNsZSI6e30sIndhdGNoZXMiOltdfQ==" data-wrn-hydration="Counter:1skggk6" data-wrn-hydrate="load" data-wrn-runtime="universal" data-wrn-client-module="__WRNEXUS_CLIENT_MODULE__">
|
|
<div data-component="Button"\${__wrnSpreadAttrs(__attrs)} on:click="\${__wrnProp(increment)}"><span data-text="label">\${__wrnHtml(label)}</span>: <span data-text="count">\${__wrnHtml(count)}</span></div>
|
|
</div>\`;
|
|
}
|
|
|
|
export default { name: "Counter", kind: "component", render };
|
|
"
|
|
,
|
|
"diagnostics": [],
|
|
}
|
|
`;
|