feat: release design system engine, studio and component contracts
This commit is contained in:
1 parent
ff1065fb27
commit
3943b946d6
693 files changed
+175546
-3894
No files matched your search
+124
-30
@@ -1,6 +1,6 @@
|
||||
"use strict";
|
||||
// Generated by scripts/build-editor-compiler.mjs. Do not edit directly.
|
||||
// WRN editor compiler source hash: 89199942be0196a3d06ea3d30dff80d361253192108bd978b5b80d921195c59f
|
||||
// WRN editor compiler source hash: 25aeef88c2c4f44d42ae203ccec54d2ca1ab215e11dffbca6e451e8a1ec83f64
|
||||
// WRN editor compiler generator hash: f8c1094b47e695151205899de28cd63d574356d26ac49219c4a43db0f2391ef5
|
||||
// Generated with TypeScript: 6.0.3
|
||||
const __nodeRequire = require;
|
||||
@@ -649,7 +649,6 @@ function _functionEntry(ast, fn, availableFunctions) {
|
||||
: "";
|
||||
const stateAliases = stateNames.length ? `let { ${stateNames.join(", ")} } = context.state;` : "";
|
||||
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(" ");
|
||||
@@ -657,7 +656,12 @@ function _functionEntry(ast, fn, availableFunctions) {
|
||||
? functionAliases
|
||||
.map((name) => `const ${name} = (...__wrnexusPeerArgs) => context.functions[${JSON.stringify(name)}](...__wrnexusPeerArgs);`)
|
||||
.join("\n")
|
||||
: `const __wrnexusFlush = () => { ${syncStateToContext} };
|
||||
: `const __wrnexusFlush = () => {
|
||||
const __wrnexusPendingState = { ${stateNames.map((name) => `${JSON.stringify(name)}: ${name}`).join(", ")} };
|
||||
const __wrnexusApplyState = () => { ${stateNames.map((name) => `context.state.${name} = __wrnexusPendingState.${name};`).join(" ")} };
|
||||
if (typeof context.batch === "function") context.batch(__wrnexusApplyState);
|
||||
else __wrnexusApplyState();
|
||||
};
|
||||
const __wrnexusRestore = () => { ${syncStateFromContext} };
|
||||
const __wrnexusPeer = (name, args) => {
|
||||
__wrnexusFlush();
|
||||
@@ -854,19 +858,76 @@ function generateBrowserModule(ast) {
|
||||
!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(" ");
|
||||
// A display helper must not subscribe to unrelated state just to synchronize
|
||||
// the closure. Conservatively include identifiers from called/returned peers
|
||||
// (including callbacks and parameter defaults) so indirect reads remain reactive.
|
||||
const referencesPeer = (source, name) => {
|
||||
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
const pattern = new RegExp(`(?:^|[^A-Za-z0-9_$.])${escaped}(?![A-Za-z0-9_$])`);
|
||||
// Permission strings such as "calendar.create" are not calls to create().
|
||||
// Keep template interpolations conservative; masking a whole template would
|
||||
// otherwise hide helper references inside ${...}.
|
||||
return (pattern.test(maskStringsAndComments(source)) ||
|
||||
(source.includes("${") && pattern.test(source)));
|
||||
};
|
||||
const functionSources = new Map(functions.map((fn) => [
|
||||
fn.name,
|
||||
fn.body + "\n" + fn.parameters.map((parameter) => parameter.default ?? "").join("\n"),
|
||||
]));
|
||||
const restoredNames = new Map();
|
||||
for (const fn of functions) {
|
||||
const visited = new Set();
|
||||
const collect = (name) => {
|
||||
if (visited.has(name))
|
||||
return "";
|
||||
visited.add(name);
|
||||
const source = functionSources.get(name) ?? "";
|
||||
return (source +
|
||||
"\n" +
|
||||
functions
|
||||
.filter((peer) => referencesPeer(source, peer.name))
|
||||
.map((peer) => collect(peer.name))
|
||||
.join("\n"));
|
||||
};
|
||||
const source = collect(fn.name);
|
||||
restoredNames.set(fn.name, [...sharedState, ...sharedProps].filter((name) => identifierReferenced(source, name)));
|
||||
}
|
||||
const sharedCommit = `const values = { ${sharedState.map((name) => `${JSON.stringify(name)}: ${name}`).join(", ")} };
|
||||
const pending = {};
|
||||
for (const name of Object.keys(values)) {
|
||||
if (!Object.is(values[name], committed[name])) { pending[name] = values[name]; committed[name] = values[name]; }
|
||||
}
|
||||
if (Object.keys(pending).length === 0) return;
|
||||
const apply = () => { for (const name of Object.keys(pending)) context.state[name] = pending[name]; };
|
||||
if (typeof context.batch === "function") context.batch(apply); else apply();`;
|
||||
const restores = [...sharedState, ...sharedProps]
|
||||
.map((name) => `${JSON.stringify(name)}:()=>{${sharedState.includes(name)
|
||||
? `${name} = context.state.${name}; committed.${name} = ${name};`
|
||||
: `${name} = context.props.${name};`}}`)
|
||||
.join(",\n");
|
||||
const restoreGroups = [];
|
||||
const restoreKeys = {};
|
||||
for (const [name, keys] of restoredNames) {
|
||||
let index = restoreGroups.findIndex((group) => JSON.stringify(group) === JSON.stringify(keys));
|
||||
if (index < 0) {
|
||||
index = restoreGroups.length;
|
||||
restoreGroups.push(keys);
|
||||
}
|
||||
restoreKeys[name] = index;
|
||||
}
|
||||
const hasAuthoredCommit = callableAliases.includes("commit");
|
||||
const hasAuthoredSetTimeout = callableAliases.includes("setTimeout");
|
||||
const implementations = functions
|
||||
.map((fn) => {
|
||||
const parameters = fn.parameters.map((parameter) => parameter.name).join(", ");
|
||||
const parameters = fn.parameters
|
||||
.map((parameter) => parameter.name +
|
||||
(parameter.default !== undefined
|
||||
? ` = (${(0, syntax_1.eraseFunctionTypes)(parameter.default)})`
|
||||
: ""))
|
||||
.join(", ");
|
||||
return `${JSON.stringify(fn.name)}: ${fn.async ? "async " : ""}function(${parameters}) {
|
||||
try { ${(0, syntax_1.eraseFunctionTypes)(fn.body)} } finally { __wrnexusCommit(); }
|
||||
}`;
|
||||
${(0, syntax_1.eraseFunctionTypes)(fn.body)}
|
||||
}`;
|
||||
})
|
||||
.join(",\n");
|
||||
return `// generated WRNexusJS browser module for ${ast.name}
|
||||
@@ -887,8 +948,11 @@ function __wrnexusCreateClientFunctions(context) {
|
||||
const props = context.props;
|
||||
const refs = context.refs;
|
||||
${apiBindings(ast)}
|
||||
const committed = { ${sharedState.map((name) => `${JSON.stringify(name)}: ${name}`).join(", ")} };
|
||||
const __wrnexusCommit = () => { ${sharedCommit} };
|
||||
const __wrnexusRestore = () => { ${sharedRestore} };
|
||||
const __wrnexusRestores = { ${restores} };
|
||||
const __wrnexusRestoreKeys = ${JSON.stringify(restoreKeys)};
|
||||
const __wrnexusRestoreGroups = ${JSON.stringify(restoreGroups)};
|
||||
${!hasAuthoredCommit ? "const commit = __wrnexusCommit;" : ""}
|
||||
${!hasAuthoredSetTimeout
|
||||
? `const setTimeout = (callback, delay, ...args) => globalThis.setTimeout(() => {
|
||||
@@ -898,12 +962,19 @@ function __wrnexusCreateClientFunctions(context) {
|
||||
const implementations = {
|
||||
${implementations}
|
||||
};
|
||||
${callableAliases.map((name) => `const ${name} = (...args) => implementations[${JSON.stringify(name)}](...args);`).join("\n ")}
|
||||
${callableAliases.map((name) => `const ${name} = (...args) => ${functions.find((fn) => fn.name === name)?.async ? `__wrnexusInvoke(implementations[${JSON.stringify(name)}], args)` : `implementations[${JSON.stringify(name)}](...args)`};`).join("\n ")}
|
||||
const __wrnexusInvoke = (fn, args) => {
|
||||
let result;
|
||||
try { result = fn(...args); } catch (error) { __wrnexusCommit(); throw error; }
|
||||
__wrnexusCommit();
|
||||
if (result && typeof result.then === "function") return Promise.resolve(result).finally(__wrnexusCommit);
|
||||
return result;
|
||||
};
|
||||
const functions = {};
|
||||
for (const name of Object.keys(implementations)) {
|
||||
functions[name] = (...args) => {
|
||||
__wrnexusRestore();
|
||||
return implementations[name](...args);
|
||||
for (const key of __wrnexusRestoreGroups[__wrnexusRestoreKeys[name]]) __wrnexusRestores[key]();
|
||||
return __wrnexusInvoke(implementations[name], args);
|
||||
};
|
||||
}
|
||||
return functions;
|
||||
@@ -1655,7 +1726,10 @@ function renderNestedComponentInvocation(node, ctx) {
|
||||
: compileAttrValue(attr.value, ctx, attr.name === "pattern");
|
||||
const rendered = ` ${attr.name}="${compiledValue}"`;
|
||||
if (!attr.value.includes("{") ||
|
||||
(!exprRefsState(attr.value, ctx.stateNames) && !exprRefsState(attr.value, ctx.propNames))) {
|
||||
// A bare callback reference is not a computed field value. Keep its
|
||||
// existing transport while subscribing helper calls to their reads.
|
||||
(wholeExpression && ctx.functionNames.has(wholeExpression.trim())) ||
|
||||
!exprRefsComponentReactiveValue(attr.value, ctx)) {
|
||||
return rendered;
|
||||
}
|
||||
const marker = attrEscape(JSON.stringify([attr.name, attr.value]));
|
||||
@@ -1672,6 +1746,7 @@ function renderNestedComponentInvocation(node, ctx) {
|
||||
: { ...ctx, forwardRestAttrs: false };
|
||||
const inner = node.children.map((child) => renderComponentNode(child, childCtx)).join("");
|
||||
return (`<div data-component="${attrEscape(node.tag)}"` +
|
||||
serverLoopLocalsAttribute(ctx) +
|
||||
`${ctx.forwardRestAttrs ? "${__wrnSpreadAttrs(__attrs)}" : ""}` +
|
||||
`${attrs}>${inner}</div>`);
|
||||
}
|
||||
@@ -2676,9 +2751,18 @@ function behaviorAttribute(behavior) {
|
||||
return ` data-wrn-behavior="${encoded}"`;
|
||||
}
|
||||
const INTERP_RE = /\{([^{}]+)\}/g;
|
||||
/**
|
||||
* Does the expression read one of these names as a value of its own?
|
||||
*
|
||||
* A name after a dot belongs to whatever precedes it, so `item.label` reads the
|
||||
* loop item, not a `label` prop of the surrounding component. Counting it as a
|
||||
* reference made the caller mark the attribute reactive and emit a client
|
||||
* binding for it; on hydration the loop item is out of scope there, so the
|
||||
* expression fell back to its default and overwrote the server's value.
|
||||
*/
|
||||
function exprRefsState(expr, stateNames) {
|
||||
for (const name of stateNames) {
|
||||
if (new RegExp(`\\b${name}\\b`).test(expr))
|
||||
if (new RegExp(`(?<!\\.)\\b${name}\\b`).test(expr))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -2845,7 +2929,7 @@ function renderClientControlTemplate(nodes) {
|
||||
}
|
||||
const rendered = ` ${name}="${attrEscape(attribute.value)}"`;
|
||||
return attribute.value.includes("{")
|
||||
? `${rendered} data-wrn-bind-${bindIndex++}="${attrEscape(JSON.stringify([name, attribute.value]))}"`
|
||||
? `${rendered} data-wrn-${componentTag ? "prop-bind" : "bind"}-${bindIndex++}="${attrEscape(JSON.stringify([name, attribute.value]))}"`
|
||||
: rendered;
|
||||
})
|
||||
.join("");
|
||||
@@ -2866,21 +2950,32 @@ function encodeClientControl(value) {
|
||||
function renderComponentIfNode(node, ctx) {
|
||||
let expression = "``";
|
||||
const clientBranches = [];
|
||||
let previousConditions = "false";
|
||||
const selectedConditions = node.branches.map((branch) => {
|
||||
const condition = branch.cond === null ? "true" : `(${ctx.resolveExpr(branch.cond)})`;
|
||||
const selected = `!(${previousConditions}) && ${condition}`;
|
||||
previousConditions += ` || ${condition}`;
|
||||
return selected;
|
||||
});
|
||||
for (let index = node.branches.length - 1; index >= 0; index--) {
|
||||
const branch = node.branches[index];
|
||||
const body = branch.body.map((child) => renderComponentNode(child, ctx)).join("");
|
||||
const bodyExpression = "`" + body + "`";
|
||||
clientBranches.unshift(`{ cond: ${branch.cond === null ? "null" : JSON.stringify(branch.cond)}, body: ${bodyExpression} }`);
|
||||
clientBranches.unshift(`{ cond: ${branch.cond === null ? "null" : JSON.stringify(branch.cond)}, body: (${selectedConditions[index]}) ? ${bodyExpression} : ${JSON.stringify(renderClientControlTemplate(branch.body))} }`);
|
||||
expression =
|
||||
branch.cond === null
|
||||
? bodyExpression
|
||||
: `(${ctx.resolveExpr(branch.cond)}) ? ${bodyExpression} : ${expression}`;
|
||||
? `__branches[${index}].body`
|
||||
: `(${ctx.resolveExpr(branch.cond)}) ? __branches[${index}].body : ${expression}`;
|
||||
}
|
||||
// Render all branches on the server into an inert, encoded definition.
|
||||
// A branch first selected in the browser therefore contains the real nested
|
||||
// component HTML and scope metadata, not a data-component placeholder.
|
||||
const definition = `\${__wrnexusEncodeControl([${clientBranches.join(",")}])}`;
|
||||
return `<template data-wrn-if="${definition}"></template>${"${" + expression + "}"}<template data-wrn-control-end></template>`;
|
||||
// Only evaluate the selected branch on the server. Inactive branches retain
|
||||
// browser templates so guarded values may remain null until state changes.
|
||||
return ("${(() => { const __branches = [" +
|
||||
clientBranches.join(",") +
|
||||
']; return `<template data-wrn-if="${__wrnexusEncodeControl(__branches)}"' +
|
||||
serverLoopLocalsAttribute(ctx) +
|
||||
"></template>${" +
|
||||
expression +
|
||||
"}<template data-wrn-control-end></template>`; })()}");
|
||||
}
|
||||
function renderComponentEachNode(node, ctx) {
|
||||
const item = node.item;
|
||||
@@ -2913,7 +3008,7 @@ function renderComponentEachNode(node, ctx) {
|
||||
body: renderClientControlTemplate(node.body),
|
||||
empty: renderClientControlTemplate(node.empty),
|
||||
});
|
||||
return `<template data-wrn-each="${definition}"></template>${serverBody}<template data-wrn-control-end></template>`;
|
||||
return `<template data-wrn-each="${definition}"${serverLoopLocalsAttribute(ctx)}></template>${serverBody}<template data-wrn-control-end></template>`;
|
||||
}
|
||||
function serverLoopLocalsAttribute(ctx) {
|
||||
const locals = [...(ctx.serverLocals ?? [])];
|
||||
@@ -3441,6 +3536,7 @@ function __wrnSpreadAttrs(value: unknown): string {
|
||||
// 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 !== "data-wrn-loop-locals" &&
|
||||
!lowerName.startsWith("data-wrn-out-") &&
|
||||
!lowerName.startsWith("data-wrn-prop-bind-"))
|
||||
) {
|
||||
@@ -3477,9 +3573,7 @@ function __wrnRaw(v: unknown): string {
|
||||
}`);
|
||||
}
|
||||
if (needsScope) {
|
||||
out.push(`function __wrnexusEncodeControl(value: unknown): string {
|
||||
return __WrnexusBuffer.from(JSON.stringify(value), "utf8").toString("base64");
|
||||
}`);
|
||||
out.push(`import { encodeControlTemplate as __wrnexusEncodeControl } from "@wrnexus/core";`);
|
||||
out.push(`function __wrnexusSerializeScopeValue(value: unknown): string {
|
||||
if (value === undefined) {
|
||||
return "undefined";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// WRN editor extension source hash: fd585db47099c8b781bf49e4ce7c86146bad583f781d0aa93196eb200a95b20f
|
||||
// WRN editor extension source hash: c6818affd7aeed6ffa1b061d878b53a820f1a254b677b244cb630ca959fe26cf
|
||||
// WRN editor extension generator hash: 456d1d614e44e5fb1f19b784176c09cf2ade9b64ef73a17934c2698150b62728
|
||||
"use strict";
|
||||
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env node
|
||||
// WRN editor language server source hash: d192eefe86b41eaa54eb48a69202842dbeb8ec4ee4e962c912b288820a65b162
|
||||
// WRN editor language server source hash: a9bc2580e5b16534f08c9e051c665b2583fac5cef7e49e7626188621d7f95fe0
|
||||
// WRN editor language server generator hash: f593a44aaf05495b789ce7a3086bee1eebb951b884d41c0e017bbcfe5f547e72
|
||||
// @bun @bun-cjs
|
||||
(function(exports, require, module, __filename, __dirname) {var __create = Object.create;
|
||||
|
||||
Reference in new issue
Block a user