complete framework remediation validation

This commit is contained in:
2026-08-09 14:39:22 +05:30
parent 905cbce0c1
commit 51286d0fa3
21 changed files with 898 additions and 1474 deletions
+137 -61
View File
@@ -1,6 +1,6 @@
"use strict";
// Generated by scripts/build-editor-compiler.mjs. Do not edit directly.
// WRN editor compiler source hash: 451706f47a7734fd5808cdeeb5786e1b97a183afec98db99fc041369eb16a205
// WRN editor compiler source hash: 4f9249b868459eb792fcd6dc7814e440bd2c0ad6d08f1dec947939dc48db92b3
// WRN editor compiler generator hash: c71e7fe4258c97b73b384ff14b321f0cf0b30cc2ed0322f5f84b04e757159b18
// Generated with TypeScript: 5.9.3
const __nodeRequire = require;
@@ -558,7 +558,7 @@ function browserModuleRequired(ast) {
const functions = ast.runtimeFunctions.filter((fn) => ["legacy", "client", "shared"].includes(fn.runtime));
return functions.length > 0 || selectedBrowserImports(ast, functions).length > 0;
}
function functionEntry(ast, fn, availableFunctions) {
function _functionEntry(ast, fn, availableFunctions) {
const parameterNames = new Set(fn.parameters.map((parameter) => parameter.name));
/*
* Names the function body declares for itself.
@@ -608,32 +608,42 @@ function functionEntry(ast, fn, availableFunctions) {
const syncStateFromContext = stateNames
.map((name) => `${name} = context.state.${name};`)
.join(" ");
const peerAliases = functionAliases
.map((name) => {
const call = `context.functions[${JSON.stringify(name)}](...__wrnexusPeerArgs)`;
if (!stateNames.length) {
return `const ${name} = (...__wrnexusPeerArgs) => ${call};`;
}
return `const ${name} = (...__wrnexusPeerArgs) => {
${syncStateToContext}
let __wrnexusPeerResult;
const peerAliases = !stateNames.length
? functionAliases
.map((name) => `const ${name} = (...__wrnexusPeerArgs) => context.functions[${JSON.stringify(name)}](...__wrnexusPeerArgs);`)
.join("\n")
: `const __wrnexusFlush = () => { ${syncStateToContext} };
const __wrnexusRestore = () => { ${syncStateFromContext} };
const __wrnexusPeer = (name, args) => {
__wrnexusFlush();
let result;
try {
__wrnexusPeerResult = ${call};
} catch (__wrnexusPeerError) {
${syncStateFromContext}
throw __wrnexusPeerError;
result = context.functions[name](...args);
} catch (error) {
__wrnexusRestore();
throw error;
}
if (__wrnexusPeerResult && typeof __wrnexusPeerResult.then === "function") {
return Promise.resolve(__wrnexusPeerResult).finally(() => { ${syncStateFromContext} });
if (result && typeof result.then === "function") {
return Promise.resolve(result).finally(__wrnexusRestore);
}
${syncStateFromContext}
return __wrnexusPeerResult;
};`;
})
.join("\n");
__wrnexusRestore();
return result;
};
${functionAliases.map((name) => `const ${name} = (...__wrnexusPeerArgs) => __wrnexusPeer(${JSON.stringify(name)}, __wrnexusPeerArgs);`).join("\n")}`;
const copyBack = stateNames
.map((name) => `if (!Object.is(${name}, __wrnexusInitialState[${JSON.stringify(name)}])) context.state.${name} = ${name};`)
.join("\n");
const commitBinding = stateNames.length
? `const __wrnexusCommit = () => { ${copyBack} };
${!parameterNames.has("commit") && !declaredLocals.has("commit") && !functionAliases.includes("commit") ? "const commit = __wrnexusCommit;" : ""}
${!parameterNames.has("setTimeout") &&
!declaredLocals.has("setTimeout") &&
!functionAliases.includes("setTimeout")
? `const setTimeout = (callback, delay, ...args) => globalThis.setTimeout(() => {
try { return callback(...args); } finally { __wrnexusCommit(); }
}, delay);`
: ""}`
: "";
const body = (0, syntax_1.eraseFunctionTypes)(fn.body);
const runtimeBindings = [
!parameterNames.has("output") ? "const output = context.output;" : "",
@@ -647,12 +657,13 @@ function functionEntry(ast, fn, availableFunctions) {
${initialStateSnapshot}
${stateAliases}
${propAliases}
${commitBinding}
${peerAliases}
${runtimeBindings}
try {
${body}
} finally {
${copyBack}
${stateNames.length ? "__wrnexusCommit();" : ""}
}
}`;
}
@@ -663,22 +674,74 @@ function generateBrowserModule(ast) {
const selectedImports = selectedBrowserImports(ast, functions);
const imports = selectedImports.map((entry) => entry.code).join("\n");
const importedBindings = [...new Set(selectedImports.flatMap((entry) => entry.bindings))];
const sharedState = state.filter((name) => safeIdentifier(name) && !RUNTIME_BINDINGS.has(name));
const sharedProps = ast.props
.map((entry) => entry.name)
.filter((name) => safeIdentifier(name) && !RUNTIME_BINDINGS.has(name) && !sharedState.includes(name));
const callableAliases = functionNames.filter((name) => safeIdentifier(name) &&
!RUNTIME_BINDINGS.has(name) &&
!sharedState.includes(name) &&
!sharedProps.includes(name));
const sharedCommit = sharedState.map((name) => `context.state.${name} = ${name};`).join(" ");
const sharedRestore = [
...sharedState.map((name) => `${name} = context.state.${name};`),
...sharedProps.map((name) => `${name} = context.props.${name};`),
].join(" ");
const hasAuthoredCommit = callableAliases.includes("commit");
const hasAuthoredSetTimeout = callableAliases.includes("setTimeout");
const implementations = functions
.map((fn) => {
const parameters = fn.parameters.map((parameter) => parameter.name).join(", ");
return `${JSON.stringify(fn.name)}: ${fn.async ? "async " : ""}function(${parameters}) {
try { ${(0, syntax_1.eraseFunctionTypes)(fn.body)} } finally { __wrnexusCommit(); }
}`;
})
.join(",\n");
return `// generated WRNexusJS browser module for ${ast.name}
${imports}
export const __wrnexusClientFunctions = {
${functions.map((fn) => ` ${functionEntry(ast, fn, functionNames)}`).join(",\n")}
${functions
.map((fn) => ` ${JSON.stringify(fn.name)}: (context, ...args) => __wrnexusBindings(context)[${JSON.stringify(fn.name)}](...args)`)
.join(",\n")}
};
export const __wrnexusClientState = ${JSON.stringify(state)};
export const __wrnexusOutputs = ${JSON.stringify(ast.outputs)};
export const __wrnexusImportedBindings = { ${importedBindings.join(", ")} };
export function bindClientScope(context) {
function __wrnexusCreateClientFunctions(context) {
${sharedState.length ? `let { ${sharedState.join(", ")} } = context.state;` : ""}
${sharedProps.length ? `let { ${sharedProps.join(", ")} } = context.props;` : ""}
const output = context.output;
const server = context.server;
const props = context.props;
const refs = context.refs;
const __wrnexusCommit = () => { ${sharedCommit} };
const __wrnexusRestore = () => { ${sharedRestore} };
${!hasAuthoredCommit ? "const commit = __wrnexusCommit;" : ""}
${!hasAuthoredSetTimeout
? `const setTimeout = (callback, delay, ...args) => globalThis.setTimeout(() => {
try { return callback(...args); } finally { __wrnexusCommit(); }
}, delay);`
: ""}
const implementations = {
${implementations}
};
${callableAliases.map((name) => `const ${name} = (...args) => implementations[${JSON.stringify(name)}](...args);`).join("\n ")}
const functions = {};
const scopedContext = { ...context, functions };
for (const [name, handler] of Object.entries(__wrnexusClientFunctions)) {
functions[name] = (...args) => handler(scopedContext, ...args);
for (const name of Object.keys(implementations)) {
functions[name] = (...args) => {
__wrnexusRestore();
return implementations[name](...args);
};
}
return functions;
}
function __wrnexusBindings(context) {
return context.__wrnexusBoundFunctions ||
(context.__wrnexusBoundFunctions = __wrnexusCreateClientFunctions(context));
}
export function bindClientScope(context) {
return __wrnexusBindings(context);
}
`;
}
@@ -1282,13 +1345,12 @@ function renderNestedComponentInvocation(node, ctx) {
? `\${__wireProp(${ctx.resolveExpr(wholeExpression)})}`
: compileAttrValue(attr.value, ctx);
const rendered = ` ${attr.name}="${compiledValue}"`;
if (wholeExpression ||
!attr.value.includes("{") ||
!exprRefsState(attr.value, ctx.stateNames)) {
if (!attr.value.includes("{") ||
(!exprRefsState(attr.value, ctx.stateNames) && !exprRefsState(attr.value, ctx.propNames))) {
return rendered;
}
const marker = attrEscape(JSON.stringify([attr.name, attr.value]));
return rendered + ` data-wrn-bind-${bindIndex++}="${escLit(marker)}"`;
return rendered + ` data-wrn-prop-bind-${bindIndex++}="${escLit(marker)}"`;
})
.join("");
const loops = loopVarsOf(node);
@@ -2178,7 +2240,9 @@ function exprRefsState(expr, stateNames) {
return false;
}
function exprRefsComponentReactiveValue(expr, ctx) {
return exprRefsState(expr, ctx.stateNames) || exprRefsState(expr, ctx.functionNames);
return (exprRefsState(expr, ctx.stateNames) ||
exprRefsState(expr, ctx.propNames) ||
exprRefsState(expr, ctx.functionNames));
}
function viewHasEvents(nodes) {
return nodes.some((node) => {
@@ -2242,6 +2306,9 @@ function compileText(raw, ctx) {
// list renderer fills it per item; it has no server-side value.
out += escLit(`{${expr}}`);
}
else if (expr === "content") {
out += `\${__wireRaw(${ctx.resolveExpr(expr)})}`;
}
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
@@ -2251,9 +2318,6 @@ function compileText(raw, ctx) {
`\${__wireHtml(${ctx.resolveExpr(expr)})}` +
escLit(`</span>`);
}
else if (expr === "content") {
out += `\${__wireRaw(${ctx.resolveExpr(expr)})}`;
}
else {
out += `\${__wireHtml(${ctx.resolveExpr(expr)})}`;
}
@@ -2593,6 +2657,7 @@ function generateComponent(ast) {
};
const ctx = {
stateNames,
propNames: new Set(effectiveProps.map((entry) => entry.name)),
functionNames: new Set(ast.runtimeFunctions.filter((fn) => fn.runtime !== "server").map((fn) => fn.name)),
resolveExpr,
eventNames: publicOutputNames(ast),
@@ -2610,12 +2675,12 @@ function generateComponent(ast) {
.join("");
const styles = ast.styles.map((body) => body.trim()).filter(Boolean);
const styleTag = escLit(localStyleTag(ast, styles));
// A component needs a reactive scope only when it has state or event handlers.
// Prop-driven text/attributes are baked server-side, so static components ship
// no JavaScript at all.
// Props remain server-rendered and also become signals so a parent can drive
// a mounted child after hydration.
const behavior = componentBehavior(ast);
const needsScope = ast.runtime !== "server" &&
(browserStates.length > 0 ||
(effectiveProps.length > 0 ||
browserStates.length > 0 ||
ast.computed.length > 0 ||
viewHasEvents(ast.view) ||
behavior !== null);
@@ -2632,7 +2697,7 @@ function generateComponent(ast) {
if (prop.required) {
decls.push(` if (__p[${JSON.stringify(prop.name)}] === undefined) throw new TypeError(${JSON.stringify(`${ast.name} requires prop '${prop.name}' (${prop.valueType ?? "unknown"})`)});`);
}
decls.push(` const ${nameRefs.get(prop.name)}: ${prop.valueType ?? "any"} = __coerce(__p[${JSON.stringify(prop.name)}], (${resolveExpr(prop.default)}), ${JSON.stringify((0, types_ts_1.runtimeTypeOf)(prop.valueType))});`);
decls.push(` const ${nameRefs.get(prop.name)}: ${prop.valueType ?? "any"} = __coerce(__p[${JSON.stringify(prop.name)}], (${resolveExpr(prop.default)}), ${JSON.stringify((0, types_ts_1.runtimeTypeOf)(prop.valueType))}, ${JSON.stringify(prop.name)});`);
}
if (!effectiveProps.some((prop) => prop.name === "attrs")) {
decls.push(` const __attrs = __restProps(__p, new Set(${JSON.stringify(effectiveProps.map((prop) => prop.name))}));`);
@@ -2697,7 +2762,7 @@ function generateComponent(ast) {
.map((output) => ` ${JSON.stringify(output.name)}(${output.payload ? `${output.payload.name}${output.payload.optional ? "?" : ""}: ${output.payload.valueType}` : ""}): void;`)
.join("\n")}\n}`);
}
out.push(`function __coerce(v: any, def: any, declared: string = "unknown"): any {
out.push(`function __coerce(v: any, def: any, declared: string = "unknown", propName: string = "prop"): any {
if (v === undefined || v === null) {
return def;
}
@@ -2722,14 +2787,14 @@ function generateComponent(ast) {
if (typeof v === "string") {
try {
const parsed = JSON.parse(v);
return Array.isArray(parsed) ? parsed : def;
if (!Array.isArray(parsed)) throw new TypeError("Expected an array prop '" + propName + "'");
return parsed;
} catch {
if (declared === "array") throw new TypeError("Expected an array prop");
return def;
throw new TypeError("Expected an array prop '" + propName + "'");
}
}
return def;
throw new TypeError("Expected an array prop '" + propName + "'");
}
if (declared === "object" || (def !== null && typeof def === "object")) {
@@ -2745,20 +2810,16 @@ function generateComponent(ast) {
try {
const parsed = JSON.parse(v);
return (
parsed !== null &&
typeof parsed === "object" &&
!Array.isArray(parsed)
)
? parsed
: def;
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
throw new TypeError("Expected an object prop '" + propName + "'");
}
return parsed;
} catch {
if (declared === "object") throw new TypeError("Expected an object prop");
return def;
throw new TypeError("Expected an object prop '" + propName + "'");
}
}
return def;
throw new TypeError("Expected an object prop '" + propName + "'");
}
if (declared === "bigint") return BigInt(v);
@@ -2828,10 +2889,12 @@ function __wireSpreadAttrs(value: any): string {
lowerName === "style" ||
lowerName === "slot" ||
lowerName === "data-component" ||
// Internal markers must not leak through a spread -- except the
// parent's output handlers, whose whole job is to ride from the mount
// onto the view root so the mounting scope can bind them there.
(lowerName.startsWith("data-wrn") && !lowerName.startsWith("data-wrn-out-"))
// 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;
}
@@ -5634,7 +5697,12 @@ function parse(source) {
// props { name: Type = <default>; @event name = function }
lx.next();
expect("lbrace");
while (lx.peek().type !== "rbrace") {
while (true) {
if (lx.startsWithBlockComment()) {
throw new ParseError("Block comments are not allowed inside props {}; use // line comments instead", "WRN-PROPS-BLOCK-COMMENT");
}
if (lx.peek().type === "rbrace")
break;
const t = lx.peek();
if (t.type === "eof")
throw new ParseError("Unexpected end of input inside props");
@@ -6013,6 +6081,9 @@ function parse(source) {
}
expect("rbrace");
const declaredStates = new Set(states.map((state) => state.name));
if (declaredStates.has("page")) {
throw new ParseError("State name 'page' collides with the WRN 'page' keyword; choose another state name", "WRN-STATE-RESERVED-NAME");
}
for (const watcher of watches) {
if (!declaredStates.has(watcher.state)) {
throw new ParseError(`Cannot watch undeclared state '${watcher.state}'`);
@@ -6543,6 +6614,11 @@ class Lexer {
break;
}
}
/** True when the next non-trivia characters open a block comment. */
startsWithBlockComment() {
this.skipTrivia();
return this.src[this.pos] === "/" && this.src[this.pos + 1] === "*";
}
/** Read and consume the next structural token. */
next() {
this.skipTrivia();
+112 -54
View File
@@ -1,4 +1,4 @@
// WRN editor extension source hash: 6165420f37af57e441086efeb6b25528f72e77a39abb2c76ca5bc8748dd90c2f
// WRN editor extension source hash: c09cc127dcc7fbae562648b09435fb96134c18e63ba21d7a4b476b916f4a8256
// WRN editor extension generator hash: 456d1d614e44e5fb1f19b784176c09cf2ade9b64ef73a17934c2698150b62728
"use strict";
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
@@ -23202,7 +23202,7 @@ ${(0, codegen_ts_1.generate)(ast)}`,
const functions = ast.runtimeFunctions.filter((fn) => ["legacy", "client", "shared"].includes(fn.runtime));
return functions.length > 0 || selectedBrowserImports(ast, functions).length > 0;
}
function functionEntry(ast, fn, availableFunctions) {
function _functionEntry(ast, fn, availableFunctions) {
const parameterNames = new Set(fn.parameters.map((parameter) => parameter.name));
const declaredLocals = new Set;
for (const match of fn.body.matchAll(/\b(?:var|let|const)\s+([A-Za-z_$][\w$]*)|\bfunction\s+([A-Za-z_$][\w$]*)/g)) {
@@ -23220,30 +23220,33 @@ ${(0, codegen_ts_1.generate)(ast)}`,
const propAliases = propNames.length ? `const { ${propNames.join(", ")} } = context.props;` : "";
const syncStateToContext = stateNames.map((name) => `context.state.${name} = ${name};`).join(" ");
const syncStateFromContext = stateNames.map((name) => `${name} = context.state.${name};`).join(" ");
const peerAliases = functionAliases.map((name) => {
const call = `context.functions[${JSON.stringify(name)}](...__wrnexusPeerArgs)`;
if (!stateNames.length) {
return `const ${name} = (...__wrnexusPeerArgs) => ${call};`;
}
return `const ${name} = (...__wrnexusPeerArgs) => {
${syncStateToContext}
let __wrnexusPeerResult;
const peerAliases = !stateNames.length ? functionAliases.map((name) => `const ${name} = (...__wrnexusPeerArgs) => context.functions[${JSON.stringify(name)}](...__wrnexusPeerArgs);`).join(`
`) : `const __wrnexusFlush = () => { ${syncStateToContext} };
const __wrnexusRestore = () => { ${syncStateFromContext} };
const __wrnexusPeer = (name, args) => {
__wrnexusFlush();
let result;
try {
__wrnexusPeerResult = ${call};
} catch (__wrnexusPeerError) {
${syncStateFromContext}
throw __wrnexusPeerError;
result = context.functions[name](...args);
} catch (error) {
__wrnexusRestore();
throw error;
}
if (__wrnexusPeerResult && typeof __wrnexusPeerResult.then === "function") {
return Promise.resolve(__wrnexusPeerResult).finally(() => { ${syncStateFromContext} });
if (result && typeof result.then === "function") {
return Promise.resolve(result).finally(__wrnexusRestore);
}
${syncStateFromContext}
return __wrnexusPeerResult;
};`;
}).join(`
`);
__wrnexusRestore();
return result;
};
${functionAliases.map((name) => `const ${name} = (...__wrnexusPeerArgs) => __wrnexusPeer(${JSON.stringify(name)}, __wrnexusPeerArgs);`).join(`
`)}`;
const copyBack = stateNames.map((name) => `if (!Object.is(${name}, __wrnexusInitialState[${JSON.stringify(name)}])) context.state.${name} = ${name};`).join(`
`);
const commitBinding = stateNames.length ? `const __wrnexusCommit = () => { ${copyBack} };
${!parameterNames.has("commit") && !declaredLocals.has("commit") && !functionAliases.includes("commit") ? "const commit = __wrnexusCommit;" : ""}
${!parameterNames.has("setTimeout") && !declaredLocals.has("setTimeout") && !functionAliases.includes("setTimeout") ? `const setTimeout = (callback, delay, ...args) => globalThis.setTimeout(() => {
try { return callback(...args); } finally { __wrnexusCommit(); }
}, delay);` : ""}` : "";
const body = (0, syntax_1.eraseFunctionTypes)(fn.body);
const runtimeBindings = [
!parameterNames.has("output") ? "const output = context.output;" : "",
@@ -23256,12 +23259,13 @@ ${(0, codegen_ts_1.generate)(ast)}`,
${initialStateSnapshot}
${stateAliases}
${propAliases}
${commitBinding}
${peerAliases}
${runtimeBindings}
try {
${body}
} finally {
${copyBack}
${stateNames.length ? "__wrnexusCommit();" : ""}
}
}`;
}
@@ -23273,23 +23277,66 @@ ${(0, codegen_ts_1.generate)(ast)}`,
const imports = selectedImports.map((entry) => entry.code).join(`
`);
const importedBindings = [...new Set(selectedImports.flatMap((entry) => entry.bindings))];
const sharedState = state.filter((name) => safeIdentifier(name) && !RUNTIME_BINDINGS.has(name));
const sharedProps = ast.props.map((entry) => entry.name).filter((name) => safeIdentifier(name) && !RUNTIME_BINDINGS.has(name) && !sharedState.includes(name));
const callableAliases = functionNames.filter((name) => safeIdentifier(name) && !RUNTIME_BINDINGS.has(name) && !sharedState.includes(name) && !sharedProps.includes(name));
const sharedCommit = sharedState.map((name) => `context.state.${name} = ${name};`).join(" ");
const sharedRestore = [
...sharedState.map((name) => `${name} = context.state.${name};`),
...sharedProps.map((name) => `${name} = context.props.${name};`)
].join(" ");
const hasAuthoredCommit = callableAliases.includes("commit");
const hasAuthoredSetTimeout = callableAliases.includes("setTimeout");
const implementations = functions.map((fn) => {
const parameters = fn.parameters.map((parameter) => parameter.name).join(", ");
return `${JSON.stringify(fn.name)}: ${fn.async ? "async " : ""}function(${parameters}) {
try { ${(0, syntax_1.eraseFunctionTypes)(fn.body)} } finally { __wrnexusCommit(); }
}`;
}).join(`,
`);
return `// generated WRNexusJS browser module for ${ast.name}
${imports}
export const __wrnexusClientFunctions = {
${functions.map((fn) => ` ${functionEntry(ast, fn, functionNames)}`).join(`,
${functions.map((fn) => ` ${JSON.stringify(fn.name)}: (context, ...args) => __wrnexusBindings(context)[${JSON.stringify(fn.name)}](...args)`).join(`,
`)}
};
export const __wrnexusClientState = ${JSON.stringify(state)};
export const __wrnexusOutputs = ${JSON.stringify(ast.outputs)};
export const __wrnexusImportedBindings = { ${importedBindings.join(", ")} };
export function bindClientScope(context) {
function __wrnexusCreateClientFunctions(context) {
${sharedState.length ? `let { ${sharedState.join(", ")} } = context.state;` : ""}
${sharedProps.length ? `let { ${sharedProps.join(", ")} } = context.props;` : ""}
const output = context.output;
const server = context.server;
const props = context.props;
const refs = context.refs;
const __wrnexusCommit = () => { ${sharedCommit} };
const __wrnexusRestore = () => { ${sharedRestore} };
${!hasAuthoredCommit ? "const commit = __wrnexusCommit;" : ""}
${!hasAuthoredSetTimeout ? `const setTimeout = (callback, delay, ...args) => globalThis.setTimeout(() => {
try { return callback(...args); } finally { __wrnexusCommit(); }
}, delay);` : ""}
const implementations = {
${implementations}
};
${callableAliases.map((name) => `const ${name} = (...args) => implementations[${JSON.stringify(name)}](...args);`).join(`
`)}
const functions = {};
const scopedContext = { ...context, functions };
for (const [name, handler] of Object.entries(__wrnexusClientFunctions)) {
functions[name] = (...args) => handler(scopedContext, ...args);
for (const name of Object.keys(implementations)) {
functions[name] = (...args) => {
__wrnexusRestore();
return implementations[name](...args);
};
}
return functions;
}
function __wrnexusBindings(context) {
return context.__wrnexusBoundFunctions ||
(context.__wrnexusBoundFunctions = __wrnexusCreateClientFunctions(context));
}
export function bindClientScope(context) {
return __wrnexusBindings(context);
}
`;
}
},
@@ -23719,11 +23766,11 @@ export function bindClientScope(context) {
const wholeExpression = wholeAttributeExpression(attr.value);
const compiledValue = wholeExpression ? `\${__wireProp(${ctx.resolveExpr(wholeExpression)})}` : compileAttrValue(attr.value, ctx);
const rendered = ` ${attr.name}="${compiledValue}"`;
if (wholeExpression || !attr.value.includes("{") || !exprRefsState(attr.value, ctx.stateNames)) {
if (!attr.value.includes("{") || !exprRefsState(attr.value, ctx.stateNames) && !exprRefsState(attr.value, ctx.propNames)) {
return rendered;
}
const marker = attrEscape(JSON.stringify([attr.name, attr.value]));
return rendered + ` data-wrn-bind-${bindIndex++}="${escLit(marker)}"`;
return rendered + ` data-wrn-prop-bind-${bindIndex++}="${escLit(marker)}"`;
}).join("");
const loops = loopVarsOf(node);
const childCtx = loops.length > 0 ? {
@@ -24547,7 +24594,7 @@ ${handlers.join(`
return false;
}
function exprRefsComponentReactiveValue(expr, ctx) {
return exprRefsState(expr, ctx.stateNames) || exprRefsState(expr, ctx.functionNames);
return exprRefsState(expr, ctx.stateNames) || exprRefsState(expr, ctx.propNames) || exprRefsState(expr, ctx.functionNames);
}
function viewHasEvents(nodes) {
return nodes.some((node) => {
@@ -24599,10 +24646,10 @@ ${handlers.join(`
out += escLit(`<span data-t="${attrEscape(expr.slice(2).trim())}"></span>`);
} else if (ctx.loopVars && exprRefsState(expr, ctx.loopVars)) {
out += escLit(`{${expr}}`);
} else if (exprRefsComponentReactiveValue(expr, ctx)) {
out += escLit(`<span data-text="${attrEscape(expr)}">`) + `\${__wireHtml(${ctx.resolveExpr(expr)})}` + escLit(`</span>`);
} else if (expr === "content") {
out += `\${__wireRaw(${ctx.resolveExpr(expr)})}`;
} else if (exprRefsComponentReactiveValue(expr, ctx)) {
out += escLit(`<span data-text="${attrEscape(expr)}">`) + `\${__wireHtml(${ctx.resolveExpr(expr)})}` + escLit(`</span>`);
} else {
out += `\${__wireHtml(${ctx.resolveExpr(expr)})}`;
}
@@ -24855,6 +24902,7 @@ ${handlers.join(`
};
const ctx = {
stateNames,
propNames: new Set(effectiveProps.map((entry) => entry.name)),
functionNames: new Set(ast.runtimeFunctions.filter((fn) => fn.runtime !== "server").map((fn) => fn.name)),
resolveExpr,
eventNames: publicOutputNames(ast)
@@ -24867,7 +24915,7 @@ ${handlers.join(`
const styles = ast.styles.map((body) => body.trim()).filter(Boolean);
const styleTag = escLit(localStyleTag(ast, styles));
const behavior = componentBehavior(ast);
const needsScope = ast.runtime !== "server" && (browserStates.length > 0 || ast.computed.length > 0 || viewHasEvents(ast.view) || behavior !== null);
const needsScope = ast.runtime !== "server" && (effectiveProps.length > 0 || browserStates.length > 0 || ast.computed.length > 0 || viewHasEvents(ast.view) || behavior !== null);
if (hasServerEach || needsScope) {
out.push(`import { Buffer as __WrnexusBuffer } from "node:buffer";`);
}
@@ -24881,7 +24929,7 @@ ${handlers.join(`
if (prop.required) {
decls.push(` if (__p[${JSON.stringify(prop.name)}] === undefined) throw new TypeError(${JSON.stringify(`${ast.name} requires prop '${prop.name}' (${prop.valueType ?? "unknown"})`)});`);
}
decls.push(` const ${nameRefs.get(prop.name)}: ${prop.valueType ?? "any"} = __coerce(__p[${JSON.stringify(prop.name)}], (${resolveExpr(prop.default)}), ${JSON.stringify((0, types_ts_1.runtimeTypeOf)(prop.valueType))});`);
decls.push(` const ${nameRefs.get(prop.name)}: ${prop.valueType ?? "any"} = __coerce(__p[${JSON.stringify(prop.name)}], (${resolveExpr(prop.default)}), ${JSON.stringify((0, types_ts_1.runtimeTypeOf)(prop.valueType))}, ${JSON.stringify(prop.name)});`);
}
if (!effectiveProps.some((prop) => prop.name === "attrs")) {
decls.push(` const __attrs = __restProps(__p, new Set(${JSON.stringify(effectiveProps.map((prop) => prop.name))}));`);
@@ -24941,7 +24989,7 @@ ${ast.outputs.map((output) => ` ${JSON.stringify(output.name)}(${output.payload
`)}
}`);
}
out.push(`function __coerce(v: any, def: any, declared: string = "unknown"): any {
out.push(`function __coerce(v: any, def: any, declared: string = "unknown", propName: string = "prop"): any {
if (v === undefined || v === null) {
return def;
}
@@ -24966,14 +25014,14 @@ ${ast.outputs.map((output) => ` ${JSON.stringify(output.name)}(${output.payload
if (typeof v === "string") {
try {
const parsed = JSON.parse(v);
return Array.isArray(parsed) ? parsed : def;
if (!Array.isArray(parsed)) throw new TypeError("Expected an array prop '" + propName + "'");
return parsed;
} catch {
if (declared === "array") throw new TypeError("Expected an array prop");
return def;
throw new TypeError("Expected an array prop '" + propName + "'");
}
}
return def;
throw new TypeError("Expected an array prop '" + propName + "'");
}
if (declared === "object" || (def !== null && typeof def === "object")) {
@@ -24989,20 +25037,16 @@ ${ast.outputs.map((output) => ` ${JSON.stringify(output.name)}(${output.payload
try {
const parsed = JSON.parse(v);
return (
parsed !== null &&
typeof parsed === "object" &&
!Array.isArray(parsed)
)
? parsed
: def;
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
throw new TypeError("Expected an object prop '" + propName + "'");
}
return parsed;
} catch {
if (declared === "object") throw new TypeError("Expected an object prop");
return def;
throw new TypeError("Expected an object prop '" + propName + "'");
}
}
return def;
throw new TypeError("Expected an object prop '" + propName + "'");
}
if (declared === "bigint") return BigInt(v);
@@ -25072,10 +25116,12 @@ function __wireSpreadAttrs(value: any): string {
lowerName === "style" ||
lowerName === "slot" ||
lowerName === "data-component" ||
// Internal markers must not leak through a spread -- except the
// parent's output handlers, whose whole job is to ride from the mount
// onto the view root so the mounting scope can bind them there.
(lowerName.startsWith("data-wrn") && !lowerName.startsWith("data-wrn-out-"))
// 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;
}
@@ -27916,7 +27962,12 @@ ${serverFunctions}
case "props": {
lx.next();
expect("lbrace");
while (lx.peek().type !== "rbrace") {
while (true) {
if (lx.startsWithBlockComment()) {
throw new ParseError("Block comments are not allowed inside props {}; use // line comments instead", "WRN-PROPS-BLOCK-COMMENT");
}
if (lx.peek().type === "rbrace")
break;
const t = lx.peek();
if (t.type === "eof")
throw new ParseError("Unexpected end of input inside props");
@@ -28275,6 +28326,9 @@ ${serverFunctions}
}
expect("rbrace");
const declaredStates = new Set(states.map((state) => state.name));
if (declaredStates.has("page")) {
throw new ParseError("State name 'page' collides with the WRN 'page' keyword; choose another state name", "WRN-STATE-RESERVED-NAME");
}
for (const watcher of watches) {
if (!declaredStates.has(watcher.state)) {
throw new ParseError(`Cannot watch undeclared state '${watcher.state}'`);
@@ -28748,6 +28802,10 @@ ${serverFunctions}
break;
}
}
startsWithBlockComment() {
this.skipTrivia();
return this.src[this.pos] === "/" && this.src[this.pos + 1] === "*";
}
next() {
this.skipTrivia();
const { src } = this;
+14 -2
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env node
// WRN editor language server source hash: 65a5536efbc7c9fee15040559bb48afe78c4686fc5e7341ffc941cc7113c8556
// WRN editor language server source hash: 4c7e59ebeb512e23d95f4169dd80da2b951ae39c31d31919994368b8e90f5cec
// WRN editor language server generator hash: f593a44aaf05495b789ce7a3086bee1eebb951b884d41c0e017bbcfe5f547e72
// @bun @bun-cjs
(function(exports, require, module, __filename, __dirname) {var __create = Object.create;
@@ -168786,6 +168786,10 @@ class Lexer {
break;
}
}
startsWithBlockComment() {
this.skipTrivia();
return this.src[this.pos] === "/" && this.src[this.pos + 1] === "*";
}
next() {
this.skipTrivia();
const { src } = this;
@@ -170521,7 +170525,12 @@ function parse(source) {
case "props": {
lx.next();
expect("lbrace");
while (lx.peek().type !== "rbrace") {
while (true) {
if (lx.startsWithBlockComment()) {
throw new ParseError("Block comments are not allowed inside props {}; use // line comments instead", "WRN-PROPS-BLOCK-COMMENT");
}
if (lx.peek().type === "rbrace")
break;
const t = lx.peek();
if (t.type === "eof")
throw new ParseError("Unexpected end of input inside props");
@@ -170880,6 +170889,9 @@ function parse(source) {
}
expect("rbrace");
const declaredStates = new Set(states.map((state) => state.name));
if (declaredStates.has("page")) {
throw new ParseError("State name 'page' collides with the WRN 'page' keyword; choose another state name", "WRN-STATE-RESERVED-NAME");
}
for (const watcher of watches) {
if (!declaredStates.has(watcher.state)) {
throw new ParseError(`Cannot watch undeclared state '${watcher.state}'`);