release: WRNexusJS 0.5.0
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@wrnexus/compiler",
|
||||
"version": "0.4.0",
|
||||
"version": "0.5.0",
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"exports": {
|
||||
|
||||
@@ -1013,6 +1013,8 @@ const ${name} = async (ctx: any) => {${api.body}};`);
|
||||
interface CompCtx {
|
||||
/** State names — text referencing any of them stays a reactive client mustache. */
|
||||
stateNames: Set<string>;
|
||||
/** Component functions can read state and therefore make their callers reactive. */
|
||||
functionNames: Set<string>;
|
||||
/** Rewrite reserved-word prop/state identifiers to their safe const names. */
|
||||
resolveExpr: (expr: string) => string;
|
||||
/** `data-for` loop variables in scope — their mustaches stay literal for the
|
||||
@@ -1177,6 +1179,10 @@ function exprRefsState(expr: string, stateNames: Set<string>): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
function exprRefsComponentReactiveValue(expr: string, ctx: CompCtx): boolean {
|
||||
return exprRefsState(expr, ctx.stateNames) || exprRefsState(expr, ctx.functionNames);
|
||||
}
|
||||
|
||||
function viewHasEvents(nodes: ViewNode[]): boolean {
|
||||
return nodes.some((node) => {
|
||||
if (node.type === "text") return false;
|
||||
@@ -1244,7 +1250,7 @@ function compileText(raw: string, ctx: CompCtx): string {
|
||||
// Loop variable (from data-for): leave a literal client mustache — the
|
||||
// list renderer fills it per item; it has no server-side value.
|
||||
out += escLit(`{${expr}}`);
|
||||
} else if (exprRefsState(expr, ctx.stateNames)) {
|
||||
} else if (exprRefsComponentReactiveValue(expr, ctx)) {
|
||||
// State interpolation: bake the initial value AND keep it reactive via a
|
||||
// data-text span, so no-JS clients see the real value and hydration
|
||||
// updates it in place. `count` → `<span data-text="count">0</span>`.
|
||||
@@ -1450,7 +1456,7 @@ function renderComponentNode(node: ViewNode, ctx: CompCtx): string {
|
||||
if (isHtmlBooleanAttribute(a.name)) {
|
||||
const expression = wholeAttributeExpression(a.value);
|
||||
if (expression) {
|
||||
const referencesState = exprRefsState(a.value, ctx.stateNames);
|
||||
const referencesState = exprRefsComponentReactiveValue(a.value, ctx);
|
||||
const referencesLoopVariable = elementContext.loopVars
|
||||
? exprRefsState(a.value, elementContext.loopVars)
|
||||
: false;
|
||||
@@ -1472,7 +1478,7 @@ function renderComponentNode(node: ViewNode, ctx: CompCtx): string {
|
||||
|
||||
const rendered = ` ${a.name}="${compileAttrValue(a.value, elementContext)}"`;
|
||||
|
||||
const referencesState = exprRefsState(a.value, ctx.stateNames);
|
||||
const referencesState = exprRefsComponentReactiveValue(a.value, ctx);
|
||||
|
||||
const referencesLoopVariable = elementContext.loopVars
|
||||
? exprRefsState(a.value, elementContext.loopVars)
|
||||
@@ -1513,7 +1519,7 @@ function renderComponentNode(node: ViewNode, ctx: CompCtx): string {
|
||||
|
||||
const staticClassValue = staticClasses.join(" ");
|
||||
|
||||
const classReferencesState = exprRefsState(staticClassValue, ctx.stateNames);
|
||||
const classReferencesState = exprRefsComponentReactiveValue(staticClassValue, ctx);
|
||||
const classReferencesLoopVariable = elementContext.loopVars
|
||||
? exprRefsState(staticClassValue, elementContext.loopVars)
|
||||
: false;
|
||||
@@ -1569,10 +1575,6 @@ function generateComponent(ast: PageAst): string {
|
||||
if (ast.imports.length > 0) out.push(ast.imports.join("\n"));
|
||||
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")
|
||||
? [
|
||||
@@ -1608,6 +1610,14 @@ function generateComponent(ast: PageAst): string {
|
||||
};
|
||||
const ctx: CompCtx = {
|
||||
stateNames,
|
||||
functionNames: new Set(
|
||||
ast.functions.flatMap((body) => {
|
||||
return Array.from(
|
||||
body.matchAll(/(?:async\s+)?function\s+([A-Za-z_$][\w$]*)\s*\(/g),
|
||||
(match) => match[1]!,
|
||||
);
|
||||
}),
|
||||
),
|
||||
resolveExpr,
|
||||
eventNames: ast.events.map((event) => event.name),
|
||||
};
|
||||
@@ -1653,6 +1663,10 @@ function generateComponent(ast: PageAst): string {
|
||||
viewHasEvents(ast.view) ||
|
||||
behavior !== null);
|
||||
|
||||
if (hasServerEach || needsScope) {
|
||||
out.push(`import { Buffer as __WrnexusBuffer } from "node:buffer";`);
|
||||
}
|
||||
|
||||
const scopeKeys = [
|
||||
...effectiveProps.map((prop) => prop.name),
|
||||
...ast.states.map((state) => state.name),
|
||||
@@ -1690,18 +1704,20 @@ function generateComponent(ast: PageAst): string {
|
||||
const returnExpr = needsScope
|
||||
? "`" +
|
||||
styleTag +
|
||||
`<div data-scope="\${__scope}"${behaviorAttr}${hydrationAttribute(ast)}>` +
|
||||
`<div data-scope="\${__scope}" data-wrn-scope="\${__scopePayload}"${behaviorAttr}${hydrationAttribute(ast)}>` +
|
||||
viewCode +
|
||||
"</div>`"
|
||||
: "`" + styleTag + viewCode + "`";
|
||||
|
||||
const scopeLine =
|
||||
needsScope && scopeKeys.length > 0
|
||||
? ` const __scope = __wrnexusScopeDecl({ ${scopeKeys
|
||||
? ` const __scopeState = { ${scopeKeys
|
||||
.map((key) => `${JSON.stringify(key)}: ${nameRefs.get(key)}`)
|
||||
.join(", ")} });\n`
|
||||
.join(
|
||||
", ",
|
||||
)} };\n const __scope = __wrnexusScopeDecl(__scopeState);\n const __scopePayload = __WrnexusBuffer.from(JSON.stringify(__scopeState), "utf8").toString("base64");\n`
|
||||
: needsScope
|
||||
? ` const __scope = "";\n`
|
||||
? ` const __scopeState = {};\n const __scope = "";\n const __scopePayload = __WrnexusBuffer.from("{}", "utf8").toString("base64");\n`
|
||||
: "";
|
||||
|
||||
if (ast.kind === "layout") {
|
||||
@@ -1900,7 +1916,7 @@ function __wireRaw(v: any): string {
|
||||
|
||||
if (hasServerEach) {
|
||||
out.push(`function __wrnexusEncodeLoopLocals(value: Record<string, any>): string {
|
||||
return Buffer.from(JSON.stringify(value), "utf8").toString("base64");
|
||||
return __WrnexusBuffer.from(JSON.stringify(value), "utf8").toString("base64");
|
||||
}`);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user