Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
973d580bc5 | ||
|
|
8a8328a308 | ||
|
|
0f915c3c98 |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/ai",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/authz",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/authz — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
+11
-11
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/cli",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/cli — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -28,16 +28,16 @@
|
||||
"wrnexus": "./dist/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.2.43",
|
||||
"@wrnexus/router": "^0.2.43",
|
||||
"@wrnexus/csr": "^0.2.43",
|
||||
"@wrnexus/compiler": "^0.2.43",
|
||||
"@wrnexus/styles": "^0.2.43",
|
||||
"@wrnexus/dev-server": "^0.2.43",
|
||||
"@wrnexus/ui": "^0.2.43",
|
||||
"@wrnexus/validation": "^0.2.43",
|
||||
"@wrnexus/i18n": "^0.2.43",
|
||||
"@wrnexus/db": "^0.2.43"
|
||||
"@wrnexus/core": "^0.2.46",
|
||||
"@wrnexus/router": "^0.2.46",
|
||||
"@wrnexus/csr": "^0.2.46",
|
||||
"@wrnexus/compiler": "^0.2.46",
|
||||
"@wrnexus/styles": "^0.2.46",
|
||||
"@wrnexus/dev-server": "^0.2.46",
|
||||
"@wrnexus/ui": "^0.2.46",
|
||||
"@wrnexus/validation": "^0.2.46",
|
||||
"@wrnexus/i18n": "^0.2.46",
|
||||
"@wrnexus/db": "^0.2.46"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/compiler",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/compiler — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/core",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/core — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/csr",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/csr — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -21,7 +21,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.2.43"
|
||||
"@wrnexus/core": "^0.2.46"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/db",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/db — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/dev-server",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/dev-server — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -25,18 +25,18 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.2.43",
|
||||
"@wrnexus/router": "^0.2.43",
|
||||
"@wrnexus/ssr": "^0.2.43",
|
||||
"@wrnexus/csr": "^0.2.43",
|
||||
"@wrnexus/compiler": "^0.2.43",
|
||||
"@wrnexus/styles": "^0.2.43",
|
||||
"@wrnexus/ui": "^0.2.43",
|
||||
"@wrnexus/validation": "^0.2.43",
|
||||
"@wrnexus/i18n": "^0.2.43",
|
||||
"@wrnexus/db": "^0.2.43",
|
||||
"@wrnexus/pubsub": "^0.2.43",
|
||||
"@wrnexus/uploader": "^0.2.43"
|
||||
"@wrnexus/core": "^0.2.46",
|
||||
"@wrnexus/router": "^0.2.46",
|
||||
"@wrnexus/ssr": "^0.2.46",
|
||||
"@wrnexus/csr": "^0.2.46",
|
||||
"@wrnexus/compiler": "^0.2.46",
|
||||
"@wrnexus/styles": "^0.2.46",
|
||||
"@wrnexus/ui": "^0.2.46",
|
||||
"@wrnexus/validation": "^0.2.46",
|
||||
"@wrnexus/i18n": "^0.2.46",
|
||||
"@wrnexus/db": "^0.2.46",
|
||||
"@wrnexus/pubsub": "^0.2.46",
|
||||
"@wrnexus/uploader": "^0.2.46"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/encryption",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/encryption — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/helpers",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "Safe convenience helpers for WrNexus request contexts and common application flows.",
|
||||
"license": "MIT",
|
||||
@@ -21,7 +21,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.2.43"
|
||||
"@wrnexus/core": "^0.2.46"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/i18n",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/i18n — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -21,7 +21,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.2.43"
|
||||
"@wrnexus/core": "^0.2.46"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/jwt",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/jwt — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/mobile",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/mobile — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -21,7 +21,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/native": "^0.2.43"
|
||||
"@wrnexus/native": "^0.2.46"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/native",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/native — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/oauth",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/oauth — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/pubsub",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/pubsub — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/queue",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/queue — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/reactive",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/reactive — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/router",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/router — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -21,8 +21,8 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/compiler": "^0.2.43",
|
||||
"@wrnexus/core": "^0.2.43"
|
||||
"@wrnexus/compiler": "^0.2.46",
|
||||
"@wrnexus/core": "^0.2.46"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/ssr",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/ssr — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -21,7 +21,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.2.43"
|
||||
"@wrnexus/core": "^0.2.46"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/styles",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/styles — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -21,7 +21,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/uploader": "^0.2.43"
|
||||
"@wrnexus/uploader": "^0.2.46"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/test",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/test — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/tracking",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/tracking — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/ui",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/ui — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -22,7 +22,7 @@
|
||||
"./ui.css": "./ui.css"
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.2.43"
|
||||
"@wrnexus/core": "^0.2.46"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/uploader",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/uploader — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
@@ -21,7 +21,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@wrnexus/core": "^0.2.43"
|
||||
"@wrnexus/core": "^0.2.46"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/validation",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"description": "@wrnexus/validation — part of the WrNexus framework.",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/ai",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/authz",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/cli",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -465,6 +465,33 @@ const MIGRATIONS: Migration[] = [
|
||||
// No generated application files require automatic migration.
|
||||
},
|
||||
},
|
||||
{
|
||||
version: "0.2.44",
|
||||
id: "conditions-bug",
|
||||
description:
|
||||
"Adds server-rendered component each/if blocks and fixes dynamic component rendering.",
|
||||
apply() {
|
||||
// No generated application files require automatic migration.
|
||||
},
|
||||
},
|
||||
{
|
||||
version: "0.2.45",
|
||||
id: "conditions-bug",
|
||||
description:
|
||||
"Adds server-rendered component each/if blocks and fixes dynamic component rendering.",
|
||||
apply() {
|
||||
// No generated application files require automatic migration.
|
||||
},
|
||||
},
|
||||
{
|
||||
version: "0.2.46",
|
||||
id: "conditions-bug",
|
||||
description:
|
||||
"Adds server-rendered component each/if blocks and fixes dynamic component rendering.",
|
||||
apply() {
|
||||
// No generated application files require automatic migration.
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
/** Release tooling uses this to require an explicit migration entry per version. */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/compiler",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -524,7 +524,13 @@ function hasClientBehavior(nodes: ViewNode[]): boolean {
|
||||
// `{t:key}` is i18n sugar resolved server-side — not client reactivity.
|
||||
if (node.type === "text") return /\{(?!t:)[^{}]+\}/.test(node.value);
|
||||
// Server control blocks render on the server; they don't add client reactivity.
|
||||
if (node.type === "each" || node.type === "if") return false;
|
||||
if (node.type === "each") {
|
||||
return hasClientBehavior(node.body) || hasClientBehavior(node.empty);
|
||||
}
|
||||
|
||||
if (node.type === "if") {
|
||||
return node.branches.some((branch) => hasClientBehavior(branch.body));
|
||||
}
|
||||
return (
|
||||
node.attrs.some((attr) => attr.event || attr.name === "csrGet" || attr.name === "csrText") ||
|
||||
hasClientBehavior(node.children)
|
||||
@@ -1112,6 +1118,16 @@ function renderComponentNode(node: ViewNode, ctx: CompCtx): string {
|
||||
return renderNestedComponentInvocation(node, ctx);
|
||||
}
|
||||
|
||||
const loopVariables = loopVarsOf(node);
|
||||
|
||||
const elementContext =
|
||||
loopVariables.length > 0
|
||||
? {
|
||||
...ctx,
|
||||
loopVars: new Set([...(ctx.loopVars ?? []), ...loopVariables]),
|
||||
}
|
||||
: ctx;
|
||||
|
||||
let bindIndex = 0;
|
||||
const staticClasses: string[] = [];
|
||||
const conditionalClasses: Array<{
|
||||
@@ -1143,9 +1159,15 @@ function renderComponentNode(node: ViewNode, ctx: CompCtx): string {
|
||||
return ` ${a.name}`;
|
||||
}
|
||||
|
||||
const rendered = ` ${a.name}="${compileAttrValue(a.value, ctx)}"`;
|
||||
const rendered = ` ${a.name}="${compileAttrValue(a.value, elementContext)}"`;
|
||||
|
||||
if (!a.value.includes("{") || !exprRefsState(a.value, ctx.stateNames)) {
|
||||
const referencesState = exprRefsState(a.value, ctx.stateNames);
|
||||
|
||||
const referencesLoopVariable = elementContext.loopVars
|
||||
? exprRefsState(a.value, elementContext.loopVars)
|
||||
: false;
|
||||
|
||||
if (!a.value.includes("{") || (!referencesState && !referencesLoopVariable)) {
|
||||
return rendered;
|
||||
}
|
||||
|
||||
@@ -1157,6 +1179,16 @@ function renderComponentNode(node: ViewNode, ctx: CompCtx): string {
|
||||
|
||||
const initialConditionalClasses = conditionalClasses
|
||||
.map(({ className, expression }) => {
|
||||
const referencesLoopVariable = elementContext.loopVars
|
||||
? exprRefsState(expression, elementContext.loopVars)
|
||||
: false;
|
||||
|
||||
// data-for variables do not exist during
|
||||
// initial server rendering.
|
||||
if (referencesLoopVariable) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return `\${(${ctx.resolveExpr(expression)}) ? ${JSON.stringify(` ${className}`)} : ""}`;
|
||||
})
|
||||
.join("");
|
||||
@@ -1168,7 +1200,7 @@ function renderComponentNode(node: ViewNode, ctx: CompCtx): string {
|
||||
|
||||
const classAttribute =
|
||||
staticClasses.length > 0 || conditionalClasses.length > 0
|
||||
? ` class="${compileAttrValue(staticClassValue, ctx)}${initialConditionalClasses}"`
|
||||
? ` class="${compileAttrValue(staticClassValue, elementContext)}${initialConditionalClasses}"`
|
||||
: "";
|
||||
|
||||
const classReactiveBinding = classHasReactiveExpression
|
||||
@@ -1186,11 +1218,6 @@ function renderComponentNode(node: ViewNode, ctx: CompCtx): string {
|
||||
})
|
||||
.join("");
|
||||
|
||||
// A `data-for` element introduces loop variables for its subtree.
|
||||
const loops = loopVarsOf(node);
|
||||
const childCtx =
|
||||
loops.length > 0 ? { ...ctx, loopVars: new Set([...(ctx.loopVars ?? []), ...loops]) } : ctx;
|
||||
|
||||
const allAttrs =
|
||||
`${classAttribute}` + `${classReactiveBinding}` + `${classBindings}` + `${attrs}`;
|
||||
|
||||
@@ -1198,7 +1225,7 @@ function renderComponentNode(node: ViewNode, ctx: CompCtx): string {
|
||||
return `<${node.tag}${allAttrs}>`;
|
||||
}
|
||||
|
||||
const inner = node.children.map((child) => renderComponentNode(child, childCtx)).join("");
|
||||
const inner = node.children.map((child) => renderComponentNode(child, elementContext)).join("");
|
||||
|
||||
return `<${node.tag}${allAttrs}>${inner}</${node.tag}>`;
|
||||
}
|
||||
@@ -1276,7 +1303,9 @@ function generateComponent(ast: PageAst): string {
|
||||
|
||||
const scopeLine =
|
||||
needsScope && scopeKeys.length > 0
|
||||
? ` const __scope = __wrnexusScopeDecl({ ${scopeKeys.map((k) => `${JSON.stringify(k)}: ${nameRefs.get(k)}`).join(", ")} });\n`
|
||||
? ` const __scope = __wrnexusScopeDecl({ ${scopeKeys
|
||||
.map((key) => `${JSON.stringify(key)}: ${nameRefs.get(key)}`)
|
||||
.join(", ")} });\n`
|
||||
: needsScope
|
||||
? ` const __scope = "";\n`
|
||||
: "";
|
||||
@@ -1392,19 +1421,56 @@ function __wireRaw(v: any): string {
|
||||
}`);
|
||||
|
||||
if (needsScope) {
|
||||
out.push(`function __wrnexusScopeDecl(obj: Record<string, any>): string {
|
||||
const lit = (v: any) =>
|
||||
typeof v === "number" || typeof v === "boolean"
|
||||
? String(v)
|
||||
: "'" + String(v).replace(/\\\\/g, "\\\\\\\\").replace(/'/g, "\\\\'").replace(/\\n/g, "\\\\n") + "'";
|
||||
return Object.keys(obj)
|
||||
.map((k) => k + ": " + lit(obj[k]))
|
||||
.join(", ")
|
||||
.replace(/&/g, "&")
|
||||
.replace(/"/g, """)
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">");
|
||||
}`);
|
||||
out.push(`function __wrnexusSerializeScopeValue(value: any): 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, any>): string {
|
||||
return Object.keys(obj)
|
||||
.map(
|
||||
(key) =>
|
||||
key +
|
||||
": " +
|
||||
__wrnexusSerializeScopeValue(
|
||||
obj[key],
|
||||
),
|
||||
)
|
||||
.join(", ")
|
||||
.replace(/&/g, "&")
|
||||
.replace(/"/g, """)
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">");
|
||||
}`);
|
||||
}
|
||||
|
||||
const serverFunctionSource = serverFunctions ? `${serverFunctions}\n` : "";
|
||||
|
||||
@@ -98,10 +98,18 @@ test("stateful component: state text baked into a reactive data-text span, prop
|
||||
);
|
||||
const render = mod.render as (p: Record<string, string>) => string;
|
||||
const out = render({ start: "10", label: "Score" });
|
||||
expect(out).toContain("data-scope=\"start: 10, label: 'Score', count: 10\"");
|
||||
expect(out).toContain('data-scope="start: 10, label: "Score", count: 10"');
|
||||
expect(out).toContain('data-on-click="count++"');
|
||||
// label baked as static text; count baked as its initial value AND kept live.
|
||||
expect(out).toContain('Score: <span data-text="count">10</span>');
|
||||
|
||||
expect(out).toContain('data-scope="');
|
||||
|
||||
expect(out).toContain("start: 10");
|
||||
|
||||
expect(out).toContain("label: "Score"");
|
||||
|
||||
expect(out).toContain("count: 10");
|
||||
});
|
||||
|
||||
test("prop type coercion follows the default value's type", async () => {
|
||||
@@ -839,3 +847,37 @@ component FAQAccordion {
|
||||
|
||||
expect(output).toContain("isOpen(index)");
|
||||
});
|
||||
test("data-for conditional classes do not evaluate loop variables during SSR", () => {
|
||||
const output = generate(
|
||||
parse(`
|
||||
component Accordion {
|
||||
props {
|
||||
items = []
|
||||
}
|
||||
|
||||
state openIndexes = []
|
||||
|
||||
functions {
|
||||
function isOpen(index) {
|
||||
return openIndexes.includes(index)
|
||||
}
|
||||
}
|
||||
|
||||
view {
|
||||
<article
|
||||
data-for="item, index in items"
|
||||
class:open="isOpen(index)"
|
||||
>
|
||||
{item.title}
|
||||
</article>
|
||||
}
|
||||
}
|
||||
`),
|
||||
);
|
||||
|
||||
expect(output).toContain('data-for="item, index in items"');
|
||||
|
||||
expect(output).toContain("data-wrn-class-0");
|
||||
|
||||
expect(output).not.toContain('${(isOpen(index)) ? " open" : ""}');
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/core",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/csr",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
||||
import { test, expect, beforeEach } from "bun:test";
|
||||
import { Window } from "happy-dom";
|
||||
import { REACTIVE_RUNTIME } from "../src/reactive-runtime.ts";
|
||||
import { mountHtml } from "@wrnexus/test";
|
||||
|
||||
// Fresh DOM per test, with the runtime's globals bound.
|
||||
function mount(html: string): Window {
|
||||
@@ -164,3 +165,48 @@ test("independent signals in one scope update correctly (dependency tracking)",
|
||||
click("bb");
|
||||
expect([ta(), tb()]).toEqual(["2", "101"]);
|
||||
});
|
||||
test("data-for preserves arrays of objects from encoded component scope", () => {
|
||||
const items = [
|
||||
{
|
||||
question: "One",
|
||||
answer: "First",
|
||||
},
|
||||
{
|
||||
question: "Two",
|
||||
answer: "Second",
|
||||
},
|
||||
{
|
||||
question: "Three",
|
||||
answer: "Third",
|
||||
},
|
||||
{
|
||||
question: "Four",
|
||||
answer: "Fourth",
|
||||
},
|
||||
];
|
||||
|
||||
const encoded = Buffer.from(
|
||||
JSON.stringify({
|
||||
items,
|
||||
}),
|
||||
"utf8",
|
||||
).toString("base64");
|
||||
|
||||
const dom = mountHtml(`
|
||||
<div data-wrn-scope="${encoded}">
|
||||
<article data-for="item, index in items">
|
||||
<span>{index + 1}</span>
|
||||
<strong>{item.question}</strong>
|
||||
</article>
|
||||
</div>
|
||||
`);
|
||||
|
||||
expect(dom.querySelectorAll("article")).toHaveLength(4);
|
||||
|
||||
expect(dom.querySelectorAll("strong").map((element) => element.textContent)).toEqual([
|
||||
"One",
|
||||
"Two",
|
||||
"Three",
|
||||
"Four",
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/db",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/dev-server",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/encryption",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/helpers",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"description": "Safe convenience helpers for WrNexus request contexts and common application flows.",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/i18n",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/jwt",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/mobile",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/native",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/oauth",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/pubsub",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/queue",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/reactive",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/router",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/ssr",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/styles",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/test",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/tracking",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/ui",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/uploader",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/validation",
|
||||
"version": "0.2.43",
|
||||
"version": "0.2.46",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
|
||||
const version = "0.2.43";
|
||||
const version = "0.2.46";
|
||||
|
||||
const dependencyGroups = [
|
||||
"dependencies",
|
||||
|
||||
Reference in New Issue
Block a user