""" JS platform constants and functions for the SX bootstrap compiler. This module contains all platform-specific JS code (string constants, helper functions, and configuration dicts) shared by bootstrap_js.py and run_js_sx.py. The JSEmitter class, compile_ref_to_js function, and main entry point remain in bootstrap_js.py. """ from __future__ import annotations from shared.sx.parser import parse_all from shared.sx.types import Symbol def extract_defines(source: str) -> list[tuple[str, list]]: """Parse .sx source, return list of (name, define-expr) for top-level defines.""" exprs = parse_all(source) defines = [] for expr in exprs: if isinstance(expr, list) and expr and isinstance(expr[0], Symbol): if expr[0].name == "define": name = expr[1].name if isinstance(expr[1], Symbol) else str(expr[1]) defines.append((name, expr)) return defines ADAPTER_FILES = { "parser": ("parser.sx", "parser"), "html": ("adapter-html.sx", "adapter-html"), "sx": ("adapter-sx.sx", "adapter-sx"), "dom": ("adapter-dom.sx", "adapter-dom"), "engine": ("engine.sx", "engine"), "orchestration": ("orchestration.sx","orchestration"), "boot": ("boot.sx", "boot"), } # Dependencies ADAPTER_DEPS = { "engine": ["dom"], "orchestration": ["engine", "dom"], "boot": ["dom", "engine", "orchestration", "parser"], "parser": [], } SPEC_MODULES = { "deps": ("deps.sx", "deps (component dependency analysis)"), "router": ("router.sx", "router (client-side route matching)"), "signals": ("signals.sx", "signals (reactive signal runtime)"), "page-helpers": ("page-helpers.sx", "page-helpers (pure data transformation helpers)"), "frames": ("frames.sx", "frames (CEK continuation frames)"), "cek": ("cek.sx", "cek (explicit CEK machine evaluator)"), "types": ("types.sx", "types (gradual type system)"), } # Explicit ordering for spec modules with dependencies. # Modules listed here are emitted in this order; any not listed use alphabetical. SPEC_MODULE_ORDER = ["deps", "frames", "page-helpers", "router", "cek", "signals", "types"] EXTENSION_NAMES = {"continuations"} CONTINUATIONS_JS = ''' // ========================================================================= // Extension: Delimited continuations (shift/reset) // ========================================================================= function Continuation(fn) { var c = function(value) { return fn(value !== undefined ? value : NIL); }; c.fn = fn; c._continuation = true; c.call = function(value) { return fn(value !== undefined ? value : NIL); }; return c; } function ShiftSignal(kName, body, env) { this.kName = kName; this.body = body; this.env = env; } PRIMITIVES["continuation?"] = function(x) { return x != null && x._continuation === true; }; var _resetResume = []; function sfReset(args, env) { var body = args[0]; try { return trampoline(evalExpr(body, env)); } catch (e) { if (e instanceof ShiftSignal) { var sig = e; var cont = new Continuation(function(value) { if (value === undefined) value = NIL; _resetResume.push(value); try { return trampoline(evalExpr(body, env)); } finally { _resetResume.pop(); } }); var sigEnv = merge(sig.env); sigEnv[sig.kName] = cont; return trampoline(evalExpr(sig.body, sigEnv)); } throw e; } } function sfShift(args, env) { if (_resetResume.length > 0) { return _resetResume[_resetResume.length - 1]; } var kName = symbolName(args[0]); var body = args[1]; throw new ShiftSignal(kName, body, env); } // Wrap evalList to intercept reset/shift var _baseEvalList = evalList; evalList = function(expr, env) { var head = expr[0]; if (isSym(head)) { var name = head.name; if (name === "reset") return sfReset(expr.slice(1), env); if (name === "shift") return sfShift(expr.slice(1), env); } return _baseEvalList(expr, env); }; // Wrap aserSpecial to handle reset/shift in SX wire mode if (typeof aserSpecial === "function") { var _baseAserSpecial = aserSpecial; aserSpecial = function(name, expr, env) { if (name === "reset") return sfReset(expr.slice(1), env); if (name === "shift") return sfShift(expr.slice(1), env); return _baseAserSpecial(name, expr, env); }; } // Wrap typeOf to recognize continuations var _baseTypeOf = typeOf; typeOf = function(x) { if (x != null && x._continuation) return "continuation"; return _baseTypeOf(x); }; ''' ASYNC_IO_JS = ''' // ========================================================================= // Async IO: Promise-aware rendering for client-side IO primitives // ========================================================================= // // IO primitives (query, current-user, etc.) return Promises on the client. // asyncRenderToDom walks the component tree; when it encounters an IO // primitive, it awaits the Promise and continues rendering. // // The sync evaluator/renderer is untouched. This is a separate async path // used only when a page's component tree contains IO references. var IO_PRIMITIVES = {}; function registerIoPrimitive(name, fn) { IO_PRIMITIVES[name] = fn; } function isPromise(x) { return x != null && typeof x === "object" && typeof x.then === "function"; } // Async trampoline: resolves thunks, awaits Promises function asyncTrampoline(val) { if (isPromise(val)) return val.then(asyncTrampoline); if (isThunk(val)) return asyncTrampoline(evalExpr(thunkExpr(val), thunkEnv(val))); return val; } // Async eval: like trampoline(evalExpr(...)) but handles IO primitives function asyncEval(expr, env) { // Intercept IO primitive calls at the AST level if (Array.isArray(expr) && expr.length > 0) { var head = expr[0]; if (head && head._sym) { var name = head.name; if (IO_PRIMITIVES[name]) { // Evaluate args, then call the IO primitive return asyncEvalIoCall(name, expr.slice(1), env); } } } // Non-IO: use sync eval, but result might be a thunk var result = evalExpr(expr, env); return asyncTrampoline(result); } function asyncEvalIoCall(name, rawArgs, env) { // Parse keyword args and positional args, evaluating each (may be async) var kwargs = {}; var args = []; var promises = []; var i = 0; while (i < rawArgs.length) { var arg = rawArgs[i]; if (arg && arg._kw && (i + 1) < rawArgs.length) { var kName = arg.name; var kVal = asyncEval(rawArgs[i + 1], env); if (isPromise(kVal)) { (function(k) { promises.push(kVal.then(function(v) { kwargs[k] = v; })); })(kName); } else { kwargs[kName] = kVal; } i += 2; } else { var aVal = asyncEval(arg, env); if (isPromise(aVal)) { (function(idx) { promises.push(aVal.then(function(v) { args[idx] = v; })); })(args.length); args.push(null); // placeholder } else { args.push(aVal); } i++; } } var ioFn = IO_PRIMITIVES[name]; if (promises.length > 0) { return Promise.all(promises).then(function() { return ioFn(args, kwargs); }); } return ioFn(args, kwargs); } // Async render-to-dom: returns Promise or Node function asyncRenderToDom(expr, env, ns) { // Literals if (expr === NIL || expr === null || expr === undefined) return null; if (expr === true || expr === false) return null; if (typeof expr === "string") return document.createTextNode(expr); if (typeof expr === "number") return document.createTextNode(String(expr)); // Symbol -> async eval then render if (expr && expr._sym) { var val = asyncEval(expr, env); if (isPromise(val)) return val.then(function(v) { return asyncRenderToDom(v, env, ns); }); return asyncRenderToDom(val, env, ns); } // Keyword if (expr && expr._kw) return document.createTextNode(expr.name); // DocumentFragment / DOM nodes pass through if (expr instanceof DocumentFragment || (expr && expr.nodeType)) return expr; // Dict -> skip if (expr && typeof expr === "object" && !Array.isArray(expr)) return null; // List if (!Array.isArray(expr) || expr.length === 0) return null; var head = expr[0]; if (!head) return null; // Symbol head if (head._sym) { var hname = head.name; // IO primitive if (IO_PRIMITIVES[hname]) { var ioResult = asyncEval(expr, env); if (isPromise(ioResult)) return ioResult.then(function(v) { return asyncRenderToDom(v, env, ns); }); return asyncRenderToDom(ioResult, env, ns); } // Fragment if (hname === "<>") return asyncRenderChildren(expr.slice(1), env, ns); // raw! if (hname === "raw!") { return asyncEvalRaw(expr.slice(1), env); } // Special forms that need async handling if (hname === "if") return asyncRenderIf(expr, env, ns); if (hname === "when") return asyncRenderWhen(expr, env, ns); if (hname === "cond") return asyncRenderCond(expr, env, ns); if (hname === "case") return asyncRenderCase(expr, env, ns); if (hname === "let" || hname === "let*") return asyncRenderLet(expr, env, ns); if (hname === "begin" || hname === "do") return asyncRenderChildren(expr.slice(1), env, ns); if (hname === "map") return asyncRenderMap(expr, env, ns); if (hname === "map-indexed") return asyncRenderMapIndexed(expr, env, ns); if (hname === "for-each") return asyncRenderMap(expr, env, ns); // define/defcomp/defmacro — eval for side effects if (hname === "define" || hname === "defcomp" || hname === "defmacro" || hname === "defstyle" || hname === "defhandler") { trampoline(evalExpr(expr, env)); return null; } // quote if (hname === "quote") return null; // lambda/fn if (hname === "lambda" || hname === "fn") { trampoline(evalExpr(expr, env)); return null; } // and/or — eval and render result if (hname === "and" || hname === "or" || hname === "->") { var aoResult = asyncEval(expr, env); if (isPromise(aoResult)) return aoResult.then(function(v) { return asyncRenderToDom(v, env, ns); }); return asyncRenderToDom(aoResult, env, ns); } // set! if (hname === "set!") { asyncEval(expr, env); return null; } // Component or Island if (hname.charAt(0) === "~") { var comp = env[hname]; if (comp && comp._island) return renderDomIsland(comp, expr.slice(1), env, ns); if (comp && comp._component) return asyncRenderComponent(comp, expr.slice(1), env, ns); if (comp && comp._macro) { var expanded = trampoline(expandMacro(comp, expr.slice(1), env)); return asyncRenderToDom(expanded, env, ns); } } // Macro if (env[hname] && env[hname]._macro) { var mac = env[hname]; var expanded = trampoline(expandMacro(mac, expr.slice(1), env)); return asyncRenderToDom(expanded, env, ns); } // HTML tag if (typeof renderDomElement === "function" && contains(HTML_TAGS, hname)) { return asyncRenderElement(hname, expr.slice(1), env, ns); } // html: prefix if (hname.indexOf("html:") === 0) { return asyncRenderElement(hname.slice(5), expr.slice(1), env, ns); } // Custom element if (hname.indexOf("-") >= 0 && expr.length > 1 && expr[1] && expr[1]._kw) { return asyncRenderElement(hname, expr.slice(1), env, ns); } // SVG context if (ns) return asyncRenderElement(hname, expr.slice(1), env, ns); // Fallback: eval and render var fResult = asyncEval(expr, env); if (isPromise(fResult)) return fResult.then(function(v) { return asyncRenderToDom(v, env, ns); }); return asyncRenderToDom(fResult, env, ns); } // Non-symbol head: eval call var cResult = asyncEval(expr, env); if (isPromise(cResult)) return cResult.then(function(v) { return asyncRenderToDom(v, env, ns); }); return asyncRenderToDom(cResult, env, ns); } function asyncRenderChildren(exprs, env, ns) { var frag = document.createDocumentFragment(); var pending = []; for (var i = 0; i < exprs.length; i++) { var result = asyncRenderToDom(exprs[i], env, ns); if (isPromise(result)) { // Insert placeholder, replace when resolved var placeholder = document.createComment("async"); frag.appendChild(placeholder); (function(ph) { pending.push(result.then(function(node) { if (node) ph.parentNode.replaceChild(node, ph); else ph.parentNode.removeChild(ph); })); })(placeholder); } else if (result && !result._spread) { frag.appendChild(result); } } if (pending.length > 0) { return Promise.all(pending).then(function() { return frag; }); } return frag; } function asyncRenderElement(tag, args, env, ns) { var newNs = tag === "svg" ? SVG_NS : tag === "math" ? MATH_NS : ns; var el = domCreateElement(tag, newNs); var pending = []; var isVoid = contains(VOID_ELEMENTS, tag); for (var i = 0; i < args.length; i++) { var arg = args[i]; if (arg && arg._kw && (i + 1) < args.length) { var attrName = arg.name; var attrVal = asyncEval(args[i + 1], env); i++; if (isPromise(attrVal)) { (function(an, av) { pending.push(av.then(function(v) { if (!isNil(v) && v !== false) { if (contains(BOOLEAN_ATTRS, an)) { if (isSxTruthy(v)) el.setAttribute(an, ""); } else if (v === true) el.setAttribute(an, ""); else el.setAttribute(an, String(v)); } })); })(attrName, attrVal); } else { if (!isNil(attrVal) && attrVal !== false) { if (contains(BOOLEAN_ATTRS, attrName)) { if (isSxTruthy(attrVal)) el.setAttribute(attrName, ""); } else if (attrVal === true) { el.setAttribute(attrName, ""); } else { el.setAttribute(attrName, String(attrVal)); } } } } else if (!isVoid) { var child = asyncRenderToDom(arg, env, newNs); if (isPromise(child)) { var placeholder = document.createComment("async"); el.appendChild(placeholder); (function(ph) { pending.push(child.then(function(node) { if (node) ph.parentNode.replaceChild(node, ph); else ph.parentNode.removeChild(ph); })); })(placeholder); } else if (child) { if (child._spread) { // Spread: merge attrs onto parent element var sa = child.attrs || {}; for (var sk in sa) { if (sk === "class") { var ec = el.getAttribute("class") || ""; el.setAttribute("class", ec ? ec + " " + sa[sk] : sa[sk]); } else if (sk === "style") { var es = el.getAttribute("style") || ""; el.setAttribute("style", es ? es + ";" + sa[sk] : sa[sk]); } else { el.setAttribute(sk, String(sa[sk])); } } } else { el.appendChild(child); } } } } if (pending.length > 0) return Promise.all(pending).then(function() { return el; }); return el; } function asyncRenderComponent(comp, args, env, ns) { var kwargs = {}; var children = []; var pending = []; for (var i = 0; i < args.length; i++) { var arg = args[i]; if (arg && arg._kw && (i + 1) < args.length) { var kName = arg.name; var kVal = asyncEval(args[i + 1], env); if (isPromise(kVal)) { (function(k) { pending.push(kVal.then(function(v) { kwargs[k] = v; })); })(kName); } else { kwargs[kName] = kVal; } i++; } else { children.push(arg); } } function doRender() { var local = Object.create(componentClosure(comp)); for (var k in env) if (env.hasOwnProperty(k)) local[k] = env[k]; var params = componentParams(comp); for (var j = 0; j < params.length; j++) { local[params[j]] = params[j] in kwargs ? kwargs[params[j]] : NIL; } if (componentHasChildren(comp)) { var childResult = asyncRenderChildren(children, env, ns); if (isPromise(childResult)) { return childResult.then(function(childFrag) { local["children"] = childFrag; return asyncRenderToDom(componentBody(comp), local, ns); }); } local["children"] = childResult; } return asyncRenderToDom(componentBody(comp), local, ns); } if (pending.length > 0) return Promise.all(pending).then(doRender); return doRender(); } function asyncRenderIf(expr, env, ns) { var cond = asyncEval(expr[1], env); if (isPromise(cond)) { return cond.then(function(v) { return isSxTruthy(v) ? asyncRenderToDom(expr[2], env, ns) : (expr.length > 3 ? asyncRenderToDom(expr[3], env, ns) : null); }); } return isSxTruthy(cond) ? asyncRenderToDom(expr[2], env, ns) : (expr.length > 3 ? asyncRenderToDom(expr[3], env, ns) : null); } function asyncRenderWhen(expr, env, ns) { var cond = asyncEval(expr[1], env); if (isPromise(cond)) { return cond.then(function(v) { return isSxTruthy(v) ? asyncRenderChildren(expr.slice(2), env, ns) : null; }); } return isSxTruthy(cond) ? asyncRenderChildren(expr.slice(2), env, ns) : null; } function asyncRenderCond(expr, env, ns) { var clauses = expr.slice(1); function step(idx) { if (idx >= clauses.length) return null; var clause = clauses[idx]; if (!Array.isArray(clause) || clause.length < 2) return step(idx + 1); var test = clause[0]; if ((test && test._sym && (test.name === "else" || test.name === ":else")) || (test && test._kw && test.name === "else")) { return asyncRenderToDom(clause[1], env, ns); } var v = asyncEval(test, env); if (isPromise(v)) return v.then(function(r) { return isSxTruthy(r) ? asyncRenderToDom(clause[1], env, ns) : step(idx + 1); }); return isSxTruthy(v) ? asyncRenderToDom(clause[1], env, ns) : step(idx + 1); } return step(0); } function asyncRenderCase(expr, env, ns) { var matchVal = asyncEval(expr[1], env); function doCase(mv) { var clauses = expr.slice(2); for (var i = 0; i < clauses.length - 1; i += 2) { var test = clauses[i]; if ((test && test._kw && test.name === "else") || (test && test._sym && (test.name === "else" || test.name === ":else"))) { return asyncRenderToDom(clauses[i + 1], env, ns); } var tv = trampoline(evalExpr(test, env)); if (mv === tv || (typeof mv === "string" && typeof tv === "string" && mv === tv)) { return asyncRenderToDom(clauses[i + 1], env, ns); } } return null; } if (isPromise(matchVal)) return matchVal.then(doCase); return doCase(matchVal); } function asyncRenderLet(expr, env, ns) { var bindings = expr[1]; var local = Object.create(env); for (var k in env) if (env.hasOwnProperty(k)) local[k] = env[k]; function bindStep(idx) { if (!Array.isArray(bindings)) return asyncRenderChildren(expr.slice(2), local, ns); // Nested pairs: ((a 1) (b 2)) if (bindings.length > 0 && Array.isArray(bindings[0])) { if (idx >= bindings.length) return asyncRenderChildren(expr.slice(2), local, ns); var b = bindings[idx]; var vname = b[0]._sym ? b[0].name : String(b[0]); var val = asyncEval(b[1], local); if (isPromise(val)) return val.then(function(v) { local[vname] = v; return bindStep(idx + 1); }); local[vname] = val; return bindStep(idx + 1); } // Flat pairs: (a 1 b 2) if (idx >= bindings.length) return asyncRenderChildren(expr.slice(2), local, ns); var vn = bindings[idx]._sym ? bindings[idx].name : String(bindings[idx]); var vv = asyncEval(bindings[idx + 1], local); if (isPromise(vv)) return vv.then(function(v) { local[vn] = v; return bindStep(idx + 2); }); local[vn] = vv; return bindStep(idx + 2); } return bindStep(0); } function asyncRenderMap(expr, env, ns) { var fn = asyncEval(expr[1], env); var coll = asyncEval(expr[2], env); function doMap(f, c) { if (!Array.isArray(c)) return null; var frag = document.createDocumentFragment(); var pending = []; for (var i = 0; i < c.length; i++) { var item = c[i]; var result; if (f && f._lambda) { var lenv = Object.create(f.closure || env); for (var k in env) if (env.hasOwnProperty(k)) lenv[k] = env[k]; lenv[f.params[0]] = item; result = asyncRenderToDom(f.body, lenv, null); } else if (typeof f === "function") { var r = f(item); result = isPromise(r) ? r.then(function(v) { return asyncRenderToDom(v, env, null); }) : asyncRenderToDom(r, env, null); } else { result = asyncRenderToDom(item, env, null); } if (isPromise(result)) { var ph = document.createComment("async"); frag.appendChild(ph); (function(p) { pending.push(result.then(function(n) { if (n) p.parentNode.replaceChild(n, p); else p.parentNode.removeChild(p); })); })(ph); } else if (result && !result._spread) { frag.appendChild(result); } } if (pending.length) return Promise.all(pending).then(function() { return frag; }); return frag; } if (isPromise(fn) || isPromise(coll)) { return Promise.all([isPromise(fn) ? fn : Promise.resolve(fn), isPromise(coll) ? coll : Promise.resolve(coll)]) .then(function(r) { return doMap(r[0], r[1]); }); } return doMap(fn, coll); } function asyncRenderMapIndexed(expr, env, ns) { var fn = asyncEval(expr[1], env); var coll = asyncEval(expr[2], env); function doMap(f, c) { if (!Array.isArray(c)) return null; var frag = document.createDocumentFragment(); var pending = []; for (var i = 0; i < c.length; i++) { var item = c[i]; var result; if (f && f._lambda) { var lenv = Object.create(f.closure || env); for (var k in env) if (env.hasOwnProperty(k)) lenv[k] = env[k]; lenv[f.params[0]] = i; lenv[f.params[1]] = item; result = asyncRenderToDom(f.body, lenv, null); } else if (typeof f === "function") { var r = f(i, item); result = isPromise(r) ? r.then(function(v) { return asyncRenderToDom(v, env, null); }) : asyncRenderToDom(r, env, null); } else { result = asyncRenderToDom(item, env, null); } if (isPromise(result)) { var ph = document.createComment("async"); frag.appendChild(ph); (function(p) { pending.push(result.then(function(n) { if (n) p.parentNode.replaceChild(n, p); else p.parentNode.removeChild(p); })); })(ph); } else if (result && !result._spread) { frag.appendChild(result); } } if (pending.length) return Promise.all(pending).then(function() { return frag; }); return frag; } if (isPromise(fn) || isPromise(coll)) { return Promise.all([isPromise(fn) ? fn : Promise.resolve(fn), isPromise(coll) ? coll : Promise.resolve(coll)]) .then(function(r) { return doMap(r[0], r[1]); }); } return doMap(fn, coll); } function asyncEvalRaw(args, env) { var parts = []; var pending = []; for (var i = 0; i < args.length; i++) { var val = asyncEval(args[i], env); if (isPromise(val)) { (function(idx) { pending.push(val.then(function(v) { parts[idx] = v; })); })(parts.length); parts.push(null); } else { parts.push(val); } } function assemble() { var html = ""; for (var j = 0; j < parts.length; j++) { var p = parts[j]; if (p && p._rawHtml) html += p.html; else if (typeof p === "string") html += p; else if (p != null && !isNil(p)) html += String(p); } var el = document.createElement("span"); el.innerHTML = html; var frag = document.createDocumentFragment(); while (el.firstChild) frag.appendChild(el.firstChild); return frag; } if (pending.length) return Promise.all(pending).then(assemble); return assemble(); } // Async version of sxRenderWithEnv — returns Promise function asyncSxRenderWithEnv(source, extraEnv) { var env = extraEnv ? merge(componentEnv, extraEnv) : componentEnv; var exprs = parse(source); if (!_hasDom) return Promise.resolve(null); return asyncRenderChildren(exprs, env, null); } // IO proxy cache: key → { value, expires } var _ioCache = {}; var IO_CACHE_TTL = 300000; // 5 minutes // Register a server-proxied IO primitive: fetches from /sx/io/ // Uses GET for short args, POST for long payloads (URL length safety). // Results are cached client-side by (name + args) with a TTL. function registerProxiedIo(name) { registerIoPrimitive(name, function(args, kwargs) { // Cache key: name + serialized args var cacheKey = name; for (var ci = 0; ci < args.length; ci++) cacheKey += "\0" + String(args[ci]); for (var ck in kwargs) { if (kwargs.hasOwnProperty(ck)) cacheKey += "\0" + ck + "=" + String(kwargs[ck]); } var cached = _ioCache[cacheKey]; if (cached && cached.expires > Date.now()) return cached.value; var url = "/sx/io/" + encodeURIComponent(name); var qs = []; for (var i = 0; i < args.length; i++) { qs.push("_arg" + i + "=" + encodeURIComponent(String(args[i]))); } for (var k in kwargs) { if (kwargs.hasOwnProperty(k)) { qs.push(encodeURIComponent(k) + "=" + encodeURIComponent(String(kwargs[k]))); } } var queryStr = qs.join("&"); var fetchOpts; if (queryStr.length > 1500) { // POST with JSON body for long payloads var sArgs = []; for (var j = 0; j < args.length; j++) sArgs.push(String(args[j])); var sKwargs = {}; for (var kk in kwargs) { if (kwargs.hasOwnProperty(kk)) sKwargs[kk] = String(kwargs[kk]); } var postHeaders = { "SX-Request": "true", "Content-Type": "application/json" }; var csrf = csrfToken(); if (csrf && csrf !== NIL) postHeaders["X-CSRFToken"] = csrf; fetchOpts = { method: "POST", headers: postHeaders, body: JSON.stringify({ args: sArgs, kwargs: sKwargs }) }; } else { if (queryStr) url += "?" + queryStr; fetchOpts = { headers: { "SX-Request": "true" } }; } var result = fetch(url, fetchOpts) .then(function(resp) { if (!resp.ok) { logWarn("sx:io " + name + " failed " + resp.status); return NIL; } return resp.text(); }) .then(function(text) { if (!text || text === "nil") return NIL; try { var exprs = parse(text); var val = exprs.length === 1 ? exprs[0] : exprs; _ioCache[cacheKey] = { value: val, expires: Date.now() + IO_CACHE_TTL }; return val; } catch (e) { logWarn("sx:io " + name + " parse error: " + (e && e.message ? e.message : e)); return NIL; } }) .catch(function(e) { logWarn("sx:io " + name + " network error: " + (e && e.message ? e.message : e)); return NIL; }); // Cache the in-flight promise too (dedup concurrent calls for same args) _ioCache[cacheKey] = { value: result, expires: Date.now() + IO_CACHE_TTL }; return result; }); } // Register IO deps as proxied primitives (idempotent, called per-page) function registerIoDeps(names) { if (!names || !names.length) return; var registered = 0; for (var i = 0; i < names.length; i++) { var name = names[i]; if (!IO_PRIMITIVES[name]) { registerProxiedIo(name); registered++; } } if (registered > 0) { logInfo("sx:io registered " + registered + " proxied primitives: " + names.join(", ")); } } ''' PREAMBLE = '''\ /** * sx-ref.js — Generated from reference SX evaluator specification. * * Bootstrap-compiled from shared/sx/ref/{eval,render,primitives}.sx * Compare against hand-written sx.js for correctness verification. * * DO NOT EDIT — regenerate with: python bootstrap_js.py */ ;(function(global) { "use strict"; // ========================================================================= // Types // ========================================================================= var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } }); var SX_VERSION = "BUILD_TIMESTAMP"; function isNil(x) { return x === NIL || x === null || x === undefined; } function isSxTruthy(x) { return x !== false && !isNil(x); } function Symbol(name) { this.name = name; } Symbol.prototype.toString = function() { return this.name; }; Symbol.prototype._sym = true; function Keyword(name) { this.name = name; } Keyword.prototype.toString = function() { return ":" + this.name; }; Keyword.prototype._kw = true; function Lambda(params, body, closure, name) { this.params = params; this.body = body; this.closure = closure || {}; this.name = name || null; } Lambda.prototype._lambda = true; function Component(name, params, hasChildren, body, closure, affinity) { this.name = name; this.params = params; this.hasChildren = hasChildren; this.body = body; this.closure = closure || {}; this.affinity = affinity || "auto"; } Component.prototype._component = true; function Island(name, params, hasChildren, body, closure) { this.name = name; this.params = params; this.hasChildren = hasChildren; this.body = body; this.closure = closure || {}; } Island.prototype._island = true; function Macro(params, restParam, body, closure, name) { this.params = params; this.restParam = restParam; this.body = body; this.closure = closure || {}; this.name = name || null; } Macro.prototype._macro = true; function Thunk(expr, env) { this.expr = expr; this.env = env; } Thunk.prototype._thunk = true; function RawHTML(html) { this.html = html; } RawHTML.prototype._raw = true; function SxSpread(attrs) { this.attrs = attrs || {}; } SxSpread.prototype._spread = true; var _scopeStacks = {}; function isSym(x) { return x != null && x._sym === true; } function isKw(x) { return x != null && x._kw === true; } function merge() { var out = {}; for (var i = 0; i < arguments.length; i++) { var d = arguments[i]; if (d) for (var k in d) out[k] = d[k]; } return out; } function sxOr() { for (var i = 0; i < arguments.length; i++) { if (isSxTruthy(arguments[i])) return arguments[i]; } return arguments.length ? arguments[arguments.length - 1] : false; }''' PRIMITIVES_JS_MODULES: dict[str, str] = { "core.arithmetic": ''' // core.arithmetic PRIMITIVES["+"] = function() { var s = 0; for (var i = 0; i < arguments.length; i++) s += arguments[i]; return s; }; PRIMITIVES["-"] = function(a, b) { return arguments.length === 1 ? -a : a - b; }; PRIMITIVES["*"] = function() { var s = 1; for (var i = 0; i < arguments.length; i++) s *= arguments[i]; return s; }; PRIMITIVES["/"] = function(a, b) { return a / b; }; PRIMITIVES["mod"] = function(a, b) { return a % b; }; PRIMITIVES["inc"] = function(n) { return n + 1; }; PRIMITIVES["dec"] = function(n) { return n - 1; }; PRIMITIVES["abs"] = Math.abs; PRIMITIVES["floor"] = Math.floor; PRIMITIVES["ceil"] = Math.ceil; PRIMITIVES["round"] = function(x, n) { if (n === undefined || n === 0) return Math.round(x); var f = Math.pow(10, n); return Math.round(x * f) / f; }; PRIMITIVES["min"] = Math.min; PRIMITIVES["max"] = Math.max; PRIMITIVES["sqrt"] = Math.sqrt; PRIMITIVES["pow"] = Math.pow; PRIMITIVES["clamp"] = function(x, lo, hi) { return Math.max(lo, Math.min(hi, x)); }; ''', "core.comparison": ''' // core.comparison PRIMITIVES["="] = function(a, b) { return a === b; }; PRIMITIVES["!="] = function(a, b) { return a !== b; }; PRIMITIVES["<"] = function(a, b) { return a < b; }; PRIMITIVES[">"] = function(a, b) { return a > b; }; PRIMITIVES["<="] = function(a, b) { return a <= b; }; PRIMITIVES[">="] = function(a, b) { return a >= b; }; ''', "core.logic": ''' // core.logic PRIMITIVES["not"] = function(x) { return !isSxTruthy(x); }; ''', "core.predicates": ''' // core.predicates PRIMITIVES["nil?"] = isNil; PRIMITIVES["number?"] = function(x) { return typeof x === "number"; }; PRIMITIVES["string?"] = function(x) { return typeof x === "string"; }; PRIMITIVES["list?"] = Array.isArray; PRIMITIVES["dict?"] = function(x) { return x !== null && typeof x === "object" && !Array.isArray(x) && !x._sym && !x._kw; }; PRIMITIVES["empty?"] = function(c) { return isNil(c) || (Array.isArray(c) ? c.length === 0 : typeof c === "string" ? c.length === 0 : Object.keys(c).length === 0); }; PRIMITIVES["contains?"] = function(c, k) { if (typeof c === "string") return c.indexOf(String(k)) !== -1; if (Array.isArray(c)) return c.indexOf(k) !== -1; return k in c; }; PRIMITIVES["odd?"] = function(n) { return n % 2 !== 0; }; PRIMITIVES["even?"] = function(n) { return n % 2 === 0; }; PRIMITIVES["zero?"] = function(n) { return n === 0; }; PRIMITIVES["boolean?"] = function(x) { return x === true || x === false; }; PRIMITIVES["symbol?"] = function(x) { return x != null && x._sym === true; }; PRIMITIVES["keyword?"] = function(x) { return x != null && x._kw === true; }; PRIMITIVES["component-affinity"] = componentAffinity; ''', "core.strings": ''' // core.strings PRIMITIVES["str"] = function() { var p = []; for (var i = 0; i < arguments.length; i++) { var v = arguments[i]; if (isNil(v)) continue; p.push(String(v)); } return p.join(""); }; PRIMITIVES["upper"] = function(s) { return String(s).toUpperCase(); }; PRIMITIVES["lower"] = function(s) { return String(s).toLowerCase(); }; PRIMITIVES["trim"] = function(s) { return String(s).trim(); }; PRIMITIVES["split"] = function(s, sep) { return String(s).split(sep || " "); }; PRIMITIVES["join"] = function(sep, coll) { return coll.join(sep); }; PRIMITIVES["replace"] = function(s, old, nw) { return s.split(old).join(nw); }; PRIMITIVES["index-of"] = function(s, needle, from) { return String(s).indexOf(needle, from || 0); }; PRIMITIVES["starts-with?"] = function(s, p) { return String(s).indexOf(p) === 0; }; PRIMITIVES["ends-with?"] = function(s, p) { var str = String(s); return str.indexOf(p, str.length - p.length) !== -1; }; PRIMITIVES["slice"] = function(c, a, b) { if (!c || typeof c.slice !== "function") { console.error("[sx-debug] slice called on non-sliceable:", typeof c, c, "a=", a, "b=", b, new Error().stack); return []; } return b !== undefined ? c.slice(a, b) : c.slice(a); }; PRIMITIVES["substring"] = function(s, a, b) { return String(s).substring(a, b); }; PRIMITIVES["char-from-code"] = function(n) { return String.fromCharCode(n); }; PRIMITIVES["string-length"] = function(s) { return String(s).length; }; var stringLength = PRIMITIVES["string-length"]; PRIMITIVES["string-contains?"] = function(s, sub) { return String(s).indexOf(String(sub)) !== -1; }; PRIMITIVES["concat"] = function() { var out = []; for (var i = 0; i < arguments.length; i++) if (!isNil(arguments[i])) out = out.concat(arguments[i]); return out; }; ''', "core.collections": ''' // core.collections PRIMITIVES["list"] = function() { return Array.prototype.slice.call(arguments); }; PRIMITIVES["dict"] = function() { var d = {}; for (var i = 0; i < arguments.length - 1; i += 2) d[arguments[i]] = arguments[i + 1]; return d; }; PRIMITIVES["range"] = function(a, b, step) { var r = []; step = step || 1; for (var i = a; step > 0 ? i < b : i > b; i += step) r.push(i); return r; }; PRIMITIVES["get"] = function(c, k, def) { var v = (c && c[k]); return v !== undefined ? v : (def !== undefined ? def : NIL); }; PRIMITIVES["len"] = function(c) { return Array.isArray(c) ? c.length : typeof c === "string" ? c.length : Object.keys(c).length; }; PRIMITIVES["first"] = function(c) { return c && c.length > 0 ? c[0] : NIL; }; PRIMITIVES["last"] = function(c) { return c && c.length > 0 ? c[c.length - 1] : NIL; }; PRIMITIVES["rest"] = function(c) { if (c && typeof c.slice !== "function") { console.error("[sx-debug] rest called on non-sliceable:", typeof c, c, new Error().stack); return []; } return c ? c.slice(1) : []; }; PRIMITIVES["nth"] = function(c, n) { return c && n >= 0 && n < c.length ? c[n] : NIL; }; PRIMITIVES["cons"] = function(x, c) { return [x].concat(c || []); }; PRIMITIVES["append"] = function(c, x) { return (c || []).concat(Array.isArray(x) ? x : [x]); }; PRIMITIVES["append!"] = function(arr, x) { arr.push(x); return arr; }; PRIMITIVES["chunk-every"] = function(c, n) { var r = []; for (var i = 0; i < c.length; i += n) r.push(c.slice(i, i + n)); return r; }; PRIMITIVES["zip-pairs"] = function(c) { var r = []; for (var i = 0; i < c.length - 1; i++) r.push([c[i], c[i + 1]]); return r; }; PRIMITIVES["reverse"] = function(c) { return Array.isArray(c) ? c.slice().reverse() : String(c).split("").reverse().join(""); }; PRIMITIVES["flatten"] = function(c) { var out = []; function walk(a) { for (var i = 0; i < a.length; i++) Array.isArray(a[i]) ? walk(a[i]) : out.push(a[i]); } walk(c || []); return out; }; ''', "core.dict": ''' // core.dict PRIMITIVES["keys"] = function(d) { return Object.keys(d || {}); }; PRIMITIVES["vals"] = function(d) { var r = []; for (var k in d) r.push(d[k]); return r; }; PRIMITIVES["merge"] = function() { var out = {}; for (var i = 0; i < arguments.length; i++) { var d = arguments[i]; if (d && !isNil(d)) for (var k in d) out[k] = d[k]; } return out; }; PRIMITIVES["assoc"] = function(d) { var out = {}; if (d && !isNil(d)) for (var k in d) out[k] = d[k]; for (var i = 1; i < arguments.length - 1; i += 2) out[arguments[i]] = arguments[i + 1]; return out; }; PRIMITIVES["dissoc"] = function(d) { var out = {}; for (var k in d) out[k] = d[k]; for (var i = 1; i < arguments.length; i++) delete out[arguments[i]]; return out; }; PRIMITIVES["dict-set!"] = function(d, k, v) { d[k] = v; return v; }; PRIMITIVES["has-key?"] = function(d, k) { return d !== null && d !== undefined && k in d; }; PRIMITIVES["into"] = function(target, coll) { if (Array.isArray(target)) return Array.isArray(coll) ? coll.slice() : Object.entries(coll); var r = {}; for (var i = 0; i < coll.length; i++) { var p = coll[i]; if (Array.isArray(p) && p.length >= 2) r[p[0]] = p[1]; } return r; }; ''', "stdlib.format": ''' // stdlib.format PRIMITIVES["format-decimal"] = function(v, p) { return Number(v).toFixed(p || 2); }; PRIMITIVES["parse-int"] = function(v, d) { var n = parseInt(v, 10); return isNaN(n) ? (d || 0) : n; }; PRIMITIVES["format-date"] = function(s, fmt) { if (!s) return ""; try { var d = new Date(s); if (isNaN(d.getTime())) return String(s); var months = ["January","February","March","April","May","June","July","August","September","October","November","December"]; var short_months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]; return fmt.replace(/%-d/g, d.getDate()).replace(/%d/g, ("0"+d.getDate()).slice(-2)) .replace(/%B/g, months[d.getMonth()]).replace(/%b/g, short_months[d.getMonth()]) .replace(/%Y/g, d.getFullYear()).replace(/%m/g, ("0"+(d.getMonth()+1)).slice(-2)) .replace(/%H/g, ("0"+d.getHours()).slice(-2)).replace(/%M/g, ("0"+d.getMinutes()).slice(-2)); } catch (e) { return String(s); } }; PRIMITIVES["parse-datetime"] = function(s) { return s ? String(s) : NIL; }; ''', "stdlib.text": ''' // stdlib.text PRIMITIVES["pluralize"] = function(n, s, p) { if (s || (p && p !== "s")) return n == 1 ? (s || "") : (p || "s"); return n == 1 ? "" : "s"; }; PRIMITIVES["escape"] = function(s) { return String(s).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'"); }; PRIMITIVES["strip-tags"] = function(s) { return String(s).replace(/<[^>]+>/g, ""); }; ''', "stdlib.debug": ''' // stdlib.debug PRIMITIVES["assert"] = function(cond, msg) { if (!isSxTruthy(cond)) throw new Error("Assertion error: " + (msg || "Assertion failed")); return true; }; ''', "stdlib.spread": ''' // stdlib.spread — spread + collect + scope primitives PRIMITIVES["make-spread"] = makeSpread; PRIMITIVES["spread?"] = isSpread; PRIMITIVES["spread-attrs"] = spreadAttrs; PRIMITIVES["collect!"] = sxCollect; PRIMITIVES["collected"] = sxCollected; PRIMITIVES["clear-collected!"] = sxClearCollected; // scope — unified render-time dynamic scope PRIMITIVES["scope-push!"] = scopePush; PRIMITIVES["scope-pop!"] = scopePop; // provide-push!/provide-pop! — aliases for scope-push!/scope-pop! PRIMITIVES["provide-push!"] = providePush; PRIMITIVES["provide-pop!"] = providePop; PRIMITIVES["context"] = sxContext; PRIMITIVES["emit!"] = sxEmit; PRIMITIVES["emitted"] = sxEmitted; ''', } # Modules to include by default (all) _ALL_JS_MODULES = list(PRIMITIVES_JS_MODULES.keys()) def _assemble_primitives_js(modules: list[str] | None = None) -> str: """Assemble JS primitive code from selected modules. If modules is None, all modules are included. Core modules are always included regardless of the list. """ if modules is None: modules = _ALL_JS_MODULES parts = [] for mod in modules: if mod in PRIMITIVES_JS_MODULES: parts.append(PRIMITIVES_JS_MODULES[mod]) return "\n".join(parts) PLATFORM_JS_PRE = ''' // ========================================================================= // Platform interface — JS implementation // ========================================================================= function typeOf(x) { if (isNil(x)) return "nil"; if (typeof x === "number") return "number"; if (typeof x === "string") return "string"; if (typeof x === "boolean") return "boolean"; if (x._sym) return "symbol"; if (x._kw) return "keyword"; if (x._thunk) return "thunk"; if (x._lambda) return "lambda"; if (x._component) return "component"; if (x._island) return "island"; if (x._spread) return "spread"; if (x._macro) return "macro"; if (x._raw) return "raw-html"; if (typeof Node !== "undefined" && x instanceof Node) return "dom-node"; if (Array.isArray(x)) return "list"; if (typeof x === "object") return "dict"; return "unknown"; } function symbolName(s) { return s.name; } function keywordName(k) { return k.name; } function makeSymbol(n) { return new Symbol(n); } function makeKeyword(n) { return new Keyword(n); } function makeLambda(params, body, env) { return new Lambda(params, body, env); } function makeComponent(name, params, hasChildren, body, env, affinity) { return new Component(name, params, hasChildren, body, env, affinity); } function makeMacro(params, restParam, body, env, name) { return new Macro(params, restParam, body, env, name); } function makeThunk(expr, env) { return new Thunk(expr, env); } function makeSpread(attrs) { return new SxSpread(attrs || {}); } function isSpread(x) { return x != null && x._spread === true; } function spreadAttrs(s) { return s && s._spread ? s.attrs : {}; } function scopePush(name, value) { if (!_scopeStacks[name]) _scopeStacks[name] = []; _scopeStacks[name].push({value: value !== undefined ? value : NIL, emitted: [], dedup: false}); } function scopePop(name) { if (_scopeStacks[name] && _scopeStacks[name].length) _scopeStacks[name].pop(); } // Aliases — provide-push!/provide-pop! map to scope-push!/scope-pop! var providePush = scopePush; var providePop = scopePop; function sxContext(name) { if (_scopeStacks[name] && _scopeStacks[name].length) { return _scopeStacks[name][_scopeStacks[name].length - 1].value; } if (arguments.length > 1) return arguments[1]; throw new Error("No provider for: " + name); } function sxEmit(name, value) { if (_scopeStacks[name] && _scopeStacks[name].length) { var entry = _scopeStacks[name][_scopeStacks[name].length - 1]; if (entry.dedup && entry.emitted.indexOf(value) !== -1) return NIL; entry.emitted.push(value); } return NIL; } function sxEmitted(name) { if (_scopeStacks[name] && _scopeStacks[name].length) { return _scopeStacks[name][_scopeStacks[name].length - 1].emitted.slice(); } return []; } function sxCollect(bucket, value) { if (!_scopeStacks[bucket] || !_scopeStacks[bucket].length) { if (!_scopeStacks[bucket]) _scopeStacks[bucket] = []; _scopeStacks[bucket].push({value: NIL, emitted: [], dedup: true}); } var entry = _scopeStacks[bucket][_scopeStacks[bucket].length - 1]; if (entry.emitted.indexOf(value) === -1) entry.emitted.push(value); } function sxCollected(bucket) { return sxEmitted(bucket); } function sxClearCollected(bucket) { if (_scopeStacks[bucket] && _scopeStacks[bucket].length) { _scopeStacks[bucket][_scopeStacks[bucket].length - 1].emitted = []; } } function lambdaParams(f) { return f.params; } function lambdaBody(f) { return f.body; } function lambdaClosure(f) { return f.closure; } function lambdaName(f) { return f.name; } function setLambdaName(f, n) { f.name = n; } function componentParams(c) { return c.params; } function componentBody(c) { return c.body; } function componentClosure(c) { return c.closure; } function componentHasChildren(c) { return c.hasChildren; } function componentName(c) { return c.name; } function componentAffinity(c) { return c.affinity || "auto"; } function componentParamTypes(c) { return (c && c._paramTypes) ? c._paramTypes : NIL; } function componentSetParamTypes_b(c, t) { if (c) c._paramTypes = t; return NIL; } function macroParams(m) { return m.params; } function macroRestParam(m) { return m.restParam; } function macroBody(m) { return m.body; } function macroClosure(m) { return m.closure; } function isThunk(x) { return x != null && x._thunk === true; } function thunkExpr(t) { return t.expr; } function thunkEnv(t) { return t.env; } function isCallable(x) { return typeof x === "function" || (x != null && x._lambda === true); } function isLambda(x) { return x != null && x._lambda === true; } function isComponent(x) { return x != null && x._component === true; } function isIsland(x) { return x != null && x._island === true; } function isMacro(x) { return x != null && x._macro === true; } function isIdentical(a, b) { return a === b; } // Island platform function makeIsland(name, params, hasChildren, body, env) { return new Island(name, params, hasChildren, body, env); } // JSON / dict helpers for island state serialization function jsonSerialize(obj) { return JSON.stringify(obj); } function isEmptyDict(d) { if (!d || typeof d !== "object") return true; for (var k in d) if (d.hasOwnProperty(k)) return false; return true; } function envHas(env, name) { return name in env; } function envGet(env, name) { return env[name]; } function envBind(env, name, val) { // Direct property set — creates or overwrites on THIS env only. // Used by let, define, defcomp, lambda param binding. env[name] = val; } function envSet(env, name, val) { // Walk prototype chain to find where the variable is defined (for set!) var obj = env; while (obj !== null && obj !== Object.prototype) { if (obj.hasOwnProperty(name)) { obj[name] = val; return; } obj = Object.getPrototypeOf(obj); } // Not found in any parent scope — set on the immediate env env[name] = val; } function envExtend(env) { return Object.create(env); } function envMerge(base, overlay) { // Same env or overlay is descendant of base — just extend, no copy. // This prevents set! inside lambdas from modifying shadow copies. if (base === overlay) return Object.create(base); var p = overlay; for (var d = 0; p && p !== Object.prototype && d < 100; d++) { if (p === base) return Object.create(base); p = Object.getPrototypeOf(p); } // General case: extend base, copy ONLY overlay properties that don't // exist in the base chain (avoids shadowing closure bindings). var child = Object.create(base); if (overlay) { for (var k in overlay) { if (overlay.hasOwnProperty(k) && !(k in base)) child[k] = overlay[k]; } } return child; } function dictSet(d, k, v) { d[k] = v; return v; } function dictGet(d, k) { var v = d[k]; return v !== undefined ? v : NIL; } // Render-expression detection — lets the evaluator delegate to the active adapter. // Matches HTML tags, SVG tags, <>, raw!, ~components, html: prefix, custom elements. // Placeholder — overridden by transpiled version from render.sx function isRenderExpr(expr) { return false; } // Render dispatch — call the active adapter's render function. // Set by each adapter when loaded; defaults to identity (no rendering). var _renderExprFn = null; // Render mode flag — set by render-to-html/aser, checked by eval-list. // When false, render expressions fall through to evalCall. var _renderMode = false; function renderActiveP() { return _renderMode; } function setRenderActiveB(val) { _renderMode = !!val; } function renderExpr(expr, env) { if (_renderExprFn) return _renderExprFn(expr, env); // No adapter loaded — fall through to evalCall return evalCall(first(expr), rest(expr), env); } function stripPrefix(s, prefix) { return s.indexOf(prefix) === 0 ? s.slice(prefix.length) : s; } function error(msg) { throw new Error(msg); } function inspect(x) { return JSON.stringify(x); } function debugLog() { console.error.apply(console, ["[sx-debug]"].concat(Array.prototype.slice.call(arguments))); } ''' PLATFORM_JS_POST = ''' function isPrimitive(name) { return name in PRIMITIVES; } function getPrimitive(name) { return PRIMITIVES[name]; } // Higher-order helpers used by the transpiled code function map(fn, coll) { return coll.map(fn); } function mapIndexed(fn, coll) { return coll.map(function(item, i) { return fn(i, item); }); } function filter(fn, coll) { return coll.filter(function(x) { return isSxTruthy(fn(x)); }); } function reduce(fn, init, coll) { var acc = init; for (var i = 0; i < coll.length; i++) acc = fn(acc, coll[i]); return acc; } function some(fn, coll) { for (var i = 0; i < coll.length; i++) { var r = fn(coll[i]); if (isSxTruthy(r)) return r; } return NIL; } function forEach(fn, coll) { for (var i = 0; i < coll.length; i++) fn(coll[i]); return NIL; } function isEvery(fn, coll) { for (var i = 0; i < coll.length; i++) { if (!isSxTruthy(fn(coll[i]))) return false; } return true; } function mapDict(fn, d) { var r = {}; for (var k in d) r[k] = fn(k, d[k]); return r; } // Predicate aliases used by transpiled code // Both naming conventions: isX (from js-renames) and x_p (from js-mangle of x?) var isNumber = PRIMITIVES["number?"]; var number_p = isNumber; var isString = PRIMITIVES["string?"]; var string_p = isString; var isBoolean = PRIMITIVES["boolean?"]; var boolean_p = isBoolean; var isDict = PRIMITIVES["dict?"]; var isList = PRIMITIVES["list?"]; var list_p = isList; var isKeyword = PRIMITIVES["keyword?"]; var keyword_p = isKeyword; var isSymbol = PRIMITIVES["symbol?"]; var symbol_p = isSymbol; // List primitives used directly by transpiled code var len = PRIMITIVES["len"]; var first = PRIMITIVES["first"]; var last = PRIMITIVES["last"]; var rest = PRIMITIVES["rest"]; var nth = PRIMITIVES["nth"]; var cons = PRIMITIVES["cons"]; var append = PRIMITIVES["append"]; var isEmpty = PRIMITIVES["empty?"]; var contains = PRIMITIVES["contains?"]; var startsWith = PRIMITIVES["starts-with?"]; var slice = PRIMITIVES["slice"]; var concat = PRIMITIVES["concat"]; var str = PRIMITIVES["str"]; var join = PRIMITIVES["join"]; var keys = PRIMITIVES["keys"]; var get = PRIMITIVES["get"]; var assoc = PRIMITIVES["assoc"]; var range = PRIMITIVES["range"]; function zip(a, b) { var r = []; for (var i = 0; i < Math.min(a.length, b.length); i++) r.push([a[i], b[i]]); return r; } function append_b(arr, x) { arr.push(x); return arr; } var apply = function(f, args) { if (isLambda(f)) return trampoline(callLambda(f, args, lambdaClosure(f))); return f.apply(null, args); }; // Additional primitive aliases used by adapter/engine transpiled code var split = PRIMITIVES["split"]; var trim = PRIMITIVES["trim"]; var upper = PRIMITIVES["upper"]; var lower = PRIMITIVES["lower"]; var replace_ = function(s, old, nw) { return s.split(old).join(nw); }; var endsWith = PRIMITIVES["ends-with?"]; var parseInt_ = PRIMITIVES["parse-int"]; var dict_fn = PRIMITIVES["dict"]; // HTML rendering helpers function escapeHtml(s) { return String(s).replace(/&/g,"&").replace(//g,">").replace(/"/g,"""); } function escapeAttr(s) { return escapeHtml(s); } function rawHtmlContent(r) { return r.html; } function makeRawHtml(s) { return { _raw: true, html: s }; } function sxExprSource(x) { return x && x.source ? x.source : String(x); } // Placeholders — overridden by transpiled spec from parser.sx / adapter-sx.sx function serialize(val) { return String(val); } function isSpecialForm(n) { return false; } function isHoForm(n) { return false; } // processBindings and evalCond — now specced in render.sx, bootstrapped above function isDefinitionForm(name) { return name === "define" || name === "defcomp" || name === "defmacro" || name === "defstyle" || name === "defhandler"; } function indexOf_(s, ch) { return typeof s === "string" ? s.indexOf(ch) : -1; } function dictHas(d, k) { return d != null && k in d; } function dictDelete(d, k) { delete d[k]; } function forEachIndexed(fn, coll) { for (var i = 0; i < coll.length; i++) fn(i, coll[i]); return NIL; } // ========================================================================= // Performance overrides — evaluator hot path // ========================================================================= // Override parseKeywordArgs: imperative loop instead of reduce+assoc parseKeywordArgs = function(rawArgs, env) { var kwargs = {}; var children = []; for (var i = 0; i < rawArgs.length; i++) { var arg = rawArgs[i]; if (arg && arg._kw && (i + 1) < rawArgs.length) { kwargs[arg.name] = trampoline(evalExpr(rawArgs[i + 1], env)); i++; } else { children.push(trampoline(evalExpr(arg, env))); } } return [kwargs, children]; }; // Override callComponent: use prototype chain env, imperative kwarg binding callComponent = function(comp, rawArgs, env) { var kwargs = {}; var children = []; for (var i = 0; i < rawArgs.length; i++) { var arg = rawArgs[i]; if (arg && arg._kw && (i + 1) < rawArgs.length) { kwargs[arg.name] = trampoline(evalExpr(rawArgs[i + 1], env)); i++; } else { children.push(trampoline(evalExpr(arg, env))); } } var local = Object.create(componentClosure(comp)); for (var k in env) if (env.hasOwnProperty(k)) local[k] = env[k]; var params = componentParams(comp); for (var j = 0; j < params.length; j++) { var p = params[j]; local[p] = p in kwargs ? kwargs[p] : NIL; } if (componentHasChildren(comp)) { local["children"] = children; } return makeThunk(componentBody(comp), local); };''' PLATFORM_CEK_JS = ''' // String/number utilities needed by transpiled spec code (content-hash etc) PRIMITIVES["char-code-at"] = function(s, i) { return s.charCodeAt(i); }; var charCodeAt = PRIMITIVES["char-code-at"]; PRIMITIVES["to-hex"] = function(n) { return (n >>> 0).toString(16); }; var toHex = PRIMITIVES["to-hex"]; // ========================================================================= // Platform: CEK module — explicit CEK machine // ========================================================================= // Continuation type (needed by CEK even without the tree-walk shift/reset extension) // Continuations must be callable as JS functions so isCallable/apply work. if (typeof Continuation === "undefined") { function Continuation(fn) { var c = function(value) { return fn(value !== undefined ? value : NIL); }; c.fn = fn; c._continuation = true; c.call = function(value) { return fn(value !== undefined ? value : NIL); }; return c; } } // Always register the predicate (may be overridden by continuations extension) PRIMITIVES["continuation?"] = function(x) { return x != null && x._continuation === true; }; // Standalone aliases for primitives used by cek.sx / frames.sx var inc = PRIMITIVES["inc"]; var dec = PRIMITIVES["dec"]; var zip_pairs = PRIMITIVES["zip-pairs"]; var continuation_p = PRIMITIVES["continuation?"]; function makeCekContinuation(captured, restKont) { var c = new Continuation(function(v) { return v !== undefined ? v : NIL; }); c._cek_data = {"captured": captured, "rest-kont": restKont}; return c; } function continuationData(c) { return (c && c._cek_data) ? c._cek_data : {}; } ''' # Iterative override for cek_run — replaces transpiled recursive version CEK_FIXUPS_JS = ''' // Override recursive cekRun with iterative loop (avoids stack overflow) cekRun = function(state) { while (!cekTerminal_p(state)) { state = cekStep(state); } return cekValue(state); }; // Platform functions — defined in platform_js.py, not in .sx spec files. // Spec defines self-register via js-emit-define; these are the platform interface. PRIMITIVES["type-of"] = typeOf; PRIMITIVES["symbol-name"] = symbolName; PRIMITIVES["keyword-name"] = keywordName; PRIMITIVES["callable?"] = isCallable; PRIMITIVES["lambda?"] = isLambda; PRIMITIVES["lambda-name"] = lambdaName; PRIMITIVES["component?"] = isComponent; PRIMITIVES["island?"] = isIsland; PRIMITIVES["make-symbol"] = function(n) { return new Symbol(n); }; PRIMITIVES["is-html-tag?"] = function(n) { return HTML_TAGS.indexOf(n) >= 0; }; PRIMITIVES["make-env"] = function() { return merge(componentEnv, PRIMITIVES); }; // localStorage — defined here (before boot) so islands can use at hydration PRIMITIVES["local-storage-get"] = function(key) { try { var v = localStorage.getItem(key); return v === null ? NIL : v; } catch (e) { return NIL; } }; PRIMITIVES["local-storage-set"] = function(key, val) { try { localStorage.setItem(key, val); } catch (e) {} return NIL; }; PRIMITIVES["local-storage-remove"] = function(key) { try { localStorage.removeItem(key); } catch (e) {} return NIL; }; ''' PLATFORM_DEPS_JS = ''' // ========================================================================= // Platform: deps module — component dependency analysis // ========================================================================= function componentDeps(c) { return c.deps ? c.deps.slice() : []; } function componentSetDeps(c, deps) { c.deps = deps; } function componentCssClasses(c) { return c.cssClasses ? c.cssClasses.slice() : []; } function envComponents(env) { var names = []; for (var k in env) { var v = env[k]; if (v && (v._component || v._macro)) names.push(k); } return names; } function regexFindAll(pattern, source) { var re = new RegExp(pattern, "g"); var results = []; var m; while ((m = re.exec(source)) !== null) { if (m[1] !== undefined) results.push(m[1]); else results.push(m[0]); } return results; } function scanCssClasses(source) { var classes = {}; var result = []; var m; var re1 = /:class\\s+"([^"]*)"/g; while ((m = re1.exec(source)) !== null) { var parts = m[1].split(/\\s+/); for (var i = 0; i < parts.length; i++) { if (parts[i] && !classes[parts[i]]) { classes[parts[i]] = true; result.push(parts[i]); } } } var re2 = /:class\\s+\\(str\\s+((?:"[^"]*"\\s*)+)\\)/g; while ((m = re2.exec(source)) !== null) { var re3 = /"([^"]*)"/g; var m2; while ((m2 = re3.exec(m[1])) !== null) { var parts2 = m2[1].split(/\\s+/); for (var j = 0; j < parts2.length; j++) { if (parts2[j] && !classes[parts2[j]]) { classes[parts2[j]] = true; result.push(parts2[j]); } } } } var re4 = /;;\\s*@css\\s+(.+)/g; while ((m = re4.exec(source)) !== null) { var parts3 = m[1].split(/\\s+/); for (var k = 0; k < parts3.length; k++) { if (parts3[k] && !classes[parts3[k]]) { classes[parts3[k]] = true; result.push(parts3[k]); } } } return result; } function componentIoRefs(c) { return c.ioRefs ? c.ioRefs.slice() : []; } function componentSetIoRefs(c, refs) { c.ioRefs = refs; } ''' PLATFORM_PARSER_JS = r""" // ========================================================================= // Platform interface — Parser // ========================================================================= // Character classification derived from the grammar: // ident-start → [a-zA-Z_~*+\-><=/!?&] // ident-char → ident-start + [0-9.:\/\#,] var _identStartRe = /[a-zA-Z_~*+\-><=/!?&]/; var _identCharRe = /[a-zA-Z0-9_~*+\-><=/!?.:&/#,]/; function isIdentStart(ch) { return _identStartRe.test(ch); } function isIdentChar(ch) { return _identCharRe.test(ch); } function parseNumber(s) { return Number(s); } function escapeString(s) { return s.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\t/g, "\\t"); } function sxExprSource(e) { return typeof e === "string" ? e : String(e); } var charFromCode = PRIMITIVES["char-from-code"]; """ PLATFORM_DOM_JS = """ // ========================================================================= // Platform interface — DOM adapter (browser-only) // ========================================================================= var _hasDom = typeof document !== "undefined"; // Register DOM adapter as the render dispatch target for the evaluator. _renderExprFn = function(expr, env) { return renderToDom(expr, env, null); }; _renderMode = true; // Browser always evaluates in render context. var SVG_NS = "http://www.w3.org/2000/svg"; var MATH_NS = "http://www.w3.org/1998/Math/MathML"; function domCreateElement(tag, ns) { if (!_hasDom) return null; if (ns && ns !== NIL) return document.createElementNS(ns, tag); return document.createElement(tag); } function createTextNode(s) { return _hasDom ? document.createTextNode(s) : null; } function createComment(s) { return _hasDom ? document.createComment(s || "") : null; } function createFragment() { return _hasDom ? document.createDocumentFragment() : null; } function domAppend(parent, child) { if (parent && child && !child._spread) parent.appendChild(child); } function domPrepend(parent, child) { if (parent && child) parent.insertBefore(child, parent.firstChild); } function domSetAttr(el, name, val) { if (el && el.setAttribute) el.setAttribute(name, val); } function domGetAttr(el, name) { if (!el || !el.getAttribute) return NIL; var v = el.getAttribute(name); return v === null ? NIL : v; } function domRemoveAttr(el, name) { if (el && el.removeAttribute) el.removeAttribute(name); } function domHasAttr(el, name) { return !!(el && el.hasAttribute && el.hasAttribute(name)); } function domParseHtml(html) { if (!_hasDom) return null; var tpl = document.createElement("template"); tpl.innerHTML = html; return tpl.content; } function domClone(node) { return node && node.cloneNode ? node.cloneNode(true) : node; } function domParent(el) { return el ? el.parentNode : null; } function domId(el) { return el && el.id ? el.id : NIL; } function domNodeType(el) { return el ? el.nodeType : 0; } function domNodeName(el) { return el ? el.nodeName : ""; } function domTextContent(el) { return el ? el.textContent || el.nodeValue || "" : ""; } function domSetTextContent(el, s) { if (el) { if (el.nodeType === 3 || el.nodeType === 8) el.nodeValue = s; else el.textContent = s; } } function domIsFragment(el) { return el ? el.nodeType === 11 : false; } function domIsChildOf(child, parent) { return !!(parent && child && child.parentNode === parent); } function domIsActiveElement(el) { return _hasDom && el === document.activeElement; } function domIsInputElement(el) { if (!el || !el.tagName) return false; var t = el.tagName; return t === "INPUT" || t === "TEXTAREA" || t === "SELECT"; } function domFirstChild(el) { return el ? el.firstChild : null; } function domNextSibling(el) { return el ? el.nextSibling : null; } function domChildList(el) { if (!el || !el.childNodes) return []; return Array.prototype.slice.call(el.childNodes); } function domAttrList(el) { if (!el || !el.attributes) return []; var r = []; for (var i = 0; i < el.attributes.length; i++) { r.push([el.attributes[i].name, el.attributes[i].value]); } return r; } function domInsertBefore(parent, node, ref) { if (parent && node) parent.insertBefore(node, ref || null); } function domInsertAfter(ref, node) { if (ref && ref.parentNode && node && !node._spread) { ref.parentNode.insertBefore(node, ref.nextSibling); } } function domRemoveChild(parent, child) { if (parent && child && child.parentNode === parent) parent.removeChild(child); } function domReplaceChild(parent, newChild, oldChild) { if (parent && newChild && oldChild) parent.replaceChild(newChild, oldChild); } function domSetInnerHtml(el, html) { if (el) el.innerHTML = html; } function domInsertAdjacentHtml(el, pos, html) { if (el && el.insertAdjacentHTML) el.insertAdjacentHTML(pos, html); } function domGetStyle(el, prop) { return el && el.style ? el.style[prop] || "" : ""; } function domSetStyle(el, prop, val) { if (el && el.style) el.style[prop] = val; } function domGetProp(el, name) { return el ? el[name] : NIL; } function domSetProp(el, name, val) { if (el) el[name] = val; } // Call a method on an object with correct this binding: (dom-call-method obj "methodName" arg1 arg2 ...) function domCallMethod() { var obj = arguments[0], method = arguments[1]; var args = Array.prototype.slice.call(arguments, 2); if (obj && typeof obj[method] === 'function') { try { return obj[method].apply(obj, args); } catch(e) { console.error("[sx] dom-call-method error:", e); return NIL; } } return NIL; } // Post a message to an iframe's contentWindow without exposing the cross-origin // Window object to the SX evaluator (which would trigger _thunk access errors). function domPostMessage(iframe, msg, origin) { try { if (iframe && iframe.contentWindow) { iframe.contentWindow.postMessage(msg, origin || '*'); } } catch(e) { console.error("[sx] domPostMessage error:", e); } return NIL; } function domAddClass(el, cls) { if (el && el.classList) el.classList.add(cls); } function domRemoveClass(el, cls) { if (el && el.classList) el.classList.remove(cls); } function domDispatch(el, name, detail) { if (!_hasDom || !el) return false; var evt = new CustomEvent(name, { bubbles: true, cancelable: true, detail: detail || {} }); return el.dispatchEvent(evt); } function domListen(el, name, handler) { if (!_hasDom || !el) return function() {}; // Wrap SX lambdas from runtime-evaluated island code into native fns // If lambda takes 0 params, call without event arg (convenience for on-click handlers) var wrapped = isLambda(handler) ? (lambdaParams(handler).length === 0 ? function(e) { try { cekCall(handler, NIL); } catch(err) { console.error("[sx-ref] domListen handler error:", name, err); } finally { runPostRenderHooks(); } } : function(e) { try { cekCall(handler, [e]); } catch(err) { console.error("[sx-ref] domListen handler error:", name, err); } finally { runPostRenderHooks(); } }) : handler; if (name === "click") logInfo("domListen: click on <" + (el.tagName||"?").toLowerCase() + "> text=" + (el.textContent||"").substring(0,20) + " isLambda=" + isLambda(handler)); el.addEventListener(name, wrapped); return function() { el.removeEventListener(name, wrapped); }; } function eventDetail(e) { return (e && e.detail != null) ? e.detail : NIL; } function domQuery(sel) { return _hasDom ? document.querySelector(sel) : null; } function domEnsureElement(sel) { if (!_hasDom) return null; var el = document.querySelector(sel); if (el) return el; // Parse #id selector → create div with that id, append to body if (sel.charAt(0) === '#') { el = document.createElement('div'); el.id = sel.slice(1); document.body.appendChild(el); return el; } return null; } function domQueryAll(root, sel) { if (!root || !root.querySelectorAll) return []; return Array.prototype.slice.call(root.querySelectorAll(sel)); } function domTagName(el) { return el && el.tagName ? el.tagName : ""; } // Island DOM helpers function domRemove(node) { if (node && node.parentNode) node.parentNode.removeChild(node); } function domChildNodes(el) { if (!el || !el.childNodes) return []; return Array.prototype.slice.call(el.childNodes); } function domRemoveChildrenAfter(marker) { if (!marker || !marker.parentNode) return; var parent = marker.parentNode; while (marker.nextSibling) parent.removeChild(marker.nextSibling); } function domSetData(el, key, val) { if (el) { if (!el._sxData) el._sxData = {}; el._sxData[key] = val; } } function domGetData(el, key) { return (el && el._sxData) ? (el._sxData[key] != null ? el._sxData[key] : NIL) : NIL; } function domInnerHtml(el) { return (el && el.innerHTML != null) ? el.innerHTML : ""; } function jsonParse(s) { try { return JSON.parse(s); } catch(e) { return {}; } } // renderDomComponent and renderDomElement are transpiled from // adapter-dom.sx — no imperative overrides needed. """ PLATFORM_ENGINE_PURE_JS = """ // ========================================================================= // Platform interface — Engine pure logic (browser + node compatible) // ========================================================================= function browserLocationHref() { return typeof location !== "undefined" ? location.href : ""; } function browserSameOrigin(url) { try { return new URL(url, location.href).origin === location.origin; } catch (e) { return true; } } function browserPushState(url) { if (typeof history !== "undefined") { try { history.pushState({ sxUrl: url, scrollY: typeof window !== "undefined" ? window.scrollY : 0 }, "", url); } catch (e) {} } } function browserReplaceState(url) { if (typeof history !== "undefined") { try { history.replaceState({ sxUrl: url, scrollY: typeof window !== "undefined" ? window.scrollY : 0 }, "", url); } catch (e) {} } } function nowMs() { return (typeof performance !== "undefined") ? performance.now() : Date.now(); } function parseHeaderValue(s) { if (!s) return null; try { if (s.charAt(0) === "{" && s.charAt(1) === ":") return parse(s); return JSON.parse(s); } catch (e) { return null; } } """ PLATFORM_ORCHESTRATION_JS = """ // ========================================================================= // Platform interface — Orchestration (browser-only) // ========================================================================= // --- Browser/Network --- function browserNavigate(url) { if (typeof location !== "undefined") location.assign(url); } function browserReload() { if (typeof location !== "undefined") location.reload(); } function browserScrollTo(x, y) { if (typeof window !== "undefined") window.scrollTo(x, y); } function browserMediaMatches(query) { if (typeof window === "undefined") return false; return window.matchMedia(query).matches; } function browserConfirm(msg) { if (typeof window === "undefined") return false; return window.confirm(msg); } function browserPrompt(msg) { if (typeof window === "undefined") return NIL; var r = window.prompt(msg); return r === null ? NIL : r; } function csrfToken() { if (!_hasDom) return NIL; var m = document.querySelector('meta[name="csrf-token"]'); return m ? m.getAttribute("content") : NIL; } function isCrossOrigin(url) { try { var h = new URL(url, location.href).hostname; return h !== location.hostname && (h.indexOf(".rose-ash.com") >= 0 || h.indexOf(".localhost") >= 0); } catch (e) { return false; } } // --- Promises --- function promiseResolve(val) { return Promise.resolve(val); } function promiseThen(p, onResolve, onReject) { if (!p || !p.then) return p; return onReject ? p.then(onResolve, onReject) : p.then(onResolve); } function promiseCatch(p, fn) { return p && p.catch ? p.catch(fn) : p; } function promiseDelayed(ms, value) { return new Promise(function(resolve) { setTimeout(function() { resolve(value); }, ms); }); } // --- Abort controllers --- var _controllers = typeof WeakMap !== "undefined" ? new WeakMap() : null; function abortPrevious(el) { if (_controllers) { var prev = _controllers.get(el); if (prev) prev.abort(); } } function trackController(el, ctrl) { if (_controllers) _controllers.set(el, ctrl); } var _targetControllers = typeof WeakMap !== "undefined" ? new WeakMap() : null; function abortPreviousTarget(el) { if (_targetControllers) { var prev = _targetControllers.get(el); if (prev) prev.abort(); } } function trackControllerTarget(el, ctrl) { if (_targetControllers) _targetControllers.set(el, ctrl); } function newAbortController() { return typeof AbortController !== "undefined" ? new AbortController() : { signal: null, abort: function() {} }; } function controllerSignal(ctrl) { return ctrl ? ctrl.signal : null; } function isAbortError(err) { return err && err.name === "AbortError"; } // --- Timers --- function _wrapSxFn(fn) { if (fn && fn._lambda) { return function() { return trampoline(callLambda(fn, [], lambdaClosure(fn))); }; } return fn; } function setTimeout_(fn, ms) { return setTimeout(_wrapSxFn(fn), ms || 0); } function setInterval_(fn, ms) { return setInterval(_wrapSxFn(fn), ms || 1000); } function clearTimeout_(id) { clearTimeout(id); } function clearInterval_(id) { clearInterval(id); } function requestAnimationFrame_(fn) { var cb = _wrapSxFn(fn); if (typeof requestAnimationFrame !== "undefined") requestAnimationFrame(cb); else setTimeout(cb, 16); } // --- Fetch --- function fetchRequest(config, successFn, errorFn) { var opts = { method: config.method, headers: config.headers }; if (config.signal) opts.signal = config.signal; if (config.body && config.method !== "GET") opts.body = config.body; if (config["cross-origin"]) opts.credentials = "include"; var p = (config.preloaded && config.preloaded !== NIL) ? Promise.resolve({ ok: true, status: 200, headers: new Headers({ "Content-Type": config.preloaded["content-type"] || "" }), text: function() { return Promise.resolve(config.preloaded.text); } }) : fetch(config.url, opts); return p.then(function(resp) { return resp.text().then(function(text) { var getHeader = function(name) { var v = resp.headers.get(name); return v === null ? NIL : v; }; return successFn(resp.ok, resp.status, getHeader, text); }); }).catch(function(err) { return errorFn(err); }); } function fetchLocation(headerVal) { if (!_hasDom) return; var locUrl = headerVal; try { var obj = JSON.parse(headerVal); locUrl = obj.path || obj; } catch (e) {} fetch(locUrl, { headers: { "SX-Request": "true" } }).then(function(r) { return r.text().then(function(t) { var main = document.getElementById("main-panel"); if (main) { main.innerHTML = t; postSwap(main); try { history.pushState({ sxUrl: locUrl }, "", locUrl); } catch (e) {} } }); }); } function fetchAndRestore(main, url, headers, scrollY) { var opts = { headers: headers }; try { var h = new URL(url, location.href).hostname; if (h !== location.hostname && (h.indexOf(".rose-ash.com") >= 0 || h.indexOf(".localhost") >= 0)) { opts.credentials = "include"; } } catch (e) {} fetch(url, opts).then(function(resp) { return resp.text().then(function(text) { text = stripComponentScripts(text); text = extractResponseCss(text); text = text.trim(); if (text.charAt(0) === "(") { try { var dom = sxRender(text); var container = document.createElement("div"); container.appendChild(dom); processOobSwaps(container, function(t, oob, s) { swapDomNodes(t, oob, s); sxHydrate(t); processElements(t); }); var newMain = container.querySelector("#main-panel"); morphChildren(main, newMain || container); postSwap(main); if (typeof window !== "undefined") window.scrollTo(0, scrollY || 0); } catch (err) { console.error("sx-ref popstate error:", err); location.reload(); } } else { var parser = new DOMParser(); var doc = parser.parseFromString(text, "text/html"); var newMain = doc.getElementById("main-panel"); if (newMain) { morphChildren(main, newMain); postSwap(main); if (typeof window !== "undefined") window.scrollTo(0, scrollY || 0); } else { location.reload(); } } }); }).catch(function() { location.reload(); }); } function fetchStreaming(target, url, headers) { // Streaming fetch for multi-stream pages. // First chunk = OOB SX swap (shell with skeletons). // Subsequent chunks = __sxResolve script tags filling suspense slots. var opts = { headers: headers }; try { var h = new URL(url, location.href).hostname; if (h !== location.hostname && (h.indexOf(".rose-ash.com") >= 0 || h.indexOf(".localhost") >= 0)) { opts.credentials = "include"; } } catch (e) {} fetch(url, opts).then(function(resp) { if (!resp.ok || !resp.body) { // Fallback: non-streaming return resp.text().then(function(text) { text = stripComponentScripts(text); text = extractResponseCss(text); text = text.trim(); if (text.charAt(0) === "(") { var dom = sxRender(text); var container = document.createElement("div"); container.appendChild(dom); processOobSwaps(container, function(t, oob, s) { swapDomNodes(t, oob, s); sxHydrate(t); processElements(t); }); var newMain = container.querySelector("#main-panel"); morphChildren(target, newMain || container); postSwap(target); } }); } var reader = resp.body.getReader(); var decoder = new TextDecoder(); var buffer = ""; var initialSwapDone = false; // Regex to match __sxResolve script tags var RESOLVE_START = ""; function processResolveScripts() { // Strip and load any extra component defs before resolve scripts buffer = stripSxScripts(buffer); var idx; while ((idx = buffer.indexOf(RESOLVE_START)) >= 0) { var endIdx = buffer.indexOf(RESOLVE_END, idx); if (endIdx < 0) break; // incomplete, wait for more data var argsStr = buffer.substring(idx + RESOLVE_START.length, endIdx); buffer = buffer.substring(endIdx + RESOLVE_END.length); // argsStr is: "stream-id","sx source" var commaIdx = argsStr.indexOf(","); if (commaIdx >= 0) { try { var id = JSON.parse(argsStr.substring(0, commaIdx)); var sx = JSON.parse(argsStr.substring(commaIdx + 1)); if (typeof Sx !== "undefined" && Sx.resolveSuspense) { Sx.resolveSuspense(id, sx); } } catch (e) { console.error("[sx-ref] resolve parse error:", e); } } } } function pump() { return reader.read().then(function(result) { buffer += decoder.decode(result.value || new Uint8Array(), { stream: !result.done }); if (!initialSwapDone) { // Look for the first resolve script — everything before it is OOB content var scriptIdx = buffer.indexOf(" (without data-components or data-init). // These contain extra component defs from streaming resolve chunks. // data-init scripts are preserved for process-sx-scripts to evaluate as side effects. var SxObj = typeof Sx !== "undefined" ? Sx : null; return text.replace(/]*type="text\\/sx"[^>]*>[\\s\\S]*?<\\/script>/gi, function(match) { if (/data-init/.test(match)) return match; // preserve data-init scripts var m = match.match(/]*>([\\s\\S]*?)<\\/script>/i); if (m && SxObj && SxObj.loadComponents) SxObj.loadComponents(m[1]); return ""; }); } function extractResponseCss(text) { if (!_hasDom) return text; var target = document.getElementById("sx-css"); if (!target) return text; return text.replace(/]*data-sx-css[^>]*>([\\s\\S]*?)<\\/style>/gi, function(_, css) { target.textContent += css; return ""; }); } function selectFromContainer(container, sel) { var frag = document.createDocumentFragment(); sel.split(",").forEach(function(s) { container.querySelectorAll(s.trim()).forEach(function(m) { frag.appendChild(m); }); }); return frag; } function childrenToFragment(container) { var frag = document.createDocumentFragment(); while (container.firstChild) frag.appendChild(container.firstChild); return frag; } function selectHtmlFromDoc(doc, sel) { var parts = sel.split(",").map(function(s) { return s.trim(); }); var frags = []; parts.forEach(function(s) { doc.querySelectorAll(s).forEach(function(m) { frags.push(m.outerHTML); }); }); return frags.join(""); } // --- Parsing --- function tryParseJson(s) { if (!s) return NIL; try { return JSON.parse(s); } catch (e) { return NIL; } } """ PLATFORM_BOOT_JS = """ // ========================================================================= // Platform interface — Boot (mount, hydrate, scripts, cookies) // ========================================================================= function resolveMountTarget(target) { if (typeof target === "string") return _hasDom ? document.querySelector(target) : null; return target; } function sxRenderWithEnv(source, extraEnv) { var env = extraEnv ? merge(componentEnv, extraEnv) : componentEnv; var exprs = parse(source); if (!_hasDom) return null; var frag = document.createDocumentFragment(); for (var i = 0; i < exprs.length; i++) { var node = renderToDom(exprs[i], env, null); if (node && !node._spread) frag.appendChild(node); } return frag; } function getRenderEnv(extraEnv) { return extraEnv ? merge(componentEnv, extraEnv) : componentEnv; } function mergeEnvs(base, newEnv) { return newEnv ? merge(componentEnv, base, newEnv) : merge(componentEnv, base); } function sxLoadComponents(text) { try { var exprs = parse(text); for (var i = 0; i < exprs.length; i++) trampoline(evalExpr(exprs[i], componentEnv)); } catch (err) { logParseError("loadComponents", text, err); throw err; } } function setDocumentTitle(s) { if (_hasDom) document.title = s || ""; } function removeHeadElement(sel) { if (!_hasDom) return; var old = document.head.querySelector(sel); if (old) old.parentNode.removeChild(old); } function querySxScripts(root) { if (!_hasDom) return []; var r = (root && root !== NIL) ? root : document; return Array.prototype.slice.call( r.querySelectorAll('script[type="text/sx"]')); } function queryPageScripts() { if (!_hasDom) return []; return Array.prototype.slice.call( document.querySelectorAll('script[type="text/sx-pages"]')); } // --- localStorage --- function localStorageGet(key) { try { var v = localStorage.getItem(key); return v === null ? NIL : v; } catch (e) { return NIL; } } function localStorageSet(key, val) { try { localStorage.setItem(key, val); } catch (e) {} } function localStorageRemove(key) { try { localStorage.removeItem(key); } catch (e) {} } // localStorage primitives registered in CEK_FIXUPS_JS for ordering // --- Cookies --- function setSxCompCookie(hash) { if (_hasDom) document.cookie = "sx-comp-hash=" + hash + ";path=/;max-age=31536000;SameSite=Lax"; } function clearSxCompCookie() { if (_hasDom) document.cookie = "sx-comp-hash=;path=/;max-age=0;SameSite=Lax"; } // --- Env helpers --- function parseEnvAttr(el) { var attr = el && el.getAttribute ? el.getAttribute("data-sx-env") : null; if (!attr) return {}; try { return JSON.parse(attr); } catch (e) { return {}; } } function storeEnvAttr(el, base, newEnv) { var merged = merge(base, newEnv); if (el && el.setAttribute) el.setAttribute("data-sx-env", JSON.stringify(merged)); } function toKebab(s) { return s.replace(/_/g, "-"); } // --- Logging --- function logInfo(msg) { if (typeof console !== "undefined") console.log("[sx-ref] " + msg); } function logWarn(msg) { if (typeof console !== "undefined") console.warn("[sx-ref] " + msg); } function logParseError(label, text, err) { if (typeof console === "undefined") return; var msg = err && err.message ? err.message : String(err); var colMatch = msg.match(/col (\\d+)/); var lineMatch = msg.match(/line (\\d+)/); if (colMatch && text) { var errLine = lineMatch ? parseInt(lineMatch[1]) : 1; var errCol = parseInt(colMatch[1]); var lines = text.split("\\n"); var pos = 0; for (var i = 0; i < errLine - 1 && i < lines.length; i++) pos += lines[i].length + 1; pos += errCol; var ws = 80; var start = Math.max(0, pos - ws); var end = Math.min(text.length, pos + ws); console.error("[sx-ref] " + label + ":", msg, "\\n around error (pos ~" + pos + "):", "\\n \\u00ab" + text.substring(start, pos) + "\\u26d4" + text.substring(pos, end) + "\\u00bb"); } else { console.error("[sx-ref] " + label + ":", msg); } } """ def fixups_js(has_html, has_sx, has_dom, has_signals=False, has_deps=False, has_page_helpers=False): lines = [''' // ========================================================================= // Post-transpilation fixups // ========================================================================= // The reference spec's call-lambda only handles Lambda objects, but HO forms // (map, reduce, etc.) may receive native primitives. Wrap to handle both. var _rawCallLambda = callLambda; callLambda = function(f, args, callerEnv) { if (typeof f === "function") return f.apply(null, args); return _rawCallLambda(f, args, callerEnv); }; // Expose render functions as primitives so SX code can call them'''] if has_html: lines.append(' if (typeof renderToHtml === "function") PRIMITIVES["render-to-html"] = renderToHtml;') if has_sx: lines.append(' if (typeof renderToSx === "function") PRIMITIVES["render-to-sx"] = renderToSx;') lines.append(' if (typeof aser === "function") PRIMITIVES["aser"] = aser;') if has_dom: lines.append(' if (typeof renderToDom === "function") PRIMITIVES["render-to-dom"] = renderToDom;') if has_signals: lines.append(''' // Expose signal functions as primitives so runtime-evaluated SX code // (e.g. island bodies from .sx files) can call them PRIMITIVES["signal"] = signal; PRIMITIVES["signal?"] = isSignal; PRIMITIVES["deref"] = deref; PRIMITIVES["reset!"] = reset_b; PRIMITIVES["swap!"] = swap_b; PRIMITIVES["computed"] = computed; PRIMITIVES["effect"] = effect; PRIMITIVES["batch"] = batch; // Timer primitives for island code PRIMITIVES["set-interval"] = setInterval_; PRIMITIVES["clear-interval"] = clearInterval_; // Reactive DOM helpers for island code PRIMITIVES["reactive-text"] = reactiveText; PRIMITIVES["create-text-node"] = createTextNode; PRIMITIVES["dom-set-text-content"] = domSetTextContent; PRIMITIVES["dom-listen"] = domListen; PRIMITIVES["dom-dispatch"] = domDispatch; PRIMITIVES["event-detail"] = eventDetail; PRIMITIVES["resource"] = resource; PRIMITIVES["promise-delayed"] = promiseDelayed; PRIMITIVES["promise-then"] = promiseThen; PRIMITIVES["def-store"] = defStore; PRIMITIVES["use-store"] = useStore; PRIMITIVES["emit-event"] = emitEvent; PRIMITIVES["on-event"] = onEvent; PRIMITIVES["bridge-event"] = bridgeEvent; // DOM primitives for island code PRIMITIVES["dom-focus"] = domFocus; PRIMITIVES["dom-tag-name"] = domTagName; PRIMITIVES["dom-get-prop"] = domGetProp; PRIMITIVES["dom-set-prop"] = domSetProp; PRIMITIVES["dom-call-method"] = domCallMethod; PRIMITIVES["dom-post-message"] = domPostMessage; PRIMITIVES["stop-propagation"] = stopPropagation_; PRIMITIVES["error-message"] = errorMessage; PRIMITIVES["schedule-idle"] = scheduleIdle; PRIMITIVES["error"] = function(msg) { throw new Error(msg); }; PRIMITIVES["filter"] = filter; // DOM primitives for sx-on:* handlers and data-init scripts if (typeof domBody === "function") PRIMITIVES["dom-body"] = domBody; if (typeof domQuery === "function") PRIMITIVES["dom-query"] = domQuery; if (typeof domQueryAll === "function") PRIMITIVES["dom-query-all"] = domQueryAll; if (typeof domQueryById === "function") PRIMITIVES["dom-query-by-id"] = domQueryById; if (typeof domSetAttr === "function") PRIMITIVES["dom-set-attr"] = domSetAttr; if (typeof domGetAttr === "function") PRIMITIVES["dom-get-attr"] = domGetAttr; if (typeof domRemoveAttr === "function") PRIMITIVES["dom-remove-attr"] = domRemoveAttr; if (typeof domHasAttr === "function") PRIMITIVES["dom-has-attr?"] = domHasAttr; if (typeof domAddClass === "function") PRIMITIVES["dom-add-class"] = domAddClass; if (typeof domRemoveClass === "function") PRIMITIVES["dom-remove-class"] = domRemoveClass; if (typeof domHasClass === "function") PRIMITIVES["dom-has-class?"] = domHasClass; if (typeof domClosest === "function") PRIMITIVES["dom-closest"] = domClosest; if (typeof domMatches === "function") PRIMITIVES["dom-matches?"] = domMatches; if (typeof preventDefault_ === "function") PRIMITIVES["prevent-default"] = preventDefault_; if (typeof elementValue === "function") PRIMITIVES["element-value"] = elementValue; if (typeof domOuterHtml === "function") PRIMITIVES["dom-outer-html"] = domOuterHtml; if (typeof domInnerHtml === "function") PRIMITIVES["dom-inner-html"] = domInnerHtml; if (typeof domTextContent === "function") PRIMITIVES["dom-text-content"] = domTextContent; if (typeof domCreateElement === "function") PRIMITIVES["dom-create-element"] = domCreateElement; if (typeof domAppend === "function") PRIMITIVES["dom-append"] = domAppend; if (typeof domAppendToHead === "function") PRIMITIVES["dom-append-to-head"] = domAppendToHead; if (typeof jsonParse === "function") PRIMITIVES["json-parse"] = jsonParse; if (typeof nowMs === "function") PRIMITIVES["now-ms"] = nowMs; PRIMITIVES["sx-parse"] = sxParse; PRIMITIVES["console-log"] = function() { console.log.apply(console, ["[sx]"].concat(Array.prototype.slice.call(arguments))); return arguments.length > 0 ? arguments[0] : NIL; };''') if has_deps: lines.append(''' // Expose deps module functions as primitives so runtime-evaluated SX code // (e.g. test-deps.sx in browser) can call them // Platform functions (from PLATFORM_DEPS_JS) PRIMITIVES["component-deps"] = componentDeps; PRIMITIVES["component-set-deps!"] = componentSetDeps; PRIMITIVES["component-css-classes"] = componentCssClasses; PRIMITIVES["env-components"] = envComponents; PRIMITIVES["regex-find-all"] = regexFindAll; PRIMITIVES["scan-css-classes"] = scanCssClasses; // Transpiled functions (from deps.sx) PRIMITIVES["scan-refs"] = scanRefs; PRIMITIVES["scan-refs-walk"] = scanRefsWalk; PRIMITIVES["transitive-deps"] = transitiveDeps; PRIMITIVES["transitive-deps-walk"] = transitiveDepsWalk; PRIMITIVES["compute-all-deps"] = computeAllDeps; PRIMITIVES["scan-components-from-source"] = scanComponentsFromSource; PRIMITIVES["components-needed"] = componentsNeeded; PRIMITIVES["page-component-bundle"] = pageComponentBundle; PRIMITIVES["page-css-classes"] = pageCssClasses; PRIMITIVES["scan-io-refs-walk"] = scanIoRefsWalk; PRIMITIVES["scan-io-refs"] = scanIoRefs; PRIMITIVES["transitive-io-refs-walk"] = transitiveIoRefsWalk; PRIMITIVES["transitive-io-refs"] = transitiveIoRefs; PRIMITIVES["compute-all-io-refs"] = computeAllIoRefs; PRIMITIVES["component-io-refs-cached"] = componentIoRefsCached; PRIMITIVES["component-pure?"] = componentPure_p; PRIMITIVES["render-target"] = renderTarget; PRIMITIVES["page-render-plan"] = pageRenderPlan;''') if has_page_helpers: lines.append(''' // Expose page-helper functions as primitives PRIMITIVES["categorize-special-forms"] = categorizeSpecialForms; PRIMITIVES["extract-define-kwargs"] = extractDefineKwargs; PRIMITIVES["build-reference-data"] = buildReferenceData; PRIMITIVES["build-ref-items-with-href"] = buildRefItemsWithHref; PRIMITIVES["build-attr-detail"] = buildAttrDetail; PRIMITIVES["build-header-detail"] = buildHeaderDetail; PRIMITIVES["build-event-detail"] = buildEventDetail; PRIMITIVES["build-component-source"] = buildComponentSource; PRIMITIVES["build-bundle-analysis"] = buildBundleAnalysis; PRIMITIVES["build-routing-analysis"] = buildRoutingAnalysis; PRIMITIVES["build-affinity-analysis"] = buildAffinityAnalysis;''') return "\n".join(lines) def public_api_js(has_html, has_sx, has_dom, has_engine, has_orch, has_boot, has_parser, adapter_label, has_deps=False, has_router=False, has_signals=False, has_page_helpers=False, has_cek=False): # Parser: use compiled sxParse from parser.sx, or inline a minimal fallback if has_parser: parser = ''' // Parser — compiled from parser.sx (see PLATFORM_PARSER_JS for ident char classes) var parse = sxParse;''' else: parser = r''' // Minimal fallback parser (no parser adapter) function parse(text) { throw new Error("Parser adapter not included — cannot parse SX source at runtime"); }''' # Public API — conditional on adapters api_lines = [parser, ''' // ========================================================================= // Public API // ========================================================================= var componentEnv = {}; function loadComponents(source) { var exprs = parse(source); for (var i = 0; i < exprs.length; i++) { trampoline(evalExpr(exprs[i], componentEnv)); } }'''] # render() — auto-dispatches based on available adapters if has_html and has_dom: api_lines.append(''' function render(source) { if (!_hasDom) { var exprs = parse(source); var parts = []; for (var i = 0; i < exprs.length; i++) parts.push(renderToHtml(exprs[i], merge(componentEnv))); return parts.join(""); } var exprs = parse(source); var frag = document.createDocumentFragment(); for (var i = 0; i < exprs.length; i++) { var _r = renderToDom(exprs[i], merge(componentEnv), null); if (_r && !_r._spread) frag.appendChild(_r); } return frag; }''') elif has_dom: api_lines.append(''' function render(source) { var exprs = parse(source); var frag = document.createDocumentFragment(); for (var i = 0; i < exprs.length; i++) { var _r = renderToDom(exprs[i], merge(componentEnv), null); if (_r && !_r._spread) frag.appendChild(_r); } return frag; }''') elif has_html: api_lines.append(''' function render(source) { var exprs = parse(source); var parts = []; for (var i = 0; i < exprs.length; i++) parts.push(renderToHtml(exprs[i], merge(componentEnv))); return parts.join(""); }''') else: api_lines.append(''' function render(source) { var exprs = parse(source); var results = []; for (var i = 0; i < exprs.length; i++) results.push(trampoline(evalExpr(exprs[i], merge(componentEnv)))); return results.length === 1 ? results[0] : results; }''') # renderToString helper if has_html: api_lines.append(''' function renderToString(source) { var exprs = parse(source); var parts = []; for (var i = 0; i < exprs.length; i++) parts.push(renderToHtml(exprs[i], merge(componentEnv))); return parts.join(""); }''') # Build Sx object version = f"ref-2.0 ({adapter_label}, bootstrap-compiled)" api_lines.append(f''' var Sx = {{ VERSION: "ref-2.0", parse: parse, parseAll: parse, eval: function(expr, env) {{ return trampoline(evalExpr(expr, env || merge(componentEnv))); }}, loadComponents: loadComponents, render: render,{"" if has_html else ""} {"renderToString: renderToString," if has_html else ""} serialize: serialize, NIL: NIL, Symbol: Symbol, Keyword: Keyword, isTruthy: isSxTruthy, isNil: isNil, componentEnv: componentEnv,''') api_lines.append(' setRenderActive: function(val) { setRenderActiveB(val); },') if has_html: api_lines.append(' renderToHtml: function(expr, env) { return renderToHtml(expr, env || merge(componentEnv)); },') if has_sx: api_lines.append(' renderToSx: function(expr, env) { return renderToSx(expr, env || merge(componentEnv)); },') if has_dom: api_lines.append(' renderToDom: _hasDom ? function(expr, env, ns) { return renderToDom(expr, env || merge(componentEnv), ns || null); } : null,') if has_engine: api_lines.append(' parseTriggerSpec: typeof parseTriggerSpec === "function" ? parseTriggerSpec : null,') api_lines.append(' parseTime: typeof parseTime === "function" ? parseTime : null,') api_lines.append(' defaultTrigger: typeof defaultTrigger === "function" ? defaultTrigger : null,') api_lines.append(' parseSwapSpec: typeof parseSwapSpec === "function" ? parseSwapSpec : null,') api_lines.append(' parseRetrySpec: typeof parseRetrySpec === "function" ? parseRetrySpec : null,') api_lines.append(' nextRetryMs: typeof nextRetryMs === "function" ? nextRetryMs : null,') api_lines.append(' filterParams: typeof filterParams === "function" ? filterParams : null,') api_lines.append(' morphNode: typeof morphNode === "function" ? morphNode : null,') api_lines.append(' morphChildren: typeof morphChildren === "function" ? morphChildren : null,') api_lines.append(' swapDomNodes: typeof swapDomNodes === "function" ? swapDomNodes : null,') if has_orch: api_lines.append(' process: typeof processElements === "function" ? processElements : null,') api_lines.append(' executeRequest: typeof executeRequest === "function" ? executeRequest : null,') api_lines.append(' postSwap: typeof postSwap === "function" ? postSwap : null,') if has_boot: api_lines.append(' processScripts: typeof processSxScripts === "function" ? processSxScripts : null,') api_lines.append(' mount: typeof sxMount === "function" ? sxMount : null,') api_lines.append(' hydrate: typeof sxHydrateElements === "function" ? sxHydrateElements : null,') api_lines.append(' update: typeof sxUpdateElement === "function" ? sxUpdateElement : null,') api_lines.append(' renderComponent: typeof sxRenderComponent === "function" ? sxRenderComponent : null,') api_lines.append(' getEnv: function() { return componentEnv; },') api_lines.append(' resolveSuspense: typeof resolveSuspense === "function" ? resolveSuspense : null,') api_lines.append(' hydrateIslands: typeof sxHydrateIslands === "function" ? sxHydrateIslands : null,') api_lines.append(' disposeIsland: typeof disposeIsland === "function" ? disposeIsland : null,') api_lines.append(' init: typeof bootInit === "function" ? bootInit : null,') elif has_orch: api_lines.append(' init: typeof engineInit === "function" ? engineInit : null,') if has_deps: api_lines.append(' scanRefs: scanRefs,') api_lines.append(' scanComponentsFromSource: scanComponentsFromSource,') api_lines.append(' transitiveDeps: transitiveDeps,') api_lines.append(' computeAllDeps: computeAllDeps,') api_lines.append(' componentsNeeded: componentsNeeded,') api_lines.append(' pageComponentBundle: pageComponentBundle,') api_lines.append(' pageCssClasses: pageCssClasses,') api_lines.append(' scanIoRefs: scanIoRefs,') api_lines.append(' transitiveIoRefs: transitiveIoRefs,') api_lines.append(' computeAllIoRefs: computeAllIoRefs,') api_lines.append(' componentPure_p: componentPure_p,') if has_page_helpers: api_lines.append(' categorizeSpecialForms: categorizeSpecialForms,') api_lines.append(' buildReferenceData: buildReferenceData,') api_lines.append(' buildAttrDetail: buildAttrDetail,') api_lines.append(' buildHeaderDetail: buildHeaderDetail,') api_lines.append(' buildEventDetail: buildEventDetail,') api_lines.append(' buildComponentSource: buildComponentSource,') api_lines.append(' buildBundleAnalysis: buildBundleAnalysis,') api_lines.append(' buildRoutingAnalysis: buildRoutingAnalysis,') api_lines.append(' buildAffinityAnalysis: buildAffinityAnalysis,') if has_router: api_lines.append(' splitPathSegments: splitPathSegments,') api_lines.append(' parseRoutePattern: parseRoutePattern,') api_lines.append(' matchRoute: matchRoute,') api_lines.append(' findMatchingRoute: findMatchingRoute,') api_lines.append(' urlToExpr: urlToExpr,') api_lines.append(' autoQuoteUnknowns: autoQuoteUnknowns,') api_lines.append(' prepareUrlExpr: prepareUrlExpr,') if has_dom: api_lines.append(' registerIo: typeof registerIoPrimitive === "function" ? registerIoPrimitive : null,') api_lines.append(' registerIoDeps: typeof registerIoDeps === "function" ? registerIoDeps : null,') api_lines.append(' asyncRender: typeof asyncSxRenderWithEnv === "function" ? asyncSxRenderWithEnv : null,') api_lines.append(' asyncRenderToDom: typeof asyncRenderToDom === "function" ? asyncRenderToDom : null,') if has_signals: api_lines.append(' signal: signal,') api_lines.append(' deref: deref,') api_lines.append(' reset: reset_b,') api_lines.append(' swap: swap_b,') api_lines.append(' computed: computed,') api_lines.append(' effect: effect,') api_lines.append(' batch: batch,') api_lines.append(' isSignal: isSignal,') api_lines.append(' makeSignal: makeSignal,') api_lines.append(' defStore: defStore,') api_lines.append(' useStore: useStore,') api_lines.append(' clearStores: clearStores,') api_lines.append(' emitEvent: emitEvent,') api_lines.append(' onEvent: onEvent,') api_lines.append(' bridgeEvent: bridgeEvent,') api_lines.append(' makeSpread: makeSpread,') api_lines.append(' isSpread: isSpread,') api_lines.append(' spreadAttrs: spreadAttrs,') api_lines.append(' collect: sxCollect,') api_lines.append(' collected: sxCollected,') api_lines.append(' clearCollected: sxClearCollected,') api_lines.append(' scopePush: scopePush,') api_lines.append(' scopePop: scopePop,') api_lines.append(' providePush: providePush,') api_lines.append(' providePop: providePop,') api_lines.append(' context: sxContext,') api_lines.append(' emit: sxEmit,') api_lines.append(' emitted: sxEmitted,') if has_cek: api_lines.append(' cekRun: cekRun,') api_lines.append(' makeCekState: makeCekState,') api_lines.append(' makeCekValue: makeCekValue,') api_lines.append(' cekStep: cekStep,') api_lines.append(' cekTerminal: cekTerminal_p,') api_lines.append(' cekValue: cekValue,') api_lines.append(' makeReactiveResetFrame: makeReactiveResetFrame,') api_lines.append(' evalExpr: evalExpr,') api_lines.append(f' _version: "{version}"') api_lines.append(' };') api_lines.append('') if has_orch: api_lines.append(''' // --- Popstate listener --- if (typeof window !== "undefined") { window.addEventListener("popstate", function(e) { handlePopstate(e && e.state ? e.state.scrollY || 0 : 0); }); }''') if has_boot: api_lines.append(''' // --- Auto-init --- if (typeof document !== "undefined") { var _sxInit = function() { bootInit(); // Process any suspense resolutions that arrived before init if (global.__sxPending) { for (var pi = 0; pi < global.__sxPending.length; pi++) { resolveSuspense(global.__sxPending[pi].id, global.__sxPending[pi].sx); } global.__sxPending = null; } // Set up direct resolution for future chunks global.__sxResolve = function(id, sx) { resolveSuspense(id, sx); }; // Register service worker for offline data caching if ("serviceWorker" in navigator) { navigator.serviceWorker.register("/sx-sw.js", { scope: "/" }).then(function(reg) { logInfo("sx:sw registered (scope: " + reg.scope + ")"); }).catch(function(err) { logWarn("sx:sw registration failed: " + (err && err.message ? err.message : err)); }); } }; if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", _sxInit); } else { _sxInit(); } }''') elif has_orch: api_lines.append(''' // --- Auto-init --- if (typeof document !== "undefined") { var _sxInit = function() { engineInit(); }; if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", _sxInit); } else { _sxInit(); } }''') api_lines.append(' if (typeof module !== "undefined" && module.exports) module.exports = Sx;') api_lines.append(' else global.Sx = Sx;') return "\n".join(api_lines) EPILOGUE = ''' })(typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : this);'''