release: WRNexusJS 0.6.0

This commit is contained in:
2026-08-01 01:09:58 +05:30
parent 3e565e8d03
commit 687d345882
502 changed files with 33038 additions and 11358 deletions
+200
View File
@@ -0,0 +1,200 @@
import { eraseFunctionTypes, type PageAst, type RuntimeFunctionDecl } from "@wrnexus/syntax";
const RESERVED_BINDINGS = new Set([
"await",
"break",
"case",
"catch",
"class",
"const",
"continue",
"debugger",
"default",
"delete",
"do",
"else",
"enum",
"export",
"extends",
"false",
"finally",
"for",
"function",
"if",
"implements",
"import",
"in",
"instanceof",
"interface",
"let",
"new",
"null",
"package",
"private",
"protected",
"public",
"return",
"static",
"super",
"switch",
"this",
"throw",
"true",
"try",
"typeof",
"var",
"void",
"while",
"with",
"yield",
]);
const RUNTIME_BINDINGS = new Set([
"context",
"state",
"output",
"server",
"props",
"refs",
"event",
"payload",
]);
function safeIdentifier(name: string): boolean {
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name) && !RESERVED_BINDINGS.has(name);
}
function functionEntry(
ast: PageAst,
fn: RuntimeFunctionDecl,
availableFunctions: string[],
): string {
const parameterNames = new Set(fn.parameters.map((parameter) => parameter.name));
const stateNames = ast.states
.filter(
(state) =>
state.runtime !== "server" &&
safeIdentifier(state.name) &&
!RUNTIME_BINDINGS.has(state.name) &&
!parameterNames.has(state.name),
)
.map((state) => state.name);
const stateSet = new Set(stateNames);
const propNames = ast.props
.filter(
(prop) =>
safeIdentifier(prop.name) &&
!RUNTIME_BINDINGS.has(prop.name) &&
!parameterNames.has(prop.name) &&
!stateSet.has(prop.name),
)
.map((prop) => prop.name);
const functionAliases = availableFunctions.filter(
(name) =>
safeIdentifier(name) &&
!RUNTIME_BINDINGS.has(name) &&
!parameterNames.has(name) &&
!stateSet.has(name) &&
!propNames.includes(name),
);
const parameters = fn.parameters.map((parameter) => parameter.name).join(", ");
const initialStateSnapshot = stateNames.length
? `const __wrnexusInitialState = { ${stateNames.map((name) => `${JSON.stringify(name)}: context.state.${name}`).join(", ")} };`
: "";
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(" ");
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;
try {
__wrnexusPeerResult = ${call};
} catch (__wrnexusPeerError) {
${syncStateFromContext}
throw __wrnexusPeerError;
}
if (__wrnexusPeerResult && typeof __wrnexusPeerResult.then === "function") {
return Promise.resolve(__wrnexusPeerResult).finally(() => { ${syncStateFromContext} });
}
${syncStateFromContext}
return __wrnexusPeerResult;
};`;
})
.join("\n");
const copyBack = stateNames
.map(
(name) =>
`if (!Object.is(${name}, __wrnexusInitialState[${JSON.stringify(name)}])) context.state.${name} = ${name};`,
)
.join("\n");
const body = eraseFunctionTypes(fn.body);
const runtimeBindings = [
!parameterNames.has("output") ? "const output = context.output;" : "",
!parameterNames.has("server") ? "const server = context.server;" : "",
!parameterNames.has("props") ? "const props = context.props;" : "",
!parameterNames.has("refs") ? "const refs = context.refs;" : "",
]
.filter(Boolean)
.join("\n ");
return `${JSON.stringify(fn.name)}: ${fn.async ? "async " : ""}function(context${parameters ? `, ${parameters}` : ""}) {
${initialStateSnapshot}
${stateAliases}
${propAliases}
${peerAliases}
${runtimeBindings}
try {
${body}
} finally {
${copyBack}
}
}`;
}
export function generateBrowserModule(ast: PageAst): string {
const functions = ast.runtimeFunctions.filter((fn) =>
["legacy", "client", "shared"].includes(fn.runtime),
);
const functionNames = functions.map((fn) => fn.name);
const state = ast.states.filter((entry) => entry.runtime !== "server").map((entry) => entry.name);
const storeImports = ast.structuredImports.filter(
(entry) =>
!entry.typeOnly && entry.source.endsWith(".wrn") && /(?:^|\/)stores?\//.test(entry.source),
);
const imports = ast.structuredImports
.filter((entry) => !entry.typeOnly)
.filter((entry) => !entry.source.endsWith(".wrn") || /(?:^|\/)stores?\//.test(entry.source))
.map((entry) => entry.raw)
.join("\n");
const importedBindings = storeImports
.flatMap((entry) => [
...(entry.defaultImport ? [entry.defaultImport] : []),
...(entry.namespaceImport ? [entry.namespaceImport] : []),
...entry.namedImports.map((item) => item.local),
])
.filter(safeIdentifier);
return `// generated WRNexusJS browser module for ${ast.name}
${imports}
export const __wrnexusClientFunctions = {
${functions.map((fn) => ` ${functionEntry(ast, fn, functionNames)}`).join(",\n")}
};
export const __wrnexusClientState = ${JSON.stringify(state)};
export const __wrnexusOutputs = ${JSON.stringify(ast.outputs)};
export const __wrnexusImportedBindings = { ${importedBindings.join(", ")} };
export function bindClientScope(context) {
const functions = {};
const scopedContext = { ...context, functions };
for (const [name, handler] of Object.entries(__wrnexusClientFunctions)) {
functions[name] = (...args) => handler(scopedContext, ...args);
}
return functions;
}
`;
}