release: WRNexusJS 0.2.47

This commit is contained in:
2026-07-18 13:12:16 +05:30
parent 973d580bc5
commit d22824fa62
57 changed files with 420 additions and 129 deletions
+62 -6
View File
@@ -996,6 +996,20 @@ function viewHasEvents(nodes: ViewNode[]): boolean {
});
}
function viewHasServerEach(nodes: ViewNode[]): boolean {
return nodes.some((node) => {
if (node.type === "text") return false;
if (node.type === "each") return true;
if (node.type === "if") {
return node.branches.some((branch) => viewHasServerEach(branch.body));
}
return viewHasServerEach(node.children);
});
}
/**
* Compile a text node. Interpolations that reference state stay as client
* mustaches (`{expr}`, hydrated by the reactive runtime); interpolations of
@@ -1102,6 +1116,18 @@ function renderComponentEachNode(node: EachNode, ctx: CompCtx): string {
);
}
function serverLoopLocalsAttribute(ctx: CompCtx): string {
const locals = [...(ctx.serverLocals ?? [])];
if (locals.length === 0) {
return "";
}
const entries = locals.map((name) => `${JSON.stringify(name)}: ${name}`).join(", ");
return ` data-wrn-loop-locals="\${__wrnexusEncodeLoopLocals({ ${entries} })}"`;
}
/** Render a component view node into template-literal-ready source. */
function renderComponentNode(node: ViewNode, ctx: CompCtx): string {
if (node.type === "text") return compileText(node.value, ctx);
@@ -1167,7 +1193,14 @@ function renderComponentNode(node: ViewNode, ctx: CompCtx): string {
? exprRefsState(a.value, elementContext.loopVars)
: false;
if (!a.value.includes("{") || (!referencesState && !referencesLoopVariable)) {
const referencesServerLocal = ctx.serverLocals
? exprRefsState(a.value, ctx.serverLocals)
: false;
if (
!a.value.includes("{") ||
(!referencesState && !referencesLoopVariable && !referencesServerLocal)
) {
return rendered;
}
@@ -1195,8 +1228,17 @@ function renderComponentNode(node: ViewNode, ctx: CompCtx): string {
const staticClassValue = staticClasses.join(" ");
const classReferencesState = exprRefsState(staticClassValue, ctx.stateNames);
const classReferencesLoopVariable = elementContext.loopVars
? exprRefsState(staticClassValue, elementContext.loopVars)
: false;
const classReferencesServerLocal = ctx.serverLocals
? exprRefsState(staticClassValue, ctx.serverLocals)
: false;
const classHasReactiveExpression =
staticClassValue.includes("{") && exprRefsState(staticClassValue, ctx.stateNames);
staticClassValue.includes("{") &&
(classReferencesState || classReferencesLoopVariable || classReferencesServerLocal);
const classAttribute =
staticClasses.length > 0 || conditionalClasses.length > 0
@@ -1208,9 +1250,6 @@ function renderComponentNode(node: ViewNode, ctx: CompCtx): string {
: "";
const classBindings = conditionalClasses
.filter(({ expression }) => {
return !ctx.serverLocals || !exprRefsState(expression, ctx.serverLocals);
})
.map(({ className, expression }, index) => {
const marker = attrEscape(JSON.stringify([className, expression]));
@@ -1218,8 +1257,14 @@ function renderComponentNode(node: ViewNode, ctx: CompCtx): string {
})
.join("");
const loopLocalsAttribute = serverLoopLocalsAttribute(ctx);
const allAttrs =
`${classAttribute}` + `${classReactiveBinding}` + `${classBindings}` + `${attrs}`;
`${loopLocalsAttribute}` +
`${classAttribute}` +
`${classReactiveBinding}` +
`${classBindings}` +
`${attrs}`;
if (VOID_ELEMENTS.has(node.tag.toLowerCase())) {
return `<${node.tag}${allAttrs}>`;
@@ -1232,6 +1277,11 @@ function renderComponentNode(node: ViewNode, ctx: CompCtx): string {
function generateComponent(ast: PageAst): string {
const out: string[] = [];
const hasServerEach = viewHasServerEach(ast.view);
if (hasServerEach) {
out.push(`import { Buffer } from "node:buffer";`);
}
const effectiveProps =
ast.kind === "layout" && !ast.props.some((prop) => prop.name === "content")
@@ -1420,6 +1470,12 @@ function __wireRaw(v: any): string {
return String(v == null ? "" : v);
}`);
if (hasServerEach) {
out.push(`function __wrnexusEncodeLoopLocals(value: Record<string, any>): string {
return Buffer.from(JSON.stringify(value), "utf8").toString("base64");
}`);
}
if (needsScope) {
out.push(`function __wrnexusSerializeScopeValue(value: any): string {
if (value === undefined) {