release: WRNexusJS 0.3.2

This commit is contained in:
2026-07-22 20:10:44 +05:30
parent 304819dfe9
commit 58ba2f2046
63 changed files with 242 additions and 121 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/ai", "name": "@wrnexus/ai",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.", "description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.",
"license": "MIT", "license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/authz", "name": "@wrnexus/authz",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/authz — part of the WrNexus framework.", "description": "@wrnexus/authz — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+13 -13
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/cli", "name": "@wrnexus/cli",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/cli — part of the WrNexus framework.", "description": "@wrnexus/cli — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
@@ -28,18 +28,18 @@
"wrnexus": "./dist/index.js" "wrnexus": "./dist/index.js"
}, },
"dependencies": { "dependencies": {
"@wrnexus/core": "^0.3.1", "@wrnexus/core": "^0.3.2",
"@wrnexus/router": "^0.3.1", "@wrnexus/router": "^0.3.2",
"@wrnexus/csr": "^0.3.1", "@wrnexus/csr": "^0.3.2",
"@wrnexus/compiler": "^0.3.1", "@wrnexus/compiler": "^0.3.2",
"@wrnexus/styles": "^0.3.1", "@wrnexus/styles": "^0.3.2",
"@wrnexus/dev-server": "^0.3.1", "@wrnexus/dev-server": "^0.3.2",
"@wrnexus/ui": "^0.3.1", "@wrnexus/ui": "^0.3.2",
"@wrnexus/validation": "^0.3.1", "@wrnexus/validation": "^0.3.2",
"@wrnexus/i18n": "^0.3.1", "@wrnexus/i18n": "^0.3.2",
"@wrnexus/db": "^0.3.1", "@wrnexus/db": "^0.3.2",
"@wrnexus/plugin": "^0.3.1", "@wrnexus/plugin": "^0.3.2",
"@wrnexus/syntax": "^0.3.1" "@wrnexus/syntax": "^0.3.2"
}, },
"files": [ "files": [
"dist" "dist"
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/compiler", "name": "@wrnexus/compiler",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/compiler — part of the WrNexus framework.", "description": "@wrnexus/compiler — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
@@ -21,7 +21,7 @@
} }
}, },
"dependencies": { "dependencies": {
"@wrnexus/syntax": "^0.3.1" "@wrnexus/syntax": "^0.3.2"
}, },
"files": [ "files": [
"dist" "dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/core", "name": "@wrnexus/core",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/core — part of the WrNexus framework.", "description": "@wrnexus/core — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/csr", "name": "@wrnexus/csr",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/csr — part of the WrNexus framework.", "description": "@wrnexus/csr — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
@@ -21,7 +21,7 @@
} }
}, },
"dependencies": { "dependencies": {
"@wrnexus/core": "^0.3.1" "@wrnexus/core": "^0.3.2"
}, },
"files": [ "files": [
"dist" "dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/db", "name": "@wrnexus/db",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/db — part of the WrNexus framework.", "description": "@wrnexus/db — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+15 -15
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/dev-server", "name": "@wrnexus/dev-server",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/dev-server — part of the WrNexus framework.", "description": "@wrnexus/dev-server — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
@@ -25,20 +25,20 @@
} }
}, },
"dependencies": { "dependencies": {
"@wrnexus/core": "^0.3.1", "@wrnexus/core": "^0.3.2",
"@wrnexus/dev-toolbar": "^0.3.1", "@wrnexus/dev-toolbar": "^0.3.2",
"@wrnexus/router": "^0.3.1", "@wrnexus/router": "^0.3.2",
"@wrnexus/ssr": "^0.3.1", "@wrnexus/ssr": "^0.3.2",
"@wrnexus/csr": "^0.3.1", "@wrnexus/csr": "^0.3.2",
"@wrnexus/compiler": "^0.3.1", "@wrnexus/compiler": "^0.3.2",
"@wrnexus/styles": "^0.3.1", "@wrnexus/styles": "^0.3.2",
"@wrnexus/ui": "^0.3.1", "@wrnexus/ui": "^0.3.2",
"@wrnexus/validation": "^0.3.1", "@wrnexus/validation": "^0.3.2",
"@wrnexus/i18n": "^0.3.1", "@wrnexus/i18n": "^0.3.2",
"@wrnexus/db": "^0.3.1", "@wrnexus/db": "^0.3.2",
"@wrnexus/pubsub": "^0.3.1", "@wrnexus/pubsub": "^0.3.2",
"@wrnexus/uploader": "^0.3.1", "@wrnexus/uploader": "^0.3.2",
"@wrnexus/plugin": "^0.3.1" "@wrnexus/plugin": "^0.3.2"
}, },
"files": [ "files": [
"dist" "dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/dev-toolbar", "name": "@wrnexus/dev-toolbar",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/dev-toolbar — part of the WrNexus framework.", "description": "@wrnexus/dev-toolbar — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/encryption", "name": "@wrnexus/encryption",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/encryption — part of the WrNexus framework.", "description": "@wrnexus/encryption — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/helpers", "name": "@wrnexus/helpers",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "Safe convenience helpers for WrNexus request contexts and common application flows.", "description": "Safe convenience helpers for WrNexus request contexts and common application flows.",
"license": "MIT", "license": "MIT",
@@ -21,7 +21,7 @@
} }
}, },
"dependencies": { "dependencies": {
"@wrnexus/core": "^0.3.1" "@wrnexus/core": "^0.3.2"
}, },
"files": [ "files": [
"dist" "dist"
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/i18n", "name": "@wrnexus/i18n",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/i18n — part of the WrNexus framework.", "description": "@wrnexus/i18n — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
@@ -21,7 +21,7 @@
} }
}, },
"dependencies": { "dependencies": {
"@wrnexus/core": "^0.3.1" "@wrnexus/core": "^0.3.2"
}, },
"files": [ "files": [
"dist" "dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/jwt", "name": "@wrnexus/jwt",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/jwt — part of the WrNexus framework.", "description": "@wrnexus/jwt — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/mobile", "name": "@wrnexus/mobile",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/mobile — part of the WrNexus framework.", "description": "@wrnexus/mobile — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
@@ -21,7 +21,7 @@
} }
}, },
"dependencies": { "dependencies": {
"@wrnexus/native": "^0.3.1" "@wrnexus/native": "^0.3.2"
}, },
"files": [ "files": [
"dist" "dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/native", "name": "@wrnexus/native",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/native — part of the WrNexus framework.", "description": "@wrnexus/native — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/oauth", "name": "@wrnexus/oauth",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/oauth — part of the WrNexus framework.", "description": "@wrnexus/oauth — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/plugin", "name": "@wrnexus/plugin",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/plugin — part of the WrNexus framework.", "description": "@wrnexus/plugin — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
@@ -21,7 +21,7 @@
} }
}, },
"dependencies": { "dependencies": {
"@wrnexus/syntax": "^0.3.1" "@wrnexus/syntax": "^0.3.2"
}, },
"files": [ "files": [
"dist" "dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/pubsub", "name": "@wrnexus/pubsub",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/pubsub — part of the WrNexus framework.", "description": "@wrnexus/pubsub — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/queue", "name": "@wrnexus/queue",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/queue — part of the WrNexus framework.", "description": "@wrnexus/queue — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/reactive", "name": "@wrnexus/reactive",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/reactive — part of the WrNexus framework.", "description": "@wrnexus/reactive — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+3 -3
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/router", "name": "@wrnexus/router",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/router — part of the WrNexus framework.", "description": "@wrnexus/router — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
@@ -21,8 +21,8 @@
} }
}, },
"dependencies": { "dependencies": {
"@wrnexus/compiler": "^0.3.1", "@wrnexus/compiler": "^0.3.2",
"@wrnexus/core": "^0.3.1" "@wrnexus/core": "^0.3.2"
}, },
"files": [ "files": [
"dist" "dist"
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/ssr", "name": "@wrnexus/ssr",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/ssr — part of the WrNexus framework.", "description": "@wrnexus/ssr — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
@@ -21,7 +21,7 @@
} }
}, },
"dependencies": { "dependencies": {
"@wrnexus/core": "^0.3.1" "@wrnexus/core": "^0.3.2"
}, },
"files": [ "files": [
"dist" "dist"
+4 -4
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/styles", "name": "@wrnexus/styles",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/styles — part of the WrNexus framework.", "description": "@wrnexus/styles — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
@@ -21,9 +21,9 @@
} }
}, },
"dependencies": { "dependencies": {
"@wrnexus/uploader": "^0.3.1", "@wrnexus/uploader": "^0.3.2",
"@wrnexus/core": "^0.3.1", "@wrnexus/core": "^0.3.2",
"@wrnexus/plugin": "^0.3.1" "@wrnexus/plugin": "^0.3.2"
}, },
"files": [ "files": [
"dist" "dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/syntax", "name": "@wrnexus/syntax",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/syntax — part of the WrNexus framework.", "description": "@wrnexus/syntax — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/test", "name": "@wrnexus/test",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/test — part of the WrNexus framework.", "description": "@wrnexus/test — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/tracking", "name": "@wrnexus/tracking",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/tracking — part of the WrNexus framework.", "description": "@wrnexus/tracking — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/ui", "name": "@wrnexus/ui",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/ui — part of the WrNexus framework.", "description": "@wrnexus/ui — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
@@ -25,7 +25,7 @@
"./ui.css": "./ui.css" "./ui.css": "./ui.css"
}, },
"dependencies": { "dependencies": {
"@wrnexus/core": "^0.3.1" "@wrnexus/core": "^0.3.2"
}, },
"files": [ "files": [
"dist", "dist",
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/uploader", "name": "@wrnexus/uploader",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/uploader — part of the WrNexus framework.", "description": "@wrnexus/uploader — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
@@ -21,7 +21,7 @@
} }
}, },
"dependencies": { "dependencies": {
"@wrnexus/core": "^0.3.1" "@wrnexus/core": "^0.3.2"
}, },
"files": [ "files": [
"dist" "dist"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/validation", "name": "@wrnexus/validation",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"description": "@wrnexus/validation — part of the WrNexus framework.", "description": "@wrnexus/validation — part of the WrNexus framework.",
"license": "MIT", "license": "MIT",
+32 -19
View File
@@ -602,10 +602,11 @@ function generate(ast) {
seedScope[entry.name] = undefined; seedScope[entry.name] = undefined;
} }
} }
const reactiveNames = [...ast.states.map((entry) => entry.name), ...ast.computed.map((entry) => entry.name)]; const reactiveNames = [
const reactive = reactiveNames.length > 0 ...ast.states.map((entry) => entry.name),
? { stateNames: new Set(reactiveNames), scope: seedScope } ...ast.computed.map((entry) => entry.name),
: null; ];
const reactive = reactiveNames.length > 0 ? { stateNames: new Set(reactiveNames), scope: seedScope } : null;
const loops = []; const loops = [];
let html = ast.view let html = ast.view
.map((node) => renderNode(node, ssrBindings, csrBindings, apiBindings, loops, reactive)) .map((node) => renderNode(node, ssrBindings, csrBindings, apiBindings, loops, reactive))
@@ -613,7 +614,10 @@ function generate(ast) {
const styles = ast.styles.map((body) => body.trim()).filter(Boolean); const styles = ast.styles.map((body) => body.trim()).filter(Boolean);
const pageBehavior = ast.runtime === "server" ? null : componentBehavior(ast); const pageBehavior = ast.runtime === "server" ? null : componentBehavior(ast);
const needsClientRuntime = ast.runtime !== "server" && const needsClientRuntime = ast.runtime !== "server" &&
(ast.states.length > 0 || ast.computed.length > 0 || hasClientBehavior(ast.view) || pageBehavior !== null); (ast.states.length > 0 ||
ast.computed.length > 0 ||
hasClientBehavior(ast.view) ||
pageBehavior !== null);
if (needsClientRuntime) { if (needsClientRuntime) {
const scopePlaceholder = "__WRNEXUS_DYNAMIC_SCOPE__"; const scopePlaceholder = "__WRNEXUS_DYNAMIC_SCOPE__";
html = `<div data-scope="${scopePlaceholder}"${behaviorAttribute(pageBehavior)}${hydrationAttribute(ast)}>${html}</div>`; html = `<div data-scope="${scopePlaceholder}"${behaviorAttribute(pageBehavior)}${hydrationAttribute(ast)}>${html}</div>`;
@@ -721,7 +725,9 @@ function generate(ast) {
out.push(`export async function __wrnexusLoad(ctx: any) {\n${serverLoads.map((entry) => entry.body).join("\n")}\n}`); out.push(`export async function __wrnexusLoad(ctx: any) {\n${serverLoads.map((entry) => entry.body).join("\n")}\n}`);
} }
if (clientLoads.length > 0) { if (clientLoads.length > 0) {
out.push(`export const __wrnexusClientLoad = ${JSON.stringify(clientLoads.map((entry) => entry.body))};`); out.push(`export async function __wrnexusClientLoad(ctx: any) {
${clientLoads.map((entry) => entry.body).join("\n")}
}`);
} }
} }
if (ast.actions.length > 0) { if (ast.actions.length > 0) {
@@ -1200,7 +1206,10 @@ function generateComponent(ast) {
// no JavaScript at all. // no JavaScript at all.
const behavior = componentBehavior(ast); const behavior = componentBehavior(ast);
const needsScope = ast.runtime !== "server" && const needsScope = ast.runtime !== "server" &&
(ast.states.length > 0 || ast.computed.length > 0 || viewHasEvents(ast.view) || behavior !== null); (ast.states.length > 0 ||
ast.computed.length > 0 ||
viewHasEvents(ast.view) ||
behavior !== null);
const scopeKeys = [ const scopeKeys = [
...effectiveProps.map((prop) => prop.name), ...effectiveProps.map((prop) => prop.name),
...ast.states.map((state) => state.name), ...ast.states.map((state) => state.name),
@@ -1220,7 +1229,11 @@ function generateComponent(ast) {
decls.push(` const ${nameRefs.get(entry.name)} = (${resolveExpr(entry.expr)});`); decls.push(` const ${nameRefs.get(entry.name)} = (${resolveExpr(entry.expr)});`);
} }
const returnExpr = needsScope const returnExpr = needsScope
? "`" + styleTag + `<div data-scope="\${__scope}"${behaviorAttr}${hydrationAttribute(ast)}>` + viewCode + "</div>`" ? "`" +
styleTag +
`<div data-scope="\${__scope}"${behaviorAttr}${hydrationAttribute(ast)}>` +
viewCode +
"</div>`"
: "`" + styleTag + viewCode + "`"; : "`" + styleTag + viewCode + "`";
const scopeLine = needsScope && scopeKeys.length > 0 const scopeLine = needsScope && scopeKeys.length > 0
? ` const __scope = __wrnexusScopeDecl({ ${scopeKeys ? ` const __scope = __wrnexusScopeDecl({ ${scopeKeys
@@ -1948,7 +1961,7 @@ function astDiagnostics(ast, options) {
code: spec_ts_1.WRN_DIAGNOSTIC_CODES.accessibility, code: spec_ts_1.WRN_DIAGNOSTIC_CODES.accessibility,
severity: "warning", severity: "warning",
message: "Image is missing an alt attribute.", message: "Image is missing an alt attribute.",
hint: "Add alt text, or alt=\"\" for a decorative image.", hint: 'Add alt text, or alt="" for a decorative image.',
file: options.file, file: options.file,
}); });
} }
@@ -1958,7 +1971,7 @@ function astDiagnostics(ast, options) {
code: spec_ts_1.WRN_DIAGNOSTIC_CODES.serverInteractive, code: spec_ts_1.WRN_DIAGNOSTIC_CODES.serverInteractive,
severity: "error", severity: "error",
message: "A server-only WRN root cannot contain client state, effects, watches, or event handlers.", message: "A server-only WRN root cannot contain client state, effects, watches, or event handlers.",
hint: "Use runtime = \"universal\" or remove interactive behavior.", hint: 'Use runtime = "universal" or remove interactive behavior.',
file: options.file, file: options.file,
}); });
} }
@@ -1989,8 +2002,14 @@ function isRuntimeTarget(value) {
function formatDiagnostic(source, diagnostic) { function formatDiagnostic(source, diagnostic) {
const location = diagnostic.position const location = diagnostic.position
? `${diagnostic.file ?? "<inline .wrn>"}:${diagnostic.position.line}:${diagnostic.position.column}` ? `${diagnostic.file ?? "<inline .wrn>"}:${diagnostic.position.line}:${diagnostic.position.column}`
: diagnostic.file ?? "<inline .wrn>"; : (diagnostic.file ?? "<inline .wrn>");
const lines = [`${diagnostic.code} ${diagnostic.severity.toUpperCase()}`, "", diagnostic.message, "", location]; const lines = [
`${diagnostic.code} ${diagnostic.severity.toUpperCase()}`,
"",
diagnostic.message,
"",
location,
];
if (diagnostic.position) { if (diagnostic.position) {
const sourceLine = source.split(/\r?\n/)[diagnostic.position.line - 1] ?? ""; const sourceLine = source.split(/\r?\n/)[diagnostic.position.line - 1] ?? "";
lines.push("", sourceLine, `${" ".repeat(Math.max(0, diagnostic.position.column - 1))}^`); lines.push("", sourceLine, `${" ".repeat(Math.max(0, diagnostic.position.column - 1))}^`);
@@ -2829,13 +2848,7 @@ exports.WRN_ROOT_MEMBERS = [
"style", "style",
"functions", "functions",
]; ];
exports.WRN_HYDRATION_STRATEGIES = [ exports.WRN_HYDRATION_STRATEGIES = ["load", "idle", "visible", "interaction", "none"];
"load",
"idle",
"visible",
"interaction",
"none",
];
exports.WRN_RUNTIME_TARGETS = ["server", "client", "universal"]; exports.WRN_RUNTIME_TARGETS = ["server", "client", "universal"];
exports.WRN_DIAGNOSTIC_CODES = { exports.WRN_DIAGNOSTIC_CODES = {
parse: "WRN-PARSE-001", parse: "WRN-PARSE-001",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/ai", "name": "@wrnexus/ai",
"version": "0.3.1", "version": "0.3.2",
"private": true, "private": true,
"type": "module", "type": "module",
"description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.", "description": "Zero-dependency Claude (Anthropic) client for WrNexus apps.",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/authz", "name": "@wrnexus/authz",
"version": "0.3.1", "version": "0.3.2",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/cli", "name": "@wrnexus/cli",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"exports": { "exports": {
+8
View File
@@ -961,6 +961,14 @@ const MIGRATIONS: Migration[] = [
// CLI-only transaction fix. No generated application files require migration. // CLI-only transaction fix. No generated application files require migration.
}, },
}, },
{
version: "0.3.2",
id: "ssr-page-state-control-scope",
description: "Makes page state variables available to server-rendered if and each expressions.",
apply() {
// Compiler-only fix. Existing WRN source files require no migration.
},
},
]; ];
/** Release tooling uses this to require an explicit migration entry per version. */ /** Release tooling uses this to require an explicit migration entry per version. */
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/compiler", "name": "@wrnexus/compiler",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"exports": { "exports": {
+19 -2
View File
@@ -675,6 +675,20 @@ function hydrationId(ast: PageAst): string {
return `${ast.name}:${stableHash(shape)}`; return `${ast.name}:${stableHash(shape)}`;
} }
function isSafeGeneratedIdentifier(name: string): boolean {
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name);
}
function generateSsrStateAliases(stateNames: string[]): string {
const names = [...new Set(stateNames)].filter(isSafeGeneratedIdentifier);
if (!names.length) {
return "";
}
return `const { ${names.join(", ")} } = __state;\n`;
}
function hydrationAttribute(ast: PageAst): string { function hydrationAttribute(ast: PageAst): string {
const strategy = ast.hydrate ?? "load"; const strategy = ast.hydrate ?? "load";
return ` data-wrn-hydration="${attrEscape(hydrationId(ast))}" data-wrn-hydrate="${attrEscape(strategy)}" data-wrn-runtime="${attrEscape(ast.runtime ?? "universal")}"`; return ` data-wrn-hydration="${attrEscape(hydrationId(ast))}" data-wrn-hydrate="${attrEscape(strategy)}" data-wrn-runtime="${attrEscape(ast.runtime ?? "universal")}"`;
@@ -776,6 +790,9 @@ export function generate(ast: PageAst): string {
.map((state) => `${JSON.stringify(state.name)}: ${state.valueType ?? "unknown"}`) .map((state) => `${JSON.stringify(state.name)}: ${state.valueType ?? "unknown"}`)
.join("; ")} }` .join("; ")} }`
: "Record<string, never>"; : "Record<string, never>";
const ssrStateAliases = generateSsrStateAliases(ast.states.map((state) => state.name));
loops.forEach((code, idx) => { loops.forEach((code, idx) => {
body = body.replace(`\x00WRNEACH${idx}\x00`, () => code); body = body.replace(`\x00WRNEACH${idx}\x00`, () => code);
}); });
@@ -806,7 +823,7 @@ export function generate(ast: PageAst): string {
`export default async function ${ast.name}(ctx: any) { `export default async function ${ast.name}(ctx: any) {
${decls} ${decls}
const __state: ${stateType} = { ${dynamicStateScope} }; const __state: ${stateType} = { ${dynamicStateScope} };
${ssrStateAliases}
const __scopeValue = Object.entries(__state) const __scopeValue = Object.entries(__state)
.map(([key, value]) => { .map(([key, value]) => {
const encoded = const encoded =
@@ -834,7 +851,7 @@ export function generate(ast: PageAst): string {
out.push( out.push(
`export default function ${ast.name}(ctx: any) { `export default function ${ast.name}(ctx: any) {
const __state: ${stateType} = { ${dynamicStateScope} }; const __state: ${stateType} = { ${dynamicStateScope} };
${ssrStateAliases}
const __scopeValue = Object.entries(__state) const __scopeValue = Object.entries(__state)
.map(([key, value]) => { .map(([key, value]) => {
const encoded = const encoded =
+84 -1
View File
@@ -1,5 +1,5 @@
import { test, expect } from "bun:test"; import { test, expect } from "bun:test";
import { writeFileSync, mkdirSync } from "node:fs"; import { writeFileSync, mkdirSync, mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os"; import { tmpdir } from "node:os";
import { join } from "node:path"; import { join } from "node:path";
import { pathToFileURL } from "node:url"; import { pathToFileURL } from "node:url";
@@ -1105,3 +1105,86 @@ test("WRN 0.3 metadata, computed values, loaders, and actions compile additively
expect(output).toContain("export const __wrnexusActions"); expect(output).toContain("export const __wrnexusActions");
expect(output).toContain('data-wrn-hydrate="idle"'); expect(output).toContain('data-wrn-hydrate="idle"');
}); });
test("page state is available inside server-rendered if blocks", () => {
const source = `
page Pricing {
state billingCycle = "monthly"
view {
{#if billingCycle === "annual"}
<p>Annual</p>
{:else}
<p>Monthly</p>
{/if}
}
}
`;
const ast = parse(source);
const code = generate(ast);
expect(code).toContain("const { billingCycle } = __state;");
expect(code).toContain('billingCycle === "annual"');
});
test("page state SSR condition renders without ReferenceError", async () => {
const root = mkdtempSync(join(tmpdir(), "wrnexus-page-state-"));
const generatedFile = join(root, "pricing.generated.ts");
try {
const source = `
page Pricing {
state billingCycle = "monthly"
view {
{#if billingCycle === "annual"}
<p>Annual</p>
{:else}
<p>Monthly</p>
{/if}
}
}
`;
const code = generate(parse(source));
expect(code).toContain("const { billingCycle } = __state;");
expect(code).toContain('billingCycle === "annual"');
writeFileSync(generatedFile, code, "utf8");
const moduleUrl = pathToFileURL(generatedFile).href + `?test=${Date.now()}-${Math.random()}`;
const generatedModule = await import(moduleUrl);
const html = await generatedModule.default({});
expect(html).toContain("<p>Monthly</p>");
expect(html).not.toContain("<p>Annual</p>");
} finally {
rmSync(root, {
recursive: true,
force: true,
});
}
});
test("page state is declared for server-rendered control blocks", () => {
const source = `
page Pricing {
state billingCycle = "monthly"
view {
{#if billingCycle === "annual"}
<p>Annual</p>
{:else}
<p>Monthly</p>
{/if}
}
}
`;
const code = generate(parse(source));
expect(code).toContain("const { billingCycle } = __state;");
expect(code).toContain('billingCycle === "annual"');
});
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/core", "name": "@wrnexus/core",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"exports": { "exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/csr", "name": "@wrnexus/csr",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"exports": { "exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/db", "name": "@wrnexus/db",
"version": "0.3.1", "version": "0.3.2",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/dev-server", "name": "@wrnexus/dev-server",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"exports": { "exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/dev-toolbar", "name": "@wrnexus/dev-toolbar",
"version": "0.3.1", "version": "0.3.2",
"private": true, "private": true,
"type": "module", "type": "module",
"sideEffects": false, "sideEffects": false,
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/encryption", "name": "@wrnexus/encryption",
"version": "0.3.1", "version": "0.3.2",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/helpers", "name": "@wrnexus/helpers",
"version": "0.3.1", "version": "0.3.2",
"private": true, "private": true,
"type": "module", "type": "module",
"description": "Safe convenience helpers for WrNexus request contexts and common application flows.", "description": "Safe convenience helpers for WrNexus request contexts and common application flows.",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/i18n", "name": "@wrnexus/i18n",
"version": "0.3.1", "version": "0.3.2",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/jwt", "name": "@wrnexus/jwt",
"version": "0.3.1", "version": "0.3.2",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/mobile", "name": "@wrnexus/mobile",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"exports": { "exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/native", "name": "@wrnexus/native",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"exports": { "exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/oauth", "name": "@wrnexus/oauth",
"version": "0.3.1", "version": "0.3.2",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/plugin", "name": "@wrnexus/plugin",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"exports": { "exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/pubsub", "name": "@wrnexus/pubsub",
"version": "0.3.1", "version": "0.3.2",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/queue", "name": "@wrnexus/queue",
"version": "0.3.1", "version": "0.3.2",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/reactive", "name": "@wrnexus/reactive",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"exports": { "exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/router", "name": "@wrnexus/router",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"exports": { "exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/ssr", "name": "@wrnexus/ssr",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"exports": { "exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/styles", "name": "@wrnexus/styles",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"exports": { "exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/syntax", "name": "@wrnexus/syntax",
"version": "0.3.1", "version": "0.3.2",
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
"exports": { "exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/test", "name": "@wrnexus/test",
"version": "0.3.1", "version": "0.3.2",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/tracking", "name": "@wrnexus/tracking",
"version": "0.3.1", "version": "0.3.2",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/ui", "name": "@wrnexus/ui",
"version": "0.3.1", "version": "0.3.2",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/uploader", "name": "@wrnexus/uploader",
"version": "0.3.1", "version": "0.3.2",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@wrnexus/validation", "name": "@wrnexus/validation",
"version": "0.3.1", "version": "0.3.2",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/index.ts", "main": "src/index.ts",
+1 -1
View File
@@ -1,7 +1,7 @@
import { existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs"; import { existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path"; import { join } from "node:path";
const version = "0.3.1"; const version = "0.3.2";
const dependencyGroups = [ const dependencyGroups = [
"dependencies", "dependencies",