diff --git a/.gitignore b/.gitignore index bb308f13..bb970b6f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ node_modules/ .wrnexus/ dist/ +!vendor/compiler/dist/ +!vendor/compiler/dist/** **/.wrnexus/ coverage/ .env diff --git a/vendor/compiler/dist/index.d.ts b/vendor/compiler/dist/index.d.ts new file mode 100644 index 00000000..d2196ffb --- /dev/null +++ b/vendor/compiler/dist/index.d.ts @@ -0,0 +1,242 @@ +import { PageAst as PageAst$1, StructuredImportDecl, WrnDiagnostic } from '@wrnexus/syntax'; +export { ActionBlock, ApiBlock, Attr, ComputedDecl, DataApiBlock, DataMode, EffectBlock, EventDecl, FormatWrnOptions, LexError, Lexer, LoadBlock, ModeFunctionsBlock, OutputDecl, PageAst, ParseError, PropDecl, RealtimeBlock, RuntimeFunctionDecl, SeoBlock, StateDecl, StateRuntime, StoreKind, StructuredImportDecl, ViewNode, WrnDiagnostic, assertValidAst, diagnose, diagnosticFromError, eraseFunctionTypes, formatDiagnostic, formatWrn, inferredRuntimeType, parse, runtimeTypeOf } from '@wrnexus/syntax'; +import { PageAst } from '@wrnexus/syntax/parser'; + +/** + * Code generation: lower a `.wrn` AST to TypeScript that targets the framework's + * existing primitives. + * + * state -> a `data-scope` declaration consumed by the runtime + * view -> an HTML string returned by a page component + * @event="..." -> data-on-="..." + * "...{expr}..." -> text kept verbatim ({expr} is mustache for runtime) + * api="" -> SSR/client data binding declared in a mode block + * ssrGet/ssrText -> legacy server-side API fetch + render + * csrGet/csrText -> legacy browser-side API fetch + render + * style -> tagged local stylesheet metadata promoted by SSR + * functions -> server-only helpers for API/realtime code + * api M /p {b} -> export const M = async (ctx) => { b } + * realtime {..} -> export const websocket = { evt(ws, ...args) { b } } + */ + +declare function generate(ast: PageAst): string; + +interface ComponentContractMetadata { + name: string; + kind: PageAst$1["kind"]; + props: Array<{ + name: string; + type: string; + required: boolean; + default?: string; + options?: string[]; + }>; + outputs: Array<{ + name: string; + payloadName?: string; + payloadType?: string; + }>; + functions: Array<{ + name: string; + runtime: string; + async: boolean; + parameters: Array<{ + name: string; + type: string; + optional: boolean; + }>; + returnType: string; + }>; + states: Array<{ + name: string; + runtime: string; + type: string; + initializer: string; + }>; + computed: Array<{ + name: string; + type: string; + expression: string; + }>; + imports: Array<{ + source: string; + typeOnly: boolean; + defaultImport?: string; + namedImports: string[]; + }>; +} +declare function createComponentContract(ast: PageAst$1): ComponentContractMetadata; + +interface RpcManifestEntry { + id: string; + component: string; + function: string; + parameters: Array<{ + name: string; + type: string; + optional: boolean; + }>; + returnType: string; +} +declare function rpcManifest(ast: PageAst$1): RpcManifestEntry[]; +declare function generateServerFunctionsModule(ast: PageAst$1): string; + +interface CompileTargets { + server: string; + browser: string; + declarations: string; + contract: ReturnType; + rpc: ReturnType; +} +declare function generateTargets(ast: PageAst$1): CompileTargets; + +declare function generateBrowserModule(ast: PageAst$1): string; + +declare function generateDeclarations(ast: PageAst$1): string; + +declare function generateStoreModule(ast: PageAst$1): string; +/** Standalone browser artifact for an imported `.wrn` store. */ +declare function generateStoreBrowserModule(ast: PageAst$1): string; + +type ImportMode = "legacy" | "compatible" | "explicit"; +interface ImportResolverOptions { + appRoot: string; + mode?: ImportMode; + aliases?: Record; +} +interface ResolvedImport { + declaration: StructuredImportDecl; + resolved?: string; + diagnostic?: { + code: string; + message: string; + severity: "error" | "warning"; + }; +} +declare function resolveWrnImport(declaration: StructuredImportDecl, importer: string, options: ImportResolverOptions): ResolvedImport; +declare function resolveWrnImports(declarations: StructuredImportDecl[], importer: string, options: ImportResolverOptions): ResolvedImport[]; + +interface WrnSourceMapEntry { + generatedLine: number; + sourceLine: number; + sourceColumn: number; + kind: string; +} +interface WrnSourceMap { + version: 1; + source: string; + generated: string; + mappings: WrnSourceMapEntry[]; +} +declare function createWrnSourceMap(source: string, generated: string): WrnSourceMap; + +type RouteExecutionKind = "static" | "static-interactive" | "request-ssr" | "authenticated-ssr" | "streaming-ssr" | "dynamic"; +interface RuntimeRequirements { + kind: RouteExecutionKind; + canPrerender: boolean; + needsClientRuntime: boolean; + needsServerRuntime: boolean; + hydrationStrategy: string | null; + reasons: string[]; + optimization: OptimizationReport; + cachePolicy: Record; + requiredPermission: string | null; +} +interface OptimizationReport { + staticNodes: number; + reactiveRegions: number; + eliminatedBranches: number; + unusedState: string[]; + unusedHandlers: string[]; + constantProps: string[]; + unusedLocalCssClasses: string[]; + batchableStateUpdates: number; + memoizableComponents: string[]; + preloadDependencies: string[]; + serverOnlyModules: string[]; +} +/** Safe compile-time folding for literal conditional branches. */ +declare function optimizeAst(ast: PageAst$1): { + ast: PageAst$1; + eliminatedBranches: number; +}; +declare function analyzeOptimizations(ast: PageAst$1): OptimizationReport; +declare function analyzeRuntimeRequirements(ast: PageAst$1): RuntimeRequirements; + +type DeploymentRuntime = "bun" | "node" | "edge" | "worker" | "service-worker" | "browser"; +type RuntimeCapability = "filesystem" | "tcp" | "process" | "websocket" | "crypto" | "streams" | "background-tasks"; +interface RuntimeCapabilityDiagnostic { + code: "WRN-RUNTIME-CAPABILITY"; + runtime: DeploymentRuntime; + module: string; + capability: RuntimeCapability; + message: string; +} +declare function runtimeCapabilities(runtime: DeploymentRuntime): ReadonlySet; +declare function analyzeRuntimeImports(source: string, runtime: DeploymentRuntime): RuntimeCapabilityDiagnostic[]; + +declare class NativeCompileError extends Error { + constructor(message: string); +} +/** Compile a parsed `.wrn` page to an Expo Router React Native screen. */ +declare function generateNative(ast: PageAst): string; + +interface CompilationCacheEntry extends CompileResult { + key: string; + file: string; + sourceHash: string; + createdAt: number; +} +interface CompilationCacheOptions { + maxEntries?: number; + now?: () => number; +} +interface CompilationCache { + compile(source: string, file?: string, salt?: string): CompilationCacheEntry; + get(key: string): CompilationCacheEntry | undefined; + invalidate(file?: string): number; + clear(): void; + size(): number; + stats(): { + hits: number; + misses: number; + entries: number; + }; +} +declare function compilationKey(source: string, file?: string, salt?: string): string; +declare function createCompilationCache(options?: CompilationCacheOptions): CompilationCache; +declare class DependencyGraph { + #private; + set(file: string, dependencies: Iterable): void; + remove(file: string): void; + dependencies(file: string): string[]; + dependents(file: string): string[]; + affected(file: string): string[]; +} + +/** + * @wrnexus/compiler — the `.wrn` language compiler. + * + * Parsing and language diagnostics are provided by the canonical + * `@wrnexus/syntax` package. This package owns platform-specific codegen. + */ + +interface CompileResult { + code: string; + ast: PageAst$1; + /** Backward-compatible plain diagnostic messages. */ + diagnostics: string[]; + /** Structured diagnostics for editors, CI, and the DevToolbar. */ + richDiagnostics: WrnDiagnostic[]; +} +/** Compile `.wrn` source into an Expo Router React Native screen. */ +declare function compileNativeWireFile(source: string): string; +/** + * Compile `.wrn` source into TypeScript source. Errors include a stable code, + * source location, code frame, and actionable hint whenever available. + */ +declare function compileWireFile(source: string, filePath?: string): string; +/** Richer entry point returning the AST and structured diagnostics. */ +declare function compile(source: string, filePath?: string): CompileResult; + +export { type CompilationCache, type CompilationCacheEntry, type CompilationCacheOptions, type CompileResult, DependencyGraph, type DeploymentRuntime, NativeCompileError, type OptimizationReport, type RouteExecutionKind, type RuntimeCapability, type RuntimeCapabilityDiagnostic, type RuntimeRequirements, analyzeOptimizations, analyzeRuntimeImports, analyzeRuntimeRequirements, compilationKey, compile, compileNativeWireFile, compileWireFile, createCompilationCache, createComponentContract, createWrnSourceMap, generate, generateBrowserModule, generateDeclarations, generateNative, generateServerFunctionsModule, generateStoreBrowserModule, generateStoreModule, generateTargets, optimizeAst, resolveWrnImport, resolveWrnImports, rpcManifest, runtimeCapabilities }; diff --git a/vendor/compiler/dist/index.js b/vendor/compiler/dist/index.js new file mode 100644 index 00000000..0acabe47 --- /dev/null +++ b/vendor/compiler/dist/index.js @@ -0,0 +1,3292 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default")); + +// packages/compiler/src/index.ts +import { + assertValidAst, + diagnose as diagnose2, + diagnosticFromError, + formatDiagnostic, + parse as parse2, + ParseError as ParseError2 +} from "@wrnexus/syntax"; +import { formatWrn } from "@wrnexus/syntax"; + +// packages/compiler/src/codegen.ts +import { Buffer as Buffer2 } from "buffer"; + +// packages/compiler/src/parser.ts +var parser_exports = {}; +__reExport(parser_exports, parser_star); +import * as parser_star from "@wrnexus/syntax/parser"; + +// packages/compiler/src/types.ts +var types_exports = {}; +__reExport(types_exports, types_star); +import * as types_star from "@wrnexus/syntax/types"; + +// packages/compiler/src/codegen.ts +import { stripRuntimeFunctionModifiers as stripRuntimeFunctionModifiers2 } from "@wrnexus/syntax"; + +// packages/compiler/src/store-codegen.ts +import { eraseFunctionTypes } from "@wrnexus/syntax"; + +// packages/compiler/src/type-codegen.ts +function member(name) { + return /^[A-Za-z_$][\w$]*$/.test(name) ? name : JSON.stringify(name); +} +function params(astParams) { + return astParams.map( + (param) => `${member(param.name)}${param.optional ? "?" : ""}: ${param.valueType ?? "unknown"}` + ).join(", "); +} +function generateDeclarations(ast) { + const inline = ast.types.map((body) => body.trim()).filter(Boolean).join("\n\n"); + if (ast.kind === "global-store" || ast.kind === "page-store") { + const state = ast.states.filter((entry) => entry.runtime !== "server").map((entry) => ` readonly ${member(entry.name)}: ${entry.valueType ?? "unknown"};`).join("\n"); + const computed = ast.computed.map((entry) => ` readonly ${member(entry.name)}: ${entry.valueType ?? "unknown"};`).join("\n"); + const actions = ast.runtimeFunctions.filter((fn) => fn.runtime !== "server").map( + (fn) => ` ${member(fn.name)}(${params(fn.parameters)}): ${fn.returnType ?? (fn.async ? "Promise" : "unknown")};` + ).join("\n"); + return `${inline ? `${inline} + +` : ""}export interface ${ast.name}State { +${state} +} + +export interface ${ast.name}Computed { +${computed} +} + +export interface ${ast.name}Actions { +${actions} +} + +export interface ${ast.name}Instance extends ${ast.name}State, ${ast.name}Computed, ${ast.name}Actions { + reset(): void; + snapshot(): Readonly<${ast.name}State>; +} + +declare const store: ${ast.name}Instance; +export default store; +`; + } + const props = ast.props.map( + (prop) => ` readonly ${member(prop.name)}${prop.required ? "" : "?"}: ${prop.valueType ?? "unknown"};` + ).join("\n"); + const outputs = ast.outputs.map( + (output) => ` ${member(output.name)}(${output.payload ? `${member(output.payload.name)}${output.payload.optional ? "?" : ""}: ${output.payload.valueType}` : ""}): void;` + ).join("\n"); + const clientFunctions = ast.runtimeFunctions.filter((fn) => fn.runtime === "client" || fn.runtime === "shared" || fn.runtime === "legacy").map( + (fn) => ` ${member(fn.name)}(${params(fn.parameters)}): ${fn.returnType ?? (fn.async ? "Promise" : "unknown")};` + ).join("\n"); + const serverFunctions = ast.runtimeFunctions.filter((fn) => fn.runtime === "server").map( + (fn) => ` ${member(fn.name)}(${params(fn.parameters)}): Promise>;` + ).join("\n"); + return `${inline ? `${inline} + +` : ""}export interface ${ast.name}Props { +${props} +} + +export interface ${ast.name}Outputs { +${outputs} +} + +export interface ${ast.name}ClientFunctions { +${clientFunctions} +} + +export interface ${ast.name}ServerCalls { +${serverFunctions} +} +`; +} + +// packages/compiler/src/server-codegen.ts +import { stripRuntimeFunctionModifiers } from "@wrnexus/syntax"; +function stableId(value) { + let hash = 2166136261; + for (let index = 0; index < value.length; index++) { + hash ^= value.charCodeAt(index); + hash = Math.imul(hash, 16777619); + } + return `wrn_${(hash >>> 0).toString(36)}`; +} +function remotelyReferencedServerFunctions(ast) { + const browserSources = ast.runtimeFunctions.filter((fn) => ["legacy", "client", "shared"].includes(fn.runtime)).map((fn) => fn.body); + for (const [hook, body] of Object.entries(ast.storeLifecycle)) { + if (hook !== "serverInit" && body) browserSources.push(body); + } + const names = /* @__PURE__ */ new Set(); + const call = /\bserver\.([A-Za-z_$][\w$]*)\s*\(/g; + for (const source of browserSources) { + for (const match of source.matchAll(call)) names.add(match[1]); + } + return names; +} +function rpcManifest(ast) { + const exposed = remotelyReferencedServerFunctions(ast); + return ast.runtimeFunctions.filter((fn) => fn.runtime === "server" && exposed.has(fn.name)).map((fn) => ({ + id: stableId(`${ast.name}:${fn.name}`), + component: ast.name, + function: fn.name, + parameters: fn.parameters.map((param) => ({ + name: param.name, + type: param.valueType ?? "unknown", + optional: param.optional + })), + returnType: fn.returnType ?? (fn.async ? "Promise" : "unknown") + })); +} +function generateServerFunctionsModule(ast) { + const source = ast.functions.map((body) => stripRuntimeFunctionModifiers(body, ["legacy", "server", "shared"])).filter(Boolean).join("\n\n"); + const names = ast.runtimeFunctions.filter((fn) => ["legacy", "server", "shared"].includes(fn.runtime)).map((fn) => fn.name); + const manifest = rpcManifest(ast); + return `// generated WRNexusJS server module for ${ast.name} +${source} + +export const __wrnexusServerFunctions = { ${[...new Set(names)].join(", ")} }; +export const __wrnexusRpcManifest = ${JSON.stringify(manifest, null, 2)}; +`; +} + +// packages/compiler/src/store-codegen.ts +var RESERVED_BINDINGS = /* @__PURE__ */ 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" +]); +function safeBinding(name) { + return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name) && !RESERVED_BINDINGS.has(name); +} +function stateObject(ast, runtime) { + const entries = ast.states.filter((state) => state.runtime === runtime).map((state) => `${JSON.stringify(state.name)}: (${state.expr})`); + return `{ ${entries.join(", ")} }`; +} +function actionSource(fn, stateNames, eraseTypes = false) { + const parameterNames = new Set(fn.parameters.map((param) => param.name)); + const params2 = fn.parameters.map((param) => param.name).join(", "); + const aliases = stateNames.filter((name) => safeBinding(name) && !parameterNames.has(name)); + const aliasSource = aliases.length ? `let { ${aliases.join(", ")} } = context.state;` : ""; + const runtimeAliases = ["server"].filter((name) => !parameterNames.has(name)).map((name) => `const ${name} = context.${name};`).join("\n"); + const copyBack = aliases.map((name) => `context.state.${name} = ${name};`).join("\n"); + const body = eraseTypes ? eraseFunctionTypes(fn.body) : fn.body; + return `{ runtime: ${JSON.stringify(fn.runtime)}, handler: ${fn.async ? "async " : ""}function(context${params2 ? `, ${params2}` : ""}) { ${runtimeAliases} +${aliasSource} +try { ${body} } finally { ${copyBack} } } }`; +} +function persistedCallback(source, functionName) { + if (!source?.trim()) return void 0; + const body = eraseFunctionTypes(source); + if (functionName === "migrate") { + return `(value, fromVersion, toVersion) => { +${body} +if (typeof migrate === "function") return migrate(value, fromVersion, toVersion); +return value; +}`; + } + return `(value) => { +${body} +if (typeof validate === "function") return validate(value); +return value && typeof value === "object" && !Array.isArray(value) ? value : null; +}`; +} +function persistenceSource(ast) { + if (!ast.persist) return "undefined"; + const migrate = persistedCallback(ast.persist.migrations, "migrate"); + const validate = persistedCallback(ast.persist.validation, "validate"); + return `{ storage: ${JSON.stringify(ast.persist.storage)}, include: ${JSON.stringify(ast.persist.include)}, version: ${ast.persist.version}${migrate ? `, migrate: ${migrate}` : ""}${validate ? `, validate: ${validate}` : ""} }`; +} +function lifecycleSource(ast, stateNames, browser) { + return Object.entries(ast.storeLifecycle).filter(([name]) => !browser || name !== "serverInit").map(([name, body]) => { + const aliases = stateNames.filter(safeBinding); + const aliasSource = aliases.length ? `let { ${aliases.join(", ")} } = context.state;` : ""; + const runtimeAliases = browser ? "const server = context.server;" : ""; + const copyBack = aliases.map((state) => `context.state.${state} = ${state};`).join("\n"); + const emittedBody = browser ? eraseFunctionTypes(body) : body; + return `${name}: async (context) => { ${runtimeAliases} ${aliasSource} try { ${emittedBody} } finally { ${copyBack} } }`; + }).join(",\n"); +} +function generateStoreModule(ast) { + if (ast.kind !== "global-store" && ast.kind !== "page-store") { + throw new Error("generateStoreModule requires a store AST"); + } + const stateNames = ast.states.map((state) => state.name); + const safeStateNames = stateNames.filter(safeBinding); + const computed = ast.computed.map( + (entry) => `${JSON.stringify(entry.name)}: (state) => { ${safeStateNames.length ? `const { ${safeStateNames.join(", ")} } = state;` : ""} return (${entry.expr}); }` + ).join(",\n"); + const actionGroups = /* @__PURE__ */ new Map(); + for (const fn of ast.runtimeFunctions) { + const group = actionGroups.get(fn.name) ?? []; + group.push(fn); + actionGroups.set(fn.name, group); + } + const actions = Array.from( + actionGroups, + ([name, functions]) => `${JSON.stringify(name)}: [${functions.map((fn) => actionSource(fn, stateNames)).join(", ")}]` + ).join(",\n"); + const persistence = persistenceSource(ast); + const lifecycle = lifecycleSource(ast, stateNames, false); + const manifest = rpcManifest(ast); + const remoteFunctions = manifest.map((entry) => entry.function); + const rpcWrappers = remoteFunctions.map( + (name) => `${JSON.stringify(name)}: async (...received) => { + const rpcContext = received.pop(); + if (!rpcContext || !rpcContext.request) throw new Error("WRN-RPC-CONTEXT: request context is required"); + let container = __wrnexusRpcContainers.get(rpcContext.request); + if (!container) { + const url = new URL(rpcContext.request.url); + container = createRequestStoreContainer(rpcContext.request, url.pathname + url.search); + __wrnexusRpcContainers.set(rpcContext.request, container); + } + const store = await container.use(${ast.name}); + const action = store.actions[${JSON.stringify(name)}]; + if (typeof action !== "function") throw new Error(${JSON.stringify(`WRN-RPC-FUNCTION: store action '${name}' is unavailable on the server`)}); + return action(...received); + }` + ).join(",\n"); + return `${ast.imports.join("\n")} +import { defineStore } from "@wrnexus/store"; +import { createRequestStoreContainer } from "@wrnexus/store/server"; + +${ast.types.join("\n\n")} + +export const ${ast.name} = defineStore({ + name: ${JSON.stringify(ast.name)}, + kind: ${JSON.stringify(ast.storeKind)}, + createSharedState: () => (${stateObject(ast, "shared")}), + createClientState: () => (${stateObject(ast, "client")}), + createServerState: () => (${stateObject(ast, "server")}), + computed: { ${computed} }, + actions: { ${actions} }, + persist: ${persistence}, + lifecycle: { ${lifecycle} }, +}); + +export default ${ast.name}; + +const __wrnexusRpcContainers = new WeakMap(); +export const __wrnexusServerFunctions = { +${rpcWrappers} +}; +export const __wrnexusRpcManifest = ${JSON.stringify(manifest, null, 2)}; + +${generateDeclarations(ast)} +`; +} +function generateStoreBrowserModule(ast) { + if (ast.kind !== "global-store" && ast.kind !== "page-store") { + throw new Error("generateStoreBrowserModule requires a store AST"); + } + const browserStates = ast.states.filter((state) => state.runtime !== "server"); + const stateNames = browserStates.map((state) => state.name); + const safeStateNames = stateNames.filter(safeBinding); + const initialState = `{ ${browserStates.map((state) => `${JSON.stringify(state.name)}: (${state.expr})`).join(", ")} }`; + const computed = ast.computed.map( + (entry) => `${JSON.stringify(entry.name)}: (state) => { ${safeStateNames.length ? `const { ${safeStateNames.join(", ")} } = state;` : ""} return (${entry.expr}); }` + ).join(",\n"); + const groups = /* @__PURE__ */ new Map(); + for (const fn of ast.runtimeFunctions.filter( + (entry) => ["client", "shared", "legacy"].includes(entry.runtime) + )) { + const group = groups.get(fn.name) ?? []; + group.push(fn); + groups.set(fn.name, group); + } + const actions = Array.from( + groups, + ([name, functions]) => `${JSON.stringify(name)}: [${functions.map((fn) => actionSource(fn, stateNames, true)).join(", ")}]` + ).join(",\n"); + const persistence = persistenceSource(ast); + const lifecycleEntries = lifecycleSource(ast, stateNames, true); + return `// generated WRNexusJS browser store module for ${ast.name} +const __root = globalThis; +const __registry = __root.__wrnexusStoreRegistry || (__root.__wrnexusStoreRegistry = new Map()); +const __hydrationNode = typeof document !== "undefined" ? document.querySelector("script[data-wrnexus-store-hydration]") : null; +let __hydration = {}; +try { __hydration = __hydrationNode ? JSON.parse(__hydrationNode.textContent || "{}") : {}; } catch (_) {} +function __clone(value) { try { return structuredClone(value); } catch (_) { return JSON.parse(JSON.stringify(value)); } } +function __storage(kind) { if (typeof window === "undefined") return null; return kind === "local" ? window.localStorage : kind === "session" ? window.sessionStorage : null; } +function __diagnostic(code, message, details) { + const detail = { code, message, store: ${JSON.stringify(ast.name)}, details }; + try { __root.dispatchEvent && __root.dispatchEvent(new CustomEvent("wrnexus:store-diagnostic", { detail })); } catch (_) {} + if (typeof console !== "undefined" && console.warn) console.warn("[wrnexus:store] " + code + ": " + message, details || ""); +} +function __csrfToken() { + if (typeof document === "undefined") return undefined; + const match = /(?:^|;\\s*)wire-csrf=([^;]+)/.exec(document.cookie || ""); + return match ? decodeURIComponent(match[1]) : undefined; +} +async function __callServerFunction(storeName, functionName, args, options) { + options = options || {}; + const csrf = options.csrfToken || __csrfToken(); + const traceId = options.traceId || (globalThis.crypto && crypto.randomUUID ? crypto.randomUUID() : String(Date.now())); + const response = await fetch(options.endpoint || "/__wrnexus/rpc", { + method: "POST", + credentials: "same-origin", + signal: options.signal, + headers: Object.assign({ "content-type": "application/json", "x-request-id": traceId }, csrf ? { "x-csrf-token": csrf } : {}, options.headers || {}), + body: JSON.stringify({ component: storeName, function: functionName, args: args }), + }); + const payload = await response.json().catch(function () { return null; }); + if (!response.ok || !payload || !payload.ok) { + const error = new Error(payload && payload.error && payload.error.message || "Server call failed (" + response.status + ")"); + error.code = payload && payload.error && payload.error.code || "WRN-RPC-FAILED"; + error.status = response.status; + error.details = payload && payload.error && payload.error.details; + error.traceId = payload && payload.error && payload.error.traceId || traceId; + throw error; + } + return payload.value; +} +function __compatible(expected, value) { + if (expected === null || value === null) return expected === value || expected === null; + if (Array.isArray(expected)) return Array.isArray(value); + return typeof expected === typeof value; +} +function __create(definition) { + const routeId = typeof location !== "undefined" ? location.pathname + location.search : "default"; + const key = definition.kind === "page" ? definition.name + "@" + routeId : definition.name; + if (__registry.has(key)) return __registry.get(key); + let currentDefinition = definition; + const listeners = new Set(); + const initial = currentDefinition.createState(); + let restored = null; + if (currentDefinition.persist) { + try { + const storage = __storage(currentDefinition.persist.storage); + const rawValue = storage && storage.getItem("wrnexus:store:" + currentDefinition.name); + const parsed = rawValue ? JSON.parse(rawValue) : null; + if (parsed) { + let candidate = parsed.state; + const fromVersion = Number(parsed.version || 0); + if (fromVersion !== currentDefinition.persist.version) { + if (typeof currentDefinition.persist.migrate === "function") candidate = currentDefinition.persist.migrate(candidate, fromVersion, currentDefinition.persist.version); + else { __diagnostic("WRN-PERSIST-VERSION", "Persisted state version cannot be restored without a migration.", { fromVersion, toVersion: currentDefinition.persist.version }); candidate = null; } + } + if (candidate && typeof currentDefinition.persist.validate === "function") candidate = currentDefinition.persist.validate(candidate); + if (candidate && typeof candidate === "object" && !Array.isArray(candidate)) { + restored = {}; + currentDefinition.persist.include.forEach(function (name) { if (Object.prototype.hasOwnProperty.call(candidate, name)) restored[name] = candidate[name]; }); + } else if (candidate != null) { + __diagnostic("WRN-PERSIST-INVALID", "Persisted state failed validation and was reset.", candidate); + } + } + } catch (error) { __diagnostic("WRN-PERSIST-RESTORE", "Persisted state could not be restored and was reset.", error); } + } + const raw = Object.assign({}, initial, restored || {}, __hydration[currentDefinition.name] || {}); + let mutable = false; + let actionName = "direct"; + function persistState() { + if (!currentDefinition.persist) return; + try { + const picked = {}; + currentDefinition.persist.include.forEach(function (name) { picked[name] = raw[name]; }); + const storage = __storage(currentDefinition.persist.storage); + if (storage) storage.setItem("wrnexus:store:" + currentDefinition.name, JSON.stringify({ version: currentDefinition.persist.version, state: picked })); + } catch (error) { __diagnostic("WRN-PERSIST-WRITE", "Persisted state could not be written.", error); } + } + const state = new Proxy(raw, { + set(target, property, value) { + if (!mutable) throw new TypeError("WRN-STORE-READONLY: " + currentDefinition.name + "." + String(property) + " must be changed by a store action."); + if (Object.is(target[property], value)) return true; + target[property] = value; + persistState(); + listeners.forEach(function (listener) { listener(instance.snapshot(), { store: currentDefinition.name, action: actionName, changed: [String(property)] }); }); + return true; + }, + deleteProperty(target, property) { + if (!mutable) throw new TypeError("WRN-STORE-READONLY: store state is readonly outside actions"); + return Reflect.deleteProperty(target, property); + }, + }); + const actions = {}; + const server = new Proxy({}, { get: function (_target, property) { return function () { return __callServerFunction(currentDefinition.name, String(property), Array.prototype.slice.call(arguments)); }; } }); + function installActions() { + Object.keys(actions).forEach(function (name) { delete actions[name]; }); + Object.entries(currentDefinition.actions || {}).forEach(function (pair) { + const name = pair[0], candidates = pair[1]; + const selected = candidates.find(function (entry) { return entry.runtime === "client"; }) || candidates.find(function (entry) { return entry.runtime === "shared"; }) || candidates.find(function (entry) { return entry.runtime === "legacy"; }); + if (!selected) return; + actions[name] = async function () { + const args = Array.prototype.slice.call(arguments); + const previousMutable = mutable, previousAction = actionName; + mutable = true; actionName = name; + try { return await selected.handler({ state, snapshot: function () { return __clone(state); }, reset: function () { return instance.reset(); }, runtime: "client", routeId, server }, ...args); } + finally { mutable = previousMutable; actionName = previousAction; } + }; + }); + } + installActions(); + const core = { + name: currentDefinition.name, + kind: currentDefinition.kind, + state, + actions, + whenReady: Promise.resolve(), + reset() { + mutable = true; actionName = "$reset"; + try { + const next = currentDefinition.createState(); + Object.keys(raw).forEach(function (name) { if (!(name in next)) delete raw[name]; }); + Object.assign(raw, next); persistState(); + listeners.forEach(function (listener) { listener(instance.snapshot(), { store: currentDefinition.name, action: "$reset", changed: Object.keys(next) }); }); + } finally { mutable = false; actionName = "direct"; } + }, + snapshot() { return Object.freeze(__clone(raw)); }, + subscribe(listener) { listeners.add(listener); return function () { listeners.delete(listener); }; }, + async dispose() { + mutable = true; actionName = "$dispose"; + try { await currentDefinition.lifecycle && currentDefinition.lifecycle.dispose && currentDefinition.lifecycle.dispose({ state, runtime: "client", routeId, server }); } + finally { mutable = false; actionName = "direct"; listeners.clear(); __registry.delete(key); } + }, + async __hotUpdate(nextDefinition) { + const previous = __clone(raw); + const nextShape = nextDefinition.createState(); + const preserved = [], reset = [], added = [], removed = []; + Object.keys(previous).forEach(function (name) { + if (!(name in nextShape)) { removed.push(name); return; } + if (__compatible(nextShape[name], previous[name])) { nextShape[name] = previous[name]; preserved.push(name); } + else reset.push(name); + }); + Object.keys(nextShape).forEach(function (name) { if (!(name in previous)) added.push(name); }); + currentDefinition = nextDefinition; + mutable = true; actionName = "$hmr"; + try { + Object.keys(raw).forEach(function (name) { delete raw[name]; }); + Object.assign(raw, nextShape); + installActions(); persistState(); + } finally { mutable = false; actionName = "direct"; } + const result = { store: currentDefinition.name, preserved, reset, added, removed }; + listeners.forEach(function (listener) { listener(instance.snapshot(), { store: currentDefinition.name, action: "$hmr", changed: added.concat(reset, removed) }); }); + try { __root.dispatchEvent && __root.dispatchEvent(new CustomEvent("wrnexus:store-hmr", { detail: result })); } catch (_) {} + return result; + }, + }; + const instance = new Proxy(core, { + get(target, property, receiver) { + if (Reflect.has(target, property)) return Reflect.get(target, property, receiver); + if (property in actions) return actions[property]; + if (property in (currentDefinition.computed || {})) return currentDefinition.computed[property](state); + return state[property]; + }, + set() { throw new TypeError("WRN-STORE-READONLY: store state is readonly outside actions"); }, + }); + __registry.set(key, instance); + const hydrationSource = __hydration[currentDefinition.name]; + const init = async function () { + const run = async function (name, hook) { + if (!hook) return; + mutable = true; actionName = name; + try { await hook({ state, runtime: "client", routeId, server }); } + finally { mutable = false; actionName = "direct"; } + }; + await run("$clientInit", currentDefinition.lifecycle && currentDefinition.lifecycle.clientInit); + if (hydrationSource) await run("$hydrate", currentDefinition.lifecycle && currentDefinition.lifecycle.hydrate); + }; + core.whenReady = init(); + return instance; +} +if (!__root.__wrnexusApplyStoreHotUpdate) { + __root.__wrnexusApplyStoreHotUpdate = async function (name, definition) { + const results = []; + for (const item of Array.from(__registry.values())) if (item.name === name && typeof item.__hotUpdate === "function") results.push(await item.__hotUpdate(definition)); + return results; + }; +} +if (!__root.__wrnexusStoreContainer) { + __root.__wrnexusStoreContainer = { + async disposePageStores() { for (const item of Array.from(__registry.values())) if (item.kind === "page") await item.dispose(); }, + async hotUpdate(name, definition) { return __root.__wrnexusApplyStoreHotUpdate(name, definition); }, + inspect() { return Array.from(__registry.values()).map(function (item) { return { name: item.name, kind: item.kind, state: item.snapshot() }; }); }, + }; +} +export const ${ast.name}Definition = { + name: ${JSON.stringify(ast.name)}, + kind: ${JSON.stringify(ast.storeKind)}, + createState: () => (${initialState}), + computed: { ${computed} }, + actions: { ${actions} }, + persist: ${persistence}, + lifecycle: { ${lifecycleEntries} }, +}; +export const ${ast.name} = __create(${ast.name}Definition); +export default ${ast.name}; +`; +} + +// packages/compiler/src/analysis.ts +function identifiers(value) { + return new Set(value.match(/[A-Za-z_$][\w$]*/g) ?? []); +} +function literalBoolean(expression2) { + if (expression2 === null) return true; + const value = expression2.trim(); + if (value === "true") return true; + if (value === "false" || value === "null" || value === "undefined" || value === "0" || value === "''" || value === '""') + return false; + if (/^-?(?:[1-9]\d*|0?\.\d+)$/.test(value) || /^(['"]).+\1$/.test(value)) return true; + return void 0; +} +function optimizeNodes(nodes, report) { + const output = []; + for (const node of nodes) { + if (node.type === "element") + output.push({ + ...node, + attrs: node.attrs.map((attribute) => ({ ...attribute })), + children: optimizeNodes(node.children, report) + }); + else if (node.type === "each") + output.push({ + ...node, + body: optimizeNodes(node.body, report), + empty: optimizeNodes(node.empty, report) + }); + else if (node.type === "if") { + let selected; + let dynamic = false; + for (const branch of node.branches) { + const value = literalBoolean(branch.cond); + if (value === void 0) { + dynamic = true; + break; + } + report.eliminated++; + if (value) { + selected = branch.body; + break; + } + } + if (dynamic) + output.push({ + ...node, + branches: node.branches.map((branch) => ({ + ...branch, + body: optimizeNodes(branch.body, report) + })) + }); + else if (selected) output.push(...optimizeNodes(selected, report)); + } else output.push({ ...node }); + } + return output; +} +function optimizeAst(ast) { + const report = { eliminated: 0 }; + return { + ast: { ...ast, view: optimizeNodes(ast.view, report) }, + eliminatedBranches: report.eliminated + }; +} +function analyzeOptimizations(ast) { + const used = /* @__PURE__ */ new Set(); + let staticNodes = 0; + let reactiveRegions = 0; + const componentNames = /* @__PURE__ */ new Set(); + const staticClasses = /* @__PURE__ */ new Set(); + const visit = (nodes) => { + for (const node of nodes) { + if (node.type === "text") { + const refs = identifiers(node.value); + refs.forEach((name) => used.add(name)); + if (node.value.includes("{")) reactiveRegions++; + else staticNodes++; + } else if (node.type === "element") { + if (/^[A-Z]/.test(node.tag)) componentNames.add(node.tag); + let reactive = false; + for (const attribute of node.attrs) { + identifiers(attribute.value).forEach((name) => used.add(name)); + reactive ||= attribute.event || attribute.value.includes("{"); + if (attribute.name === "class" && !attribute.value.includes("{")) { + for (const name of attribute.value.split(/\s+/)) if (name) staticClasses.add(name); + } + } + if (reactive) reactiveRegions++; + else staticNodes++; + visit(node.children); + } else if (node.type === "each") { + identifiers(`${node.list} ${node.key ?? ""}`).forEach((name) => used.add(name)); + reactiveRegions++; + visit(node.body); + visit(node.empty); + } else { + for (const branch of node.branches) { + identifiers(branch.cond ?? "").forEach((name) => used.add(name)); + visit(branch.body); + } + reactiveRegions++; + } + } + }; + visit(ast.view); + const handlerReferences = new Set(used); + const executable = [ + ...ast.runtimeFunctions.map((fn) => fn.body), + ...ast.functions, + ...ast.effects.map((effect) => effect.body), + ...ast.watches.map((watch) => watch.body), + ...ast.actions.map((action) => action.body) + ].join("\n"); + identifiers(executable).forEach((name) => used.add(name)); + const localCss = new Set( + ast.styles.flatMap( + (style) => [...style.matchAll(/\.([_a-zA-Z][\w-]*)/g)].map((match) => match[1]) + ) + ); + const optimized = optimizeAst(ast); + const assignmentCounts = ast.runtimeFunctions.map( + (fn) => ast.states.filter( + (state) => new RegExp(`\\b${state.name}\\s*(?:[+*/-]?=|\\+\\+|--)`).test(fn.body) + ).length + ); + return { + staticNodes, + reactiveRegions, + eliminatedBranches: optimized.eliminatedBranches, + unusedState: ast.states.filter((state) => !used.has(state.name)).map((state) => state.name), + unusedHandlers: ast.runtimeFunctions.filter((fn) => fn.runtime !== "server" && !handlerReferences.has(fn.name)).map((fn) => fn.name), + constantProps: ast.props.filter( + (prop) => /^(?:-?\d+(?:\.\d+)?|true|false|null|(['"]).*\1)$/.test(prop.default.trim()) + ).map((prop) => prop.name), + unusedLocalCssClasses: [...localCss].filter((name) => !staticClasses.has(name)).sort(), + batchableStateUpdates: assignmentCounts.filter((count) => count > 1).reduce((sum, count) => sum + count - 1, 0), + memoizableComponents: [...componentNames].sort(), + preloadDependencies: ast.structuredImports.filter((entry) => !entry.typeOnly && !entry.source.startsWith("node:")).map((entry) => entry.source), + serverOnlyModules: ast.structuredImports.filter((entry) => entry.source.startsWith("node:") || ast.runtime === "server").map((entry) => entry.source) + }; +} +function hasEvent(nodes) { + for (const node of nodes) { + if (node.type === "element") { + if (node.attrs.some((attribute) => attribute.event)) return true; + if (hasEvent(node.children)) return true; + } else if (node.type === "each") { + if (hasEvent(node.body) || hasEvent(node.empty)) return true; + } else if (node.type === "if") { + if (node.branches.some((branch) => hasEvent(branch.body))) return true; + } + } + return false; +} +function analyzeRuntimeRequirements(ast) { + const reasons = []; + const clientFunctions = ast.runtimeFunctions.some((fn) => fn.runtime !== "server"); + const clientState = ast.states.some((state) => state.runtime !== "server"); + const interactive = clientFunctions || clientState || ast.effects.length > 0 || ast.watches.length > 0 || hasEvent(ast.view); + if (interactive) reasons.push("client interactivity"); + const requestData = ast.loads.length > 0 || ast.actions.length > 0 || ast.dataApis.length > 0 || ast.apis.length > 0 || ast.realtimes.length > 0 || ast.runtimeFunctions.some((fn) => fn.runtime === "server") || ast.states.some((state) => state.runtime === "server"); + if (requestData) reasons.push("server/request data"); + const authenticated = /^(?:required|true)$/i.test(ast.security.auth ?? ""); + if (authenticated) reasons.push("authentication required"); + const streaming = /^(?:true|required)$/i.test(ast.security.streaming ?? ""); + if (streaming) reasons.push("streaming enabled"); + let kind; + if (streaming) kind = "streaming-ssr"; + else if (authenticated) kind = "authenticated-ssr"; + else if (requestData && interactive) kind = "dynamic"; + else if (requestData) kind = "request-ssr"; + else if (interactive) kind = "static-interactive"; + else kind = "static"; + if (ast.renderMode === "static") { + kind = "static"; + reasons.push("explicit static rendering"); + } else if (ast.renderMode === "server") { + kind = requestData ? "request-ssr" : "static"; + reasons.push("explicit server rendering"); + } else if (ast.renderMode === "client") { + kind = "static-interactive"; + reasons.push("explicit client rendering"); + } else if (ast.renderMode === "partial-static") { + kind = "streaming-ssr"; + reasons.push("partial-static shell with streamed dynamic regions"); + } + const clientDisabled = ast.renderMode === "static" || ast.renderMode === "server"; + const serverDisabled = ast.renderMode === "client"; + return { + kind, + canPrerender: kind === "static" || kind === "static-interactive", + needsClientRuntime: !clientDisabled && (interactive || ast.renderMode === "client") && ast.hydrate !== "none" && ast.runtime !== "server", + needsServerRuntime: !serverDisabled && (requestData || authenticated || streaming || ast.renderMode === "server" || ["server", "edge", "worker", "service-worker"].includes(ast.runtime ?? "")), + hydrationStrategy: clientDisabled ? null : interactive ? ast.hydrate ?? "load" : null, + reasons, + optimization: analyzeOptimizations(ast), + cachePolicy: { ...ast.cache ?? {} }, + requiredPermission: ast.security.permission ?? null + }; +} + +// packages/compiler/src/codegen.ts +function isComponentTag(tag) { + return /^[A-Z][A-Za-z0-9_$]*$/.test(tag); +} +var HTML_BOOLEAN_ATTRIBUTES = /* @__PURE__ */ new Set([ + "allowfullscreen", + "async", + "autofocus", + "autoplay", + "checked", + "controls", + "default", + "defer", + "disabled", + "formnovalidate", + "hidden", + "inert", + "ismap", + "itemscope", + "loop", + "multiple", + "muted", + "nomodule", + "novalidate", + "open", + "playsinline", + "readonly", + "required", + "reversed", + "selected" +]); +function isHtmlBooleanAttribute(name) { + return HTML_BOOLEAN_ATTRIBUTES.has(name.toLowerCase()); +} +var URL_ATTRIBUTES = /* @__PURE__ */ new Set([ + "href", + "src", + "action", + "formaction", + "poster", + "cite", + "background", + "xlink:href" +]); +function stripAsciiControlAndSpace(value) { + let result = ""; + for (const character of value) { + if (character.charCodeAt(0) > 32) result += character; + } + return result; +} +function sanitizeUrlAttribute(value) { + const compact = stripAsciiControlAndSpace(value.trim()); + const lower = compact.toLowerCase(); + if (/^(?:javascript|vbscript|file):/.test(lower)) return "about:blank"; + if (/^data:(?!image\/(?:png|gif|jpeg|webp|avif);)/.test(lower)) return "about:blank"; + return value; +} +function safeAttributeValue(name, value) { + if (!URL_ATTRIBUTES.has(name.toLowerCase()) || value.includes("{")) return value; + return sanitizeUrlAttribute(value); +} +function attrEscape(value) { + return value.replace(/&/g, "&").replace(/"/g, """).replace(//g, ">"); +} +function templateEscape(html) { + return html.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${"); +} +function styleEscape(css) { + return css.replace(/<\/style/gi, "<\\/style"); +} +function attrValue(attrs, name) { + return attrs.find((attr) => !attr.event && attr.name === name)?.value; +} +function renderAttr(attr) { + if (attr.event) return ` ${eventAttribute(attr.name)}="${attrEscape(attr.value)}"`; + switch (attr.name) { + case "api": + case "ssrGet": + case "ssrText": + case "csrGet": + case "csrText": + return ""; + default: + return attr.boolean ? ` ${attr.name}` : ` ${attr.name}="${attrEscape(safeAttributeValue(attr.name, attr.value))}"`; + } +} +function eventAttribute(name) { + if (name.startsWith("window:")) { + return `data-on-window-${name.slice("window:".length)}`; + } + if (name.startsWith("document:")) { + return `data-on-document-${name.slice("document:".length)}`; + } + if (name.startsWith("browser-")) { + return `data-on-wrnexus-browser-${name.slice(8)}`; + } + if (name.startsWith("mobile-")) { + return `data-on-wrnexus-mobile-${name.slice(7)}`; + } + return `data-on-${name}`; +} +function reactiveAttrValue(raw, reactive) { + let found = false; + const value = raw.replace(/\{([^{}]+)\}/g, (whole, inner) => { + const expr = inner.trim(); + if (!exprRefsState(expr, reactive.stateNames)) return whole; + found = true; + try { + const result = new Function("with(this){return (" + expr + ");}").call(reactive.scope); + return result == null ? "" : String(result); + } catch { + return whole; + } + }); + return found ? value : null; +} +function renderAttrs(attrs, csrId, reactive = null, dynamicExpressions) { + let bindIndex = 0; + const rendered = attrs.map((attr) => { + const base = renderAttr(attr); + if (!reactive || attr.event || attr.boolean || !base || !attr.value.includes("{")) + return base; + const expression2 = wholeAttributeExpression(attr.value); + if (expression2 && exprRefsState(expression2, reactive.runtimeStateNames) && dynamicExpressions) { + dynamicExpressions.push(`\${__wrnexusPropAttr(${expression2})}`); + const sentinel = `\0WRNEACH${dynamicExpressions.length - 1}\0`; + const marker2 = JSON.stringify([attr.name, attr.value]); + return ` ${attr.name}="${sentinel}" data-wrn-bind-${bindIndex++}="${attrEscape(marker2)}"`; + } + const initial = reactiveAttrValue(attr.value, reactive); + if (initial === null) return base; + const marker = JSON.stringify([attr.name, attr.value]); + return ` ${attr.name}="${attrEscape(URL_ATTRIBUTES.has(attr.name.toLowerCase()) ? sanitizeUrlAttribute(initial) : initial)}" data-wrn-bind-${bindIndex++}="${attrEscape(marker)}"`; + }).join(""); + return csrId ? `${rendered} data-wrnexus-csr="${attrEscape(csrId)}"` : rendered; +} +function substituteTMarkers(text) { + return text.replace( + /\{t:([^{}]+)\}/g, + (_m, key) => `` + ); +} +function htmlTextEscape(value) { + return value.replace(/[&<>]/g, (c) => c === "&" ? "&" : c === "<" ? "<" : ">"); +} +function evalStateSeeds(states) { + const scope = {}; + for (const s of states) { + try { + scope[s.name] = new Function("with(this){return (" + s.expr + ");}").call(scope); + } catch { + scope[s.name] = void 0; + } + } + return scope; +} +function substituteReactiveText(raw, reactive) { + const text = substituteTMarkers(raw); + if (!reactive || reactive.stateNames.size === 0) return text; + return text.replace(/\{([^{}]+)\}/g, (whole, inner) => { + const expr = inner.trim(); + if (expr.startsWith("t:") || !exprRefsState(expr, reactive.stateNames)) return whole; + let value; + try { + value = new Function("with(this){return (" + expr + ");}").call(reactive.scope); + } catch { + return whole; + } + const baked = htmlTextEscape(value == null ? "" : String(value)); + return `${baked}`; + }); +} +function bakeLoopText(raw) { + let out = ""; + let last = 0; + let m; + const re = /\{([^{}]+)\}/g; + while (m = re.exec(raw)) { + out += escLit(raw.slice(last, m.index)); + const expr = m[1].trim(); + if (expr.startsWith("t:")) { + out += escLit(``); + } else { + out += "${__wrnexusEscapeHtml(" + expr + ")}"; + } + last = m.index + m[0].length; + } + return out + escLit(raw.slice(last)); +} +function bakeLoopAttr(raw) { + if (!raw.includes("{")) return escLit(attrEscape(raw)); + let out = ""; + let last = 0; + let m; + const re = /\{([^{}]+)\}/g; + while (m = re.exec(raw)) { + out += escLit(attrEscape(raw.slice(last, m.index))); + out += "${__wrnexusEscapeHtml(" + m[1].trim() + ")}"; + last = m.index + m[0].length; + } + return out + escLit(attrEscape(raw.slice(last))); +} +function renderLoopBody(node) { + if (node.type === "text") { + return bakeLoopText(node.value); + } + if (node.type === "each") { + return compileEachExpr(node); + } + if (node.type === "if") { + return compileIfExpr(node); + } + const componentTag = isComponentTag(node.tag); + const attrs = node.attrs.filter((attr) => attr.name !== "data-component").map((attr) => { + const name = attr.event ? eventAttribute(attr.name) : attr.name; + if (attr.boolean) { + return escLit(` ${name}`); + } + return escLit(` ${name}="`) + bakeLoopAttr(attr.value) + escLit(`"`); + }).join(""); + const inner = node.children.map(renderLoopBody).join(""); + if (node.tag === "Static") return inner; + if (node.tag === "Dynamic") + return escLit('') + inner + escLit(""); + if (node.tag === "KeepAlive") { + const key = node.attrs.find((attribute) => attribute.name === "key")?.value ?? "default"; + return escLit('
`) + inner + escLit("
"); + } + if (node.tag === "Portal") { + const target = node.attrs.find((attribute) => attribute.name === "to")?.value ?? "body"; + return escLit('
') + inner + escLit("
"); + } + if (node.tag === "Transition") { + const name = node.attrs.find((attribute) => attribute.name === "name")?.value ?? "wrn-transition"; + return escLit('
') + inner + escLit("
"); + } + if (node.tag === "Component") { + const selected = node.attrs.find((attribute) => attribute.name === "is")?.value ?? ""; + return escLit('
') + inner + escLit("
"); + } + if (componentTag) { + return escLit(`
") + inner + escLit("
"); + } + if (parser_exports.VOID_ELEMENTS.has(node.tag.toLowerCase())) { + return escLit(`<${node.tag}`) + attrs + escLit(">"); + } + return escLit(`<${node.tag}`) + attrs + escLit(">") + inner + escLit(``); +} +function compileEachExpr(node) { + const item = node.item; + const index = node.index ?? "__wi"; + const body = node.body.map(renderLoopBody).join(""); + const empty = node.empty.map(renderLoopBody).join(""); + return "${(() => { const __wl = Array.isArray(" + node.list + ") ? (" + node.list + ") : []; return __wl.length ? __wl.map((" + item + ", " + index + ") => `" + body + '`).join("") : `' + empty + "`; })()}"; +} +function compileIfExpr(node) { + let expr = "``"; + for (let k = node.branches.length - 1; k >= 0; k--) { + const b = node.branches[k]; + const bodySrc = "`" + b.body.map(renderLoopBody).join("") + "`"; + expr = b.cond === null ? bodySrc : "(" + b.cond + ") ? " + bodySrc + " : " + expr; + } + return "${" + expr + "}"; +} +function collectControlExprs(nodes, out = []) { + for (const node of nodes) { + if (node.type === "text") continue; + if (node.type === "each") { + out.push(node.list); + collectControlExprs(node.body, out); + collectControlExprs(node.empty, out); + } else if (node.type === "if") { + for (const b of node.branches) { + if (b.cond) out.push(b.cond); + collectControlExprs(b.body, out); + } + } else if (node.type === "element") { + collectControlExprs(node.children, out); + } + } + return out; +} +function renderNode(node, ssrBindings, csrBindings, apiBindings, loops, reactive = null) { + if (node.type === "text") return substituteReactiveText(node.value, reactive); + if (node.type === "each" || node.type === "if") { + loops.push(node.type === "each" ? compileEachExpr(node) : compileIfExpr(node)); + return `\0WRNEACH${loops.length - 1}\0`; + } + if (node.tag === "Static" || node.tag === "Dynamic") { + const inner2 = node.children.map((child) => renderNode(child, ssrBindings, csrBindings, apiBindings, loops, reactive)).join(""); + return node.tag === "Static" ? inner2 : `${inner2}`; + } + if (node.tag === "Portal" || node.tag === "Transition" || node.tag === "Component") { + const inner2 = node.children.map((child) => renderNode(child, ssrBindings, csrBindings, apiBindings, loops, reactive)).join(""); + const attribute = node.tag === "Portal" ? "data-wrn-portal" : node.tag === "Transition" ? "data-wrn-transition" : "data-wrn-dynamic-component"; + const source = node.tag === "Portal" ? "to" : node.tag === "Transition" ? "name" : "is"; + const fallback = node.tag === "Portal" ? "body" : node.tag === "Transition" ? "wrn-transition" : ""; + const original = node.attrs.find((item) => item.name === source); + const rendered = original ? renderAttrs([{ ...original, name: attribute }], void 0, reactive, loops) : ` ${attribute}="${attrEscape(fallback)}"`; + return `${inner2}`; + } + if (node.tag === "Async") { + const source = attrValue(node.attrs, "source") ?? "data"; + const retries = attrValue(node.attrs, "retries") ?? "2"; + const serverResolved = attrValue(node.attrs, "data-wrn-async-server") === "true"; + const asyncIndex = serverResolved ? loops.push("") - 1 : -1; + const branch = (name) => { + const element = node.children.find( + (child) => child.type === "element" && child.tag === name + ); + return (element?.children ?? []).map((child) => renderNode(child, ssrBindings, csrBindings, apiBindings, loops, reactive)).join(""); + }; + const loading = branch("Loading"); + const success = branch("Success"); + const error = branch("Error"); + let initial = loading; + if (serverResolved) { + const nested = (value) => value.replace(/\\/g, "\\\\").replace(/`/g, "\\`"); + const sourcePattern = source.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + const serverSuccess = success.replace( + new RegExp(`\\{\\s*(${sourcePattern}(?:\\.[A-Za-z_$][\\w$]*)*)\\s*\\}`, "g"), + (_whole, expression2) => `\${__wrnexusEscapeHtml(${expression2})}` + ); + loops[asyncIndex] = `\${ctx[${JSON.stringify(source)}] !== undefined ? \`${nested(serverSuccess)}\` : \`${nested(loading)}\`}`; + initial = `\0WRNEACH${asyncIndex}\0`; + } + return `
${initial}
`; + } + if (node.tag === "KeepAlive") { + const key = attrValue(node.attrs, "key") ?? "default"; + const inner2 = node.children.map((child) => renderNode(child, ssrBindings, csrBindings, apiBindings, loops, reactive)).join(""); + return `
${inner2}
`; + } + if (isComponentTag(node.tag)) { + return renderPageComponentInvocation( + node, + ssrBindings, + csrBindings, + apiBindings, + loops, + reactive + ); + } + const apiName = attrValue(node.attrs, "api"); + const apiBinding = apiName ? apiBindings.get(apiName) : void 0; + if (apiName && !apiBinding) { + throw new Error(`Unknown .wrn api binding "${apiName}"`); + } + const ssrGet = attrValue(node.attrs, "ssrGet"); + const ssrText = attrValue(node.attrs, "ssrText"); + const csrGet = attrValue(node.attrs, "csrGet"); + const csrText = attrValue(node.attrs, "csrText"); + const csrId = apiBinding?.mode === "client" ? csrMarker(csrBindings, renderBinding(apiBinding)) : csrGet && csrText ? csrMarker(csrBindings, { + method: "GET", + path: apiRoutePath(csrGet), + body: expressionBody(csrText), + helpers: "" + }) : void 0; + if (parser_exports.VOID_ELEMENTS.has(node.tag.toLowerCase())) { + return `<${node.tag}${renderAttrs(node.attrs, csrId, reactive, loops)}>`; + } + const inner = apiBinding?.mode === "ssr" ? ssrMarker(ssrBindings, renderBinding(apiBinding)) : ssrGet && ssrText ? ssrMarker(ssrBindings, { + method: "GET", + path: apiRoutePath(ssrGet), + body: expressionBody(ssrText), + helpers: "" + }) : node.children.map( + (child) => renderNode(child, ssrBindings, csrBindings, apiBindings, loops, reactive) + ).join(""); + return `<${node.tag}${renderAttrs(node.attrs, csrId, reactive, loops)}>${inner}`; +} +function renderPageComponentInvocation(node, ssrBindings, csrBindings, apiBindings, loops, reactive) { + const attrs = node.attrs.filter((attr) => attr.name !== "data-component").map((attr) => renderPageComponentAttr(attr, loops)).join(""); + const inner = node.children.map((child) => renderNode(child, ssrBindings, csrBindings, apiBindings, loops, reactive)).join(""); + return `
${inner}
`; +} +function renderNestedComponentInvocation(node, ctx) { + let bindIndex = 0; + const attrs = node.attrs.filter((attr) => attr.name !== "data-component").map((attr) => { + const spread = /^\{\.\.\.([A-Za-z_$][\w$]*)\}$/.exec(attr.name); + if (spread) { + return `\${__wireSpreadAttrs(${ctx.resolveExpr(spread[1])})}`; + } + if (attr.event) { + return escLit(` ${eventAttribute(attr.name)}="`) + escLit(attrEscape(attr.value)) + escLit(`"`); + } + if (attr.boolean) { + return ` ${attr.name}`; + } + 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)) { + return rendered; + } + const marker = attrEscape(JSON.stringify([attr.name, attr.value])); + return rendered + ` data-wrn-bind-${bindIndex++}="${escLit(marker)}"`; + }).join(""); + const loops = loopVarsOf(node); + const childCtx = loops.length > 0 ? { + ...ctx, + forwardRestAttrs: false, + loopVars: /* @__PURE__ */ new Set([...ctx.loopVars ?? [], ...loops]) + } : { ...ctx, forwardRestAttrs: false }; + const inner = node.children.map((child) => renderComponentNode(child, childCtx)).join(""); + return `
${inner}
`; +} +function ssrMarker(bindings, binding) { + const marker = ``; + bindings.push({ marker, ...binding }); + return marker; +} +function csrMarker(bindings, binding) { + const id = String(bindings.length); + bindings.push({ id, ...binding }); + return id; +} +function renderBinding(binding) { + return { + method: binding.method, + path: binding.path, + body: binding.body, + helpers: binding.helpers + }; +} +function hasClientBehavior(nodes) { + return nodes.some((node) => { + if (node.type === "text") return /\{(?!t:)[^{}]+\}/.test(node.value); + if (node.type === "each") { + return hasClientBehavior(node.body) || hasClientBehavior(node.empty); + } + if (node.type === "if") { + return node.branches.some((branch) => hasClientBehavior(branch.body)); + } + return node.attrs.some((attr) => attr.event || attr.name === "csrGet" || attr.name === "csrText") || hasClientBehavior(node.children); + }); +} +function apiRoutePath(path) { + const trimmed = path.trim(); + if (!trimmed.startsWith("/")) { + throw new Error(`.wrn API paths must start with "/": ${path}`); + } + if (trimmed.includes("\0") || trimmed.includes("\\") || /(^|\/)\.\.(\/|$)/.test(trimmed)) { + throw new Error(`Unsafe .wrn API path: ${path}`); + } + if (trimmed === "/api" || trimmed.startsWith("/api/")) return trimmed; + return `/api${trimmed}`; +} +function expressionBody(expr) { + return `return (${expr});`; +} +function dataBody(source) { + const trimmed = source.trim(); + if (!trimmed) return "return undefined;"; + return /\breturn\b/.test(trimmed) ? trimmed : expressionBody(trimmed); +} +function modeHelpers(ast, mode, sharedHelpers) { + return [ + sharedHelpers, + ...ast.modeFunctions.filter((block) => block.mode === mode).map((block) => block.body.trim()).filter(Boolean) + ].filter(Boolean).join("\n\n"); +} +function apiBindingMap(ast, sharedHelpers) { + const bindings = /* @__PURE__ */ new Map(); + for (const block of ast.dataApis) { + if (bindings.has(block.name)) { + throw new Error(`Duplicate .wrn api binding "${block.name}"`); + } + bindings.set(block.name, { + mode: block.mode, + method: block.method, + path: apiRoutePath(block.path), + body: dataBody(block.body), + helpers: modeHelpers(ast, block.mode, sharedHelpers) + }); + } + return bindings; +} +function ssrRuntimeSource() { + return `const __wrnexusHtmlEscapes = { "&": "&", "<": "<", ">": ">", "\\"": """, "'": "'" }; +function __wrnexusEscapeHtml(value: unknown): string { + return String(value).replace(/[&<>"']/g, (ch) => __wrnexusHtmlEscapes[ch] ?? ch); +} + +function __wrnexusEvalData(data: unknown, body: string, helpers = "", ctx: any): unknown { + const adapters = { + cookies: ctx.cookies, + session: ctx.session, + localStorage: ctx.localStorage, + }; + return new Function("$data", "$adapters", "const cookies = $adapters.cookies;\\nconst session = $adapters.session;\\nconst localStorage = $adapters.localStorage;\\nwith ($data ?? {}) {\\n" + helpers + "\\n" + body + "\\n}")(data, adapters); +} + +function __wrnexusPropAttr( + value: unknown, +): string { + const serialized = + value !== null && + typeof value === "object" + ? JSON.stringify(value) + : String(value == null ? "" : value); + + return serialized.replace( + /[&<>"]/g, + (character) => + character === "&" + ? "&" + : character === "<" + ? "<" + : character === ">" + ? ">" + : """, + ); +} + +async function __wrnexusCallApi(path: string, method: string, ctx: any): Promise { + if (typeof ctx.__wrnexusCallApi === "function") { + return await ctx.__wrnexusCallApi(path, method); + } + + const url = new URL(path, ctx.req.url); + const res = await fetch(new Request(url, { method, headers: ctx.req.headers })); + if (!res.ok) { + throw new Error(".wrn data API request failed with status " + res.status); + } + + const type = res.headers.get("content-type") || ""; + return type.includes("application/json") ? await res.json() : await res.text(); +} + +async function __wrnexusRenderSsrBindings(html: string, ctx: any): Promise { + for (const binding of __wrnexusSsrBindings) { + const data = await __wrnexusCallApi(binding.path, binding.method, ctx); + const value = __wrnexusEvalData(data, binding.body, binding.helpers, ctx); + html = html.replace(binding.marker, __wrnexusEscapeHtml(value)); + } + return html; +}`; +} +function stableHash(value) { + let hash = 2166136261; + for (let index = 0; index < value.length; index++) { + hash ^= value.charCodeAt(index); + hash = Math.imul(hash, 16777619); + } + return (hash >>> 0).toString(36); +} +function hydrationId(ast) { + const shape = JSON.stringify({ + kind: ast.kind, + name: ast.name, + props: ast.props.map((entry) => entry.name), + events: ast.events.map((entry) => entry.name), + states: ast.states.map((entry) => entry.name), + computed: ast.computed.map((entry) => entry.name), + view: ast.view + }); + return `${ast.name}:${stableHash(shape)}`; +} +function localStyleId(ast) { + return `wrn-${ast.kind}-${stableHash(`${ast.kind}:${ast.name}`)}`; +} +function localStyleTag(ast, styles) { + if (!styles.length) return ""; + const id = localStyleId(ast); + const css = styles.map(styleEscape).join("\n"); + return ``; +} +function localStyleExport(ast, styles) { + if (!styles.length) return null; + return `export const __wrnexusStyles = ${JSON.stringify( + [ + { + id: localStyleId(ast), + owner: ast.name, + kind: ast.kind, + css: styles.join("\n") + } + ], + null, + 2 + )};`; +} +function isStoreImportSource(source) { + return /(?:^|\/)stores?\//.test(source) || source.startsWith("@wrnexus/store"); +} +function importedStoreBindings(ast) { + return ast.structuredImports.filter( + (entry) => entry.defaultImport && entry.source.endsWith(".wrn") && isStoreImportSource(entry.source) + ).map((entry) => ({ + local: entry.defaultImport, + internal: `__wrnexusStoreDefinition_${entry.defaultImport}` + })); +} +function generatedImports(ast) { + const stores = new Map(importedStoreBindings(ast).map((entry) => [entry.local, entry.internal])); + return ast.structuredImports.map((entry) => { + if (!entry.defaultImport) return entry.raw; + const internal = stores.get(entry.defaultImport); + return internal ? entry.raw.replace( + new RegExp( + `^(\\s*import\\s+(?:type\\s+)?)(?:${entry.defaultImport.replace(/[.*+?^${}()|[\\]\\]/g, "\\$&")})(\\s+from\\s+)` + ), + `$1${internal}$2` + ) : entry.raw; + }); +} +function isSafeGeneratedIdentifier(name) { + return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name); +} +function generateSsrStateAliases(stateNames) { + const names = [...new Set(stateNames)].filter(isSafeGeneratedIdentifier); + if (!names.length) { + return ""; + } + return `const { ${names.join(", ")} } = __state; +`; +} +function hydrationAttribute(ast) { + const strategy = ["static", "server"].includes(ast.renderMode ?? "") ? "none" : ast.hydrate ?? "load"; + const hasBrowserModule = ast.runtimeFunctions.some( + (fn) => ["legacy", "client", "shared"].includes(fn.runtime) + ); + const moduleAttribute = hasBrowserModule ? ' data-wrn-client-module="__WRNEXUS_CLIENT_MODULE__"' : ""; + return ` data-wrn-hydration="${attrEscape(hydrationId(ast))}" data-wrn-hydrate="${attrEscape(strategy)}" data-wrn-runtime="${attrEscape(ast.runtime ?? "universal")}"${moduleAttribute}`; +} +function targetFunctions(ast, target) { + const runtimes = target === "browser" ? ["legacy", "client", "shared"] : ["legacy", "server", "shared"]; + return ast.functions.map((body) => stripRuntimeFunctionModifiers2(body, [...runtimes])).map((body) => body.trim()).filter(Boolean).join("\n\n"); +} +function publicOutputNames(ast) { + return [ + .../* @__PURE__ */ new Set([ + ...ast.outputs.map((output) => output.name), + ...ast.events.map((event) => event.name) + ]) + ]; +} +function prepareActionForms(nodes, actions) { + for (const node of nodes) { + if (node.type === "text") continue; + if (node.type === "each") { + prepareActionForms(node.body, actions); + prepareActionForms(node.empty, actions); + continue; + } + if (node.type === "if") { + node.branches.forEach((branch) => prepareActionForms(branch.body, actions)); + continue; + } + prepareActionForms(node.children, actions); + if (node.tag.toLowerCase() !== "form") continue; + const submit = node.attrs.find((attr) => attr.event && attr.name === "submit"); + if (!submit || !actions.has(submit.value.trim())) continue; + const name = submit.value.trim(); + node.attrs = node.attrs.filter((attr) => attr !== submit); + if (!node.attrs.some((attr) => !attr.event && attr.name === "method")) { + node.attrs.push({ name: "method", value: "post", event: false }); + } + node.attrs.push({ name: "data-wrn-action", value: name, event: false }); + node.children.unshift({ + type: "element", + tag: "input", + attrs: [ + { name: "type", value: "hidden", event: false }, + { name: "name", value: "_wrnexus_action", event: false }, + { name: "value", value: name, event: false } + ], + children: [] + }); + } +} +function markServerAsyncBoundaries(nodes, serverLoads) { + for (const node of nodes) { + if (node.type === "text") continue; + if (node.type === "each") { + markServerAsyncBoundaries(node.body, serverLoads); + markServerAsyncBoundaries(node.empty, serverLoads); + continue; + } + if (node.type === "if") { + node.branches.forEach((branch) => markServerAsyncBoundaries(branch.body, serverLoads)); + continue; + } + if (node.tag === "Async") { + const source = attrValue(node.attrs, "source") ?? "data"; + if (serverLoads.has(source) && !node.attrs.some((attribute) => attribute.name === "data-wrn-async-server")) { + node.attrs.push({ name: "data-wrn-async-server", value: "true", event: false }); + } + } + markServerAsyncBoundaries(node.children, serverLoads); + } +} +function generate(ast) { + ast = optimizeAst(ast).ast; + if (ast.kind === "global-store" || ast.kind === "page-store") return generateStoreModule(ast); + if (ast.kind === "component" || ast.kind === "layout") { + return generateComponent(ast); + } + const out = []; + prepareActionForms(ast.view, new Set(ast.actions.map((action) => action.name))); + markServerAsyncBoundaries( + ast.view, + new Set( + ast.loads.filter((load) => load.mode === "server" && !load.deferred && load.name).map((load) => load.name) + ) + ); + if (ast.actions.length > 0) { + out.push( + `import { createActionClient } from "@wrnexus/csr"; +import type { InferSchema } from "@wrnexus/validation";` + ); + } + if (ast.imports.length > 0) out.push(generatedImports(ast).join("\n")); + const ssrBindings = []; + const csrBindings = []; + const helpers = targetFunctions(ast, "server"); + const apiBindings = apiBindingMap(ast, helpers); + const typeSource = ast.types.map((body2) => body2.trim()).filter(Boolean).join("\n\n"); + if (typeSource) out.push(typeSource); + if (helpers) { + out.push(`// --- .wrn functions --- +${helpers}`); + } + out.push(`export const meta = ${JSON.stringify({ title: ast.name, ...ast.seo }, null, 2)};`); + if (ast.layout) + out.push( + `export const layout = ${ast.layoutIsSymbol ? ast.layout : JSON.stringify(ast.layout)};` + ); + out.push(`export const __wrnexusRuntime = ${JSON.stringify(ast.runtime ?? "universal")};`); + out.push(`export const __wrnexusRender = ${JSON.stringify(ast.renderMode ?? "hybrid")};`); + out.push( + `export const __wrnexusHydrate = ${JSON.stringify(["static", "server"].includes(ast.renderMode ?? "") ? "none" : ast.hydrate ?? "load")};` + ); + out.push(`export const __wrnexusHydrationId = ${JSON.stringify(hydrationId(ast))};`); + if (Object.keys(ast.cache ?? {}).length > 0) + out.push(`export const __wrnexusCache = ${JSON.stringify(ast.cache, null, 2)};`); + if (Object.keys(ast.security).length > 0) { + out.push(`export const __wrnexusSecurity = ${JSON.stringify(ast.security, null, 2)};`); + } + if (Object.keys(ast.navigation).length > 0) { + out.push(`export const __wrnexusNavigation = ${JSON.stringify(ast.navigation, null, 2)};`); + } + const browserStates = ast.states.filter((state) => state.runtime !== "server"); + const seedScope = evalStateSeeds(ast.states); + for (const entry of ast.computed) { + try { + seedScope[entry.name] = new Function("with(this){return (" + entry.expr + ");}").call( + seedScope + ); + } catch { + seedScope[entry.name] = void 0; + } + } + const reactiveNames = [ + ...browserStates.map((entry) => entry.name), + ...ast.computed.map((entry) => entry.name) + ]; + const runtimeStateNames = new Set( + ast.states.filter((entry) => /\bctx\b/.test(entry.expr)).map((entry) => entry.name) + ); + const reactive = reactiveNames.length > 0 ? { stateNames: new Set(reactiveNames), runtimeStateNames, scope: seedScope } : null; + const loops = []; + let html = ast.view.map((node) => renderNode(node, ssrBindings, csrBindings, apiBindings, loops, reactive)).join(""); + const styles = ast.styles.map((body2) => body2.trim()).filter(Boolean); + const pageBehavior = ast.runtime === "server" ? null : componentBehavior(ast); + const needsClientRuntime = ast.runtime !== "server" && (browserStates.length > 0 || ast.computed.length > 0 || hasClientBehavior(ast.view) || pageBehavior !== null); + if (needsClientRuntime) { + const scopePlaceholder = "__WRNEXUS_DYNAMIC_SCOPE__"; + html = `
${html}
`; + } + const pageStyleTag = localStyleTag(ast, styles); + if (pageStyleTag) { + html = `${pageStyleTag}${html}`; + } + if (ast.renderMode === "client") { + const clientRoot = hydrationId(ast); + html = `
`; + } + const pageStyleExport = localStyleExport(ast, styles); + if (pageStyleExport) out.push(pageStyleExport); + if (csrBindings.length > 0) { + out.push(`export const __wrnexusCsr = ${JSON.stringify(csrBindings, null, 2)};`); + } + if (pageBehavior) { + out.push(`export const __wrnexusBehavior = ${JSON.stringify(pageBehavior, null, 2)};`); + } + let body = templateEscape(html); + let staticShellBody; + if (ast.renderMode === "partial-static") { + const shellHtml = html.replace( + /]*>[\s\S]*?<\/wrn-dynamic-region>/gi, + '' + ); + staticShellBody = templateEscape(shellHtml); + } + const dynamicStateScope = ast.states.map( + (state) => `${JSON.stringify(state.name)}: (() => { try { return (${state.expr}); } catch { return undefined; } })()` + ).join(", "); + const stateType = ast.states.length > 0 ? `{ ${ast.states.map((state) => `${JSON.stringify(state.name)}: ${state.valueType ?? "unknown"}`).join("; ")} }` : "Record"; + const hydrationStateNames = JSON.stringify(browserStates.map((state) => state.name)); + const ssrStateAliases = generateSsrStateAliases(ast.states.map((state) => state.name)); + const storeBindings = importedStoreBindings(ast); + const storeDeclarations = storeBindings.map( + (entry) => ` const ${entry.local} = await ctx.__wrnexusUseStore(${entry.internal});` + ).join("\n"); + const serverLoadAliases = ast.loads.filter((load) => load.mode === "server" && !load.deferred && load.name).map((load) => ` const ${load.name} = ctx[${JSON.stringify(load.name)}];`).join("\n"); + loops.forEach((code, idx) => { + body = body.replace(`\0WRNEACH${idx}\0`, () => code); + if (staticShellBody?.includes(`\0WRNEACH${idx}\0`)) { + staticShellBody = staticShellBody.replace(`\0WRNEACH${idx}\0`, () => code); + } + }); + const loopConsts = []; + if (loops.length > 0) { + const lists = collectControlExprs(ast.view); + for (const [name, binding] of apiBindings) { + if (binding.mode !== "ssr") continue; + if (!lists.some((expr) => new RegExp(`\\b${name}\\b`).test(expr))) continue; + loopConsts.push( + ` const ${name} = __wrnexusEvalData(await __wrnexusCallApi(${JSON.stringify(binding.path)}, ${JSON.stringify(binding.method)}, ctx), ${JSON.stringify(binding.body)}, ${JSON.stringify(binding.helpers)}, ctx);` + ); + } + } + const needsSsrRuntime = ssrBindings.length > 0 || loops.length > 0 || ast.states.some((state) => /\bctx\b/.test(state.expr)); + if (needsSsrRuntime) { + out.push(ssrRuntimeSource()); + out.push(`const __wrnexusSsrBindings = ${JSON.stringify(ssrBindings, null, 2)};`); + const decls = loopConsts.length > 0 ? loopConsts.join("\n") + "\n" : ""; + out.push( + `export default async function ${ast.name}(ctx: any) { + ${storeDeclarations} + ${serverLoadAliases} + ${decls} + const __state: ${stateType} = { ${dynamicStateScope} }; + ${ssrStateAliases} + const __hydrationState = Object.fromEntries(${hydrationStateNames}.map((key) => [key, (__state as any)[key]])); + const __scopeValue = Object.entries(__hydrationState) + .map(([key, value]) => { + const encoded = + typeof value === "number" || typeof value === "boolean" + ? String(value) + : JSON.stringify(value == null ? "" : String(value)); + + return key + ": " + encoded; + }) + .join(", ") + .replace(/&/g, "&") + .replace(/"/g, """) + .replace(//g, ">"); + + const html = \`${body}\`.replace( + "__WRNEXUS_DYNAMIC_SCOPE__", + __scopeValue, + ); + + return await __wrnexusRenderSsrBindings(html, ctx); + }` + ); + } else { + out.push( + `export default ${storeBindings.length > 0 ? "async " : ""}function ${ast.name}(ctx: any) { + ${storeDeclarations} + ${serverLoadAliases} + const __state: ${stateType} = { ${dynamicStateScope} }; + ${ssrStateAliases} + const __hydrationState = Object.fromEntries(${hydrationStateNames}.map((key) => [key, (__state as any)[key]])); + const __scopeValue = Object.entries(__hydrationState) + .map(([key, value]) => { + const encoded = + typeof value === "number" || typeof value === "boolean" + ? String(value) + : JSON.stringify(value == null ? "" : String(value)); + + return key + ": " + encoded; + }) + .join(", ") + .replace(/&/g, "&") + .replace(/"/g, """) + .replace(//g, ">"); + + return \`${body}\`.replace( + "__WRNEXUS_DYNAMIC_SCOPE__", + __scopeValue, + ); + }` + ); + } + if (staticShellBody !== void 0) { + out.push( + `export async function __wrnexusBuildStaticShell(ctx: any = {}) { + ${storeDeclarations} + ${serverLoadAliases} + ${loopConsts.length > 0 ? loopConsts.join("\n") : ""} + const __state: ${stateType} = { ${dynamicStateScope} }; + ${ssrStateAliases} + const __hydrationState = Object.fromEntries(${hydrationStateNames}.map((key) => [key, (__state as any)[key]])); + const __scopeValue = Object.entries(__hydrationState) + .map(([key, value]) => { + const encoded = typeof value === "number" || typeof value === "boolean" + ? String(value) + : JSON.stringify(value == null ? "" : String(value)); + return key + ": " + encoded; + }) + .join(", ") + .replace(/&/g, "&") + .replace(/"/g, """) + .replace(//g, ">"); + return \`${staticShellBody}\`.replace("__WRNEXUS_DYNAMIC_SCOPE__", __scopeValue); + }` + ); + } + if (ast.loads.length > 0) { + const serverLoads = ast.loads.filter((entry) => entry.mode === "server" && !entry.deferred); + const publicClientLoads = ast.loads.filter( + (entry) => entry.mode === "client" || entry.deferred + ); + const namedByName = new Map( + ast.loads.filter((entry) => entry.name).map((entry) => [entry.name, entry]) + ); + const clientNames = new Set( + publicClientLoads.flatMap((entry) => entry.name ? [entry.name] : []) + ); + const includeDependencies = (name) => { + for (const dependency of namedByName.get(name)?.dependsOn ?? []) { + if (clientNames.has(dependency)) continue; + clientNames.add(dependency); + includeDependencies(dependency); + } + }; + for (const name of [...clientNames]) includeDependencies(name); + const clientLoads = ast.loads.filter((entry) => !entry.name || clientNames.has(entry.name)); + const renderLoads = (exportName, execution, exposed) => { + const declarations = execution.filter((entry) => entry.name).map((entry) => { + const dependencies = (entry.dependsOn ?? []).map((dependency) => `const ${dependency} = await __load_${dependency}();`).join("\n"); + return ` let __promise_${entry.name}: Promise | undefined; + const __load_${entry.name} = () => (__promise_${entry.name} ??= (async () => { + ${dependencies} + ${entry.body} + })());`; + }).join("\n"); + const visible = exposed.filter((entry) => entry.name); + return `export async function ${exportName}(ctx: any) { +${exposed.filter((entry) => !entry.name).map((entry) => entry.body).join("\n")} +${declarations} +${visible.length ? ` const __values = await Promise.all([${visible.map((entry) => `__load_${entry.name}()`).join(", ")}]); + return { ${visible.map((entry, index) => `${JSON.stringify(entry.name)}: __values[${index}]`).join(", ")} };` : ""} +}`; + }; + if (serverLoads.length > 0) out.push(renderLoads("__wrnexusLoad", serverLoads, serverLoads)); + if (publicClientLoads.length > 0) + out.push(renderLoads("__wrnexusClientLoad", clientLoads, publicClientLoads)); + } + if (ast.actions.length > 0) { + for (const action of ast.actions) { + if (!action.schema) { + out.push( + `export async function ${action.name}(${action.args.join(", ")}) {${action.body}}` + ); + continue; + } + out.push(`export async function ${action.name}(input: any, ctx: any) { + const invalidate = (...tags: string[]) => { + const bucket = (ctx.locals.__wrnexusInvalidatedTags ??= []); + bucket.push(...tags.flat()); + }; +${action.body} +}`); + } + out.push( + `export const __wrnexusActions = { ${ast.actions.map( + (action) => `${action.name}: { run: ${action.name}, schema: ${action.schema ?? "undefined"} }` + ).join(", ")} };` + ); + out.push(`export const __wrnexusActionClients = { +${ast.actions.map( + (action) => ` ${action.name}: createActionClient<${action.schema ? `InferSchema` : "Record"}, Awaited>>("", ${JSON.stringify(action.name)}),` + ).join("\n")} +};`); + } + if (ast.apis.length > 0) { + ast.apis.forEach((api, index) => { + const name = `__wrnexusApi_${api.method}_${index}`; + out.push(`// ${api.method} ${apiRoutePath(api.path)} +const ${name} = async (ctx: any) => {${api.body}};`); + }); + const entries = ast.apis.map( + (api, index) => ` ${JSON.stringify(`${api.method} ${apiRoutePath(api.path)}`)}: __wrnexusApi_${api.method}_${index},` + ); + out.push(`export const __wrnexusApi = { +${entries.join("\n")} +};`); + const exported = /* @__PURE__ */ new Set(); + ast.apis.forEach((api, index) => { + if (exported.has(api.method)) return; + exported.add(api.method); + out.push(`export const ${api.method} = __wrnexusApi_${api.method}_${index};`); + }); + } + if (ast.realtimes.length > 0) { + const handlers = ast.realtimes.flatMap( + (rt) => rt.handlers.map((h) => { + const params2 = ["ws", ...h.args].join(", "); + return ` ${h.event}(${params2}: any) {${h.body}},`; + }) + ); + out.push(`export const websocket = { +${handlers.join("\n")} +};`); + } + return out.join("\n\n") + "\n"; +} +function parseForExpr(value) { + const m = /^\s*([A-Za-z_$][\w$]*)\s*(?:,\s*([A-Za-z_$][\w$]*)\s*)?\s+in\s+([\s\S]+?)(?:\s+key\s+([\s\S]+?))?\s*$/.exec( + value + ); + if (!m) return null; + return { item: m[1], index: m[2], list: m[3].trim(), key: m[4]?.trim() }; +} +function loopVarsOf(node) { + if (node.type !== "element") return []; + const attr = node.attrs.find((a) => !a.event && a.name === "data-for"); + if (!attr) return []; + const parsed = parseForExpr(attr.value); + return parsed ? [parsed.item, ...parsed.index ? [parsed.index] : []] : []; +} +var JS_RESERVED = /* @__PURE__ */ new Set([ + "class", + "for", + "default", + "function", + "return", + "if", + "else", + "new", + "delete", + "typeof", + "in", + "instanceof", + "void", + "do", + "while", + "switch", + "case", + "break", + "continue", + "this", + "super", + "import", + "export", + "extends", + "var", + "let", + "const", + "null", + "true", + "false", + "try", + "catch", + "finally", + "throw", + "yield", + "await", + "enum", + "with", + "debugger", + "implements", + "interface", + "package", + "private", + "protected", + "public", + "static" +]); +function safeRef(name) { + return JS_RESERVED.has(name) ? `__p_${name}` : name; +} +function escLit(s) { + return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${"); +} +function componentBehavior(ast) { + const functions = (0, types_exports.eraseFunctionTypes)(targetFunctions(ast, "browser")); + const computed = ast.computed.map((entry) => ({ name: entry.name, expr: entry.expr.trim() })); + const effects = ast.effects.map((entry) => entry.body.trim()).filter(Boolean); + const lifecycle = { + ...ast.lifecycle.mount?.trim() ? { mount: ast.lifecycle.mount.trim() } : {}, + ...ast.lifecycle.update?.trim() ? { update: ast.lifecycle.update.trim() } : {}, + ...ast.lifecycle.unmount?.trim() ? { unmount: ast.lifecycle.unmount.trim() } : {} + }; + const watches = ast.watches.map((watch) => ({ + state: watch.state, + body: watch.body.trim() + })); + if (!functions && ast.outputs.length === 0 && computed.length === 0 && effects.length === 0 && Object.keys(lifecycle).length === 0 && watches.length === 0) { + return null; + } + return { + functions, + outputs: ast.outputs, + computed, + effects, + lifecycle, + watches + }; +} +function behaviorAttribute(behavior) { + if (!behavior) { + return ""; + } + const encoded = Buffer2.from(JSON.stringify(behavior), "utf8").toString("base64"); + return ` data-wrn-behavior="${encoded}"`; +} +var INTERP_RE = /\{([^{}]+)\}/g; +function exprRefsState(expr, stateNames) { + for (const name of stateNames) { + if (new RegExp(`\\b${name}\\b`).test(expr)) return true; + } + return false; +} +function exprRefsComponentReactiveValue(expr, ctx) { + return exprRefsState(expr, ctx.stateNames) || exprRefsState(expr, ctx.functionNames); +} +function viewHasEvents(nodes) { + return nodes.some((node) => { + if (node.type === "text") return false; + if (node.type === "each") { + return viewHasEvents(node.body) || viewHasEvents(node.empty); + } + if (node.type === "if") { + return node.branches.some((branch) => viewHasEvents(branch.body)); + } + return node.attrs.some((attr) => attr.event) || viewHasEvents(node.children); + }); +} +function viewHasServerEach(nodes) { + return nodes.some((node) => { + if (node.type === "text") return false; + if (node.type === "each") return true; + if (node.type === "if") { + return node.branches.some((branch) => viewHasServerEach(branch.body)); + } + return viewHasServerEach(node.children); + }); +} +function viewHasRestAttributeSpread(nodes) { + return nodes.some((node) => { + if (node.type === "text") return false; + if (node.type === "each") { + return viewHasRestAttributeSpread(node.body) || viewHasRestAttributeSpread(node.empty); + } + if (node.type === "if") { + return node.branches.some((branch) => viewHasRestAttributeSpread(branch.body)); + } + return node.attrs.some((attr) => /^\{\.\.\.([A-Za-z_$][\w$]*)\}$/.test(attr.name)) || viewHasRestAttributeSpread(node.children); + }); +} +function compileText(raw, ctx) { + let out = ""; + let last = 0; + let m; + INTERP_RE.lastIndex = 0; + while (m = INTERP_RE.exec(raw)) { + out += escLit(raw.slice(last, m.index)); + const expr = m[1].trim(); + if (expr.startsWith("t:")) { + out += escLit(``); + } else if (ctx.loopVars && exprRefsState(expr, ctx.loopVars)) { + out += escLit(`{${expr}}`); + } else if (exprRefsComponentReactiveValue(expr, ctx)) { + out += escLit(``) + `\${__wireHtml(${ctx.resolveExpr(expr)})}` + escLit(``); + } else if (expr === "content") { + out += `\${__wireRaw(${ctx.resolveExpr(expr)})}`; + } else { + out += `\${__wireHtml(${ctx.resolveExpr(expr)})}`; + } + last = m.index + m[0].length; + } + return out + escLit(raw.slice(last)); +} +function compileAttrValue(raw, ctx) { + if (!raw.includes("{")) return escLit(attrEscape(raw)); + let out = ""; + let last = 0; + let m; + INTERP_RE.lastIndex = 0; + while (m = INTERP_RE.exec(raw)) { + out += escLit(attrEscape(raw.slice(last, m.index))); + const expr = m[1].trim(); + if (ctx.loopVars && exprRefsState(expr, ctx.loopVars)) { + out += escLit(`{${expr}}`); + } else { + out += `\${__wireAttr(${ctx.resolveExpr(expr)})}`; + } + last = m.index + m[0].length; + } + return out + escLit(attrEscape(raw.slice(last))); +} +function renderComponentIfNode(node, ctx) { + let expression2 = "``"; + 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 + "`"; + expression2 = branch.cond === null ? bodyExpression : `(${ctx.resolveExpr(branch.cond)}) ? ${bodyExpression} : ${expression2}`; + } + return "${" + expression2 + "}"; +} +function renderComponentEachNode(node, ctx) { + const item = node.item; + const index = node.index ?? "__wi"; + const list = ctx.resolveExpr(node.list); + const childCtx = { + ...ctx, + serverLocals: /* @__PURE__ */ new Set([...ctx.serverLocals ?? [], item, index]) + }; + const body = node.body.map((child) => renderComponentNode(child, childCtx)).join(""); + const empty = node.empty.map((child) => renderComponentNode(child, ctx)).join(""); + return "${(() => { const __wl = Array.isArray(" + list + ") ? (" + list + ") : []; return __wl.length ? __wl.map((" + item + ", " + index + ") => `" + body + '`).join("") : `' + empty + "`; })()}"; +} +function serverLoopLocalsAttribute(ctx) { + const locals = [...ctx.serverLocals ?? []]; + if (locals.length === 0) { + return ""; + } + const entries = locals.map((name) => `${JSON.stringify(name)}: ${name}`).join(", "); + return ` data-wrn-loop-locals="\${__wrnexusEncodeLoopLocals({ ${entries} })}"`; +} +function unwrapDirectiveExpression(raw) { + const value = raw.trim(); + if (!value.startsWith("{") || !value.endsWith("}")) { + return value; + } + let depth = 0; + let quote = null; + let escaped = false; + for (let index = 0; index < value.length; index++) { + const char = value[index]; + if (escaped) { + escaped = false; + continue; + } + if (quote) { + if (char === "\\") { + escaped = true; + } else if (char === quote) { + quote = null; + } + continue; + } + if (char === '"' || char === "'" || char === "`") { + quote = char; + continue; + } + if (char === "{") depth++; + if (char === "}") depth--; + if (depth === 0 && index < value.length - 1) { + return value; + } + } + return depth === 0 ? value.slice(1, -1).trim() : value; +} +function renderComponentNode(node, ctx) { + if (node.type === "text") return compileText(node.value, ctx); + if (node.type === "each") { + return renderComponentEachNode(node, ctx); + } + if (node.type === "if") { + return renderComponentIfNode(node, ctx); + } + if (node.tag === "Static" || node.tag === "Dynamic") { + const inner2 = node.children.map((child) => renderComponentNode(child, ctx)).join(""); + return node.tag === "Static" ? inner2 : `${inner2}`; + } + if (node.tag === "KeepAlive") { + const key = node.attrs.find((attribute) => attribute.name === "key")?.value ?? "default"; + const inner2 = node.children.map((child) => renderComponentNode(child, ctx)).join(""); + return `
${inner2}
`; + } + if (node.tag === "Portal" || node.tag === "Transition" || node.tag === "Component") { + const inner2 = node.children.map((child) => renderComponentNode(child, ctx)).join(""); + const attribute = node.tag === "Portal" ? "data-wrn-portal" : node.tag === "Transition" ? "data-wrn-transition" : "data-wrn-dynamic-component"; + const source = node.tag === "Portal" ? "to" : node.tag === "Transition" ? "name" : "is"; + const fallback = node.tag === "Portal" ? "body" : node.tag === "Transition" ? "wrn-transition" : ""; + const raw = node.attrs.find((item) => item.name === source)?.value ?? fallback; + return `
${inner2}
`; + } + if (isComponentTag(node.tag)) { + return renderNestedComponentInvocation(node, ctx); + } + const loopVariables = loopVarsOf(node); + const elementContext = { + ...ctx, + forwardRestAttrs: false, + ...loopVariables.length > 0 ? { loopVars: /* @__PURE__ */ new Set([...ctx.loopVars ?? [], ...loopVariables]) } : {} + }; + let bindIndex = 0; + const staticClasses = []; + const conditionalClasses = []; + for (const attr of node.attrs) { + if (!attr.event && attr.name === "class") { + staticClasses.push(attr.value); + } + if (!attr.event && attr.name.startsWith("class:")) { + conditionalClasses.push({ + className: attr.name.slice("class:".length), + expression: unwrapDirectiveExpression(attr.value) + }); + } + } + const isExplicitComponentMount = node.attrs.some( + (attribute) => attribute.name === "data-component" + ); + const attrs = node.attrs.filter((a) => a.name !== "class" && !a.name.startsWith("class:")).map((a) => { + const spread = /^\{\.\.\.([A-Za-z_$][\w$]*)\}$/.exec(a.name); + if (spread) { + return `\${__wireSpreadAttrs(${elementContext.resolveExpr(spread[1])})}`; + } + if (a.event) { + return ` ${eventAttribute(a.name)}="${escLit(attrEscape(a.value))}"`; + } + if (a.boolean) { + return ` ${a.name}`; + } + if (isHtmlBooleanAttribute(a.name)) { + const expression2 = wholeAttributeExpression(a.value); + if (expression2) { + const referencesState2 = exprRefsComponentReactiveValue(a.value, ctx); + const referencesLoopVariable2 = elementContext.loopVars ? exprRefsState(a.value, elementContext.loopVars) : false; + const referencesServerLocal2 = ctx.serverLocals ? exprRefsState(a.value, ctx.serverLocals) : false; + const marker2 = referencesState2 || referencesLoopVariable2 || referencesServerLocal2 ? ` data-wrn-bind-${bindIndex++}="${escLit( + attrEscape(JSON.stringify([a.name, a.value])) + )}"` : ""; + return `\${__wireBooleanAttr(${JSON.stringify(a.name)}, ${elementContext.resolveExpr(expression2)})}${marker2}`; + } + if (a.value === "false") return ""; + if (a.value === "true" || a.value === "") return ` ${a.name}`; + } + const wholeExpression = wholeAttributeExpression(a.value); + const compiledValue = isExplicitComponentMount && wholeExpression ? `\${__wireProp(${elementContext.resolveExpr(wholeExpression)})}` : compileAttrValue(a.value, elementContext); + const rendered = ` ${a.name}="${compiledValue}"`; + const referencesState = exprRefsComponentReactiveValue(a.value, ctx); + const referencesLoopVariable = elementContext.loopVars ? exprRefsState(a.value, elementContext.loopVars) : false; + const referencesServerLocal = ctx.serverLocals ? exprRefsState(a.value, ctx.serverLocals) : false; + if (!a.value.includes("{") || !referencesState && !referencesLoopVariable && !referencesServerLocal) { + return rendered; + } + const marker = attrEscape(JSON.stringify([a.name, a.value])); + return `${rendered} data-wrn-bind-${bindIndex++}="${escLit(marker)}"`; + }).join(""); + const initialConditionalClasses = conditionalClasses.map(({ className, expression: expression2 }) => { + const referencesLoopVariable = elementContext.loopVars ? exprRefsState(expression2, elementContext.loopVars) : false; + if (referencesLoopVariable) { + return ""; + } + return `\${(${ctx.resolveExpr(expression2)}) ? ${JSON.stringify(` ${className}`)} : ""}`; + }).join(""); + const staticClassValue = staticClasses.join(" "); + const classReferencesState = exprRefsComponentReactiveValue(staticClassValue, ctx); + const classReferencesLoopVariable = elementContext.loopVars ? exprRefsState(staticClassValue, elementContext.loopVars) : false; + const classReferencesServerLocal = ctx.serverLocals ? exprRefsState(staticClassValue, ctx.serverLocals) : false; + const classHasReactiveExpression = staticClassValue.includes("{") && (classReferencesState || classReferencesLoopVariable || classReferencesServerLocal); + const classAttribute = staticClasses.length > 0 || conditionalClasses.length > 0 ? ` class="${compileAttrValue(staticClassValue, elementContext)}${initialConditionalClasses}"` : ""; + const classReactiveBinding = classHasReactiveExpression ? ` data-wrn-bind-class="${escLit(attrEscape(JSON.stringify(["class", staticClassValue])))}"` : ""; + const classBindings = conditionalClasses.map(({ className, expression: expression2 }, index) => { + const marker = attrEscape(JSON.stringify([className, expression2])); + return ` data-wrn-class-${index}="${escLit(marker)}"`; + }).join(""); + const loopLocalsAttribute = serverLoopLocalsAttribute(ctx); + const allAttrs = `${loopLocalsAttribute}${ctx.forwardRestAttrs ? "${__wireSpreadAttrs(__attrs)}" : ""}${ctx.eventNames?.length ? ` data-wrn-events="${attrEscape(ctx.eventNames.join(","))}"` : ""}${classAttribute}${classReactiveBinding}${classBindings}${attrs}`; + if (parser_exports.VOID_ELEMENTS.has(node.tag.toLowerCase())) { + return `<${node.tag}${allAttrs}>`; + } + const inner = node.children.map((child) => renderComponentNode(child, elementContext)).join(""); + return `<${node.tag}${allAttrs}>${inner}`; +} +function generateComponent(ast) { + const out = []; + if (ast.imports.length > 0) out.push(generatedImports(ast).join("\n")); + const hasServerEach = viewHasServerEach(ast.view); + const effectiveProps = ast.kind === "layout" && !ast.props.some((prop) => prop.name === "content") ? [ + { + name: "content", + default: '""', + valueType: "string", + required: false + }, + ...ast.props + ] : ast.props; + const browserStates = ast.states.filter((state) => state.runtime !== "server"); + const stateNames = /* @__PURE__ */ new Set([ + ...browserStates.map((entry) => entry.name), + ...ast.computed.map((entry) => entry.name) + ]); + const nameRefs = /* @__PURE__ */ new Map(); + for (const p of effectiveProps) { + nameRefs.set(p.name, safeRef(p.name)); + } + if (!nameRefs.has("attrs")) { + nameRefs.set("attrs", "__attrs"); + } + for (const s of ast.states) nameRefs.set(s.name, safeRef(s.name)); + for (const entry of ast.computed) nameRefs.set(entry.name, safeRef(entry.name)); + const resolveExpr = (expr) => { + let result = expr; + for (const [name, ref] of nameRefs) { + if (name !== ref) result = result.replace(new RegExp(`\\b${name}\\b`, "g"), ref); + } + return result; + }; + const ctx = { + stateNames, + functionNames: new Set( + ast.runtimeFunctions.filter((fn) => fn.runtime !== "server").map((fn) => fn.name) + ), + resolveExpr, + eventNames: publicOutputNames(ast) + }; + const serverFunctions = targetFunctions(ast, "server"); + const hasExplicitRestSpread = viewHasRestAttributeSpread(ast.view); + const rootElementIndex = ast.view.findIndex((node) => node.type === "element"); + const automaticallyForwardRootAttrs = !hasExplicitRestSpread && !effectiveProps.some((prop) => prop.name === "attrs") && rootElementIndex >= 0; + const viewCode = ast.view.map( + (node, index) => renderComponentNode( + node, + automaticallyForwardRootAttrs && index === rootElementIndex ? { ...ctx, forwardRestAttrs: true } : ctx + ) + ).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); + if (hasServerEach || needsScope) { + out.push(`import { Buffer as __WrnexusBuffer } from "node:buffer";`); + } + const scopeKeys = [ + ...effectiveProps.map((prop) => prop.name), + ...browserStates.map((state) => state.name) + ]; + const behaviorAttr = behaviorAttribute(behavior); + const decls = []; + for (const prop of effectiveProps) { + 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_exports.runtimeTypeOf)(prop.valueType))});` + ); + } + if (!effectiveProps.some((prop) => prop.name === "attrs")) { + decls.push( + ` const __attrs = __restProps(__p, new Set(${JSON.stringify(effectiveProps.map((prop) => prop.name))}));` + ); + } + for (const state of ast.states) { + decls.push( + ` let ${nameRefs.get(state.name)}${state.valueType ? `: ${state.valueType}` : ""} = (${resolveExpr(state.expr)});` + ); + } + for (const entry of ast.computed) { + decls.push(` const ${nameRefs.get(entry.name)} = (${resolveExpr(entry.expr)});`); + } + const returnExpr = needsScope ? "`" + styleTag + `
` + viewCode + "
`" : "`" + styleTag + viewCode + "`"; + const scopeLine = needsScope && scopeKeys.length > 0 ? ` const __scopeState = { ${scopeKeys.map((key) => `${JSON.stringify(key)}: ${nameRefs.get(key)}`).join( + ", " + )} }; + const __scope = __wrnexusScopeDecl(__scopeState); + const __scopePayload = __WrnexusBuffer.from(JSON.stringify(__scopeState), "utf8").toString("base64"); +` : needsScope ? ` const __scopeState = {}; + const __scope = ""; + const __scopePayload = __WrnexusBuffer.from("{}", "utf8").toString("base64"); +` : ""; + if (ast.kind === "layout") { + out.push(`export const __wrnexusLayout = ${JSON.stringify(ast.name)};`); + } else { + out.push(`export const __wrnexusComponent = ${JSON.stringify(ast.name)};`); + } + out.push(`export const __wrnexusRuntime = ${JSON.stringify(ast.runtime ?? "universal")};`); + out.push(`export const __wrnexusRender = ${JSON.stringify(ast.renderMode ?? "hybrid")};`); + out.push( + `export const __wrnexusHydrate = ${JSON.stringify(["static", "server"].includes(ast.renderMode ?? "") ? "none" : ast.hydrate ?? "load")};` + ); + out.push(`export const __wrnexusHydrationId = ${JSON.stringify(hydrationId(ast))};`); + if (Object.keys(ast.cache ?? {}).length > 0) + out.push(`export const __wrnexusCache = ${JSON.stringify(ast.cache, null, 2)};`); + if (Object.keys(ast.security).length > 0) { + out.push(`export const __wrnexusSecurity = ${JSON.stringify(ast.security, null, 2)};`); + } + if (Object.keys(ast.navigation).length > 0) { + out.push(`export const __wrnexusNavigation = ${JSON.stringify(ast.navigation, null, 2)};`); + } + const componentStyleExport = localStyleExport(ast, styles); + if (componentStyleExport) out.push(componentStyleExport); + if (behavior) { + out.push(`export const __wrnexusBehavior = ${JSON.stringify(behavior, null, 2)};`); + } + const typeSource = ast.types.map((body) => body.trim()).filter(Boolean).join("\n\n"); + if (typeSource) out.push(typeSource); + if (effectiveProps.length > 0) { + out.push( + `export interface ${ast.name}Props { + [attribute: string]: unknown; +${effectiveProps.map( + (prop) => ` ${JSON.stringify(prop.name)}${prop.required ? "" : "?"}: ${prop.valueType ?? "unknown"};` + ).join("\n")} +}` + ); + } + if (ast.outputs.length > 0) { + out.push( + `export interface ${ast.name}Outputs { +${ast.outputs.map( + (output) => ` ${JSON.stringify(output.name)}(${output.payload ? `${output.payload.name}${output.payload.optional ? "?" : ""}: ${output.payload.valueType}` : ""}): void;` + ).join("\n")} +}` + ); + } + out.push(`function __coerce(v: any, def: any, declared: string = "unknown"): any { + if (v === undefined || v === null) { + return def; + } + + if (declared === "number" || typeof def === "number") { + const parsed = Number(v); + if (!Number.isFinite(parsed)) throw new TypeError("Expected a finite number prop"); + return parsed; + } + + if (declared === "boolean" || typeof def === "boolean") { + if (v === true || v === "" || v === "true" || v === 1 || v === "1") return true; + if (v === false || v === "false" || v === 0 || v === "0") return false; + throw new TypeError("Expected a boolean prop"); + } + + if (declared === "array" || Array.isArray(def)) { + if (Array.isArray(v)) { + return v; + } + + if (typeof v === "string") { + try { + const parsed = JSON.parse(v); + return Array.isArray(parsed) ? parsed : def; + } catch { + if (declared === "array") throw new TypeError("Expected an array prop"); + return def; + } + } + + return def; + } + + if (declared === "object" || (def !== null && typeof def === "object")) { + if ( + v !== null && + typeof v === "object" && + !Array.isArray(v) + ) { + return v; + } + + if (typeof v === "string") { + try { + const parsed = JSON.parse(v); + + return ( + parsed !== null && + typeof parsed === "object" && + !Array.isArray(parsed) + ) + ? parsed + : def; + } catch { + if (declared === "object") throw new TypeError("Expected an object prop"); + return def; + } + } + + return def; + } + + if (declared === "bigint") return BigInt(v); + if (declared === "function" && typeof v !== "function") { + throw new TypeError("Expected a function prop"); + } + return declared === "unknown" && def === undefined ? v : String(v); +} + +function __restProps( + props: Record, + declared: Set, +): Record { + return Object.fromEntries( + Object.entries(props).filter(([name]) => !declared.has(name)), + ); +} + +function __wireHtml(v: any): string { + return String(v == null ? "" : v).replace( + /[&<>]/g, + (c) => + c === "&" + ? "&" + : c === "<" + ? "<" + : ">", + ); +} + +function __wireAttr(v: any): string { + return String(v == null ? "" : v).replace( + /[&<>"]/g, + (c) => + c === "&" + ? "&" + : c === "<" + ? "<" + : c === ">" + ? ">" + : """, + ); +} + +function __wireBooleanAttr(name: string, value: any): string { + return value === true || + value === "true" || + value === "" || + value === 1 || + value === "1" || + value === name + ? " " + name + : ""; +} + +function __wireSpreadAttrs(value: any): string { + if (value === null || typeof value !== "object" || Array.isArray(value)) return ""; + + const booleanAttributes = new Set(${JSON.stringify([...HTML_BOOLEAN_ATTRIBUTES])}); + const attributes: string[] = []; + + for (const [name, raw] of Object.entries(value)) { + const lowerName = name.toLowerCase(); + if ( + !/^[A-Za-z_:][A-Za-z0-9_.:-]*$/.test(name) || + lowerName.startsWith("on") || + lowerName === "style" || + lowerName === "slot" || + lowerName === "data-component" || + lowerName.startsWith("data-wrn") + ) { + continue; + } + + if (booleanAttributes.has(lowerName)) { + attributes.push(__wireBooleanAttr(name, raw)); + continue; + } + + if (raw === false || raw === null || raw === undefined) continue; + attributes.push(" " + name + '="' + __wireAttr(raw) + '"'); + } + + return attributes.join(""); +} + +function __wireProp(v: any): string { + const value = + v !== null && typeof v === "object" + ? JSON.stringify(v) + : String(v == null ? "" : v); + + return __wireAttr(value); +} + +function __wireRaw(v: any): string { + return String(v == null ? "" : v); +}`); + if (hasServerEach) { + out.push(`function __wrnexusEncodeLoopLocals(value: Record): string { + return __WrnexusBuffer.from(JSON.stringify(value), "utf8").toString("base64"); +}`); + } + if (needsScope) { + out.push(`function __wrnexusSerializeScopeValue(value: any): string { + if (value === undefined) { + return "undefined"; + } + + if (value === null) { + return "null"; + } + + if (typeof value === "number") { + return Number.isFinite(value) + ? String(value) + : "null"; + } + + if (typeof value === "boolean") { + return value ? "true" : "false"; + } + + if (typeof value === "string") { + return JSON.stringify(value); + } + + try { + const serialized = JSON.stringify(value); + + return serialized === undefined + ? "undefined" + : serialized; + } catch { + return "null"; + } + } + + function __wrnexusScopeDecl(obj: Record): string { + return Object.keys(obj) + .map( + (key) => + key + + ": " + + __wrnexusSerializeScopeValue( + obj[key], + ), + ) + .join(", ") + .replace(/&/g, "&") + .replace(/"/g, """) + .replace(//g, ">"); + }`); + } + const serverFunctionSource = serverFunctions ? `${serverFunctions} +` : ""; + out.push( + `export function render(props: ${effectiveProps.length > 0 ? `${ast.name}Props` : "Record"} = {} as ${effectiveProps.length > 0 ? `${ast.name}Props` : "Record"}): string { + const __p = props || {}; +` + (decls.length > 0 ? decls.join("\n") + "\n" : "") + serverFunctionSource + scopeLine + ` return ${returnExpr}; +}` + ); + out.push( + `export default { name: ${JSON.stringify(ast.name)}, kind: ${JSON.stringify(ast.kind)}, render };` + ); + return out.join("\n\n") + "\n"; +} +function wholeAttributeExpression(value) { + const match = /^\s*\{([\s\S]+)\}\s*$/.exec(value); + return match?.[1]?.trim() || null; +} +function renderPageComponentAttr(attr, dynamicExpressions) { + if (attr.event) { + return ` ${eventAttribute(attr.name)}="${attrEscape(attr.value)}"`; + } + if (attr.boolean) { + return ` ${attr.name}`; + } + const expression2 = wholeAttributeExpression(attr.value); + if (!expression2) { + return ` ${attr.name}="${attrEscape(safeAttributeValue(attr.name, attr.value))}"`; + } + dynamicExpressions.push(`\${__wrnexusPropAttr(${expression2})}`); + const marker = `\0WRNEACH${dynamicExpressions.length - 1}\0`; + return ` ${attr.name}="${marker}"`; +} + +// packages/compiler/src/native-codegen.ts +var NativeCompileError = class extends Error { + constructor(message) { + super(message); + this.name = "NativeCompileError"; + } +}; +var tagMap = { + div: "View", + main: "View", + section: "View", + article: "View", + nav: "View", + header: "View", + footer: "View", + aside: "View", + form: "View", + ul: "View", + ol: "View", + li: "View", + p: "Text", + span: "Text", + strong: "Text", + em: "Text", + small: "Text", + label: "Text", + h1: "Text", + h2: "Text", + h3: "Text", + h4: "Text", + h5: "Text", + h6: "Text", + button: "Pressable", + a: "Pressable", + input: "TextInput", + textarea: "TextInput", + img: "Image", + view: "View", + text: "Text", + pressable: "Pressable", + textinput: "TextInput", + image: "Image", + scrollview: "ScrollView", + safeareaview: "SafeAreaView", + flatlist: "FlatList", + activityindicator: "ActivityIndicator" +}; +var attrMap = { + class: "style", + className: "style", + src: "source", + alt: "accessibilityLabel", + placeholder: "placeholder", + disabled: "disabled", + value: "value", + href: "__href", + "aria-label": "accessibilityLabel" +}; +function expression(value) { + const exact = /^\{([\s\S]+)\}$/.exec(value.trim()); + return exact?.[1]?.trim() ?? null; +} +function textJsx(value) { + const pieces = []; + let last = 0; + for (const match of value.matchAll(/\{([^{}]+)\}/g)) { + if (match.index > last) pieces.push(value.slice(last, match.index)); + const expr = match[1].trim(); + pieces.push(expr.startsWith("t:") ? `{${JSON.stringify(expr.slice(2).trim())}}` : `{${expr}}`); + last = match.index + match[0].length; + } + pieces.push(value.slice(last)); + return pieces.join("").replace(/([<>])/g, (char) => char === "<" ? "<" : ">"); +} +function eventBody(value, states) { + let body = expression(value) ?? value; + for (const state of states) { + const cap = state[0].toUpperCase() + state.slice(1); + body = body.replace(new RegExp(`\\b${state}\\+\\+`, "g"), `set${cap}(value => value + 1)`).replace(new RegExp(`\\b${state}--`, "g"), `set${cap}(value => value - 1)`).replace(new RegExp(`\\b${state}\\s*=\\s*([^;]+)`, "g"), `set${cap}($1)`); + } + return `() => { ${body} }`; +} +function renderAttrs2(attrs, states) { + return attrs.map((attr) => { + if (attr.event) { + if (attr.name.startsWith("browser-")) return ""; + const eventName = attr.name.startsWith("mobile-") ? attr.name.slice(7) : attr.name; + const event = eventName === "click" || eventName === "press" ? "onPress" : eventName === "input" || eventName === "change" ? "onChangeText" : `on${eventName[0].toUpperCase()}${eventName.slice(1)}`; + return ` ${event}={${eventBody(attr.value, states)}}`; + } + if (attr.name === "data-native-browser" || attr.name.startsWith("data-native-on-browser-")) + return ""; + if (attr.name === "data-native-options" || attr.name === "data-native-only" || attr.name === "data-native-requires" || attr.name === "data-native-unsupported") + return ""; + if (attr.name === "data-native-mobile") { + throw new NativeCompileError( + `Declarative native capability "${attr.value}" currently targets browser/Capacitor pages. In Expo output, call the installed Expo package from an @mobile-event handler.` + ); + } + const name = attrMap[attr.name] ?? attr.name; + if (name === "__href") return ` onPress={() => router.push(${JSON.stringify(attr.value)})}`; + if (name === "source") { + const expr2 = expression(attr.value); + return ` source={${expr2 ? `{ uri: ${expr2} }` : `{ uri: ${JSON.stringify(attr.value)} }`}}`; + } + if (name === "style" && attr.name !== "style") { + return ` style={[${attr.value.split(/\s+/).filter(Boolean).map((value) => `styles[${JSON.stringify(value)}]`).join(", ")} ]}`; + } + if (name === "style") { + const inlineExpression = expression(attr.value); + if (inlineExpression) return ` style={${inlineExpression}}`; + throw new NativeCompileError( + 'Inline CSS strings are not portable to native; use class="name" and a page style block' + ); + } + if (attr.boolean) return ` ${name}`; + const expr = expression(attr.value); + return expr ? ` ${name}={${expr}}` : ` ${name}=${JSON.stringify(attr.value)}`; + }).join(""); +} +function renderNode2(node, states, key) { + if (node.type === "text") return textJsx(node.value); + if (node.type === "each") { + const params2 = node.index ? `${node.item}, ${node.index}` : `${node.item}, __index`; + const body = node.body.map( + (child, index) => renderNode2(child, states, index === 0 ? node.index ?? "__index" : void 0) + ).join(""); + const empty = node.empty.map((child) => renderNode2(child, states)).join(""); + return `{(${node.list})?.length ? (${node.list}).map((${params2}) => <>${body}) : <>${empty}}`; + } + if (node.type === "if") { + const result = node.branches.reduceRight( + (fallback, branch) => branch.cond === null ? `<>${branch.body.map((child) => renderNode2(child, states)).join("")}` : `(${branch.cond}) ? <>${branch.body.map((child) => renderNode2(child, states)).join("")} : ${fallback}`, + "null" + ); + return `{${result}}`; + } + const nativeOnly = node.attrs.find( + (attr) => !attr.event && attr.name === "data-native-only" + )?.value; + if (nativeOnly === "browser" || nativeOnly === "web") return ""; + const nativeTag = tagMap[node.tag.toLowerCase()] ?? (/^[A-Z]/.test(node.tag) ? node.tag : void 0); + if (!nativeTag) + throw new NativeCompileError(`HTML element <${node.tag}> has no native equivalent`); + const attrs = renderAttrs2(node.attrs, states) + (key ? ` key={${key}}` : ""); + if (nativeTag === "TextInput" || nativeTag === "Image" || nativeTag === "ActivityIndicator") + return `<${nativeTag}${attrs} />`; + const children = node.children.map((child) => { + if (child.type !== "text") return renderNode2(child, states); + if (!child.value.trim()) return ""; + const text = textJsx(child.value); + return nativeTag === "Text" ? text : `${text}`; + }).join(""); + return `<${nativeTag}${attrs}>${children}`; +} +function nativeStyles(blocks) { + const entries = []; + for (const block of blocks) { + for (const match of block.matchAll(/\.([A-Za-z_][\w-]*)\s*\{([^}]*)\}/g)) { + const props = []; + for (const declaration of match[2].split(";")) { + const colon = declaration.indexOf(":"); + if (colon < 0) continue; + const name = declaration.slice(0, colon).trim().replace(/-([a-z])/g, (_, c) => c.toUpperCase()); + let value = declaration.slice(colon + 1).trim(); + if (/^-?\d+(?:\.\d+)?px$/.test(value)) value = Number(value.slice(0, -2)); + props.push( + `${JSON.stringify(name)}: ${typeof value === "number" ? value : JSON.stringify(value)}` + ); + } + entries.push(`${JSON.stringify(match[1])}: { ${props.join(", ")} }`); + } + } + return `const styles = StyleSheet.create({ ${entries.join(",\n")} });`; +} +function generateNative(ast) { + if (ast.kind !== "page") + throw new NativeCompileError("Native route compilation currently accepts page files only"); + if (ast.dataApis.length) + throw new NativeCompileError( + "Data API blocks are not yet portable to native screens; fetch through the generated native backend helper" + ); + const states = new Set(ast.states.map((state) => state.name)); + const hooks = ast.states.map((state) => { + const cap = state.name[0].toUpperCase() + state.name.slice(1); + return ` const [${state.name}, set${cap}] = useState${state.valueType ? `<${state.valueType}>` : ""}(${state.expr});`; + }).join("\n"); + const body = ast.view.map((node) => renderNode2(node, states)).join(""); + const typeSource = ast.types.map((block) => block.trim()).filter(Boolean).join("\n\n"); + return `// generated from .wrn for Expo/React Native +import React, { useState } from "react"; +import { ActivityIndicator, FlatList, Image, Pressable, SafeAreaView, ScrollView, StyleSheet, Text, TextInput, View } from "react-native"; +import { useRouter } from "expo-router"; +${ast.imports.join("\n")} + +${typeSource} + +export default function ${ast.name}() { + const router = useRouter(); +${hooks} + return <>${body}; +} + +${nativeStyles(ast.styles)} +`; +} + +// packages/compiler/src/index.ts +import { + assertValidAst as assertValidAst2, + diagnose as diagnose3, + diagnosticFromError as diagnosticFromError2, + formatDiagnostic as formatDiagnostic2, + parse as parse3, + ParseError as ParseError3 +} from "@wrnexus/syntax"; + +// packages/compiler/src/component-contract.ts +function unionOptions(type) { + if (!type || !type.includes("|")) return void 0; + const values = type.split("|").map((part) => part.trim()).filter((part) => /^(?:"[^"]*"|'[^']*')$/.test(part)).map((part) => part.slice(1, -1)); + return values.length ? values : void 0; +} +function createComponentContract(ast) { + return { + name: ast.name, + kind: ast.kind, + props: ast.props.map((prop) => ({ + name: prop.name, + type: prop.valueType ?? "unknown", + required: prop.required, + ...prop.default !== "undefined" ? { default: prop.default } : {}, + ...unionOptions(prop.valueType) ? { options: unionOptions(prop.valueType) } : {} + })), + outputs: ast.outputs.map((output) => ({ + name: output.name, + ...output.payload ? { payloadName: output.payload.name, payloadType: output.payload.valueType } : {} + })), + functions: ast.runtimeFunctions.map((fn) => ({ + name: fn.name, + runtime: fn.runtime, + async: fn.async, + parameters: fn.parameters.map((param) => ({ + name: param.name, + type: param.valueType ?? "unknown", + optional: param.optional + })), + returnType: fn.returnType ?? (fn.async ? "Promise" : "unknown") + })), + states: ast.states.map((state) => ({ + name: state.name, + runtime: state.runtime, + type: state.valueType ?? "unknown", + initializer: state.expr + })), + computed: ast.computed.map((entry) => ({ + name: entry.name, + type: entry.valueType ?? "unknown", + expression: entry.expr + })), + imports: ast.structuredImports.map((entry) => ({ + source: entry.source, + typeOnly: entry.typeOnly, + ...entry.defaultImport ? { defaultImport: entry.defaultImport } : {}, + namedImports: entry.namedImports.map((named) => named.local) + })) + }; +} + +// packages/compiler/src/client-codegen.ts +import { eraseFunctionTypes as eraseFunctionTypes3 } from "@wrnexus/syntax"; +var RESERVED_BINDINGS2 = /* @__PURE__ */ 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" +]); +var RUNTIME_BINDINGS = /* @__PURE__ */ new Set([ + "context", + "state", + "output", + "server", + "props", + "refs", + "event", + "payload" +]); +function safeIdentifier(name) { + return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name) && !RESERVED_BINDINGS2.has(name); +} +function functionEntry(ast, fn, availableFunctions) { + 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 = eraseFunctionTypes3(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} + } + }`; +} +function generateBrowserModule(ast) { + 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; +} +`; +} + +// packages/compiler/src/targets.ts +function generateTargets(ast) { + return { + server: ast.kind === "global-store" || ast.kind === "page-store" ? generateStoreModule(ast) : generateServerFunctionsModule(ast), + browser: ast.kind === "global-store" || ast.kind === "page-store" ? generateStoreBrowserModule(ast) : generateBrowserModule(ast), + declarations: generateDeclarations(ast), + contract: createComponentContract(ast), + rpc: rpcManifest(ast) + }; +} + +// packages/compiler/src/import-resolver.ts +import { existsSync, realpathSync } from "fs"; +import { dirname, extname, join, resolve } from "path"; +function candidates(path) { + return extname(path) ? [path] : [ + path, + `${path}.wrn`, + `${path}.ts`, + `${path}.d.ts`, + join(path, "index.wrn"), + join(path, "index.ts") + ]; +} +function resolveWrnImport(declaration, importer, options) { + const source = declaration.source; + if (!source.startsWith(".") && !source.startsWith("@/")) return { declaration, resolved: source }; + const aliasRoot = options.aliases?.["@"] ?? "./app"; + const base = source.startsWith("@/") ? resolve(options.appRoot, aliasRoot, source.slice(2)) : resolve(dirname(importer), source); + const found = candidates(base).find(existsSync); + if (found) return { declaration, resolved: realpathSync(found) }; + const severity = (options.mode ?? "compatible") === "explicit" ? "error" : "warning"; + return { + declaration, + diagnostic: { + code: "WRN-IMPORT-NOT-FOUND", + message: `Cannot resolve import '${source}' from ${importer}`, + severity + } + }; +} +function resolveWrnImports(declarations, importer, options) { + return declarations.map((declaration) => resolveWrnImport(declaration, importer, options)); +} + +// packages/compiler/src/source-map.ts +function createWrnSourceMap(source, generated) { + const sourceLines = source.split(/\r?\n/).length; + const generatedLines = generated.split(/\r?\n/).length; + const mappings = Array.from({ length: Math.min(sourceLines, generatedLines) }, (_, index) => ({ + generatedLine: index + 1, + sourceLine: index + 1, + sourceColumn: 1, + kind: "line" + })); + return { version: 1, source, generated, mappings }; +} + +// packages/compiler/src/runtime-capabilities.ts +var CAPABILITIES = { + bun: /* @__PURE__ */ new Set([ + "filesystem", + "tcp", + "process", + "websocket", + "crypto", + "streams", + "background-tasks" + ]), + node: /* @__PURE__ */ new Set([ + "filesystem", + "tcp", + "process", + "websocket", + "crypto", + "streams", + "background-tasks" + ]), + edge: /* @__PURE__ */ new Set(["websocket", "crypto", "streams", "background-tasks"]), + worker: /* @__PURE__ */ new Set(["websocket", "crypto", "streams", "background-tasks"]), + "service-worker": /* @__PURE__ */ new Set(["crypto", "streams", "background-tasks"]), + browser: /* @__PURE__ */ new Set(["websocket", "crypto", "streams"]) +}; +var MODULE_CAPABILITIES = [ + [/^(?:node:)?(?:fs|path|os)(?:\/|$)/, "filesystem"], + [/^(?:node:)?(?:net|tls|dgram|http2)(?:\/|$)/, "tcp"], + [/^(?:node:)?(?:child_process|cluster|worker_threads)(?:\/|$)/, "process"] +]; +function runtimeCapabilities(runtime) { + return CAPABILITIES[runtime]; +} +function analyzeRuntimeImports(source, runtime) { + const modules = [ + ...source.matchAll(/\b(?:import\s+(?:[\s\S]*?\s+from\s+)?|require\s*\()\s*["']([^"']+)["']/g) + ].map((match) => match[1]); + const available = runtimeCapabilities(runtime); + return modules.flatMap((module) => { + const requirement = MODULE_CAPABILITIES.find(([pattern]) => pattern.test(module)); + if (!requirement || available.has(requirement[1])) return []; + return [ + { + code: "WRN-RUNTIME-CAPABILITY", + runtime, + module, + capability: requirement[1], + message: `Module '${module}' requires ${requirement[1]}, which is unavailable in the ${runtime} runtime.` + } + ]; + }); +} + +// packages/compiler/src/index.ts +import { Lexer, LexError } from "@wrnexus/syntax"; +import { eraseFunctionTypes as eraseFunctionTypes4, inferredRuntimeType, runtimeTypeOf as runtimeTypeOf2 } from "@wrnexus/syntax"; + +// packages/compiler/src/cache.ts +import { createHash } from "crypto"; +import { diagnose, parse, ParseError } from "@wrnexus/syntax"; +function compileSource(source, filePath) { + const richDiagnostics = diagnose(source, { file: filePath, accessibility: true }); + const errors = richDiagnostics.filter((diagnostic) => diagnostic.severity === "error"); + if (errors.length > 0) { + throw new ParseError( + errors.map((diagnostic) => diagnostic.message).join("\n"), + errors[0].code + ); + } + const ast = parse(source); + return { + code: `// compiled from .wrn +${generate(ast)}`, + ast, + diagnostics: richDiagnostics.map((diagnostic) => `${diagnostic.code}: ${diagnostic.message}`), + richDiagnostics + }; +} +function compilationKey(source, file = "", salt = "") { + return createHash("sha256").update(file).update("\0").update(salt).update("\0").update(source).digest("hex"); +} +function createCompilationCache(options = {}) { + const maxEntries = options.maxEntries ?? 500; + if (!Number.isInteger(maxEntries) || maxEntries < 1) + throw new RangeError("maxEntries must be positive"); + const now = options.now ?? Date.now; + const entries = /* @__PURE__ */ new Map(); + let hits = 0; + let misses = 0; + function touch(key, value) { + entries.delete(key); + entries.set(key, value); + while (entries.size > maxEntries) entries.delete(entries.keys().next().value); + } + return { + compile(source, file = "", salt = "") { + const key = compilationKey(source, file, salt); + const existing = entries.get(key); + if (existing) { + hits++; + touch(key, existing); + return existing; + } + misses++; + const result = compileSource(source, file); + const entry = { + ...result, + key, + file, + sourceHash: createHash("sha256").update(source).digest("hex"), + createdAt: now() + }; + touch(key, entry); + return entry; + }, + get(key) { + const entry = entries.get(key); + if (entry) touch(key, entry); + return entry; + }, + invalidate(file) { + let removed = 0; + for (const [key, entry] of entries) { + if (!file || entry.file === file) { + entries.delete(key); + removed++; + } + } + return removed; + }, + clear() { + entries.clear(); + }, + size: () => entries.size, + stats: () => ({ hits, misses, entries: entries.size }) + }; +} +var DependencyGraph = class { + #dependencies = /* @__PURE__ */ new Map(); + #dependents = /* @__PURE__ */ new Map(); + set(file, dependencies) { + this.remove(file); + const values = new Set(dependencies); + this.#dependencies.set(file, values); + for (const dependency of values) { + const set = this.#dependents.get(dependency) ?? /* @__PURE__ */ new Set(); + set.add(file); + this.#dependents.set(dependency, set); + } + } + remove(file) { + for (const dependency of this.#dependencies.get(file) ?? []) { + const set = this.#dependents.get(dependency); + set?.delete(file); + if (set?.size === 0) this.#dependents.delete(dependency); + } + this.#dependencies.delete(file); + } + dependencies(file) { + return [...this.#dependencies.get(file) ?? []].sort(); + } + dependents(file) { + return [...this.#dependents.get(file) ?? []].sort(); + } + affected(file) { + const found = /* @__PURE__ */ new Set(); + const queue = [file]; + while (queue.length) { + const current = queue.shift(); + for (const dependent of this.#dependents.get(current) ?? []) { + if (found.has(dependent)) continue; + found.add(dependent); + queue.push(dependent); + } + } + return [...found].sort(); + } +}; + +// packages/compiler/src/index.ts +function compileNativeWireFile(source) { + const ast = parse2(source); + assertValidAst(ast); + return generateNative(ast); +} +function compileWireFile(source, filePath = "") { + try { + const ast = parse2(source); + assertValidAst(ast, { file: filePath, accessibility: true }); + return `// compiled from .wrn +${generate(ast)}`; + } catch (error) { + const diagnostic = diagnosticFromError(source, error, { file: filePath }); + throw new Error(`Failed to parse ${filePath}: + +${formatDiagnostic(source, diagnostic)}`, { + cause: error + }); + } +} +function compile(source, filePath = "") { + const richDiagnostics = diagnose2(source, { file: filePath, accessibility: true }); + const errors = richDiagnostics.filter((diagnostic) => diagnostic.severity === "error"); + if (errors.length > 0) { + throw new ParseError2( + errors.map((diagnostic) => diagnostic.message).join("\n"), + errors[0].code + ); + } + const ast = parse2(source); + return { + code: `// compiled from .wrn +${generate(ast)}`, + ast, + diagnostics: richDiagnostics.map((diagnostic) => `${diagnostic.code}: ${diagnostic.message}`), + richDiagnostics + }; +} +export { + DependencyGraph, + LexError, + Lexer, + NativeCompileError, + ParseError3 as ParseError, + analyzeOptimizations, + analyzeRuntimeImports, + analyzeRuntimeRequirements, + assertValidAst2 as assertValidAst, + compilationKey, + compile, + compileNativeWireFile, + compileWireFile, + createCompilationCache, + createComponentContract, + createWrnSourceMap, + diagnose3 as diagnose, + diagnosticFromError2 as diagnosticFromError, + eraseFunctionTypes4 as eraseFunctionTypes, + formatDiagnostic2 as formatDiagnostic, + formatWrn, + generate, + generateBrowserModule, + generateDeclarations, + generateNative, + generateServerFunctionsModule, + generateStoreBrowserModule, + generateStoreModule, + generateTargets, + inferredRuntimeType, + optimizeAst, + parse3 as parse, + resolveWrnImport, + resolveWrnImports, + rpcManifest, + runtimeCapabilities, + runtimeTypeOf2 as runtimeTypeOf +};