Four new primitives for scoped downward value passing and upward accumulation through the render tree. Specced in .sx, bootstrapped to Python and JS across all adapters (eval, html, sx, dom, async). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
6578 lines
304 KiB
JavaScript
6578 lines
304 KiB
JavaScript
/**
|
||
* 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 = "2026-03-13T02:54:01Z";
|
||
|
||
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 SxSignal(value) {
|
||
this.value = value;
|
||
this.subscribers = [];
|
||
this.deps = [];
|
||
}
|
||
SxSignal.prototype._signal = true;
|
||
|
||
function TrackingCtx(notifyFn) {
|
||
this.notifyFn = notifyFn;
|
||
this.deps = [];
|
||
}
|
||
|
||
var _trackingContext = null;
|
||
|
||
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 _collectBuckets = {};
|
||
var _provideStacks = {};
|
||
|
||
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;
|
||
}
|
||
|
||
// =========================================================================
|
||
// 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._signal) return "signal";
|
||
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, merge(env)); }
|
||
function makeComponent(name, params, hasChildren, body, env, affinity) {
|
||
return new Component(name, params, hasChildren, body, merge(env), affinity);
|
||
}
|
||
function makeMacro(params, restParam, body, env, name) {
|
||
return new Macro(params, restParam, body, merge(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 sxCollect(bucket, value) {
|
||
if (!_collectBuckets[bucket]) _collectBuckets[bucket] = [];
|
||
var items = _collectBuckets[bucket];
|
||
if (items.indexOf(value) === -1) items.push(value);
|
||
}
|
||
function sxCollected(bucket) {
|
||
return _collectBuckets[bucket] ? _collectBuckets[bucket].slice() : [];
|
||
}
|
||
function sxClearCollected(bucket) {
|
||
if (_collectBuckets[bucket]) _collectBuckets[bucket] = [];
|
||
}
|
||
|
||
function providePush(name, value) {
|
||
if (!_provideStacks[name]) _provideStacks[name] = [];
|
||
_provideStacks[name].push({value: value !== undefined ? value : NIL, emitted: []});
|
||
}
|
||
function providePop(name) {
|
||
if (_provideStacks[name] && _provideStacks[name].length) _provideStacks[name].pop();
|
||
}
|
||
function sxContext(name) {
|
||
if (_provideStacks[name] && _provideStacks[name].length) {
|
||
return _provideStacks[name][_provideStacks[name].length - 1].value;
|
||
}
|
||
if (arguments.length > 1) return arguments[1];
|
||
throw new Error("No provider for: " + name);
|
||
}
|
||
function sxEmit(name, value) {
|
||
if (_provideStacks[name] && _provideStacks[name].length) {
|
||
_provideStacks[name][_provideStacks[name].length - 1].emitted.push(value);
|
||
} else {
|
||
throw new Error("No provider for emit!: " + name);
|
||
}
|
||
return NIL;
|
||
}
|
||
function sxEmitted(name) {
|
||
if (_provideStacks[name] && _provideStacks[name].length) {
|
||
return _provideStacks[name][_provideStacks[name].length - 1].emitted.slice();
|
||
}
|
||
return [];
|
||
}
|
||
|
||
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 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, merge(env));
|
||
}
|
||
|
||
// Signal platform
|
||
function makeSignal(value) { return new SxSignal(value); }
|
||
function isSignal(x) { return x != null && x._signal === true; }
|
||
function signalValue(s) { return s.value; }
|
||
function signalSetValue(s, v) { s.value = v; }
|
||
function signalSubscribers(s) { return s.subscribers.slice(); }
|
||
function signalAddSub(s, fn) { if (s.subscribers.indexOf(fn) < 0) s.subscribers.push(fn); }
|
||
function signalRemoveSub(s, fn) { var i = s.subscribers.indexOf(fn); if (i >= 0) s.subscribers.splice(i, 1); }
|
||
function signalDeps(s) { return s.deps.slice(); }
|
||
function signalSetDeps(s, deps) { s.deps = Array.isArray(deps) ? deps.slice() : []; }
|
||
function setTrackingContext(ctx) { _trackingContext = ctx; }
|
||
function getTrackingContext() { return _trackingContext || NIL; }
|
||
function makeTrackingContext(notifyFn) { return new TrackingCtx(notifyFn); }
|
||
function trackingContextDeps(ctx) { return ctx ? ctx.deps : []; }
|
||
function trackingContextAddDep(ctx, s) { if (ctx && ctx.deps.indexOf(s) < 0) ctx.deps.push(s); }
|
||
function trackingContextNotifyFn(ctx) { return ctx ? ctx.notifyFn : NIL; }
|
||
|
||
// invoke — call any callable (native fn or SX lambda) with args.
|
||
// Transpiled code emits direct calls f(args) which fail on SX lambdas
|
||
// from runtime-evaluated island bodies. invoke dispatches correctly.
|
||
function invoke() {
|
||
var f = arguments[0];
|
||
var args = Array.prototype.slice.call(arguments, 1);
|
||
if (isLambda(f)) return trampoline(callLambda(f, args, lambdaClosure(f)));
|
||
if (typeof f === 'function') return f.apply(null, args);
|
||
return NIL;
|
||
}
|
||
|
||
// 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 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))); }
|
||
|
||
|
||
|
||
// =========================================================================
|
||
// Primitives
|
||
// =========================================================================
|
||
|
||
var PRIMITIVES = {};
|
||
|
||
// 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
|
||
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
|
||
PRIMITIVES["not"] = function(x) { return !isSxTruthy(x); };
|
||
|
||
|
||
// 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["component-affinity"] = componentAffinity;
|
||
|
||
|
||
// 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["string-length"] = function(s) { return String(s).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
|
||
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([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
|
||
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
|
||
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
|
||
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,""").replace(/'/g,"'");
|
||
};
|
||
PRIMITIVES["strip-tags"] = function(s) { return String(s).replace(/<[^>]+>/g, ""); };
|
||
|
||
|
||
// stdlib.debug
|
||
PRIMITIVES["assert"] = function(cond, msg) {
|
||
if (!isSxTruthy(cond)) throw new Error("Assertion error: " + (msg || "Assertion failed"));
|
||
return true;
|
||
};
|
||
|
||
|
||
// stdlib.spread — spread + collect primitives
|
||
PRIMITIVES["make-spread"] = makeSpread;
|
||
PRIMITIVES["spread?"] = isSpread;
|
||
PRIMITIVES["spread-attrs"] = spreadAttrs;
|
||
PRIMITIVES["collect!"] = sxCollect;
|
||
PRIMITIVES["collected"] = sxCollected;
|
||
PRIMITIVES["clear-collected!"] = sxClearCollected;
|
||
// provide/context/emit! — render-time dynamic scope
|
||
PRIMITIVES["provide-push!"] = providePush;
|
||
PRIMITIVES["provide-pop!"] = providePop;
|
||
PRIMITIVES["context"] = sxContext;
|
||
PRIMITIVES["emit!"] = sxEmit;
|
||
PRIMITIVES["emitted"] = sxEmitted;
|
||
|
||
|
||
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; }
|
||
|
||
// 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,">").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: 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 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); }
|
||
|
||
|
||
// === Transpiled from eval ===
|
||
|
||
// trampoline
|
||
var trampoline = function(val) { return (function() {
|
||
var result = val;
|
||
return (isSxTruthy(isThunk(result)) ? trampoline(evalExpr(thunkExpr(result), thunkEnv(result))) : result);
|
||
})(); };
|
||
|
||
// eval-expr
|
||
var evalExpr = function(expr, env) { return (function() { var _m = typeOf(expr); if (_m == "number") return expr; if (_m == "string") return expr; if (_m == "boolean") return expr; if (_m == "nil") return NIL; if (_m == "symbol") return (function() {
|
||
var name = symbolName(expr);
|
||
return (isSxTruthy(envHas(env, name)) ? envGet(env, name) : (isSxTruthy(isPrimitive(name)) ? getPrimitive(name) : (isSxTruthy((name == "true")) ? true : (isSxTruthy((name == "false")) ? false : (isSxTruthy((name == "nil")) ? NIL : (debugLog("Undefined symbol:", name, "primitive?:", isPrimitive(name)), error((String("Undefined symbol: ") + String(name)))))))));
|
||
})(); if (_m == "keyword") return keywordName(expr); if (_m == "dict") return mapDict(function(k, v) { return trampoline(evalExpr(v, env)); }, expr); if (_m == "list") return (isSxTruthy(isEmpty(expr)) ? [] : evalList(expr, env)); return expr; })(); };
|
||
|
||
// eval-list
|
||
var evalList = function(expr, env) { return (function() {
|
||
var head = first(expr);
|
||
var args = rest(expr);
|
||
return (isSxTruthy(!isSxTruthy(sxOr((typeOf(head) == "symbol"), (typeOf(head) == "lambda"), (typeOf(head) == "list")))) ? map(function(x) { return trampoline(evalExpr(x, env)); }, expr) : (isSxTruthy((typeOf(head) == "symbol")) ? (function() {
|
||
var name = symbolName(head);
|
||
return (isSxTruthy((name == "if")) ? sfIf(args, env) : (isSxTruthy((name == "when")) ? sfWhen(args, env) : (isSxTruthy((name == "cond")) ? sfCond(args, env) : (isSxTruthy((name == "case")) ? sfCase(args, env) : (isSxTruthy((name == "and")) ? sfAnd(args, env) : (isSxTruthy((name == "or")) ? sfOr(args, env) : (isSxTruthy((name == "let")) ? sfLet(args, env) : (isSxTruthy((name == "let*")) ? sfLet(args, env) : (isSxTruthy((name == "letrec")) ? sfLetrec(args, env) : (isSxTruthy((name == "lambda")) ? sfLambda(args, env) : (isSxTruthy((name == "fn")) ? sfLambda(args, env) : (isSxTruthy((name == "define")) ? sfDefine(args, env) : (isSxTruthy((name == "defcomp")) ? sfDefcomp(args, env) : (isSxTruthy((name == "defisland")) ? sfDefisland(args, env) : (isSxTruthy((name == "defmacro")) ? sfDefmacro(args, env) : (isSxTruthy((name == "defstyle")) ? sfDefstyle(args, env) : (isSxTruthy((name == "defhandler")) ? sfDefhandler(args, env) : (isSxTruthy((name == "defpage")) ? sfDefpage(args, env) : (isSxTruthy((name == "defquery")) ? sfDefquery(args, env) : (isSxTruthy((name == "defaction")) ? sfDefaction(args, env) : (isSxTruthy((name == "deftype")) ? sfDeftype(args, env) : (isSxTruthy((name == "defeffect")) ? sfDefeffect(args, env) : (isSxTruthy((name == "begin")) ? sfBegin(args, env) : (isSxTruthy((name == "do")) ? sfBegin(args, env) : (isSxTruthy((name == "quote")) ? sfQuote(args, env) : (isSxTruthy((name == "quasiquote")) ? sfQuasiquote(args, env) : (isSxTruthy((name == "->")) ? sfThreadFirst(args, env) : (isSxTruthy((name == "set!")) ? sfSetBang(args, env) : (isSxTruthy((name == "reset")) ? sfReset(args, env) : (isSxTruthy((name == "shift")) ? sfShift(args, env) : (isSxTruthy((name == "dynamic-wind")) ? sfDynamicWind(args, env) : (isSxTruthy((name == "provide")) ? sfProvide(args, env) : (isSxTruthy((name == "map")) ? hoMap(args, env) : (isSxTruthy((name == "map-indexed")) ? hoMapIndexed(args, env) : (isSxTruthy((name == "filter")) ? hoFilter(args, env) : (isSxTruthy((name == "reduce")) ? hoReduce(args, env) : (isSxTruthy((name == "some")) ? hoSome(args, env) : (isSxTruthy((name == "every?")) ? hoEvery(args, env) : (isSxTruthy((name == "for-each")) ? hoForEach(args, env) : (isSxTruthy((isSxTruthy(envHas(env, name)) && isMacro(envGet(env, name)))) ? (function() {
|
||
var mac = envGet(env, name);
|
||
return makeThunk(expandMacro(mac, args, env), env);
|
||
})() : (isSxTruthy((isSxTruthy(renderActiveP()) && isRenderExpr(expr))) ? renderExpr(expr, env) : evalCall(head, args, env))))))))))))))))))))))))))))))))))))))))));
|
||
})() : evalCall(head, args, env)));
|
||
})(); };
|
||
|
||
// eval-call
|
||
var evalCall = function(head, args, env) { return (function() {
|
||
var f = trampoline(evalExpr(head, env));
|
||
var evaluatedArgs = map(function(a) { return trampoline(evalExpr(a, env)); }, args);
|
||
return (isSxTruthy((isSxTruthy(isCallable(f)) && isSxTruthy(!isSxTruthy(isLambda(f))) && isSxTruthy(!isSxTruthy(isComponent(f))) && !isSxTruthy(isIsland(f)))) ? apply(f, evaluatedArgs) : (isSxTruthy(isLambda(f)) ? callLambda(f, evaluatedArgs, env) : (isSxTruthy(isComponent(f)) ? callComponent(f, args, env) : (isSxTruthy(isIsland(f)) ? callComponent(f, args, env) : error((String("Not callable: ") + String(inspect(f))))))));
|
||
})(); };
|
||
|
||
// call-lambda
|
||
var callLambda = function(f, args, callerEnv) { return (function() {
|
||
var params = lambdaParams(f);
|
||
var local = envMerge(lambdaClosure(f), callerEnv);
|
||
return (isSxTruthy((len(args) > len(params))) ? error((String(sxOr(lambdaName(f), "lambda")) + String(" expects ") + String(len(params)) + String(" args, got ") + String(len(args)))) : (forEach(function(pair) { return envSet(local, first(pair), nth(pair, 1)); }, zip(params, args)), forEach(function(p) { return envSet(local, p, NIL); }, slice(params, len(args))), makeThunk(lambdaBody(f), local)));
|
||
})(); };
|
||
|
||
// call-component
|
||
var callComponent = function(comp, rawArgs, env) { return (function() {
|
||
var parsed = parseKeywordArgs(rawArgs, env);
|
||
var kwargs = first(parsed);
|
||
var children = nth(parsed, 1);
|
||
var local = envMerge(componentClosure(comp), env);
|
||
{ var _c = componentParams(comp); for (var _i = 0; _i < _c.length; _i++) { var p = _c[_i]; envSet(local, p, sxOr(dictGet(kwargs, p), NIL)); } }
|
||
if (isSxTruthy(componentHasChildren(comp))) {
|
||
envSet(local, "children", children);
|
||
}
|
||
return makeThunk(componentBody(comp), local);
|
||
})(); };
|
||
|
||
// parse-keyword-args
|
||
var parseKeywordArgs = function(rawArgs, env) { return (function() {
|
||
var kwargs = {};
|
||
var children = [];
|
||
var i = 0;
|
||
reduce(function(state, arg) { return (function() {
|
||
var idx = get(state, "i");
|
||
var skip = get(state, "skip");
|
||
return (isSxTruthy(skip) ? assoc(state, "skip", false, "i", (idx + 1)) : (isSxTruthy((isSxTruthy((typeOf(arg) == "keyword")) && ((idx + 1) < len(rawArgs)))) ? (dictSet(kwargs, keywordName(arg), trampoline(evalExpr(nth(rawArgs, (idx + 1)), env))), assoc(state, "skip", true, "i", (idx + 1))) : (append_b(children, trampoline(evalExpr(arg, env))), assoc(state, "i", (idx + 1)))));
|
||
})(); }, {["i"]: 0, ["skip"]: false}, rawArgs);
|
||
return [kwargs, children];
|
||
})(); };
|
||
|
||
// sf-if
|
||
var sfIf = function(args, env) { return (function() {
|
||
var condition = trampoline(evalExpr(first(args), env));
|
||
return (isSxTruthy((isSxTruthy(condition) && !isSxTruthy(isNil(condition)))) ? makeThunk(nth(args, 1), env) : (isSxTruthy((len(args) > 2)) ? makeThunk(nth(args, 2), env) : NIL));
|
||
})(); };
|
||
|
||
// sf-when
|
||
var sfWhen = function(args, env) { return (function() {
|
||
var condition = trampoline(evalExpr(first(args), env));
|
||
return (isSxTruthy((isSxTruthy(condition) && !isSxTruthy(isNil(condition)))) ? (forEach(function(e) { return trampoline(evalExpr(e, env)); }, slice(args, 1, (len(args) - 1))), makeThunk(last(args), env)) : NIL);
|
||
})(); };
|
||
|
||
// cond-scheme?
|
||
var condScheme_p = function(clauses) { return isEvery(function(c) { return (isSxTruthy((typeOf(c) == "list")) && (len(c) == 2)); }, clauses); };
|
||
|
||
// sf-cond
|
||
var sfCond = function(args, env) { return (isSxTruthy(condScheme_p(args)) ? sfCondScheme(args, env) : sfCondClojure(args, env)); };
|
||
|
||
// sf-cond-scheme
|
||
var sfCondScheme = function(clauses, env) { return (isSxTruthy(isEmpty(clauses)) ? NIL : (function() {
|
||
var clause = first(clauses);
|
||
var test = first(clause);
|
||
var body = nth(clause, 1);
|
||
return (isSxTruthy(sxOr((isSxTruthy((typeOf(test) == "symbol")) && sxOr((symbolName(test) == "else"), (symbolName(test) == ":else"))), (isSxTruthy((typeOf(test) == "keyword")) && (keywordName(test) == "else")))) ? makeThunk(body, env) : (isSxTruthy(trampoline(evalExpr(test, env))) ? makeThunk(body, env) : sfCondScheme(rest(clauses), env)));
|
||
})()); };
|
||
|
||
// sf-cond-clojure
|
||
var sfCondClojure = function(clauses, env) { return (isSxTruthy((len(clauses) < 2)) ? NIL : (function() {
|
||
var test = first(clauses);
|
||
var body = nth(clauses, 1);
|
||
return (isSxTruthy(sxOr((isSxTruthy((typeOf(test) == "keyword")) && (keywordName(test) == "else")), (isSxTruthy((typeOf(test) == "symbol")) && sxOr((symbolName(test) == "else"), (symbolName(test) == ":else"))))) ? makeThunk(body, env) : (isSxTruthy(trampoline(evalExpr(test, env))) ? makeThunk(body, env) : sfCondClojure(slice(clauses, 2), env)));
|
||
})()); };
|
||
|
||
// sf-case
|
||
var sfCase = function(args, env) { return (function() {
|
||
var matchVal = trampoline(evalExpr(first(args), env));
|
||
var clauses = rest(args);
|
||
return sfCaseLoop(matchVal, clauses, env);
|
||
})(); };
|
||
|
||
// sf-case-loop
|
||
var sfCaseLoop = function(matchVal, clauses, env) { return (isSxTruthy((len(clauses) < 2)) ? NIL : (function() {
|
||
var test = first(clauses);
|
||
var body = nth(clauses, 1);
|
||
return (isSxTruthy(sxOr((isSxTruthy((typeOf(test) == "keyword")) && (keywordName(test) == "else")), (isSxTruthy((typeOf(test) == "symbol")) && sxOr((symbolName(test) == "else"), (symbolName(test) == ":else"))))) ? makeThunk(body, env) : (isSxTruthy((matchVal == trampoline(evalExpr(test, env)))) ? makeThunk(body, env) : sfCaseLoop(matchVal, slice(clauses, 2), env)));
|
||
})()); };
|
||
|
||
// sf-and
|
||
var sfAnd = function(args, env) { return (isSxTruthy(isEmpty(args)) ? true : (function() {
|
||
var val = trampoline(evalExpr(first(args), env));
|
||
return (isSxTruthy(!isSxTruthy(val)) ? val : (isSxTruthy((len(args) == 1)) ? val : sfAnd(rest(args), env)));
|
||
})()); };
|
||
|
||
// sf-or
|
||
var sfOr = function(args, env) { return (isSxTruthy(isEmpty(args)) ? false : (function() {
|
||
var val = trampoline(evalExpr(first(args), env));
|
||
return (isSxTruthy(val) ? val : sfOr(rest(args), env));
|
||
})()); };
|
||
|
||
// sf-let
|
||
var sfLet = function(args, env) { return (isSxTruthy((typeOf(first(args)) == "symbol")) ? sfNamedLet(args, env) : (function() {
|
||
var bindings = first(args);
|
||
var body = rest(args);
|
||
var local = envExtend(env);
|
||
(isSxTruthy((isSxTruthy((typeOf(first(bindings)) == "list")) && (len(first(bindings)) == 2))) ? forEach(function(binding) { return (function() {
|
||
var vname = (isSxTruthy((typeOf(first(binding)) == "symbol")) ? symbolName(first(binding)) : first(binding));
|
||
return envSet(local, vname, trampoline(evalExpr(nth(binding, 1), local)));
|
||
})(); }, bindings) : (function() {
|
||
var i = 0;
|
||
return reduce(function(acc, pairIdx) { return (function() {
|
||
var vname = (isSxTruthy((typeOf(nth(bindings, (pairIdx * 2))) == "symbol")) ? symbolName(nth(bindings, (pairIdx * 2))) : nth(bindings, (pairIdx * 2)));
|
||
var valExpr = nth(bindings, ((pairIdx * 2) + 1));
|
||
return envSet(local, vname, trampoline(evalExpr(valExpr, local)));
|
||
})(); }, NIL, range(0, (len(bindings) / 2)));
|
||
})());
|
||
{ var _c = slice(body, 0, (len(body) - 1)); for (var _i = 0; _i < _c.length; _i++) { var e = _c[_i]; trampoline(evalExpr(e, local)); } }
|
||
return makeThunk(last(body), local);
|
||
})()); };
|
||
|
||
// sf-named-let
|
||
var sfNamedLet = function(args, env) { return (function() {
|
||
var loopName = symbolName(first(args));
|
||
var bindings = nth(args, 1);
|
||
var body = slice(args, 2);
|
||
var params = [];
|
||
var inits = [];
|
||
(isSxTruthy((isSxTruthy((typeOf(first(bindings)) == "list")) && (len(first(bindings)) == 2))) ? forEach(function(binding) { params.push((isSxTruthy((typeOf(first(binding)) == "symbol")) ? symbolName(first(binding)) : first(binding)));
|
||
return append_b(inits, nth(binding, 1)); }, bindings) : reduce(function(acc, pairIdx) { return (append_b(params, (isSxTruthy((typeOf(nth(bindings, (pairIdx * 2))) == "symbol")) ? symbolName(nth(bindings, (pairIdx * 2))) : nth(bindings, (pairIdx * 2)))), append_b(inits, nth(bindings, ((pairIdx * 2) + 1)))); }, NIL, range(0, (len(bindings) / 2))));
|
||
return (function() {
|
||
var loopBody = (isSxTruthy((len(body) == 1)) ? first(body) : cons(makeSymbol("begin"), body));
|
||
var loopFn = makeLambda(params, loopBody, env);
|
||
loopFn.name = loopName;
|
||
envSet(lambdaClosure(loopFn), loopName, loopFn);
|
||
return (function() {
|
||
var initVals = map(function(e) { return trampoline(evalExpr(e, env)); }, inits);
|
||
return callLambda(loopFn, initVals, env);
|
||
})();
|
||
})();
|
||
})(); };
|
||
|
||
// sf-lambda
|
||
var sfLambda = function(args, env) { return (function() {
|
||
var paramsExpr = first(args);
|
||
var bodyExprs = rest(args);
|
||
var body = (isSxTruthy((len(bodyExprs) == 1)) ? first(bodyExprs) : cons(makeSymbol("begin"), bodyExprs));
|
||
var paramNames = map(function(p) { return (isSxTruthy((typeOf(p) == "symbol")) ? symbolName(p) : (isSxTruthy((isSxTruthy((typeOf(p) == "list")) && isSxTruthy((len(p) == 3)) && isSxTruthy((typeOf(nth(p, 1)) == "keyword")) && (keywordName(nth(p, 1)) == "as"))) ? symbolName(first(p)) : p)); }, paramsExpr);
|
||
return makeLambda(paramNames, body, env);
|
||
})(); };
|
||
|
||
// sf-define
|
||
var sfDefine = function(args, env) { return (function() {
|
||
var nameSym = first(args);
|
||
var hasEffects = (isSxTruthy((len(args) >= 4)) && isSxTruthy((typeOf(nth(args, 1)) == "keyword")) && (keywordName(nth(args, 1)) == "effects"));
|
||
var valIdx = (isSxTruthy((isSxTruthy((len(args) >= 4)) && isSxTruthy((typeOf(nth(args, 1)) == "keyword")) && (keywordName(nth(args, 1)) == "effects"))) ? 3 : 1);
|
||
var value = trampoline(evalExpr(nth(args, valIdx), env));
|
||
if (isSxTruthy((isSxTruthy(isLambda(value)) && isNil(lambdaName(value))))) {
|
||
value.name = symbolName(nameSym);
|
||
}
|
||
envSet(env, symbolName(nameSym), value);
|
||
if (isSxTruthy(hasEffects)) {
|
||
(function() {
|
||
var effectsRaw = nth(args, 2);
|
||
var effectList = (isSxTruthy((typeOf(effectsRaw) == "list")) ? map(function(e) { return (isSxTruthy((typeOf(e) == "symbol")) ? symbolName(e) : (String(e))); }, effectsRaw) : [(String(effectsRaw))]);
|
||
var effectAnns = (isSxTruthy(envHas(env, "*effect-annotations*")) ? envGet(env, "*effect-annotations*") : {});
|
||
effectAnns[symbolName(nameSym)] = effectList;
|
||
return envSet(env, "*effect-annotations*", effectAnns);
|
||
})();
|
||
}
|
||
return value;
|
||
})(); };
|
||
|
||
// sf-defcomp
|
||
var sfDefcomp = function(args, env) { return (function() {
|
||
var nameSym = first(args);
|
||
var paramsRaw = nth(args, 1);
|
||
var body = last(args);
|
||
var compName = stripPrefix(symbolName(nameSym), "~");
|
||
var parsed = parseCompParams(paramsRaw);
|
||
var params = first(parsed);
|
||
var hasChildren = nth(parsed, 1);
|
||
var paramTypes = nth(parsed, 2);
|
||
var affinity = defcompKwarg(args, "affinity", "auto");
|
||
return (function() {
|
||
var comp = makeComponent(compName, params, hasChildren, body, env, affinity);
|
||
var effects = defcompKwarg(args, "effects", NIL);
|
||
if (isSxTruthy((isSxTruthy(!isSxTruthy(isNil(paramTypes))) && !isSxTruthy(isEmpty(keys(paramTypes)))))) {
|
||
componentSetParamTypes_b(comp, paramTypes);
|
||
}
|
||
if (isSxTruthy(!isSxTruthy(isNil(effects)))) {
|
||
(function() {
|
||
var effectList = (isSxTruthy((typeOf(effects) == "list")) ? map(function(e) { return (isSxTruthy((typeOf(e) == "symbol")) ? symbolName(e) : (String(e))); }, effects) : [(String(effects))]);
|
||
var effectAnns = (isSxTruthy(envHas(env, "*effect-annotations*")) ? envGet(env, "*effect-annotations*") : {});
|
||
effectAnns[symbolName(nameSym)] = effectList;
|
||
return envSet(env, "*effect-annotations*", effectAnns);
|
||
})();
|
||
}
|
||
envSet(env, symbolName(nameSym), comp);
|
||
return comp;
|
||
})();
|
||
})(); };
|
||
|
||
// defcomp-kwarg
|
||
var defcompKwarg = function(args, key, default_) { return (function() {
|
||
var end = (len(args) - 1);
|
||
var result = default_;
|
||
{ var _c = range(2, end, 1); for (var _i = 0; _i < _c.length; _i++) { var i = _c[_i]; if (isSxTruthy((isSxTruthy((typeOf(nth(args, i)) == "keyword")) && isSxTruthy((keywordName(nth(args, i)) == key)) && ((i + 1) < end)))) {
|
||
(function() {
|
||
var val = nth(args, (i + 1));
|
||
return (result = (isSxTruthy((typeOf(val) == "keyword")) ? keywordName(val) : val));
|
||
})();
|
||
} } }
|
||
return result;
|
||
})(); };
|
||
|
||
// parse-comp-params
|
||
var parseCompParams = function(paramsExpr) { return (function() {
|
||
var params = [];
|
||
var paramTypes = {};
|
||
var hasChildren = false;
|
||
var inKey = false;
|
||
{ var _c = paramsExpr; for (var _i = 0; _i < _c.length; _i++) { var p = _c[_i]; (isSxTruthy((isSxTruthy((typeOf(p) == "list")) && isSxTruthy((len(p) == 3)) && isSxTruthy((typeOf(first(p)) == "symbol")) && isSxTruthy((typeOf(nth(p, 1)) == "keyword")) && (keywordName(nth(p, 1)) == "as"))) ? (function() {
|
||
var name = symbolName(first(p));
|
||
var ptype = nth(p, 2);
|
||
return (function() {
|
||
var typeVal = (isSxTruthy((typeOf(ptype) == "symbol")) ? symbolName(ptype) : ptype);
|
||
return (isSxTruthy(!isSxTruthy(hasChildren)) ? (append_b(params, name), dictSet(paramTypes, name, typeVal)) : NIL);
|
||
})();
|
||
})() : (isSxTruthy((typeOf(p) == "symbol")) ? (function() {
|
||
var name = symbolName(p);
|
||
return (isSxTruthy((name == "&key")) ? (inKey = true) : (isSxTruthy((name == "&rest")) ? (hasChildren = true) : (isSxTruthy((name == "&children")) ? (hasChildren = true) : (isSxTruthy(hasChildren) ? NIL : (isSxTruthy(inKey) ? append_b(params, name) : append_b(params, name))))));
|
||
})() : NIL)); } }
|
||
return [params, hasChildren, paramTypes];
|
||
})(); };
|
||
|
||
// sf-defisland
|
||
var sfDefisland = function(args, env) { return (function() {
|
||
var nameSym = first(args);
|
||
var paramsRaw = nth(args, 1);
|
||
var body = last(args);
|
||
var compName = stripPrefix(symbolName(nameSym), "~");
|
||
var parsed = parseCompParams(paramsRaw);
|
||
var params = first(parsed);
|
||
var hasChildren = nth(parsed, 1);
|
||
return (function() {
|
||
var island = makeIsland(compName, params, hasChildren, body, env);
|
||
envSet(env, symbolName(nameSym), island);
|
||
return island;
|
||
})();
|
||
})(); };
|
||
|
||
// sf-defmacro
|
||
var sfDefmacro = function(args, env) { return (function() {
|
||
var nameSym = first(args);
|
||
var paramsRaw = nth(args, 1);
|
||
var body = nth(args, 2);
|
||
var parsed = parseMacroParams(paramsRaw);
|
||
var params = first(parsed);
|
||
var restParam = nth(parsed, 1);
|
||
return (function() {
|
||
var mac = makeMacro(params, restParam, body, env, symbolName(nameSym));
|
||
envSet(env, symbolName(nameSym), mac);
|
||
return mac;
|
||
})();
|
||
})(); };
|
||
|
||
// parse-macro-params
|
||
var parseMacroParams = function(paramsExpr) { return (function() {
|
||
var params = [];
|
||
var restParam = NIL;
|
||
reduce(function(state, p) { return (isSxTruthy((isSxTruthy((typeOf(p) == "symbol")) && (symbolName(p) == "&rest"))) ? assoc(state, "in-rest", true) : (isSxTruthy(get(state, "in-rest")) ? ((restParam = (isSxTruthy((typeOf(p) == "symbol")) ? symbolName(p) : p)), state) : (append_b(params, (isSxTruthy((typeOf(p) == "symbol")) ? symbolName(p) : p)), state))); }, {["in-rest"]: false}, paramsExpr);
|
||
return [params, restParam];
|
||
})(); };
|
||
|
||
// sf-defstyle
|
||
var sfDefstyle = function(args, env) { return (function() {
|
||
var nameSym = first(args);
|
||
var value = trampoline(evalExpr(nth(args, 1), env));
|
||
envSet(env, symbolName(nameSym), value);
|
||
return value;
|
||
})(); };
|
||
|
||
// make-type-def
|
||
var makeTypeDef = function(name, params, body) { return {"name": name, "params": params, "body": body}; };
|
||
|
||
// normalize-type-body
|
||
var normalizeTypeBody = function(body) { return (isSxTruthy(isNil(body)) ? "nil" : (isSxTruthy((typeOf(body) == "symbol")) ? symbolName(body) : (isSxTruthy((typeOf(body) == "string")) ? body : (isSxTruthy((typeOf(body) == "keyword")) ? keywordName(body) : (isSxTruthy((typeOf(body) == "dict")) ? mapDict(function(k, v) { return normalizeTypeBody(v); }, body) : (isSxTruthy((typeOf(body) == "list")) ? (isSxTruthy(isEmpty(body)) ? "any" : (function() {
|
||
var head = first(body);
|
||
return (function() {
|
||
var headName = (isSxTruthy((typeOf(head) == "symbol")) ? symbolName(head) : (String(head)));
|
||
return (isSxTruthy((headName == "union")) ? cons("or", map(normalizeTypeBody, rest(body))) : cons(headName, map(normalizeTypeBody, rest(body))));
|
||
})();
|
||
})()) : (String(body)))))))); };
|
||
|
||
// sf-deftype
|
||
var sfDeftype = function(args, env) { return (function() {
|
||
var nameOrForm = first(args);
|
||
var bodyExpr = nth(args, 1);
|
||
var typeName = NIL;
|
||
var typeParams = [];
|
||
(isSxTruthy((typeOf(nameOrForm) == "symbol")) ? (typeName = symbolName(nameOrForm)) : (isSxTruthy((typeOf(nameOrForm) == "list")) ? ((typeName = symbolName(first(nameOrForm))), (typeParams = map(function(p) { return (isSxTruthy((typeOf(p) == "symbol")) ? symbolName(p) : (String(p))); }, rest(nameOrForm)))) : NIL));
|
||
return (function() {
|
||
var body = normalizeTypeBody(bodyExpr);
|
||
var registry = (isSxTruthy(envHas(env, "*type-registry*")) ? envGet(env, "*type-registry*") : {});
|
||
registry[typeName] = makeTypeDef(typeName, typeParams, body);
|
||
envSet(env, "*type-registry*", registry);
|
||
return NIL;
|
||
})();
|
||
})(); };
|
||
|
||
// sf-defeffect
|
||
var sfDefeffect = function(args, env) { return (function() {
|
||
var effectName = (isSxTruthy((typeOf(first(args)) == "symbol")) ? symbolName(first(args)) : (String(first(args))));
|
||
var registry = (isSxTruthy(envHas(env, "*effect-registry*")) ? envGet(env, "*effect-registry*") : []);
|
||
if (isSxTruthy(!isSxTruthy(contains(registry, effectName)))) {
|
||
registry.push(effectName);
|
||
}
|
||
envSet(env, "*effect-registry*", registry);
|
||
return NIL;
|
||
})(); };
|
||
|
||
// sf-begin
|
||
var sfBegin = function(args, env) { return (isSxTruthy(isEmpty(args)) ? NIL : (forEach(function(e) { return trampoline(evalExpr(e, env)); }, slice(args, 0, (len(args) - 1))), makeThunk(last(args), env))); };
|
||
|
||
// sf-quote
|
||
var sfQuote = function(args, env) { return (isSxTruthy(isEmpty(args)) ? NIL : first(args)); };
|
||
|
||
// sf-quasiquote
|
||
var sfQuasiquote = function(args, env) { return qqExpand(first(args), env); };
|
||
|
||
// qq-expand
|
||
var qqExpand = function(template, env) { return (isSxTruthy(!isSxTruthy((typeOf(template) == "list"))) ? template : (isSxTruthy(isEmpty(template)) ? [] : (function() {
|
||
var head = first(template);
|
||
return (isSxTruthy((isSxTruthy((typeOf(head) == "symbol")) && (symbolName(head) == "unquote"))) ? trampoline(evalExpr(nth(template, 1), env)) : reduce(function(result, item) { return (isSxTruthy((isSxTruthy((typeOf(item) == "list")) && isSxTruthy((len(item) == 2)) && isSxTruthy((typeOf(first(item)) == "symbol")) && (symbolName(first(item)) == "splice-unquote"))) ? (function() {
|
||
var spliced = trampoline(evalExpr(nth(item, 1), env));
|
||
return (isSxTruthy((typeOf(spliced) == "list")) ? concat(result, spliced) : (isSxTruthy(isNil(spliced)) ? result : concat(result, [spliced])));
|
||
})() : concat(result, [qqExpand(item, env)])); }, [], template));
|
||
})())); };
|
||
|
||
// sf-thread-first
|
||
var sfThreadFirst = function(args, env) { return (function() {
|
||
var val = trampoline(evalExpr(first(args), env));
|
||
return reduce(function(result, form) { return (isSxTruthy((typeOf(form) == "list")) ? (function() {
|
||
var f = trampoline(evalExpr(first(form), env));
|
||
var restArgs = map(function(a) { return trampoline(evalExpr(a, env)); }, rest(form));
|
||
var allArgs = cons(result, restArgs);
|
||
return (isSxTruthy((isSxTruthy(isCallable(f)) && !isSxTruthy(isLambda(f)))) ? apply(f, allArgs) : (isSxTruthy(isLambda(f)) ? trampoline(callLambda(f, allArgs, env)) : error((String("-> form not callable: ") + String(inspect(f))))));
|
||
})() : (function() {
|
||
var f = trampoline(evalExpr(form, env));
|
||
return (isSxTruthy((isSxTruthy(isCallable(f)) && !isSxTruthy(isLambda(f)))) ? f(result) : (isSxTruthy(isLambda(f)) ? trampoline(callLambda(f, [result], env)) : error((String("-> form not callable: ") + String(inspect(f))))));
|
||
})()); }, val, rest(args));
|
||
})(); };
|
||
|
||
// sf-set!
|
||
var sfSetBang = function(args, env) { return (function() {
|
||
var name = symbolName(first(args));
|
||
var value = trampoline(evalExpr(nth(args, 1), env));
|
||
envSet(env, name, value);
|
||
return value;
|
||
})(); };
|
||
|
||
// sf-letrec
|
||
var sfLetrec = function(args, env) { return (function() {
|
||
var bindings = first(args);
|
||
var body = rest(args);
|
||
var local = envExtend(env);
|
||
var names = [];
|
||
var valExprs = [];
|
||
(isSxTruthy((isSxTruthy((typeOf(first(bindings)) == "list")) && (len(first(bindings)) == 2))) ? forEach(function(binding) { return (function() {
|
||
var vname = (isSxTruthy((typeOf(first(binding)) == "symbol")) ? symbolName(first(binding)) : first(binding));
|
||
names.push(vname);
|
||
valExprs.push(nth(binding, 1));
|
||
return envSet(local, vname, NIL);
|
||
})(); }, bindings) : reduce(function(acc, pairIdx) { return (function() {
|
||
var vname = (isSxTruthy((typeOf(nth(bindings, (pairIdx * 2))) == "symbol")) ? symbolName(nth(bindings, (pairIdx * 2))) : nth(bindings, (pairIdx * 2)));
|
||
var valExpr = nth(bindings, ((pairIdx * 2) + 1));
|
||
names.push(vname);
|
||
valExprs.push(valExpr);
|
||
return envSet(local, vname, NIL);
|
||
})(); }, NIL, range(0, (len(bindings) / 2))));
|
||
(function() {
|
||
var values = map(function(e) { return trampoline(evalExpr(e, local)); }, valExprs);
|
||
{ var _c = zip(names, values); for (var _i = 0; _i < _c.length; _i++) { var pair = _c[_i]; envSet(local, first(pair), nth(pair, 1)); } }
|
||
return forEach(function(val) { return (isSxTruthy(isLambda(val)) ? forEach(function(n) { return envSet(lambdaClosure(val), n, envGet(local, n)); }, names) : NIL); }, values);
|
||
})();
|
||
{ var _c = slice(body, 0, (len(body) - 1)); for (var _i = 0; _i < _c.length; _i++) { var e = _c[_i]; trampoline(evalExpr(e, local)); } }
|
||
return makeThunk(last(body), local);
|
||
})(); };
|
||
|
||
// sf-dynamic-wind
|
||
var sfDynamicWind = function(args, env) { return (function() {
|
||
var before = trampoline(evalExpr(first(args), env));
|
||
var body = trampoline(evalExpr(nth(args, 1), env));
|
||
var after = trampoline(evalExpr(nth(args, 2), env));
|
||
callThunk(before, env);
|
||
pushWind(before, after);
|
||
return (function() {
|
||
var result = callThunk(body, env);
|
||
popWind();
|
||
callThunk(after, env);
|
||
return result;
|
||
})();
|
||
})(); };
|
||
|
||
// sf-provide
|
||
var sfProvide = function(args, env) { return (function() {
|
||
var name = trampoline(evalExpr(first(args), env));
|
||
var val = trampoline(evalExpr(nth(args, 1), env));
|
||
var bodyExprs = slice(args, 2);
|
||
var result = NIL;
|
||
providePush(name, val);
|
||
{ var _c = bodyExprs; for (var _i = 0; _i < _c.length; _i++) { var e = _c[_i]; result = trampoline(evalExpr(e, env)); } }
|
||
providePop(name);
|
||
return result;
|
||
})(); };
|
||
|
||
// expand-macro
|
||
var expandMacro = function(mac, rawArgs, env) { return (function() {
|
||
var local = envMerge(macroClosure(mac), env);
|
||
{ var _c = mapIndexed(function(i, p) { return [p, i]; }, macroParams(mac)); for (var _i = 0; _i < _c.length; _i++) { var pair = _c[_i]; envSet(local, first(pair), (isSxTruthy((nth(pair, 1) < len(rawArgs))) ? nth(rawArgs, nth(pair, 1)) : NIL)); } }
|
||
if (isSxTruthy(macroRestParam(mac))) {
|
||
envSet(local, macroRestParam(mac), slice(rawArgs, len(macroParams(mac))));
|
||
}
|
||
return trampoline(evalExpr(macroBody(mac), local));
|
||
})(); };
|
||
|
||
// call-fn
|
||
var callFn = function(f, args, env) { return (isSxTruthy(isLambda(f)) ? trampoline(callLambda(f, args, env)) : (isSxTruthy(isCallable(f)) ? apply(f, args) : error((String("Not callable in HO form: ") + String(inspect(f)))))); };
|
||
|
||
// ho-map
|
||
var hoMap = function(args, env) { return (function() {
|
||
var f = trampoline(evalExpr(first(args), env));
|
||
var coll = trampoline(evalExpr(nth(args, 1), env));
|
||
return map(function(item) { return callFn(f, [item], env); }, coll);
|
||
})(); };
|
||
|
||
// ho-map-indexed
|
||
var hoMapIndexed = function(args, env) { return (function() {
|
||
var f = trampoline(evalExpr(first(args), env));
|
||
var coll = trampoline(evalExpr(nth(args, 1), env));
|
||
return mapIndexed(function(i, item) { return callFn(f, [i, item], env); }, coll);
|
||
})(); };
|
||
|
||
// ho-filter
|
||
var hoFilter = function(args, env) { return (function() {
|
||
var f = trampoline(evalExpr(first(args), env));
|
||
var coll = trampoline(evalExpr(nth(args, 1), env));
|
||
return filter(function(item) { return callFn(f, [item], env); }, coll);
|
||
})(); };
|
||
|
||
// ho-reduce
|
||
var hoReduce = function(args, env) { return (function() {
|
||
var f = trampoline(evalExpr(first(args), env));
|
||
var init = trampoline(evalExpr(nth(args, 1), env));
|
||
var coll = trampoline(evalExpr(nth(args, 2), env));
|
||
return reduce(function(acc, item) { return callFn(f, [acc, item], env); }, init, coll);
|
||
})(); };
|
||
|
||
// ho-some
|
||
var hoSome = function(args, env) { return (function() {
|
||
var f = trampoline(evalExpr(first(args), env));
|
||
var coll = trampoline(evalExpr(nth(args, 1), env));
|
||
return some(function(item) { return callFn(f, [item], env); }, coll);
|
||
})(); };
|
||
|
||
// ho-every
|
||
var hoEvery = function(args, env) { return (function() {
|
||
var f = trampoline(evalExpr(first(args), env));
|
||
var coll = trampoline(evalExpr(nth(args, 1), env));
|
||
return isEvery(function(item) { return callFn(f, [item], env); }, coll);
|
||
})(); };
|
||
|
||
// ho-for-each
|
||
var hoForEach = function(args, env) { return (function() {
|
||
var f = trampoline(evalExpr(first(args), env));
|
||
var coll = trampoline(evalExpr(nth(args, 1), env));
|
||
return forEach(function(item) { return callFn(f, [item], env); }, coll);
|
||
})(); };
|
||
|
||
|
||
// === Transpiled from render (core) ===
|
||
|
||
// HTML_TAGS
|
||
var HTML_TAGS = ["html", "head", "body", "title", "meta", "link", "script", "style", "noscript", "header", "nav", "main", "section", "article", "aside", "footer", "h1", "h2", "h3", "h4", "h5", "h6", "hgroup", "div", "p", "blockquote", "pre", "figure", "figcaption", "address", "details", "summary", "a", "span", "em", "strong", "small", "b", "i", "u", "s", "mark", "sub", "sup", "abbr", "cite", "code", "time", "br", "wbr", "hr", "ul", "ol", "li", "dl", "dt", "dd", "table", "thead", "tbody", "tfoot", "tr", "th", "td", "caption", "colgroup", "col", "form", "input", "textarea", "select", "option", "optgroup", "button", "label", "fieldset", "legend", "output", "datalist", "img", "video", "audio", "source", "picture", "canvas", "iframe", "svg", "math", "path", "circle", "ellipse", "rect", "line", "polyline", "polygon", "text", "tspan", "g", "defs", "use", "clipPath", "mask", "pattern", "linearGradient", "radialGradient", "stop", "filter", "feGaussianBlur", "feOffset", "feBlend", "feColorMatrix", "feComposite", "feMerge", "feMergeNode", "feTurbulence", "feComponentTransfer", "feFuncR", "feFuncG", "feFuncB", "feFuncA", "feDisplacementMap", "feFlood", "feImage", "feMorphology", "feSpecularLighting", "feDiffuseLighting", "fePointLight", "feSpotLight", "feDistantLight", "animate", "animateTransform", "foreignObject", "template", "slot", "dialog", "menu"];
|
||
|
||
// VOID_ELEMENTS
|
||
var VOID_ELEMENTS = ["area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr"];
|
||
|
||
// BOOLEAN_ATTRS
|
||
var BOOLEAN_ATTRS = ["async", "autofocus", "autoplay", "checked", "controls", "default", "defer", "disabled", "formnovalidate", "hidden", "inert", "ismap", "loop", "multiple", "muted", "nomodule", "novalidate", "open", "playsinline", "readonly", "required", "reversed", "selected"];
|
||
|
||
// definition-form?
|
||
var isDefinitionForm = function(name) { return sxOr((name == "define"), (name == "defcomp"), (name == "defisland"), (name == "defmacro"), (name == "defstyle"), (name == "defhandler"), (name == "deftype"), (name == "defeffect")); };
|
||
|
||
// parse-element-args
|
||
var parseElementArgs = function(args, env) { return (function() {
|
||
var attrs = {};
|
||
var children = [];
|
||
reduce(function(state, arg) { return (function() {
|
||
var skip = get(state, "skip");
|
||
return (isSxTruthy(skip) ? assoc(state, "skip", false, "i", (get(state, "i") + 1)) : (isSxTruthy((isSxTruthy((typeOf(arg) == "keyword")) && ((get(state, "i") + 1) < len(args)))) ? (function() {
|
||
var val = trampoline(evalExpr(nth(args, (get(state, "i") + 1)), env));
|
||
attrs[keywordName(arg)] = val;
|
||
return assoc(state, "skip", true, "i", (get(state, "i") + 1));
|
||
})() : (append_b(children, arg), assoc(state, "i", (get(state, "i") + 1)))));
|
||
})(); }, {["i"]: 0, ["skip"]: false}, args);
|
||
return [attrs, children];
|
||
})(); };
|
||
|
||
// render-attrs
|
||
var renderAttrs = function(attrs) { return join("", map(function(key) { return (function() {
|
||
var val = dictGet(attrs, key);
|
||
return (isSxTruthy((isSxTruthy(contains(BOOLEAN_ATTRS, key)) && val)) ? (String(" ") + String(key)) : (isSxTruthy((isSxTruthy(contains(BOOLEAN_ATTRS, key)) && !isSxTruthy(val))) ? "" : (isSxTruthy(isNil(val)) ? "" : (String(" ") + String(key) + String("=\"") + String(escapeAttr((String(val)))) + String("\"")))));
|
||
})(); }, keys(attrs))); };
|
||
|
||
// eval-cond
|
||
var evalCond = function(clauses, env) { return (isSxTruthy(condScheme_p(clauses)) ? evalCondScheme(clauses, env) : evalCondClojure(clauses, env)); };
|
||
|
||
// eval-cond-scheme
|
||
var evalCondScheme = function(clauses, env) { return (isSxTruthy(isEmpty(clauses)) ? NIL : (function() {
|
||
var clause = first(clauses);
|
||
var test = first(clause);
|
||
var body = nth(clause, 1);
|
||
return (isSxTruthy(sxOr((isSxTruthy((typeOf(test) == "symbol")) && sxOr((symbolName(test) == "else"), (symbolName(test) == ":else"))), (isSxTruthy((typeOf(test) == "keyword")) && (keywordName(test) == "else")))) ? body : (isSxTruthy(trampoline(evalExpr(test, env))) ? body : evalCondScheme(rest(clauses), env)));
|
||
})()); };
|
||
|
||
// eval-cond-clojure
|
||
var evalCondClojure = function(clauses, env) { return (isSxTruthy((len(clauses) < 2)) ? NIL : (function() {
|
||
var test = first(clauses);
|
||
var body = nth(clauses, 1);
|
||
return (isSxTruthy(sxOr((isSxTruthy((typeOf(test) == "keyword")) && (keywordName(test) == "else")), (isSxTruthy((typeOf(test) == "symbol")) && sxOr((symbolName(test) == "else"), (symbolName(test) == ":else"))))) ? body : (isSxTruthy(trampoline(evalExpr(test, env))) ? body : evalCondClojure(slice(clauses, 2), env)));
|
||
})()); };
|
||
|
||
// process-bindings
|
||
var processBindings = function(bindings, env) { return (function() {
|
||
var local = envExtend(env);
|
||
{ var _c = bindings; for (var _i = 0; _i < _c.length; _i++) { var pair = _c[_i]; if (isSxTruthy((isSxTruthy((typeOf(pair) == "list")) && (len(pair) >= 2)))) {
|
||
(function() {
|
||
var name = (isSxTruthy((typeOf(first(pair)) == "symbol")) ? symbolName(first(pair)) : (String(first(pair))));
|
||
return envSet(local, name, trampoline(evalExpr(nth(pair, 1), local)));
|
||
})();
|
||
} } }
|
||
return local;
|
||
})(); };
|
||
|
||
// is-render-expr?
|
||
var isRenderExpr = function(expr) { return (isSxTruthy(sxOr(!isSxTruthy((typeOf(expr) == "list")), isEmpty(expr))) ? false : (function() {
|
||
var h = first(expr);
|
||
return (isSxTruthy(!isSxTruthy((typeOf(h) == "symbol"))) ? false : (function() {
|
||
var n = symbolName(h);
|
||
return sxOr((n == "<>"), (n == "raw!"), startsWith(n, "~"), startsWith(n, "html:"), contains(HTML_TAGS, n), (isSxTruthy((indexOf_(n, "-") > 0)) && isSxTruthy((len(expr) > 1)) && (typeOf(nth(expr, 1)) == "keyword")));
|
||
})());
|
||
})()); };
|
||
|
||
// merge-spread-attrs
|
||
var mergeSpreadAttrs = function(target, spreadDict) { return forEach(function(key) { return (function() {
|
||
var val = dictGet(spreadDict, key);
|
||
return (isSxTruthy((key == "class")) ? (function() {
|
||
var existing = dictGet(target, "class");
|
||
return dictSet(target, "class", (isSxTruthy((isSxTruthy(existing) && !isSxTruthy((existing == "")))) ? (String(existing) + String(" ") + String(val)) : val));
|
||
})() : (isSxTruthy((key == "style")) ? (function() {
|
||
var existing = dictGet(target, "style");
|
||
return dictSet(target, "style", (isSxTruthy((isSxTruthy(existing) && !isSxTruthy((existing == "")))) ? (String(existing) + String(";") + String(val)) : val));
|
||
})() : dictSet(target, key, val)));
|
||
})(); }, keys(spreadDict)); };
|
||
|
||
|
||
// === Transpiled from parser ===
|
||
|
||
// sx-parse
|
||
var sxParse = function(source) { return (function() {
|
||
var pos = 0;
|
||
var lenSrc = len(source);
|
||
var skipComment = function() { while(true) { if (isSxTruthy((isSxTruthy((pos < lenSrc)) && !isSxTruthy((nth(source, pos) == "\n"))))) { pos = (pos + 1);
|
||
continue; } else { return NIL; } } };
|
||
var skipWs = function() { while(true) { if (isSxTruthy((pos < lenSrc))) { { var ch = nth(source, pos);
|
||
if (isSxTruthy(sxOr((ch == " "), (ch == "\t"), (ch == "\n"), (ch == "\r")))) { pos = (pos + 1);
|
||
continue; } else if (isSxTruthy((ch == ";"))) { pos = (pos + 1);
|
||
skipComment();
|
||
continue; } else { return NIL; } } } else { return NIL; } } };
|
||
var readString = function() { pos = (pos + 1);
|
||
return (function() {
|
||
var buf = "";
|
||
var readStrLoop = function() { while(true) { if (isSxTruthy((pos >= lenSrc))) { return error("Unterminated string"); } else { { var ch = nth(source, pos);
|
||
if (isSxTruthy((ch == "\""))) { pos = (pos + 1);
|
||
return NIL; } else if (isSxTruthy((ch == "\\"))) { pos = (pos + 1);
|
||
{ var esc = nth(source, pos);
|
||
buf = (String(buf) + String((isSxTruthy((esc == "n")) ? "\n" : (isSxTruthy((esc == "t")) ? "\t" : (isSxTruthy((esc == "r")) ? "\r" : esc)))));
|
||
pos = (pos + 1);
|
||
continue; } } else { buf = (String(buf) + String(ch));
|
||
pos = (pos + 1);
|
||
continue; } } } } };
|
||
readStrLoop();
|
||
return buf;
|
||
})(); };
|
||
var readIdent = function() { return (function() {
|
||
var start = pos;
|
||
var readIdentLoop = function() { while(true) { if (isSxTruthy((isSxTruthy((pos < lenSrc)) && isIdentChar(nth(source, pos))))) { pos = (pos + 1);
|
||
continue; } else { return NIL; } } };
|
||
readIdentLoop();
|
||
return slice(source, start, pos);
|
||
})(); };
|
||
var readKeyword = function() { pos = (pos + 1);
|
||
return makeKeyword(readIdent()); };
|
||
var readNumber = function() { return (function() {
|
||
var start = pos;
|
||
if (isSxTruthy((isSxTruthy((pos < lenSrc)) && (nth(source, pos) == "-")))) {
|
||
pos = (pos + 1);
|
||
}
|
||
var readDigits = function() { while(true) { if (isSxTruthy((isSxTruthy((pos < lenSrc)) && (function() {
|
||
var c = nth(source, pos);
|
||
return (isSxTruthy((c >= "0")) && (c <= "9"));
|
||
})()))) { pos = (pos + 1);
|
||
continue; } else { return NIL; } } };
|
||
readDigits();
|
||
if (isSxTruthy((isSxTruthy((pos < lenSrc)) && (nth(source, pos) == ".")))) {
|
||
pos = (pos + 1);
|
||
readDigits();
|
||
}
|
||
if (isSxTruthy((isSxTruthy((pos < lenSrc)) && sxOr((nth(source, pos) == "e"), (nth(source, pos) == "E"))))) {
|
||
pos = (pos + 1);
|
||
if (isSxTruthy((isSxTruthy((pos < lenSrc)) && sxOr((nth(source, pos) == "+"), (nth(source, pos) == "-"))))) {
|
||
pos = (pos + 1);
|
||
}
|
||
readDigits();
|
||
}
|
||
return parseNumber(slice(source, start, pos));
|
||
})(); };
|
||
var readSymbol = function() { return (function() {
|
||
var name = readIdent();
|
||
return (isSxTruthy((name == "true")) ? true : (isSxTruthy((name == "false")) ? false : (isSxTruthy((name == "nil")) ? NIL : makeSymbol(name))));
|
||
})(); };
|
||
var readList = function(closeCh) { return (function() {
|
||
var items = [];
|
||
var readListLoop = function() { while(true) { skipWs();
|
||
if (isSxTruthy((pos >= lenSrc))) { return error("Unterminated list"); } else { if (isSxTruthy((nth(source, pos) == closeCh))) { pos = (pos + 1);
|
||
return NIL; } else { items.push(readExpr());
|
||
continue; } } } };
|
||
readListLoop();
|
||
return items;
|
||
})(); };
|
||
var readMap = function() { return (function() {
|
||
var result = {};
|
||
var readMapLoop = function() { while(true) { skipWs();
|
||
if (isSxTruthy((pos >= lenSrc))) { return error("Unterminated map"); } else { if (isSxTruthy((nth(source, pos) == "}"))) { pos = (pos + 1);
|
||
return NIL; } else { { var keyExpr = readExpr();
|
||
var keyStr = (isSxTruthy((typeOf(keyExpr) == "keyword")) ? keywordName(keyExpr) : (String(keyExpr)));
|
||
var valExpr = readExpr();
|
||
result[keyStr] = valExpr;
|
||
continue; } } } } };
|
||
readMapLoop();
|
||
return result;
|
||
})(); };
|
||
var readRawString = function() { return (function() {
|
||
var buf = "";
|
||
var rawLoop = function() { while(true) { if (isSxTruthy((pos >= lenSrc))) { return error("Unterminated raw string"); } else { { var ch = nth(source, pos);
|
||
if (isSxTruthy((ch == "|"))) { pos = (pos + 1);
|
||
return NIL; } else { buf = (String(buf) + String(ch));
|
||
pos = (pos + 1);
|
||
continue; } } } } };
|
||
rawLoop();
|
||
return buf;
|
||
})(); };
|
||
var readExpr = function() { while(true) { skipWs();
|
||
if (isSxTruthy((pos >= lenSrc))) { return error("Unexpected end of input"); } else { { var ch = nth(source, pos);
|
||
if (isSxTruthy((ch == "("))) { pos = (pos + 1);
|
||
return readList(")"); } else if (isSxTruthy((ch == "["))) { pos = (pos + 1);
|
||
return readList("]"); } else if (isSxTruthy((ch == "{"))) { pos = (pos + 1);
|
||
return readMap(); } else if (isSxTruthy((ch == "\""))) { return readString(); } else if (isSxTruthy((ch == ":"))) { return readKeyword(); } else if (isSxTruthy((ch == "`"))) { pos = (pos + 1);
|
||
return [makeSymbol("quasiquote"), readExpr()]; } else if (isSxTruthy((ch == ","))) { pos = (pos + 1);
|
||
if (isSxTruthy((isSxTruthy((pos < lenSrc)) && (nth(source, pos) == "@")))) { pos = (pos + 1);
|
||
return [makeSymbol("splice-unquote"), readExpr()]; } else { return [makeSymbol("unquote"), readExpr()]; } } else if (isSxTruthy((ch == "#"))) { pos = (pos + 1);
|
||
if (isSxTruthy((pos >= lenSrc))) { return error("Unexpected end of input after #"); } else { { var dispatchCh = nth(source, pos);
|
||
if (isSxTruthy((dispatchCh == ";"))) { pos = (pos + 1);
|
||
readExpr();
|
||
continue; } else if (isSxTruthy((dispatchCh == "|"))) { pos = (pos + 1);
|
||
return readRawString(); } else if (isSxTruthy((dispatchCh == "'"))) { pos = (pos + 1);
|
||
return [makeSymbol("quote"), readExpr()]; } else if (isSxTruthy(isIdentStart(dispatchCh))) { { var macroName = readIdent();
|
||
{ var handler = readerMacroGet(macroName);
|
||
if (isSxTruthy(handler)) { return handler(readExpr()); } else { return error((String("Unknown reader macro: #") + String(macroName))); } } } } else { return error((String("Unknown reader macro: #") + String(dispatchCh))); } } } } else if (isSxTruthy(sxOr((isSxTruthy((ch >= "0")) && (ch <= "9")), (isSxTruthy((ch == "-")) && isSxTruthy(((pos + 1) < lenSrc)) && (function() {
|
||
var nextCh = nth(source, (pos + 1));
|
||
return (isSxTruthy((nextCh >= "0")) && (nextCh <= "9"));
|
||
})())))) { return readNumber(); } else if (isSxTruthy((isSxTruthy((ch == ".")) && isSxTruthy(((pos + 2) < lenSrc)) && isSxTruthy((nth(source, (pos + 1)) == ".")) && (nth(source, (pos + 2)) == ".")))) { pos = (pos + 3);
|
||
return makeSymbol("..."); } else if (isSxTruthy(isIdentStart(ch))) { return readSymbol(); } else { return error((String("Unexpected character: ") + String(ch))); } } } } };
|
||
return (function() {
|
||
var exprs = [];
|
||
var parseLoop = function() { while(true) { skipWs();
|
||
if (isSxTruthy((pos < lenSrc))) { exprs.push(readExpr());
|
||
continue; } else { return NIL; } } };
|
||
parseLoop();
|
||
return exprs;
|
||
})();
|
||
})(); };
|
||
|
||
// sx-serialize
|
||
var sxSerialize = function(val) { return (function() { var _m = typeOf(val); if (_m == "nil") return "nil"; if (_m == "boolean") return (isSxTruthy(val) ? "true" : "false"); if (_m == "number") return (String(val)); if (_m == "string") return (String("\"") + String(escapeString(val)) + String("\"")); if (_m == "symbol") return symbolName(val); if (_m == "keyword") return (String(":") + String(keywordName(val))); if (_m == "list") return (String("(") + String(join(" ", map(sxSerialize, val))) + String(")")); if (_m == "dict") return sxSerializeDict(val); if (_m == "sx-expr") return sxExprSource(val); return (String(val)); })(); };
|
||
|
||
// sx-serialize-dict
|
||
var sxSerializeDict = function(d) { return (String("{") + String(join(" ", reduce(function(acc, key) { return concat(acc, [(String(":") + String(key)), sxSerialize(dictGet(d, key))]); }, [], keys(d)))) + String("}")); };
|
||
|
||
// serialize
|
||
var serialize = sxSerialize;
|
||
|
||
|
||
// === Transpiled from adapter-html ===
|
||
|
||
// render-to-html
|
||
var renderToHtml = function(expr, env) { setRenderActiveB(true);
|
||
return (function() { var _m = typeOf(expr); if (_m == "nil") return ""; if (_m == "string") return escapeHtml(expr); if (_m == "number") return (String(expr)); if (_m == "boolean") return (isSxTruthy(expr) ? "true" : "false"); if (_m == "list") return (isSxTruthy(isEmpty(expr)) ? "" : renderListToHtml(expr, env)); if (_m == "symbol") return renderValueToHtml(trampoline(evalExpr(expr, env)), env); if (_m == "keyword") return escapeHtml(keywordName(expr)); if (_m == "raw-html") return rawHtmlContent(expr); if (_m == "spread") return expr; return renderValueToHtml(trampoline(evalExpr(expr, env)), env); })(); };
|
||
|
||
// render-value-to-html
|
||
var renderValueToHtml = function(val, env) { return (function() { var _m = typeOf(val); if (_m == "nil") return ""; if (_m == "string") return escapeHtml(val); if (_m == "number") return (String(val)); if (_m == "boolean") return (isSxTruthy(val) ? "true" : "false"); if (_m == "list") return renderListToHtml(val, env); if (_m == "raw-html") return rawHtmlContent(val); if (_m == "spread") return val; return escapeHtml((String(val))); })(); };
|
||
|
||
// RENDER_HTML_FORMS
|
||
var RENDER_HTML_FORMS = ["if", "when", "cond", "case", "let", "let*", "begin", "do", "define", "defcomp", "defisland", "defmacro", "defstyle", "defhandler", "deftype", "defeffect", "map", "map-indexed", "filter", "for-each", "provide"];
|
||
|
||
// render-html-form?
|
||
var isRenderHtmlForm = function(name) { return contains(RENDER_HTML_FORMS, name); };
|
||
|
||
// render-list-to-html
|
||
var renderListToHtml = function(expr, env) { return (isSxTruthy(isEmpty(expr)) ? "" : (function() {
|
||
var head = first(expr);
|
||
return (isSxTruthy(!isSxTruthy((typeOf(head) == "symbol"))) ? join("", filter(function(x) { return !isSxTruthy(isSpread(x)); }, map(function(x) { return renderValueToHtml(x, env); }, expr))) : (function() {
|
||
var name = symbolName(head);
|
||
var args = rest(expr);
|
||
return (isSxTruthy((name == "<>")) ? join("", filter(function(x) { return !isSxTruthy(isSpread(x)); }, map(function(x) { return renderToHtml(x, env); }, args))) : (isSxTruthy((name == "raw!")) ? join("", map(function(x) { return (String(trampoline(evalExpr(x, env)))); }, args)) : (isSxTruthy((name == "lake")) ? renderHtmlLake(args, env) : (isSxTruthy((name == "marsh")) ? renderHtmlMarsh(args, env) : (isSxTruthy(contains(HTML_TAGS, name)) ? renderHtmlElement(name, args, env) : (isSxTruthy((isSxTruthy(startsWith(name, "~")) && isSxTruthy(envHas(env, name)) && isIsland(envGet(env, name)))) ? renderHtmlIsland(envGet(env, name), args, env) : (isSxTruthy(startsWith(name, "~")) ? (function() {
|
||
var val = envGet(env, name);
|
||
return (isSxTruthy(isComponent(val)) ? renderHtmlComponent(val, args, env) : (isSxTruthy(isMacro(val)) ? renderToHtml(expandMacro(val, args, env), env) : error((String("Unknown component: ") + String(name)))));
|
||
})() : (isSxTruthy(isRenderHtmlForm(name)) ? dispatchHtmlForm(name, expr, env) : (isSxTruthy((isSxTruthy(envHas(env, name)) && isMacro(envGet(env, name)))) ? renderToHtml(expandMacro(envGet(env, name), args, env), env) : renderValueToHtml(trampoline(evalExpr(expr, env)), env))))))))));
|
||
})());
|
||
})()); };
|
||
|
||
// dispatch-html-form
|
||
var dispatchHtmlForm = function(name, expr, env) { return (isSxTruthy((name == "if")) ? (function() {
|
||
var condVal = trampoline(evalExpr(nth(expr, 1), env));
|
||
return (isSxTruthy(condVal) ? renderToHtml(nth(expr, 2), env) : (isSxTruthy((len(expr) > 3)) ? renderToHtml(nth(expr, 3), env) : ""));
|
||
})() : (isSxTruthy((name == "when")) ? (isSxTruthy(!isSxTruthy(trampoline(evalExpr(nth(expr, 1), env)))) ? "" : (isSxTruthy((len(expr) == 3)) ? renderToHtml(nth(expr, 2), env) : (function() {
|
||
var results = map(function(i) { return renderToHtml(nth(expr, i), env); }, range(2, len(expr)));
|
||
return join("", filter(function(r) { return !isSxTruthy(isSpread(r)); }, results));
|
||
})())) : (isSxTruthy((name == "cond")) ? (function() {
|
||
var branch = evalCond(rest(expr), env);
|
||
return (isSxTruthy(branch) ? renderToHtml(branch, env) : "");
|
||
})() : (isSxTruthy((name == "case")) ? renderToHtml(trampoline(evalExpr(expr, env)), env) : (isSxTruthy(sxOr((name == "let"), (name == "let*"))) ? (function() {
|
||
var local = processBindings(nth(expr, 1), env);
|
||
return (isSxTruthy((len(expr) == 3)) ? renderToHtml(nth(expr, 2), local) : (function() {
|
||
var results = map(function(i) { return renderToHtml(nth(expr, i), local); }, range(2, len(expr)));
|
||
return join("", filter(function(r) { return !isSxTruthy(isSpread(r)); }, results));
|
||
})());
|
||
})() : (isSxTruthy(sxOr((name == "begin"), (name == "do"))) ? (isSxTruthy((len(expr) == 2)) ? renderToHtml(nth(expr, 1), env) : (function() {
|
||
var results = map(function(i) { return renderToHtml(nth(expr, i), env); }, range(1, len(expr)));
|
||
return join("", filter(function(r) { return !isSxTruthy(isSpread(r)); }, results));
|
||
})()) : (isSxTruthy(isDefinitionForm(name)) ? (trampoline(evalExpr(expr, env)), "") : (isSxTruthy((name == "map")) ? (function() {
|
||
var f = trampoline(evalExpr(nth(expr, 1), env));
|
||
var coll = trampoline(evalExpr(nth(expr, 2), env));
|
||
return join("", filter(function(r) { return !isSxTruthy(isSpread(r)); }, map(function(item) { return (isSxTruthy(isLambda(f)) ? renderLambdaHtml(f, [item], env) : renderToHtml(apply(f, [item]), env)); }, coll)));
|
||
})() : (isSxTruthy((name == "map-indexed")) ? (function() {
|
||
var f = trampoline(evalExpr(nth(expr, 1), env));
|
||
var coll = trampoline(evalExpr(nth(expr, 2), env));
|
||
return join("", filter(function(r) { return !isSxTruthy(isSpread(r)); }, mapIndexed(function(i, item) { return (isSxTruthy(isLambda(f)) ? renderLambdaHtml(f, [i, item], env) : renderToHtml(apply(f, [i, item]), env)); }, coll)));
|
||
})() : (isSxTruthy((name == "filter")) ? renderToHtml(trampoline(evalExpr(expr, env)), env) : (isSxTruthy((name == "for-each")) ? (function() {
|
||
var f = trampoline(evalExpr(nth(expr, 1), env));
|
||
var coll = trampoline(evalExpr(nth(expr, 2), env));
|
||
return join("", filter(function(r) { return !isSxTruthy(isSpread(r)); }, map(function(item) { return (isSxTruthy(isLambda(f)) ? renderLambdaHtml(f, [item], env) : renderToHtml(apply(f, [item]), env)); }, coll)));
|
||
})() : (isSxTruthy((name == "provide")) ? (function() {
|
||
var provName = trampoline(evalExpr(nth(expr, 1), env));
|
||
var provVal = trampoline(evalExpr(nth(expr, 2), env));
|
||
var bodyStart = 3;
|
||
var bodyCount = (len(expr) - 3);
|
||
providePush(provName, provVal);
|
||
return (function() {
|
||
var result = (isSxTruthy((bodyCount == 1)) ? renderToHtml(nth(expr, bodyStart), env) : join("", filter(function(r) { return !isSxTruthy(isSpread(r)); }, map(function(i) { return renderToHtml(nth(expr, i), env); }, range(bodyStart, (bodyStart + bodyCount))))));
|
||
providePop(provName);
|
||
return result;
|
||
})();
|
||
})() : renderValueToHtml(trampoline(evalExpr(expr, env)), env))))))))))))); };
|
||
|
||
// render-lambda-html
|
||
var renderLambdaHtml = function(f, args, env) { return (function() {
|
||
var local = envMerge(lambdaClosure(f), env);
|
||
forEachIndexed(function(i, p) { return envSet(local, p, nth(args, i)); }, lambdaParams(f));
|
||
return renderToHtml(lambdaBody(f), local);
|
||
})(); };
|
||
|
||
// render-html-component
|
||
var renderHtmlComponent = function(comp, args, env) { return (function() {
|
||
var kwargs = {};
|
||
var children = [];
|
||
reduce(function(state, arg) { return (function() {
|
||
var skip = get(state, "skip");
|
||
return (isSxTruthy(skip) ? assoc(state, "skip", false, "i", (get(state, "i") + 1)) : (isSxTruthy((isSxTruthy((typeOf(arg) == "keyword")) && ((get(state, "i") + 1) < len(args)))) ? (function() {
|
||
var val = trampoline(evalExpr(nth(args, (get(state, "i") + 1)), env));
|
||
kwargs[keywordName(arg)] = val;
|
||
return assoc(state, "skip", true, "i", (get(state, "i") + 1));
|
||
})() : (append_b(children, arg), assoc(state, "i", (get(state, "i") + 1)))));
|
||
})(); }, {["i"]: 0, ["skip"]: false}, args);
|
||
return (function() {
|
||
var local = envMerge(componentClosure(comp), env);
|
||
{ var _c = componentParams(comp); for (var _i = 0; _i < _c.length; _i++) { var p = _c[_i]; envSet(local, p, (isSxTruthy(dictHas(kwargs, p)) ? dictGet(kwargs, p) : NIL)); } }
|
||
if (isSxTruthy(componentHasChildren(comp))) {
|
||
(function() {
|
||
var parts = [];
|
||
{ var _c = children; for (var _i = 0; _i < _c.length; _i++) { var c = _c[_i]; (function() {
|
||
var r = renderToHtml(c, env);
|
||
return (isSxTruthy(!isSxTruthy(isSpread(r))) ? append_b(parts, r) : NIL);
|
||
})(); } }
|
||
return envSet(local, "children", makeRawHtml(join("", parts)));
|
||
})();
|
||
}
|
||
return renderToHtml(componentBody(comp), local);
|
||
})();
|
||
})(); };
|
||
|
||
// render-html-element
|
||
var renderHtmlElement = function(tag, args, env) { return (function() {
|
||
var parsed = parseElementArgs(args, env);
|
||
var attrs = first(parsed);
|
||
var children = nth(parsed, 1);
|
||
var isVoid = contains(VOID_ELEMENTS, tag);
|
||
return (isSxTruthy(isVoid) ? (String("<") + String(tag) + String(renderAttrs(attrs)) + String(" />")) : (function() {
|
||
var contentParts = [];
|
||
{ var _c = children; for (var _i = 0; _i < _c.length; _i++) { var c = _c[_i]; (function() {
|
||
var result = renderToHtml(c, env);
|
||
return (isSxTruthy(isSpread(result)) ? mergeSpreadAttrs(attrs, spreadAttrs(result)) : append_b(contentParts, result));
|
||
})(); } }
|
||
return (String("<") + String(tag) + String(renderAttrs(attrs)) + String(">") + String(join("", contentParts)) + String("</") + String(tag) + String(">"));
|
||
})());
|
||
})(); };
|
||
|
||
// render-html-lake
|
||
var renderHtmlLake = function(args, env) { return (function() {
|
||
var lakeId = NIL;
|
||
var lakeTag = "div";
|
||
var children = [];
|
||
reduce(function(state, arg) { return (function() {
|
||
var skip = get(state, "skip");
|
||
return (isSxTruthy(skip) ? assoc(state, "skip", false, "i", (get(state, "i") + 1)) : (isSxTruthy((isSxTruthy((typeOf(arg) == "keyword")) && ((get(state, "i") + 1) < len(args)))) ? (function() {
|
||
var kname = keywordName(arg);
|
||
var kval = trampoline(evalExpr(nth(args, (get(state, "i") + 1)), env));
|
||
(isSxTruthy((kname == "id")) ? (lakeId = kval) : (isSxTruthy((kname == "tag")) ? (lakeTag = kval) : NIL));
|
||
return assoc(state, "skip", true, "i", (get(state, "i") + 1));
|
||
})() : (append_b(children, arg), assoc(state, "i", (get(state, "i") + 1)))));
|
||
})(); }, {["i"]: 0, ["skip"]: false}, args);
|
||
return (function() {
|
||
var lakeAttrs = {["data-sx-lake"]: sxOr(lakeId, "")};
|
||
var contentParts = [];
|
||
{ var _c = children; for (var _i = 0; _i < _c.length; _i++) { var c = _c[_i]; (function() {
|
||
var result = renderToHtml(c, env);
|
||
return (isSxTruthy(isSpread(result)) ? mergeSpreadAttrs(lakeAttrs, spreadAttrs(result)) : append_b(contentParts, result));
|
||
})(); } }
|
||
return (String("<") + String(lakeTag) + String(renderAttrs(lakeAttrs)) + String(">") + String(join("", contentParts)) + String("</") + String(lakeTag) + String(">"));
|
||
})();
|
||
})(); };
|
||
|
||
// render-html-marsh
|
||
var renderHtmlMarsh = function(args, env) { return (function() {
|
||
var marshId = NIL;
|
||
var marshTag = "div";
|
||
var children = [];
|
||
reduce(function(state, arg) { return (function() {
|
||
var skip = get(state, "skip");
|
||
return (isSxTruthy(skip) ? assoc(state, "skip", false, "i", (get(state, "i") + 1)) : (isSxTruthy((isSxTruthy((typeOf(arg) == "keyword")) && ((get(state, "i") + 1) < len(args)))) ? (function() {
|
||
var kname = keywordName(arg);
|
||
var kval = trampoline(evalExpr(nth(args, (get(state, "i") + 1)), env));
|
||
(isSxTruthy((kname == "id")) ? (marshId = kval) : (isSxTruthy((kname == "tag")) ? (marshTag = kval) : (isSxTruthy((kname == "transform")) ? NIL : NIL)));
|
||
return assoc(state, "skip", true, "i", (get(state, "i") + 1));
|
||
})() : (append_b(children, arg), assoc(state, "i", (get(state, "i") + 1)))));
|
||
})(); }, {["i"]: 0, ["skip"]: false}, args);
|
||
return (function() {
|
||
var marshAttrs = {["data-sx-marsh"]: sxOr(marshId, "")};
|
||
var contentParts = [];
|
||
{ var _c = children; for (var _i = 0; _i < _c.length; _i++) { var c = _c[_i]; (function() {
|
||
var result = renderToHtml(c, env);
|
||
return (isSxTruthy(isSpread(result)) ? mergeSpreadAttrs(marshAttrs, spreadAttrs(result)) : append_b(contentParts, result));
|
||
})(); } }
|
||
return (String("<") + String(marshTag) + String(renderAttrs(marshAttrs)) + String(">") + String(join("", contentParts)) + String("</") + String(marshTag) + String(">"));
|
||
})();
|
||
})(); };
|
||
|
||
// render-html-island
|
||
var renderHtmlIsland = function(island, args, env) { return (function() {
|
||
var kwargs = {};
|
||
var children = [];
|
||
reduce(function(state, arg) { return (function() {
|
||
var skip = get(state, "skip");
|
||
return (isSxTruthy(skip) ? assoc(state, "skip", false, "i", (get(state, "i") + 1)) : (isSxTruthy((isSxTruthy((typeOf(arg) == "keyword")) && ((get(state, "i") + 1) < len(args)))) ? (function() {
|
||
var val = trampoline(evalExpr(nth(args, (get(state, "i") + 1)), env));
|
||
kwargs[keywordName(arg)] = val;
|
||
return assoc(state, "skip", true, "i", (get(state, "i") + 1));
|
||
})() : (append_b(children, arg), assoc(state, "i", (get(state, "i") + 1)))));
|
||
})(); }, {["i"]: 0, ["skip"]: false}, args);
|
||
return (function() {
|
||
var local = envMerge(componentClosure(island), env);
|
||
var islandName = componentName(island);
|
||
{ var _c = componentParams(island); for (var _i = 0; _i < _c.length; _i++) { var p = _c[_i]; envSet(local, p, (isSxTruthy(dictHas(kwargs, p)) ? dictGet(kwargs, p) : NIL)); } }
|
||
if (isSxTruthy(componentHasChildren(island))) {
|
||
(function() {
|
||
var parts = [];
|
||
{ var _c = children; for (var _i = 0; _i < _c.length; _i++) { var c = _c[_i]; (function() {
|
||
var r = renderToHtml(c, env);
|
||
return (isSxTruthy(!isSxTruthy(isSpread(r))) ? append_b(parts, r) : NIL);
|
||
})(); } }
|
||
return envSet(local, "children", makeRawHtml(join("", parts)));
|
||
})();
|
||
}
|
||
return (function() {
|
||
var bodyHtml = renderToHtml(componentBody(island), local);
|
||
var stateSx = serializeIslandState(kwargs);
|
||
return (String("<span data-sx-island=\"") + String(escapeAttr(islandName)) + String("\"") + String((isSxTruthy(stateSx) ? (String(" data-sx-state=\"") + String(escapeAttr(stateSx)) + String("\"")) : "")) + String(">") + String(bodyHtml) + String("</span>"));
|
||
})();
|
||
})();
|
||
})(); };
|
||
|
||
// serialize-island-state
|
||
var serializeIslandState = function(kwargs) { return (isSxTruthy(isEmptyDict(kwargs)) ? NIL : sxSerialize(kwargs)); };
|
||
|
||
|
||
// === Transpiled from adapter-sx ===
|
||
|
||
// render-to-sx
|
||
var renderToSx = function(expr, env) { return (function() {
|
||
var result = aser(expr, env);
|
||
return (isSxTruthy((typeOf(result) == "string")) ? result : serialize(result));
|
||
})(); };
|
||
|
||
// aser
|
||
var aser = function(expr, env) { setRenderActiveB(true);
|
||
return (function() { var _m = typeOf(expr); if (_m == "number") return expr; if (_m == "string") return expr; if (_m == "boolean") return expr; if (_m == "nil") return NIL; if (_m == "symbol") return (function() {
|
||
var name = symbolName(expr);
|
||
return (isSxTruthy(envHas(env, name)) ? envGet(env, name) : (isSxTruthy(isPrimitive(name)) ? getPrimitive(name) : (isSxTruthy((name == "true")) ? true : (isSxTruthy((name == "false")) ? false : (isSxTruthy((name == "nil")) ? NIL : error((String("Undefined symbol: ") + String(name))))))));
|
||
})(); if (_m == "keyword") return keywordName(expr); if (_m == "list") return (isSxTruthy(isEmpty(expr)) ? [] : aserList(expr, env)); if (_m == "spread") return expr; return expr; })(); };
|
||
|
||
// aser-list
|
||
var aserList = function(expr, env) { return (function() {
|
||
var head = first(expr);
|
||
var args = rest(expr);
|
||
return (isSxTruthy(!isSxTruthy((typeOf(head) == "symbol"))) ? map(function(x) { return aser(x, env); }, expr) : (function() {
|
||
var name = symbolName(head);
|
||
return (isSxTruthy((name == "<>")) ? aserFragment(args, env) : (isSxTruthy(startsWith(name, "~")) ? aserCall(name, args, env) : (isSxTruthy((name == "lake")) ? aserCall(name, args, env) : (isSxTruthy((name == "marsh")) ? aserCall(name, args, env) : (isSxTruthy(contains(HTML_TAGS, name)) ? aserCall(name, args, env) : (isSxTruthy(sxOr(isSpecialForm(name), isHoForm(name))) ? aserSpecial(name, expr, env) : (isSxTruthy((isSxTruthy(envHas(env, name)) && isMacro(envGet(env, name)))) ? aser(expandMacro(envGet(env, name), args, env), env) : (function() {
|
||
var f = trampoline(evalExpr(head, env));
|
||
var evaledArgs = map(function(a) { return trampoline(evalExpr(a, env)); }, args);
|
||
return (isSxTruthy((isSxTruthy(isCallable(f)) && isSxTruthy(!isSxTruthy(isLambda(f))) && isSxTruthy(!isSxTruthy(isComponent(f))) && !isSxTruthy(isIsland(f)))) ? apply(f, evaledArgs) : (isSxTruthy(isLambda(f)) ? trampoline(callLambda(f, evaledArgs, env)) : (isSxTruthy(isComponent(f)) ? aserCall((String("~") + String(componentName(f))), args, env) : (isSxTruthy(isIsland(f)) ? aserCall((String("~") + String(componentName(f))), args, env) : error((String("Not callable: ") + String(inspect(f))))))));
|
||
})())))))));
|
||
})());
|
||
})(); };
|
||
|
||
// aser-fragment
|
||
var aserFragment = function(children, env) { return (function() {
|
||
var parts = [];
|
||
{ var _c = children; for (var _i = 0; _i < _c.length; _i++) { var c = _c[_i]; (function() {
|
||
var result = aser(c, env);
|
||
return (isSxTruthy((typeOf(result) == "list")) ? forEach(function(item) { return (isSxTruthy(!isSxTruthy(isNil(item))) ? append_b(parts, serialize(item)) : NIL); }, result) : (isSxTruthy(!isSxTruthy(isNil(result))) ? append_b(parts, serialize(result)) : NIL));
|
||
})(); } }
|
||
return (isSxTruthy(isEmpty(parts)) ? "" : (String("(<> ") + String(join(" ", parts)) + String(")")));
|
||
})(); };
|
||
|
||
// aser-call
|
||
var aserCall = function(name, args, env) { return (function() {
|
||
var parts = [name];
|
||
var skip = false;
|
||
var i = 0;
|
||
{ var _c = args; for (var _i = 0; _i < _c.length; _i++) { var arg = _c[_i]; (isSxTruthy(skip) ? ((skip = false), (i = (i + 1))) : (isSxTruthy((isSxTruthy((typeOf(arg) == "keyword")) && ((i + 1) < len(args)))) ? (function() {
|
||
var val = aser(nth(args, (i + 1)), env);
|
||
if (isSxTruthy(!isSxTruthy(isNil(val)))) {
|
||
parts.push((String(":") + String(keywordName(arg))));
|
||
parts.push(serialize(val));
|
||
}
|
||
skip = true;
|
||
return (i = (i + 1));
|
||
})() : (function() {
|
||
var val = aser(arg, env);
|
||
if (isSxTruthy(!isSxTruthy(isNil(val)))) {
|
||
(isSxTruthy((typeOf(val) == "list")) ? forEach(function(item) { return (isSxTruthy(!isSxTruthy(isNil(item))) ? append_b(parts, serialize(item)) : NIL); }, val) : append_b(parts, serialize(val)));
|
||
}
|
||
return (i = (i + 1));
|
||
})())); } }
|
||
return (String("(") + String(join(" ", parts)) + String(")"));
|
||
})(); };
|
||
|
||
// SPECIAL_FORM_NAMES
|
||
var SPECIAL_FORM_NAMES = ["if", "when", "cond", "case", "and", "or", "let", "let*", "lambda", "fn", "define", "defcomp", "defmacro", "defstyle", "defhandler", "defpage", "defquery", "defaction", "defrelation", "begin", "do", "quote", "quasiquote", "->", "set!", "letrec", "dynamic-wind", "defisland", "deftype", "defeffect", "provide"];
|
||
|
||
// HO_FORM_NAMES
|
||
var HO_FORM_NAMES = ["map", "map-indexed", "filter", "reduce", "some", "every?", "for-each"];
|
||
|
||
// special-form?
|
||
var isSpecialForm = function(name) { return contains(SPECIAL_FORM_NAMES, name); };
|
||
|
||
// ho-form?
|
||
var isHoForm = function(name) { return contains(HO_FORM_NAMES, name); };
|
||
|
||
// aser-special
|
||
var aserSpecial = function(name, expr, env) { return (function() {
|
||
var args = rest(expr);
|
||
return (isSxTruthy((name == "if")) ? (isSxTruthy(trampoline(evalExpr(first(args), env))) ? aser(nth(args, 1), env) : (isSxTruthy((len(args) > 2)) ? aser(nth(args, 2), env) : NIL)) : (isSxTruthy((name == "when")) ? (isSxTruthy(!isSxTruthy(trampoline(evalExpr(first(args), env)))) ? NIL : (function() {
|
||
var result = NIL;
|
||
{ var _c = rest(args); for (var _i = 0; _i < _c.length; _i++) { var body = _c[_i]; result = aser(body, env); } }
|
||
return result;
|
||
})()) : (isSxTruthy((name == "cond")) ? (function() {
|
||
var branch = evalCond(args, env);
|
||
return (isSxTruthy(branch) ? aser(branch, env) : NIL);
|
||
})() : (isSxTruthy((name == "case")) ? (function() {
|
||
var matchVal = trampoline(evalExpr(first(args), env));
|
||
var clauses = rest(args);
|
||
return evalCaseAser(matchVal, clauses, env);
|
||
})() : (isSxTruthy(sxOr((name == "let"), (name == "let*"))) ? (function() {
|
||
var local = processBindings(first(args), env);
|
||
var result = NIL;
|
||
{ var _c = rest(args); for (var _i = 0; _i < _c.length; _i++) { var body = _c[_i]; result = aser(body, local); } }
|
||
return result;
|
||
})() : (isSxTruthy(sxOr((name == "begin"), (name == "do"))) ? (function() {
|
||
var result = NIL;
|
||
{ var _c = args; for (var _i = 0; _i < _c.length; _i++) { var body = _c[_i]; result = aser(body, env); } }
|
||
return result;
|
||
})() : (isSxTruthy((name == "and")) ? (function() {
|
||
var result = true;
|
||
some(function(arg) { result = trampoline(evalExpr(arg, env));
|
||
return !isSxTruthy(result); }, args);
|
||
return result;
|
||
})() : (isSxTruthy((name == "or")) ? (function() {
|
||
var result = false;
|
||
some(function(arg) { result = trampoline(evalExpr(arg, env));
|
||
return result; }, args);
|
||
return result;
|
||
})() : (isSxTruthy((name == "map")) ? (function() {
|
||
var f = trampoline(evalExpr(first(args), env));
|
||
var coll = trampoline(evalExpr(nth(args, 1), env));
|
||
return map(function(item) { return (isSxTruthy(isLambda(f)) ? (function() {
|
||
var local = envMerge(lambdaClosure(f), env);
|
||
envSet(local, first(lambdaParams(f)), item);
|
||
return aser(lambdaBody(f), local);
|
||
})() : invoke(f, item)); }, coll);
|
||
})() : (isSxTruthy((name == "map-indexed")) ? (function() {
|
||
var f = trampoline(evalExpr(first(args), env));
|
||
var coll = trampoline(evalExpr(nth(args, 1), env));
|
||
return mapIndexed(function(i, item) { return (isSxTruthy(isLambda(f)) ? (function() {
|
||
var local = envMerge(lambdaClosure(f), env);
|
||
envSet(local, first(lambdaParams(f)), i);
|
||
envSet(local, nth(lambdaParams(f), 1), item);
|
||
return aser(lambdaBody(f), local);
|
||
})() : invoke(f, i, item)); }, coll);
|
||
})() : (isSxTruthy((name == "for-each")) ? (function() {
|
||
var f = trampoline(evalExpr(first(args), env));
|
||
var coll = trampoline(evalExpr(nth(args, 1), env));
|
||
var results = [];
|
||
{ var _c = coll; for (var _i = 0; _i < _c.length; _i++) { var item = _c[_i]; (isSxTruthy(isLambda(f)) ? (function() {
|
||
var local = envMerge(lambdaClosure(f), env);
|
||
envSet(local, first(lambdaParams(f)), item);
|
||
return append_b(results, aser(lambdaBody(f), local));
|
||
})() : invoke(f, item)); } }
|
||
return (isSxTruthy(isEmpty(results)) ? NIL : results);
|
||
})() : (isSxTruthy((name == "defisland")) ? (trampoline(evalExpr(expr, env)), serialize(expr)) : (isSxTruthy(sxOr((name == "define"), (name == "defcomp"), (name == "defmacro"), (name == "defstyle"), (name == "defhandler"), (name == "defpage"), (name == "defquery"), (name == "defaction"), (name == "defrelation"), (name == "deftype"), (name == "defeffect"))) ? (trampoline(evalExpr(expr, env)), NIL) : (isSxTruthy((name == "provide")) ? (function() {
|
||
var provName = trampoline(evalExpr(first(args), env));
|
||
var provVal = trampoline(evalExpr(nth(args, 1), env));
|
||
var result = NIL;
|
||
providePush(provName, provVal);
|
||
{ var _c = slice(args, 2); for (var _i = 0; _i < _c.length; _i++) { var body = _c[_i]; result = aser(body, env); } }
|
||
providePop(provName);
|
||
return result;
|
||
})() : trampoline(evalExpr(expr, env))))))))))))))));
|
||
})(); };
|
||
|
||
// eval-case-aser
|
||
var evalCaseAser = function(matchVal, clauses, env) { return (isSxTruthy((len(clauses) < 2)) ? NIL : (function() {
|
||
var test = first(clauses);
|
||
var body = nth(clauses, 1);
|
||
return (isSxTruthy(sxOr((isSxTruthy((typeOf(test) == "keyword")) && (keywordName(test) == "else")), (isSxTruthy((typeOf(test) == "symbol")) && sxOr((symbolName(test) == ":else"), (symbolName(test) == "else"))))) ? aser(body, env) : (isSxTruthy((matchVal == trampoline(evalExpr(test, env)))) ? aser(body, env) : evalCaseAser(matchVal, slice(clauses, 2), env)));
|
||
})()); };
|
||
|
||
|
||
// === Transpiled from adapter-dom ===
|
||
|
||
// SVG_NS
|
||
var SVG_NS = "http://www.w3.org/2000/svg";
|
||
|
||
// MATH_NS
|
||
var MATH_NS = "http://www.w3.org/1998/Math/MathML";
|
||
|
||
// render-to-dom
|
||
var renderToDom = function(expr, env, ns) { setRenderActiveB(true);
|
||
return (function() { var _m = typeOf(expr); if (_m == "nil") return createFragment(); if (_m == "boolean") return createFragment(); if (_m == "raw-html") return domParseHtml(rawHtmlContent(expr)); if (_m == "string") return createTextNode(expr); if (_m == "number") return createTextNode((String(expr))); if (_m == "symbol") return renderToDom(trampoline(evalExpr(expr, env)), env, ns); if (_m == "keyword") return createTextNode(keywordName(expr)); if (_m == "dom-node") return expr; if (_m == "spread") return expr; if (_m == "dict") return createFragment(); if (_m == "list") return (isSxTruthy(isEmpty(expr)) ? createFragment() : renderDomList(expr, env, ns)); return (isSxTruthy(isSignal(expr)) ? (isSxTruthy(_islandScope) ? reactiveText(expr) : createTextNode((String(deref(expr))))) : createTextNode((String(expr)))); })(); };
|
||
|
||
// render-dom-list
|
||
var renderDomList = function(expr, env, ns) { return (function() {
|
||
var head = first(expr);
|
||
return (isSxTruthy((typeOf(head) == "symbol")) ? (function() {
|
||
var name = symbolName(head);
|
||
var args = rest(expr);
|
||
return (isSxTruthy((name == "raw!")) ? renderDomRaw(args, env) : (isSxTruthy((name == "<>")) ? renderDomFragment(args, env, ns) : (isSxTruthy((name == "lake")) ? renderDomLake(args, env, ns) : (isSxTruthy((name == "marsh")) ? renderDomMarsh(args, env, ns) : (isSxTruthy(startsWith(name, "html:")) ? renderDomElement(slice(name, 5), args, env, ns) : (isSxTruthy(isRenderDomForm(name)) ? (isSxTruthy((isSxTruthy(contains(HTML_TAGS, name)) && sxOr((isSxTruthy((len(args) > 0)) && (typeOf(first(args)) == "keyword")), ns))) ? renderDomElement(name, args, env, ns) : dispatchRenderForm(name, expr, env, ns)) : (isSxTruthy((isSxTruthy(envHas(env, name)) && isMacro(envGet(env, name)))) ? renderToDom(expandMacro(envGet(env, name), args, env), env, ns) : (isSxTruthy(contains(HTML_TAGS, name)) ? renderDomElement(name, args, env, ns) : (isSxTruthy((isSxTruthy(startsWith(name, "~")) && isSxTruthy(envHas(env, name)) && isIsland(envGet(env, name)))) ? renderDomIsland(envGet(env, name), args, env, ns) : (isSxTruthy(startsWith(name, "~")) ? (function() {
|
||
var comp = envGet(env, name);
|
||
return (isSxTruthy(isComponent(comp)) ? renderDomComponent(comp, args, env, ns) : renderDomUnknownComponent(name));
|
||
})() : (isSxTruthy((isSxTruthy((indexOf_(name, "-") > 0)) && isSxTruthy((len(args) > 0)) && (typeOf(first(args)) == "keyword"))) ? renderDomElement(name, args, env, ns) : (isSxTruthy(ns) ? renderDomElement(name, args, env, ns) : (isSxTruthy((isSxTruthy((name == "deref")) && _islandScope)) ? (function() {
|
||
var sigOrVal = trampoline(evalExpr(first(args), env));
|
||
return (isSxTruthy(isSignal(sigOrVal)) ? reactiveText(sigOrVal) : createTextNode((String(deref(sigOrVal)))));
|
||
})() : renderToDom(trampoline(evalExpr(expr, env)), env, ns))))))))))))));
|
||
})() : (isSxTruthy(sxOr(isLambda(head), (typeOf(head) == "list"))) ? renderToDom(trampoline(evalExpr(expr, env)), env, ns) : (function() {
|
||
var frag = createFragment();
|
||
{ var _c = expr; for (var _i = 0; _i < _c.length; _i++) { var x = _c[_i]; domAppend(frag, renderToDom(x, env, ns)); } }
|
||
return frag;
|
||
})()));
|
||
})(); };
|
||
|
||
// render-dom-element
|
||
var renderDomElement = function(tag, args, env, ns) { return (function() {
|
||
var newNs = (isSxTruthy((tag == "svg")) ? SVG_NS : (isSxTruthy((tag == "math")) ? MATH_NS : ns));
|
||
var el = domCreateElement(tag, newNs);
|
||
reduce(function(state, arg) { return (function() {
|
||
var skip = get(state, "skip");
|
||
return (isSxTruthy(skip) ? assoc(state, "skip", false, "i", (get(state, "i") + 1)) : (isSxTruthy((isSxTruthy((typeOf(arg) == "keyword")) && ((get(state, "i") + 1) < len(args)))) ? (function() {
|
||
var attrName = keywordName(arg);
|
||
var attrExpr = nth(args, (get(state, "i") + 1));
|
||
(isSxTruthy(startsWith(attrName, "on-")) ? (function() {
|
||
var attrVal = trampoline(evalExpr(attrExpr, env));
|
||
return (isSxTruthy(isCallable(attrVal)) ? domListen(el, slice(attrName, 3), attrVal) : NIL);
|
||
})() : (isSxTruthy((attrName == "bind")) ? (function() {
|
||
var attrVal = trampoline(evalExpr(attrExpr, env));
|
||
return (isSxTruthy(isSignal(attrVal)) ? bindInput(el, attrVal) : NIL);
|
||
})() : (isSxTruthy((attrName == "ref")) ? (function() {
|
||
var attrVal = trampoline(evalExpr(attrExpr, env));
|
||
return dictSet(attrVal, "current", el);
|
||
})() : (isSxTruthy((attrName == "key")) ? (function() {
|
||
var attrVal = trampoline(evalExpr(attrExpr, env));
|
||
return domSetAttr(el, "key", (String(attrVal)));
|
||
})() : (isSxTruthy(_islandScope) ? reactiveAttr(el, attrName, function() { return trampoline(evalExpr(attrExpr, env)); }) : (function() {
|
||
var attrVal = trampoline(evalExpr(attrExpr, env));
|
||
return (isSxTruthy(sxOr(isNil(attrVal), (attrVal == false))) ? NIL : (isSxTruthy(contains(BOOLEAN_ATTRS, attrName)) ? (isSxTruthy(attrVal) ? domSetAttr(el, attrName, "") : NIL) : (isSxTruthy((attrVal == true)) ? domSetAttr(el, attrName, "") : domSetAttr(el, attrName, (String(attrVal))))));
|
||
})())))));
|
||
return assoc(state, "skip", true, "i", (get(state, "i") + 1));
|
||
})() : ((isSxTruthy(!isSxTruthy(contains(VOID_ELEMENTS, tag))) ? (function() {
|
||
var child = renderToDom(arg, env, newNs);
|
||
return (isSxTruthy(isSpread(child)) ? forEach(function(key) { return (function() {
|
||
var val = dictGet(spreadAttrs(child), key);
|
||
return (isSxTruthy((key == "class")) ? (function() {
|
||
var existing = domGetAttr(el, "class");
|
||
return domSetAttr(el, "class", (isSxTruthy((isSxTruthy(existing) && !isSxTruthy((existing == "")))) ? (String(existing) + String(" ") + String(val)) : val));
|
||
})() : (isSxTruthy((key == "style")) ? (function() {
|
||
var existing = domGetAttr(el, "style");
|
||
return domSetAttr(el, "style", (isSxTruthy((isSxTruthy(existing) && !isSxTruthy((existing == "")))) ? (String(existing) + String(";") + String(val)) : val));
|
||
})() : domSetAttr(el, key, (String(val)))));
|
||
})(); }, keys(spreadAttrs(child))) : domAppend(el, child));
|
||
})() : NIL), assoc(state, "i", (get(state, "i") + 1)))));
|
||
})(); }, {["i"]: 0, ["skip"]: false}, args);
|
||
return el;
|
||
})(); };
|
||
|
||
// render-dom-component
|
||
var renderDomComponent = function(comp, args, env, ns) { return (function() {
|
||
var kwargs = {};
|
||
var children = [];
|
||
reduce(function(state, arg) { return (function() {
|
||
var skip = get(state, "skip");
|
||
return (isSxTruthy(skip) ? assoc(state, "skip", false, "i", (get(state, "i") + 1)) : (isSxTruthy((isSxTruthy((typeOf(arg) == "keyword")) && ((get(state, "i") + 1) < len(args)))) ? (function() {
|
||
var val = trampoline(evalExpr(nth(args, (get(state, "i") + 1)), env));
|
||
kwargs[keywordName(arg)] = val;
|
||
return assoc(state, "skip", true, "i", (get(state, "i") + 1));
|
||
})() : (append_b(children, arg), assoc(state, "i", (get(state, "i") + 1)))));
|
||
})(); }, {["i"]: 0, ["skip"]: false}, args);
|
||
return (function() {
|
||
var local = envMerge(componentClosure(comp), env);
|
||
{ var _c = componentParams(comp); for (var _i = 0; _i < _c.length; _i++) { var p = _c[_i]; envSet(local, p, (isSxTruthy(dictHas(kwargs, p)) ? dictGet(kwargs, p) : NIL)); } }
|
||
if (isSxTruthy(componentHasChildren(comp))) {
|
||
(function() {
|
||
var childFrag = createFragment();
|
||
{ var _c = children; for (var _i = 0; _i < _c.length; _i++) { var c = _c[_i]; domAppend(childFrag, renderToDom(c, env, ns)); } }
|
||
return envSet(local, "children", childFrag);
|
||
})();
|
||
}
|
||
return renderToDom(componentBody(comp), local, ns);
|
||
})();
|
||
})(); };
|
||
|
||
// render-dom-fragment
|
||
var renderDomFragment = function(args, env, ns) { return (function() {
|
||
var frag = createFragment();
|
||
{ var _c = args; for (var _i = 0; _i < _c.length; _i++) { var x = _c[_i]; domAppend(frag, renderToDom(x, env, ns)); } }
|
||
return frag;
|
||
})(); };
|
||
|
||
// render-dom-raw
|
||
var renderDomRaw = function(args, env) { return (function() {
|
||
var frag = createFragment();
|
||
{ var _c = args; for (var _i = 0; _i < _c.length; _i++) { var arg = _c[_i]; (function() {
|
||
var val = trampoline(evalExpr(arg, env));
|
||
return (isSxTruthy((typeOf(val) == "string")) ? domAppend(frag, domParseHtml(val)) : (isSxTruthy((typeOf(val) == "dom-node")) ? domAppend(frag, domClone(val)) : (isSxTruthy(!isSxTruthy(isNil(val))) ? domAppend(frag, createTextNode((String(val)))) : NIL)));
|
||
})(); } }
|
||
return frag;
|
||
})(); };
|
||
|
||
// render-dom-unknown-component
|
||
var renderDomUnknownComponent = function(name) { return error((String("Unknown component: ") + String(name))); };
|
||
|
||
// RENDER_DOM_FORMS
|
||
var RENDER_DOM_FORMS = ["if", "when", "cond", "case", "let", "let*", "begin", "do", "define", "defcomp", "defisland", "defmacro", "defstyle", "defhandler", "map", "map-indexed", "filter", "for-each", "portal", "error-boundary", "provide"];
|
||
|
||
// render-dom-form?
|
||
var isRenderDomForm = function(name) { return contains(RENDER_DOM_FORMS, name); };
|
||
|
||
// dispatch-render-form
|
||
var dispatchRenderForm = function(name, expr, env, ns) { return (isSxTruthy((name == "if")) ? (isSxTruthy(_islandScope) ? (function() {
|
||
var marker = createComment("r-if");
|
||
var currentNodes = [];
|
||
var initialResult = NIL;
|
||
effect(function() { return (function() {
|
||
var result = (function() {
|
||
var condVal = trampoline(evalExpr(nth(expr, 1), env));
|
||
return (isSxTruthy(condVal) ? renderToDom(nth(expr, 2), env, ns) : (isSxTruthy((len(expr) > 3)) ? renderToDom(nth(expr, 3), env, ns) : createFragment()));
|
||
})();
|
||
return (isSxTruthy(domParent(marker)) ? (forEach(function(n) { return domRemove(n); }, currentNodes), (currentNodes = (isSxTruthy(domIsFragment(result)) ? domChildNodes(result) : [result])), domInsertAfter(marker, result)) : (initialResult = result));
|
||
})(); });
|
||
return (function() {
|
||
var frag = createFragment();
|
||
domAppend(frag, marker);
|
||
if (isSxTruthy(initialResult)) {
|
||
currentNodes = (isSxTruthy(domIsFragment(initialResult)) ? domChildNodes(initialResult) : [initialResult]);
|
||
domAppend(frag, initialResult);
|
||
}
|
||
return frag;
|
||
})();
|
||
})() : (function() {
|
||
var condVal = trampoline(evalExpr(nth(expr, 1), env));
|
||
return (isSxTruthy(condVal) ? renderToDom(nth(expr, 2), env, ns) : (isSxTruthy((len(expr) > 3)) ? renderToDom(nth(expr, 3), env, ns) : createFragment()));
|
||
})()) : (isSxTruthy((name == "when")) ? (isSxTruthy(_islandScope) ? (function() {
|
||
var marker = createComment("r-when");
|
||
var currentNodes = [];
|
||
var initialResult = NIL;
|
||
effect(function() { return (isSxTruthy(domParent(marker)) ? (forEach(function(n) { return domRemove(n); }, currentNodes), (currentNodes = []), (isSxTruthy(trampoline(evalExpr(nth(expr, 1), env))) ? (function() {
|
||
var frag = createFragment();
|
||
{ var _c = range(2, len(expr)); for (var _i = 0; _i < _c.length; _i++) { var i = _c[_i]; domAppend(frag, renderToDom(nth(expr, i), env, ns)); } }
|
||
currentNodes = domChildNodes(frag);
|
||
return domInsertAfter(marker, frag);
|
||
})() : NIL)) : (isSxTruthy(trampoline(evalExpr(nth(expr, 1), env))) ? (function() {
|
||
var frag = createFragment();
|
||
{ var _c = range(2, len(expr)); for (var _i = 0; _i < _c.length; _i++) { var i = _c[_i]; domAppend(frag, renderToDom(nth(expr, i), env, ns)); } }
|
||
currentNodes = domChildNodes(frag);
|
||
return (initialResult = frag);
|
||
})() : NIL)); });
|
||
return (function() {
|
||
var frag = createFragment();
|
||
domAppend(frag, marker);
|
||
if (isSxTruthy(initialResult)) {
|
||
domAppend(frag, initialResult);
|
||
}
|
||
return frag;
|
||
})();
|
||
})() : (isSxTruthy(!isSxTruthy(trampoline(evalExpr(nth(expr, 1), env)))) ? createFragment() : (function() {
|
||
var frag = createFragment();
|
||
{ var _c = range(2, len(expr)); for (var _i = 0; _i < _c.length; _i++) { var i = _c[_i]; domAppend(frag, renderToDom(nth(expr, i), env, ns)); } }
|
||
return frag;
|
||
})())) : (isSxTruthy((name == "cond")) ? (isSxTruthy(_islandScope) ? (function() {
|
||
var marker = createComment("r-cond");
|
||
var currentNodes = [];
|
||
var initialResult = NIL;
|
||
effect(function() { return (function() {
|
||
var branch = evalCond(rest(expr), env);
|
||
return (isSxTruthy(domParent(marker)) ? (forEach(function(n) { return domRemove(n); }, currentNodes), (currentNodes = []), (isSxTruthy(branch) ? (function() {
|
||
var result = renderToDom(branch, env, ns);
|
||
currentNodes = (isSxTruthy(domIsFragment(result)) ? domChildNodes(result) : [result]);
|
||
return domInsertAfter(marker, result);
|
||
})() : NIL)) : (isSxTruthy(branch) ? (function() {
|
||
var result = renderToDom(branch, env, ns);
|
||
currentNodes = (isSxTruthy(domIsFragment(result)) ? domChildNodes(result) : [result]);
|
||
return (initialResult = result);
|
||
})() : NIL));
|
||
})(); });
|
||
return (function() {
|
||
var frag = createFragment();
|
||
domAppend(frag, marker);
|
||
if (isSxTruthy(initialResult)) {
|
||
domAppend(frag, initialResult);
|
||
}
|
||
return frag;
|
||
})();
|
||
})() : (function() {
|
||
var branch = evalCond(rest(expr), env);
|
||
return (isSxTruthy(branch) ? renderToDom(branch, env, ns) : createFragment());
|
||
})()) : (isSxTruthy((name == "case")) ? renderToDom(trampoline(evalExpr(expr, env)), env, ns) : (isSxTruthy(sxOr((name == "let"), (name == "let*"))) ? (function() {
|
||
var local = processBindings(nth(expr, 1), env);
|
||
var frag = createFragment();
|
||
{ var _c = range(2, len(expr)); for (var _i = 0; _i < _c.length; _i++) { var i = _c[_i]; domAppend(frag, renderToDom(nth(expr, i), local, ns)); } }
|
||
return frag;
|
||
})() : (isSxTruthy(sxOr((name == "begin"), (name == "do"))) ? (function() {
|
||
var frag = createFragment();
|
||
{ var _c = range(1, len(expr)); for (var _i = 0; _i < _c.length; _i++) { var i = _c[_i]; domAppend(frag, renderToDom(nth(expr, i), env, ns)); } }
|
||
return frag;
|
||
})() : (isSxTruthy(isDefinitionForm(name)) ? (trampoline(evalExpr(expr, env)), createFragment()) : (isSxTruthy((name == "map")) ? (function() {
|
||
var collExpr = nth(expr, 2);
|
||
return (isSxTruthy((isSxTruthy(_islandScope) && isSxTruthy((typeOf(collExpr) == "list")) && isSxTruthy((len(collExpr) > 1)) && isSxTruthy((typeOf(first(collExpr)) == "symbol")) && (symbolName(first(collExpr)) == "deref"))) ? (function() {
|
||
var f = trampoline(evalExpr(nth(expr, 1), env));
|
||
var sig = trampoline(evalExpr(nth(collExpr, 1), env));
|
||
return (isSxTruthy(isSignal(sig)) ? reactiveList(f, sig, env, ns) : (function() {
|
||
var coll = deref(sig);
|
||
var frag = createFragment();
|
||
{ var _c = coll; for (var _i = 0; _i < _c.length; _i++) { var item = _c[_i]; (function() {
|
||
var val = (isSxTruthy(isLambda(f)) ? renderLambdaDom(f, [item], env, ns) : renderToDom(apply(f, [item]), env, ns));
|
||
return domAppend(frag, val);
|
||
})(); } }
|
||
return frag;
|
||
})());
|
||
})() : (function() {
|
||
var f = trampoline(evalExpr(nth(expr, 1), env));
|
||
var coll = trampoline(evalExpr(nth(expr, 2), env));
|
||
var frag = createFragment();
|
||
{ var _c = coll; for (var _i = 0; _i < _c.length; _i++) { var item = _c[_i]; (function() {
|
||
var val = (isSxTruthy(isLambda(f)) ? renderLambdaDom(f, [item], env, ns) : renderToDom(apply(f, [item]), env, ns));
|
||
return domAppend(frag, val);
|
||
})(); } }
|
||
return frag;
|
||
})());
|
||
})() : (isSxTruthy((name == "map-indexed")) ? (function() {
|
||
var f = trampoline(evalExpr(nth(expr, 1), env));
|
||
var coll = trampoline(evalExpr(nth(expr, 2), env));
|
||
var frag = createFragment();
|
||
forEachIndexed(function(i, item) { return (function() {
|
||
var val = (isSxTruthy(isLambda(f)) ? renderLambdaDom(f, [i, item], env, ns) : renderToDom(apply(f, [i, item]), env, ns));
|
||
return domAppend(frag, val);
|
||
})(); }, coll);
|
||
return frag;
|
||
})() : (isSxTruthy((name == "filter")) ? renderToDom(trampoline(evalExpr(expr, env)), env, ns) : (isSxTruthy((name == "portal")) ? renderDomPortal(rest(expr), env, ns) : (isSxTruthy((name == "error-boundary")) ? renderDomErrorBoundary(rest(expr), env, ns) : (isSxTruthy((name == "for-each")) ? (function() {
|
||
var f = trampoline(evalExpr(nth(expr, 1), env));
|
||
var coll = trampoline(evalExpr(nth(expr, 2), env));
|
||
var frag = createFragment();
|
||
{ var _c = coll; for (var _i = 0; _i < _c.length; _i++) { var item = _c[_i]; (function() {
|
||
var val = (isSxTruthy(isLambda(f)) ? renderLambdaDom(f, [item], env, ns) : renderToDom(apply(f, [item]), env, ns));
|
||
return domAppend(frag, val);
|
||
})(); } }
|
||
return frag;
|
||
})() : (isSxTruthy((name == "provide")) ? (function() {
|
||
var provName = trampoline(evalExpr(nth(expr, 1), env));
|
||
var provVal = trampoline(evalExpr(nth(expr, 2), env));
|
||
var frag = createFragment();
|
||
providePush(provName, provVal);
|
||
{ var _c = range(3, len(expr)); for (var _i = 0; _i < _c.length; _i++) { var i = _c[_i]; domAppend(frag, renderToDom(nth(expr, i), env, ns)); } }
|
||
providePop(provName);
|
||
return frag;
|
||
})() : renderToDom(trampoline(evalExpr(expr, env)), env, ns))))))))))))))); };
|
||
|
||
// render-lambda-dom
|
||
var renderLambdaDom = function(f, args, env, ns) { return (function() {
|
||
var local = envMerge(lambdaClosure(f), env);
|
||
forEachIndexed(function(i, p) { return envSet(local, p, nth(args, i)); }, lambdaParams(f));
|
||
return renderToDom(lambdaBody(f), local, ns);
|
||
})(); };
|
||
|
||
// render-dom-island
|
||
var renderDomIsland = function(island, args, env, ns) { return (function() {
|
||
var kwargs = {};
|
||
var children = [];
|
||
reduce(function(state, arg) { return (function() {
|
||
var skip = get(state, "skip");
|
||
return (isSxTruthy(skip) ? assoc(state, "skip", false, "i", (get(state, "i") + 1)) : (isSxTruthy((isSxTruthy((typeOf(arg) == "keyword")) && ((get(state, "i") + 1) < len(args)))) ? (function() {
|
||
var val = trampoline(evalExpr(nth(args, (get(state, "i") + 1)), env));
|
||
kwargs[keywordName(arg)] = val;
|
||
return assoc(state, "skip", true, "i", (get(state, "i") + 1));
|
||
})() : (append_b(children, arg), assoc(state, "i", (get(state, "i") + 1)))));
|
||
})(); }, {["i"]: 0, ["skip"]: false}, args);
|
||
return (function() {
|
||
var local = envMerge(componentClosure(island), env);
|
||
var islandName = componentName(island);
|
||
{ var _c = componentParams(island); for (var _i = 0; _i < _c.length; _i++) { var p = _c[_i]; envSet(local, p, (isSxTruthy(dictHas(kwargs, p)) ? dictGet(kwargs, p) : NIL)); } }
|
||
if (isSxTruthy(componentHasChildren(island))) {
|
||
(function() {
|
||
var childFrag = createFragment();
|
||
{ var _c = children; for (var _i = 0; _i < _c.length; _i++) { var c = _c[_i]; domAppend(childFrag, renderToDom(c, env, ns)); } }
|
||
return envSet(local, "children", childFrag);
|
||
})();
|
||
}
|
||
return (function() {
|
||
var container = domCreateElement("span", NIL);
|
||
var disposers = [];
|
||
domSetAttr(container, "data-sx-island", islandName);
|
||
markProcessed(container, "island-hydrated");
|
||
return (function() {
|
||
var bodyDom = withIslandScope(function(disposable) { return append_b(disposers, disposable); }, function() { return renderToDom(componentBody(island), local, ns); });
|
||
domAppend(container, bodyDom);
|
||
domSetData(container, "sx-disposers", disposers);
|
||
return container;
|
||
})();
|
||
})();
|
||
})();
|
||
})(); };
|
||
|
||
// render-dom-lake
|
||
var renderDomLake = function(args, env, ns) { return (function() {
|
||
var lakeId = NIL;
|
||
var lakeTag = "div";
|
||
var children = [];
|
||
reduce(function(state, arg) { return (function() {
|
||
var skip = get(state, "skip");
|
||
return (isSxTruthy(skip) ? assoc(state, "skip", false, "i", (get(state, "i") + 1)) : (isSxTruthy((isSxTruthy((typeOf(arg) == "keyword")) && ((get(state, "i") + 1) < len(args)))) ? (function() {
|
||
var kname = keywordName(arg);
|
||
var kval = trampoline(evalExpr(nth(args, (get(state, "i") + 1)), env));
|
||
(isSxTruthy((kname == "id")) ? (lakeId = kval) : (isSxTruthy((kname == "tag")) ? (lakeTag = kval) : NIL));
|
||
return assoc(state, "skip", true, "i", (get(state, "i") + 1));
|
||
})() : (append_b(children, arg), assoc(state, "i", (get(state, "i") + 1)))));
|
||
})(); }, {["i"]: 0, ["skip"]: false}, args);
|
||
return (function() {
|
||
var el = domCreateElement(lakeTag, NIL);
|
||
domSetAttr(el, "data-sx-lake", sxOr(lakeId, ""));
|
||
{ var _c = children; for (var _i = 0; _i < _c.length; _i++) { var c = _c[_i]; domAppend(el, renderToDom(c, env, ns)); } }
|
||
return el;
|
||
})();
|
||
})(); };
|
||
|
||
// render-dom-marsh
|
||
var renderDomMarsh = function(args, env, ns) { return (function() {
|
||
var marshId = NIL;
|
||
var marshTag = "div";
|
||
var marshTransform = NIL;
|
||
var children = [];
|
||
reduce(function(state, arg) { return (function() {
|
||
var skip = get(state, "skip");
|
||
return (isSxTruthy(skip) ? assoc(state, "skip", false, "i", (get(state, "i") + 1)) : (isSxTruthy((isSxTruthy((typeOf(arg) == "keyword")) && ((get(state, "i") + 1) < len(args)))) ? (function() {
|
||
var kname = keywordName(arg);
|
||
var kval = trampoline(evalExpr(nth(args, (get(state, "i") + 1)), env));
|
||
(isSxTruthy((kname == "id")) ? (marshId = kval) : (isSxTruthy((kname == "tag")) ? (marshTag = kval) : (isSxTruthy((kname == "transform")) ? (marshTransform = kval) : NIL)));
|
||
return assoc(state, "skip", true, "i", (get(state, "i") + 1));
|
||
})() : (append_b(children, arg), assoc(state, "i", (get(state, "i") + 1)))));
|
||
})(); }, {["i"]: 0, ["skip"]: false}, args);
|
||
return (function() {
|
||
var el = domCreateElement(marshTag, NIL);
|
||
domSetAttr(el, "data-sx-marsh", sxOr(marshId, ""));
|
||
if (isSxTruthy(marshTransform)) {
|
||
domSetData(el, "sx-marsh-transform", marshTransform);
|
||
}
|
||
domSetData(el, "sx-marsh-env", env);
|
||
{ var _c = children; for (var _i = 0; _i < _c.length; _i++) { var c = _c[_i]; domAppend(el, renderToDom(c, env, ns)); } }
|
||
return el;
|
||
})();
|
||
})(); };
|
||
|
||
// reactive-text
|
||
var reactiveText = function(sig) { return (function() {
|
||
var node = createTextNode((String(deref(sig))));
|
||
effect(function() { return domSetTextContent(node, (String(deref(sig)))); });
|
||
return node;
|
||
})(); };
|
||
|
||
// reactive-attr
|
||
var reactiveAttr = function(el, attrName, computeFn) { (function() {
|
||
var existing = sxOr(domGetAttr(el, "data-sx-reactive-attrs"), "");
|
||
var updated = (isSxTruthy(isEmpty(existing)) ? attrName : (String(existing) + String(",") + String(attrName)));
|
||
return domSetAttr(el, "data-sx-reactive-attrs", updated);
|
||
})();
|
||
return effect(function() { return (function() {
|
||
var raw = computeFn();
|
||
return (function() {
|
||
var val = (isSxTruthy(isSignal(raw)) ? deref(raw) : raw);
|
||
return (isSxTruthy(sxOr(isNil(val), (val == false))) ? domRemoveAttr(el, attrName) : (isSxTruthy((val == true)) ? domSetAttr(el, attrName, "") : domSetAttr(el, attrName, (String(val)))));
|
||
})();
|
||
})(); }); };
|
||
|
||
// reactive-fragment
|
||
var reactiveFragment = function(testFn, renderFn, env, ns) { return (function() {
|
||
var marker = createComment("island-fragment");
|
||
var currentNodes = [];
|
||
effect(function() { { var _c = currentNodes; for (var _i = 0; _i < _c.length; _i++) { var n = _c[_i]; domRemove(n); } }
|
||
currentNodes = [];
|
||
return (isSxTruthy(testFn()) ? (function() {
|
||
var frag = renderFn();
|
||
currentNodes = domChildNodes(frag);
|
||
return domInsertAfter(marker, frag);
|
||
})() : NIL); });
|
||
return marker;
|
||
})(); };
|
||
|
||
// render-list-item
|
||
var renderListItem = function(mapFn, item, env, ns) { return (isSxTruthy(isLambda(mapFn)) ? renderLambdaDom(mapFn, [item], env, ns) : renderToDom(apply(mapFn, [item]), env, ns)); };
|
||
|
||
// extract-key
|
||
var extractKey = function(node, index) { return (function() {
|
||
var k = domGetAttr(node, "key");
|
||
return (isSxTruthy(k) ? (domRemoveAttr(node, "key"), k) : (function() {
|
||
var dk = domGetData(node, "key");
|
||
return (isSxTruthy(dk) ? (String(dk)) : (String("__idx_") + String(index)));
|
||
})());
|
||
})(); };
|
||
|
||
// reactive-list
|
||
var reactiveList = function(mapFn, itemsSig, env, ns) { return (function() {
|
||
var container = createFragment();
|
||
var marker = createComment("island-list");
|
||
var keyMap = {};
|
||
var keyOrder = [];
|
||
domAppend(container, marker);
|
||
effect(function() { return (function() {
|
||
var items = deref(itemsSig);
|
||
return (isSxTruthy(domParent(marker)) ? (function() {
|
||
var newMap = {};
|
||
var newKeys = [];
|
||
var hasKeys = false;
|
||
forEachIndexed(function(idx, item) { return (function() {
|
||
var rendered = renderListItem(mapFn, item, env, ns);
|
||
var key = extractKey(rendered, idx);
|
||
if (isSxTruthy((isSxTruthy(!isSxTruthy(hasKeys)) && !isSxTruthy(startsWith(key, "__idx_"))))) {
|
||
hasKeys = true;
|
||
}
|
||
(isSxTruthy(dictHas(keyMap, key)) ? dictSet(newMap, key, dictGet(keyMap, key)) : dictSet(newMap, key, rendered));
|
||
return append_b(newKeys, key);
|
||
})(); }, items);
|
||
(isSxTruthy(!isSxTruthy(hasKeys)) ? (domRemoveChildrenAfter(marker), (function() {
|
||
var frag = createFragment();
|
||
{ var _c = newKeys; for (var _i = 0; _i < _c.length; _i++) { var k = _c[_i]; domAppend(frag, dictGet(newMap, k)); } }
|
||
return domInsertAfter(marker, frag);
|
||
})()) : (forEach(function(oldKey) { return (isSxTruthy(!isSxTruthy(dictHas(newMap, oldKey))) ? domRemove(dictGet(keyMap, oldKey)) : NIL); }, keyOrder), (function() {
|
||
var cursor = marker;
|
||
return forEach(function(k) { return (function() {
|
||
var node = dictGet(newMap, k);
|
||
var next = domNextSibling(cursor);
|
||
if (isSxTruthy(!isSxTruthy(isIdentical(node, next)))) {
|
||
domInsertAfter(cursor, node);
|
||
}
|
||
return (cursor = node);
|
||
})(); }, newKeys);
|
||
})()));
|
||
keyMap = newMap;
|
||
return (keyOrder = newKeys);
|
||
})() : forEachIndexed(function(idx, item) { return (function() {
|
||
var rendered = renderListItem(mapFn, item, env, ns);
|
||
var key = extractKey(rendered, idx);
|
||
keyMap[key] = rendered;
|
||
keyOrder.push(key);
|
||
return domAppend(container, rendered);
|
||
})(); }, items));
|
||
})(); });
|
||
return container;
|
||
})(); };
|
||
|
||
// bind-input
|
||
var bindInput = function(el, sig) { return (function() {
|
||
var inputType = lower(sxOr(domGetAttr(el, "type"), ""));
|
||
var isCheckbox = sxOr((inputType == "checkbox"), (inputType == "radio"));
|
||
(isSxTruthy(isCheckbox) ? domSetProp(el, "checked", deref(sig)) : domSetProp(el, "value", (String(deref(sig)))));
|
||
effect(function() { return (isSxTruthy(isCheckbox) ? domSetProp(el, "checked", deref(sig)) : (function() {
|
||
var v = (String(deref(sig)));
|
||
return (isSxTruthy((domGetProp(el, "value") != v)) ? domSetProp(el, "value", v) : NIL);
|
||
})()); });
|
||
return domListen(el, (isSxTruthy(isCheckbox) ? "change" : "input"), function(e) { return (isSxTruthy(isCheckbox) ? reset_b(sig, domGetProp(el, "checked")) : reset_b(sig, domGetProp(el, "value"))); });
|
||
})(); };
|
||
|
||
// render-dom-portal
|
||
var renderDomPortal = function(args, env, ns) { return (function() {
|
||
var selector = trampoline(evalExpr(first(args), env));
|
||
var target = sxOr(domQuery(selector), domEnsureElement(selector));
|
||
return (isSxTruthy(!isSxTruthy(target)) ? createComment((String("portal: ") + String(selector) + String(" (not found)"))) : (function() {
|
||
var marker = createComment((String("portal: ") + String(selector)));
|
||
var frag = createFragment();
|
||
{ var _c = rest(args); for (var _i = 0; _i < _c.length; _i++) { var child = _c[_i]; domAppend(frag, renderToDom(child, env, ns)); } }
|
||
(function() {
|
||
var portalNodes = domChildNodes(frag);
|
||
domAppend(target, frag);
|
||
return registerInScope(function() { return forEach(function(n) { return domRemove(n); }, portalNodes); });
|
||
})();
|
||
return marker;
|
||
})());
|
||
})(); };
|
||
|
||
// render-dom-error-boundary
|
||
var renderDomErrorBoundary = function(args, env, ns) { return (function() {
|
||
var fallbackExpr = first(args);
|
||
var bodyExprs = rest(args);
|
||
var container = domCreateElement("div", NIL);
|
||
var retryVersion = signal(0);
|
||
domSetAttr(container, "data-sx-boundary", "true");
|
||
effect(function() { deref(retryVersion);
|
||
domSetProp(container, "innerHTML", "");
|
||
return (function() {
|
||
var savedScope = _islandScope;
|
||
_islandScope = NIL;
|
||
return tryCatch(function() { (function() {
|
||
var frag = createFragment();
|
||
{ var _c = bodyExprs; for (var _i = 0; _i < _c.length; _i++) { var child = _c[_i]; domAppend(frag, renderToDom(child, env, ns)); } }
|
||
return domAppend(container, frag);
|
||
})();
|
||
return (_islandScope = savedScope); }, function(err) { _islandScope = savedScope;
|
||
return (function() {
|
||
var fallbackFn = trampoline(evalExpr(fallbackExpr, env));
|
||
var retryFn = function() { return swap_b(retryVersion, function(n) { return (n + 1); }); };
|
||
return (function() {
|
||
var fallbackDom = (isSxTruthy(isLambda(fallbackFn)) ? renderLambdaDom(fallbackFn, [err, retryFn], env, ns) : renderToDom(apply(fallbackFn, [err, retryFn]), env, ns));
|
||
return domAppend(container, fallbackDom);
|
||
})();
|
||
})(); });
|
||
})(); });
|
||
return container;
|
||
})(); };
|
||
|
||
|
||
// === Transpiled from engine ===
|
||
|
||
// ENGINE_VERBS
|
||
var ENGINE_VERBS = ["get", "post", "put", "delete", "patch"];
|
||
|
||
// DEFAULT_SWAP
|
||
var DEFAULT_SWAP = "outerHTML";
|
||
|
||
// parse-time
|
||
var parseTime = function(s) { return (isSxTruthy(isNil(s)) ? 0 : (isSxTruthy(endsWith(s, "ms")) ? parseInt_(s, 0) : (isSxTruthy(endsWith(s, "s")) ? (parseInt_(replace_(s, "s", ""), 0) * 1000) : parseInt_(s, 0)))); };
|
||
|
||
// parse-trigger-spec
|
||
var parseTriggerSpec = function(spec) { return (isSxTruthy(isNil(spec)) ? NIL : (function() {
|
||
var rawParts = split(spec, ",");
|
||
return filter(function(x) { return !isSxTruthy(isNil(x)); }, map(function(part) { return (function() {
|
||
var tokens = split(trim(part), " ");
|
||
return (isSxTruthy(isEmpty(tokens)) ? NIL : (isSxTruthy((isSxTruthy((first(tokens) == "every")) && (len(tokens) >= 2))) ? {["event"]: "every", ["modifiers"]: {["interval"]: parseTime(nth(tokens, 1))}} : (function() {
|
||
var mods = {};
|
||
{ var _c = rest(tokens); for (var _i = 0; _i < _c.length; _i++) { var tok = _c[_i]; (isSxTruthy((tok == "once")) ? dictSet(mods, "once", true) : (isSxTruthy((tok == "changed")) ? dictSet(mods, "changed", true) : (isSxTruthy(startsWith(tok, "delay:")) ? dictSet(mods, "delay", parseTime(slice(tok, 6))) : (isSxTruthy(startsWith(tok, "from:")) ? dictSet(mods, "from", slice(tok, 5)) : NIL)))); } }
|
||
return {["event"]: first(tokens), ["modifiers"]: mods};
|
||
})()));
|
||
})(); }, rawParts));
|
||
})()); };
|
||
|
||
// default-trigger
|
||
var defaultTrigger = function(tagName) { return (isSxTruthy((tagName == "FORM")) ? [{["event"]: "submit", ["modifiers"]: {}}] : (isSxTruthy(sxOr((tagName == "INPUT"), (tagName == "SELECT"), (tagName == "TEXTAREA"))) ? [{["event"]: "change", ["modifiers"]: {}}] : [{["event"]: "click", ["modifiers"]: {}}])); };
|
||
|
||
// get-verb-info
|
||
var getVerbInfo = function(el) { return some(function(verb) { return (function() {
|
||
var url = domGetAttr(el, (String("sx-") + String(verb)));
|
||
return (isSxTruthy(url) ? {["method"]: upper(verb), ["url"]: url} : NIL);
|
||
})(); }, ENGINE_VERBS); };
|
||
|
||
// build-request-headers
|
||
var buildRequestHeaders = function(el, loadedComponents, cssHash) { return (function() {
|
||
var headers = {["SX-Request"]: "true", ["SX-Current-URL"]: browserLocationHref()};
|
||
(function() {
|
||
var targetSel = domGetAttr(el, "sx-target");
|
||
return (isSxTruthy(targetSel) ? dictSet(headers, "SX-Target", targetSel) : NIL);
|
||
})();
|
||
if (isSxTruthy(!isSxTruthy(isEmpty(loadedComponents)))) {
|
||
headers["SX-Components"] = join(",", loadedComponents);
|
||
}
|
||
if (isSxTruthy(cssHash)) {
|
||
headers["SX-Css"] = cssHash;
|
||
}
|
||
(function() {
|
||
var extraH = domGetAttr(el, "sx-headers");
|
||
return (isSxTruthy(extraH) ? (function() {
|
||
var parsed = parseHeaderValue(extraH);
|
||
return (isSxTruthy(parsed) ? forEach(function(key) { return dictSet(headers, key, (String(get(parsed, key)))); }, keys(parsed)) : NIL);
|
||
})() : NIL);
|
||
})();
|
||
return headers;
|
||
})(); };
|
||
|
||
// process-response-headers
|
||
var processResponseHeaders = function(getHeader) { return {["redirect"]: getHeader("SX-Redirect"), ["refresh"]: getHeader("SX-Refresh"), ["trigger"]: getHeader("SX-Trigger"), ["retarget"]: getHeader("SX-Retarget"), ["reswap"]: getHeader("SX-Reswap"), ["location"]: getHeader("SX-Location"), ["replace-url"]: getHeader("SX-Replace-Url"), ["css-hash"]: getHeader("SX-Css-Hash"), ["trigger-swap"]: getHeader("SX-Trigger-After-Swap"), ["trigger-settle"]: getHeader("SX-Trigger-After-Settle"), ["content-type"]: getHeader("Content-Type"), ["cache-invalidate"]: getHeader("SX-Cache-Invalidate"), ["cache-update"]: getHeader("SX-Cache-Update")}; };
|
||
|
||
// parse-swap-spec
|
||
var parseSwapSpec = function(rawSwap, globalTransitions_p) { return (function() {
|
||
var parts = split(sxOr(rawSwap, DEFAULT_SWAP), " ");
|
||
var style = first(parts);
|
||
var useTransition = globalTransitions_p;
|
||
{ var _c = rest(parts); for (var _i = 0; _i < _c.length; _i++) { var p = _c[_i]; (isSxTruthy((p == "transition:true")) ? (useTransition = true) : (isSxTruthy((p == "transition:false")) ? (useTransition = false) : NIL)); } }
|
||
return {["style"]: style, ["transition"]: useTransition};
|
||
})(); };
|
||
|
||
// parse-retry-spec
|
||
var parseRetrySpec = function(retryAttr) { return (isSxTruthy(isNil(retryAttr)) ? NIL : (function() {
|
||
var parts = split(retryAttr, ":");
|
||
return {["strategy"]: first(parts), ["start-ms"]: parseInt_(nth(parts, 1), 1000), ["cap-ms"]: parseInt_(nth(parts, 2), 30000)};
|
||
})()); };
|
||
|
||
// next-retry-ms
|
||
var nextRetryMs = function(currentMs, capMs) { return min((currentMs * 2), capMs); };
|
||
|
||
// filter-params
|
||
var filterParams = function(paramsSpec, allParams) { return (isSxTruthy(isNil(paramsSpec)) ? allParams : (isSxTruthy((paramsSpec == "none")) ? [] : (isSxTruthy((paramsSpec == "*")) ? allParams : (isSxTruthy(startsWith(paramsSpec, "not ")) ? (function() {
|
||
var excluded = map(trim, split(slice(paramsSpec, 4), ","));
|
||
return filter(function(p) { return !isSxTruthy(contains(excluded, first(p))); }, allParams);
|
||
})() : (function() {
|
||
var allowed = map(trim, split(paramsSpec, ","));
|
||
return filter(function(p) { return contains(allowed, first(p)); }, allParams);
|
||
})())))); };
|
||
|
||
// resolve-target
|
||
var resolveTarget = function(el) { return (function() {
|
||
var sel = domGetAttr(el, "sx-target");
|
||
return (isSxTruthy(sxOr(isNil(sel), (sel == "this"))) ? el : (isSxTruthy((sel == "closest")) ? domParent(el) : domQuery(sel)));
|
||
})(); };
|
||
|
||
// apply-optimistic
|
||
var applyOptimistic = function(el) { return (function() {
|
||
var directive = domGetAttr(el, "sx-optimistic");
|
||
return (isSxTruthy(isNil(directive)) ? NIL : (function() {
|
||
var target = sxOr(resolveTarget(el), el);
|
||
var state = {["target"]: target, ["directive"]: directive};
|
||
(isSxTruthy((directive == "remove")) ? (dictSet(state, "opacity", domGetStyle(target, "opacity")), domSetStyle(target, "opacity", "0"), domSetStyle(target, "pointer-events", "none")) : (isSxTruthy((directive == "disable")) ? (dictSet(state, "disabled", domGetProp(target, "disabled")), domSetProp(target, "disabled", true)) : (isSxTruthy(startsWith(directive, "add-class:")) ? (function() {
|
||
var cls = slice(directive, 10);
|
||
state["add-class"] = cls;
|
||
return domAddClass(target, cls);
|
||
})() : NIL)));
|
||
return state;
|
||
})());
|
||
})(); };
|
||
|
||
// revert-optimistic
|
||
var revertOptimistic = function(state) { return (isSxTruthy(state) ? (function() {
|
||
var target = get(state, "target");
|
||
var directive = get(state, "directive");
|
||
return (isSxTruthy((directive == "remove")) ? (domSetStyle(target, "opacity", sxOr(get(state, "opacity"), "")), domSetStyle(target, "pointer-events", "")) : (isSxTruthy((directive == "disable")) ? domSetProp(target, "disabled", sxOr(get(state, "disabled"), false)) : (isSxTruthy(get(state, "add-class")) ? domRemoveClass(target, get(state, "add-class")) : NIL)));
|
||
})() : NIL); };
|
||
|
||
// find-oob-swaps
|
||
var findOobSwaps = function(container) { return (function() {
|
||
var results = [];
|
||
{ var _c = ["sx-swap-oob", "hx-swap-oob"]; for (var _i = 0; _i < _c.length; _i++) { var attr = _c[_i]; (function() {
|
||
var oobEls = domQueryAll(container, (String("[") + String(attr) + String("]")));
|
||
return forEach(function(oob) { return (function() {
|
||
var swapType = sxOr(domGetAttr(oob, attr), "outerHTML");
|
||
var targetId = domId(oob);
|
||
domRemoveAttr(oob, attr);
|
||
return (isSxTruthy(targetId) ? append_b(results, {["element"]: oob, ["swap-type"]: swapType, ["target-id"]: targetId}) : NIL);
|
||
})(); }, oobEls);
|
||
})(); } }
|
||
return results;
|
||
})(); };
|
||
|
||
// morph-node
|
||
var morphNode = function(oldNode, newNode) { return (isSxTruthy(sxOr(domHasAttr(oldNode, "sx-preserve"), domHasAttr(oldNode, "sx-ignore"))) ? NIL : (isSxTruthy((isSxTruthy(domHasAttr(oldNode, "data-sx-island")) && isSxTruthy(isProcessed(oldNode, "island-hydrated")) && isSxTruthy(domHasAttr(newNode, "data-sx-island")) && (domGetAttr(oldNode, "data-sx-island") == domGetAttr(newNode, "data-sx-island")))) ? morphIslandChildren(oldNode, newNode) : (isSxTruthy(sxOr(!isSxTruthy((domNodeType(oldNode) == domNodeType(newNode))), !isSxTruthy((domNodeName(oldNode) == domNodeName(newNode))))) ? domReplaceChild(domParent(oldNode), domClone(newNode), oldNode) : (isSxTruthy(sxOr((domNodeType(oldNode) == 3), (domNodeType(oldNode) == 8))) ? (isSxTruthy(!isSxTruthy((domTextContent(oldNode) == domTextContent(newNode)))) ? domSetTextContent(oldNode, domTextContent(newNode)) : NIL) : (isSxTruthy((domNodeType(oldNode) == 1)) ? (syncAttrs(oldNode, newNode), (isSxTruthy(!isSxTruthy((isSxTruthy(domIsActiveElement(oldNode)) && domIsInputElement(oldNode)))) ? morphChildren(oldNode, newNode) : NIL)) : NIL))))); };
|
||
|
||
// sync-attrs
|
||
var syncAttrs = function(oldEl, newEl) { return (function() {
|
||
var raStr = sxOr(domGetAttr(oldEl, "data-sx-reactive-attrs"), "");
|
||
var reactiveAttrs = (isSxTruthy(isEmpty(raStr)) ? [] : split(raStr, ","));
|
||
{ var _c = domAttrList(newEl); for (var _i = 0; _i < _c.length; _i++) { var attr = _c[_i]; (function() {
|
||
var name = first(attr);
|
||
var val = nth(attr, 1);
|
||
return (isSxTruthy((isSxTruthy(!isSxTruthy((domGetAttr(oldEl, name) == val))) && !isSxTruthy(contains(reactiveAttrs, name)))) ? domSetAttr(oldEl, name, val) : NIL);
|
||
})(); } }
|
||
return forEach(function(attr) { return (function() {
|
||
var aname = first(attr);
|
||
return (isSxTruthy((isSxTruthy(!isSxTruthy(domHasAttr(newEl, aname))) && isSxTruthy(!isSxTruthy(contains(reactiveAttrs, aname))) && !isSxTruthy((aname == "data-sx-reactive-attrs")))) ? domRemoveAttr(oldEl, aname) : NIL);
|
||
})(); }, domAttrList(oldEl));
|
||
})(); };
|
||
|
||
// morph-children
|
||
var morphChildren = function(oldParent, newParent) { return (function() {
|
||
var oldKids = domChildList(oldParent);
|
||
var newKids = domChildList(newParent);
|
||
var oldById = reduce(function(acc, kid) { return (function() {
|
||
var id = domId(kid);
|
||
return (isSxTruthy(id) ? (dictSet(acc, id, kid), acc) : acc);
|
||
})(); }, {}, oldKids);
|
||
var oi = 0;
|
||
{ var _c = newKids; for (var _i = 0; _i < _c.length; _i++) { var newChild = _c[_i]; (function() {
|
||
var matchId = domId(newChild);
|
||
var matchById = (isSxTruthy(matchId) ? dictGet(oldById, matchId) : NIL);
|
||
return (isSxTruthy((isSxTruthy(matchById) && !isSxTruthy(isNil(matchById)))) ? ((isSxTruthy((isSxTruthy((oi < len(oldKids))) && !isSxTruthy((matchById == nth(oldKids, oi))))) ? domInsertBefore(oldParent, matchById, (isSxTruthy((oi < len(oldKids))) ? nth(oldKids, oi) : NIL)) : NIL), morphNode(matchById, newChild), (oi = (oi + 1))) : (isSxTruthy((oi < len(oldKids))) ? (function() {
|
||
var oldChild = nth(oldKids, oi);
|
||
return (isSxTruthy((isSxTruthy(domId(oldChild)) && !isSxTruthy(matchId))) ? domInsertBefore(oldParent, domClone(newChild), oldChild) : (morphNode(oldChild, newChild), (oi = (oi + 1))));
|
||
})() : domAppend(oldParent, domClone(newChild))));
|
||
})(); } }
|
||
return forEach(function(i) { return (isSxTruthy((i >= oi)) ? (function() {
|
||
var leftover = nth(oldKids, i);
|
||
return (isSxTruthy((isSxTruthy(domIsChildOf(leftover, oldParent)) && isSxTruthy(!isSxTruthy(domHasAttr(leftover, "sx-preserve"))) && !isSxTruthy(domHasAttr(leftover, "sx-ignore")))) ? domRemoveChild(oldParent, leftover) : NIL);
|
||
})() : NIL); }, range(oi, len(oldKids)));
|
||
})(); };
|
||
|
||
// morph-island-children
|
||
var morphIslandChildren = function(oldIsland, newIsland) { return (function() {
|
||
var oldLakes = domQueryAll(oldIsland, "[data-sx-lake]");
|
||
var newLakes = domQueryAll(newIsland, "[data-sx-lake]");
|
||
var oldMarshes = domQueryAll(oldIsland, "[data-sx-marsh]");
|
||
var newMarshes = domQueryAll(newIsland, "[data-sx-marsh]");
|
||
return (function() {
|
||
var newLakeMap = {};
|
||
var newMarshMap = {};
|
||
{ var _c = newLakes; for (var _i = 0; _i < _c.length; _i++) { var lake = _c[_i]; (function() {
|
||
var id = domGetAttr(lake, "data-sx-lake");
|
||
return (isSxTruthy(id) ? dictSet(newLakeMap, id, lake) : NIL);
|
||
})(); } }
|
||
{ var _c = newMarshes; for (var _i = 0; _i < _c.length; _i++) { var marsh = _c[_i]; (function() {
|
||
var id = domGetAttr(marsh, "data-sx-marsh");
|
||
return (isSxTruthy(id) ? dictSet(newMarshMap, id, marsh) : NIL);
|
||
})(); } }
|
||
{ var _c = oldLakes; for (var _i = 0; _i < _c.length; _i++) { var oldLake = _c[_i]; (function() {
|
||
var id = domGetAttr(oldLake, "data-sx-lake");
|
||
return (function() {
|
||
var newLake = dictGet(newLakeMap, id);
|
||
return (isSxTruthy(newLake) ? (syncAttrs(oldLake, newLake), morphChildren(oldLake, newLake)) : NIL);
|
||
})();
|
||
})(); } }
|
||
{ var _c = oldMarshes; for (var _i = 0; _i < _c.length; _i++) { var oldMarsh = _c[_i]; (function() {
|
||
var id = domGetAttr(oldMarsh, "data-sx-marsh");
|
||
return (function() {
|
||
var newMarsh = dictGet(newMarshMap, id);
|
||
return (isSxTruthy(newMarsh) ? morphMarsh(oldMarsh, newMarsh, oldIsland) : NIL);
|
||
})();
|
||
})(); } }
|
||
return processSignalUpdates(newIsland);
|
||
})();
|
||
})(); };
|
||
|
||
// morph-marsh
|
||
var morphMarsh = function(oldMarsh, newMarsh, islandEl) { return (function() {
|
||
var transform = domGetData(oldMarsh, "sx-marsh-transform");
|
||
var env = domGetData(oldMarsh, "sx-marsh-env");
|
||
var newHtml = domInnerHtml(newMarsh);
|
||
return (isSxTruthy((isSxTruthy(env) && isSxTruthy(newHtml) && !isSxTruthy(isEmpty(newHtml)))) ? (function() {
|
||
var parsed = parse(newHtml);
|
||
return (function() {
|
||
var sxContent = (isSxTruthy(transform) ? invoke(transform, parsed) : parsed);
|
||
disposeMarshScope(oldMarsh);
|
||
return withMarshScope(oldMarsh, function() { return (function() {
|
||
var newDom = renderToDom(sxContent, env, NIL);
|
||
domRemoveChildrenAfter(oldMarsh, NIL);
|
||
return domAppend(oldMarsh, newDom);
|
||
})(); });
|
||
})();
|
||
})() : (syncAttrs(oldMarsh, newMarsh), morphChildren(oldMarsh, newMarsh)));
|
||
})(); };
|
||
|
||
// process-signal-updates
|
||
var processSignalUpdates = function(root) { return (function() {
|
||
var signalEls = domQueryAll(root, "[data-sx-signal]");
|
||
return forEach(function(el) { return (function() {
|
||
var spec = domGetAttr(el, "data-sx-signal");
|
||
return (isSxTruthy(spec) ? (function() {
|
||
var colonIdx = indexOf_(spec, ":");
|
||
return (isSxTruthy((colonIdx > 0)) ? (function() {
|
||
var storeName = slice(spec, 0, colonIdx);
|
||
var rawValue = slice(spec, (colonIdx + 1));
|
||
(function() {
|
||
var parsed = jsonParse(rawValue);
|
||
return reset_b(useStore(storeName), parsed);
|
||
})();
|
||
return domRemoveAttr(el, "data-sx-signal");
|
||
})() : NIL);
|
||
})() : NIL);
|
||
})(); }, signalEls);
|
||
})(); };
|
||
|
||
// swap-dom-nodes
|
||
var swapDomNodes = function(target, newNodes, strategy) { return (function() { var _m = strategy; if (_m == "innerHTML") return (isSxTruthy(domIsFragment(newNodes)) ? morphChildren(target, newNodes) : (function() {
|
||
var wrapper = domCreateElement("div", NIL);
|
||
domAppend(wrapper, newNodes);
|
||
return morphChildren(target, wrapper);
|
||
})()); if (_m == "outerHTML") return (function() {
|
||
var parent = domParent(target);
|
||
(isSxTruthy(domIsFragment(newNodes)) ? (function() {
|
||
var fc = domFirstChild(newNodes);
|
||
return (isSxTruthy(fc) ? (morphNode(target, fc), (function() {
|
||
var sib = domNextSibling(fc);
|
||
return insertRemainingSiblings(parent, target, sib);
|
||
})()) : domRemoveChild(parent, target));
|
||
})() : morphNode(target, newNodes));
|
||
return parent;
|
||
})(); if (_m == "afterend") return domInsertAfter(target, newNodes); if (_m == "beforeend") return domAppend(target, newNodes); if (_m == "afterbegin") return domPrepend(target, newNodes); if (_m == "beforebegin") return domInsertBefore(domParent(target), newNodes, target); if (_m == "delete") return domRemoveChild(domParent(target), target); if (_m == "none") return NIL; return (isSxTruthy(domIsFragment(newNodes)) ? morphChildren(target, newNodes) : (function() {
|
||
var wrapper = domCreateElement("div", NIL);
|
||
domAppend(wrapper, newNodes);
|
||
return morphChildren(target, wrapper);
|
||
})()); })(); };
|
||
|
||
// insert-remaining-siblings
|
||
var insertRemainingSiblings = function(parent, refNode, sib) { return (isSxTruthy(sib) ? (function() {
|
||
var next = domNextSibling(sib);
|
||
domInsertAfter(refNode, sib);
|
||
return insertRemainingSiblings(parent, sib, next);
|
||
})() : NIL); };
|
||
|
||
// swap-html-string
|
||
var swapHtmlString = function(target, html, strategy) { return (function() { var _m = strategy; if (_m == "innerHTML") return domSetInnerHtml(target, html); if (_m == "outerHTML") return (function() {
|
||
var parent = domParent(target);
|
||
domInsertAdjacentHtml(target, "afterend", html);
|
||
domRemoveChild(parent, target);
|
||
return parent;
|
||
})(); if (_m == "afterend") return domInsertAdjacentHtml(target, "afterend", html); if (_m == "beforeend") return domInsertAdjacentHtml(target, "beforeend", html); if (_m == "afterbegin") return domInsertAdjacentHtml(target, "afterbegin", html); if (_m == "beforebegin") return domInsertAdjacentHtml(target, "beforebegin", html); if (_m == "delete") return domRemoveChild(domParent(target), target); if (_m == "none") return NIL; return domSetInnerHtml(target, html); })(); };
|
||
|
||
// handle-history
|
||
var handleHistory = function(el, url, respHeaders) { return (function() {
|
||
var pushUrl = domGetAttr(el, "sx-push-url");
|
||
var replaceUrl = domGetAttr(el, "sx-replace-url");
|
||
var hdrReplace = get(respHeaders, "replace-url");
|
||
return (isSxTruthy(hdrReplace) ? browserReplaceState(hdrReplace) : (isSxTruthy((isSxTruthy(pushUrl) && !isSxTruthy((pushUrl == "false")))) ? browserPushState((isSxTruthy((pushUrl == "true")) ? url : pushUrl)) : (isSxTruthy((isSxTruthy(replaceUrl) && !isSxTruthy((replaceUrl == "false")))) ? browserReplaceState((isSxTruthy((replaceUrl == "true")) ? url : replaceUrl)) : NIL)));
|
||
})(); };
|
||
|
||
// PRELOAD_TTL
|
||
var PRELOAD_TTL = 30000;
|
||
|
||
// preload-cache-get
|
||
var preloadCacheGet = function(cache, url) { return (function() {
|
||
var entry = dictGet(cache, url);
|
||
return (isSxTruthy(isNil(entry)) ? NIL : (isSxTruthy(((nowMs() - get(entry, "timestamp")) > PRELOAD_TTL)) ? (dictDelete(cache, url), NIL) : (dictDelete(cache, url), entry)));
|
||
})(); };
|
||
|
||
// preload-cache-set
|
||
var preloadCacheSet = function(cache, url, text, contentType) { return dictSet(cache, url, {["text"]: text, ["content-type"]: contentType, ["timestamp"]: nowMs()}); };
|
||
|
||
// classify-trigger
|
||
var classifyTrigger = function(trigger) { return (function() {
|
||
var event = get(trigger, "event");
|
||
return (isSxTruthy((event == "every")) ? "poll" : (isSxTruthy((event == "intersect")) ? "intersect" : (isSxTruthy((event == "load")) ? "load" : (isSxTruthy((event == "revealed")) ? "revealed" : "event"))));
|
||
})(); };
|
||
|
||
// should-boost-link?
|
||
var shouldBoostLink = function(link) { return (function() {
|
||
var href = domGetAttr(link, "href");
|
||
return (isSxTruthy(href) && isSxTruthy(!isSxTruthy(startsWith(href, "#"))) && isSxTruthy(!isSxTruthy(startsWith(href, "javascript:"))) && isSxTruthy(!isSxTruthy(startsWith(href, "mailto:"))) && isSxTruthy(browserSameOrigin(href)) && isSxTruthy(!isSxTruthy(domHasAttr(link, "sx-get"))) && isSxTruthy(!isSxTruthy(domHasAttr(link, "sx-post"))) && !isSxTruthy(domHasAttr(link, "sx-disable")));
|
||
})(); };
|
||
|
||
// should-boost-form?
|
||
var shouldBoostForm = function(form) { return (isSxTruthy(!isSxTruthy(domHasAttr(form, "sx-get"))) && isSxTruthy(!isSxTruthy(domHasAttr(form, "sx-post"))) && !isSxTruthy(domHasAttr(form, "sx-disable"))); };
|
||
|
||
// parse-sse-swap
|
||
var parseSseSwap = function(el) { return sxOr(domGetAttr(el, "sx-sse-swap"), "message"); };
|
||
|
||
|
||
// === Transpiled from orchestration ===
|
||
|
||
// _preload-cache
|
||
var _preloadCache = {};
|
||
|
||
// _css-hash
|
||
var _cssHash = "";
|
||
|
||
// dispatch-trigger-events
|
||
var dispatchTriggerEvents = function(el, headerVal) { return (isSxTruthy(headerVal) ? (function() {
|
||
var parsed = tryParseJson(headerVal);
|
||
return (isSxTruthy(parsed) ? forEach(function(key) { return domDispatch(el, key, get(parsed, key)); }, keys(parsed)) : forEach(function(name) { return (function() {
|
||
var trimmed = trim(name);
|
||
return (isSxTruthy(!isSxTruthy(isEmpty(trimmed))) ? domDispatch(el, trimmed, {}) : NIL);
|
||
})(); }, split(headerVal, ",")));
|
||
})() : NIL); };
|
||
|
||
// init-css-tracking
|
||
var initCssTracking = function() { return (function() {
|
||
var meta = domQuery("meta[name=\"sx-css-classes\"]");
|
||
return (isSxTruthy(meta) ? (function() {
|
||
var content = domGetAttr(meta, "content");
|
||
return (isSxTruthy(content) ? (_cssHash = content) : NIL);
|
||
})() : NIL);
|
||
})(); };
|
||
|
||
// execute-request
|
||
var executeRequest = function(el, verbInfo, extraParams) { return (function() {
|
||
var info = sxOr(getVerbInfo(el), verbInfo);
|
||
return (isSxTruthy(isNil(info)) ? promiseResolve(NIL) : (function() {
|
||
var verb = get(info, "method");
|
||
var url = get(info, "url");
|
||
return (isSxTruthy((function() {
|
||
var media = domGetAttr(el, "sx-media");
|
||
return (isSxTruthy(media) && !isSxTruthy(browserMediaMatches(media)));
|
||
})()) ? promiseResolve(NIL) : (isSxTruthy((function() {
|
||
var confirmMsg = domGetAttr(el, "sx-confirm");
|
||
return (isSxTruthy(confirmMsg) && !isSxTruthy(browserConfirm(confirmMsg)));
|
||
})()) ? promiseResolve(NIL) : (function() {
|
||
var promptMsg = domGetAttr(el, "sx-prompt");
|
||
var promptVal = (isSxTruthy(promptMsg) ? browserPrompt(promptMsg) : NIL);
|
||
return (isSxTruthy((isSxTruthy(promptMsg) && isNil(promptVal))) ? promiseResolve(NIL) : (isSxTruthy(!isSxTruthy(validateForRequest(el))) ? promiseResolve(NIL) : doFetch(el, verb, verb, url, (isSxTruthy(promptVal) ? assoc(sxOr(extraParams, {}), "SX-Prompt", promptVal) : extraParams))));
|
||
})()));
|
||
})());
|
||
})(); };
|
||
|
||
// do-fetch
|
||
var doFetch = function(el, verb, method, url, extraParams) { return (function() {
|
||
var sync = domGetAttr(el, "sx-sync");
|
||
if (isSxTruthy((sync == "replace"))) {
|
||
abortPrevious(el);
|
||
}
|
||
(function() {
|
||
var targetEl = resolveTarget(el);
|
||
return (isSxTruthy((isSxTruthy(targetEl) && !isSxTruthy(isIdentical(el, targetEl)))) ? abortPreviousTarget(targetEl) : NIL);
|
||
})();
|
||
return (function() {
|
||
var ctrl = newAbortController();
|
||
trackController(el, ctrl);
|
||
(function() {
|
||
var targetEl = resolveTarget(el);
|
||
return (isSxTruthy(targetEl) ? trackControllerTarget(targetEl, ctrl) : NIL);
|
||
})();
|
||
return (function() {
|
||
var bodyInfo = buildRequestBody(el, method, url);
|
||
var finalUrl = get(bodyInfo, "url");
|
||
var body = get(bodyInfo, "body");
|
||
var ct = get(bodyInfo, "content-type");
|
||
var headers = buildRequestHeaders(el, loadedComponentNames(), _cssHash);
|
||
var csrf = csrfToken();
|
||
if (isSxTruthy(extraParams)) {
|
||
{ var _c = keys(extraParams); for (var _i = 0; _i < _c.length; _i++) { var k = _c[_i]; headers[k] = get(extraParams, k); } }
|
||
}
|
||
if (isSxTruthy(ct)) {
|
||
headers["Content-Type"] = ct;
|
||
}
|
||
if (isSxTruthy(csrf)) {
|
||
headers["X-CSRFToken"] = csrf;
|
||
}
|
||
return (function() {
|
||
var cached = preloadCacheGet(_preloadCache, finalUrl);
|
||
var optimisticState = applyOptimistic(el);
|
||
var indicator = showIndicator(el);
|
||
var disabledElts = disableElements(el);
|
||
domAddClass(el, "sx-request");
|
||
domSetAttr(el, "aria-busy", "true");
|
||
domDispatch(el, "sx:beforeRequest", {["url"]: finalUrl, ["method"]: method});
|
||
return fetchRequest({["url"]: finalUrl, ["method"]: method, ["headers"]: headers, ["body"]: body, ["signal"]: controllerSignal(ctrl), ["cross-origin"]: isCrossOrigin(finalUrl), ["preloaded"]: cached}, function(respOk, status, getHeader, text) { return (clearLoadingState(el, indicator, disabledElts), revertOptimistic(optimisticState), (isSxTruthy(!isSxTruthy(respOk)) ? (domDispatch(el, "sx:responseError", {["status"]: status, ["text"]: text}), (isSxTruthy((isSxTruthy(text) && (len(text) > 0))) ? handleFetchSuccess(el, finalUrl, verb, extraParams, getHeader, text) : handleRetry(el, verb, method, finalUrl, extraParams))) : (domDispatch(el, "sx:afterRequest", {["status"]: status}), handleFetchSuccess(el, finalUrl, verb, extraParams, getHeader, text)))); }, function(err) { return (clearLoadingState(el, indicator, disabledElts), revertOptimistic(optimisticState), (isSxTruthy(!isSxTruthy(isAbortError(err))) ? domDispatch(el, "sx:requestError", {["error"]: err}) : NIL)); });
|
||
})();
|
||
})();
|
||
})();
|
||
})(); };
|
||
|
||
// handle-fetch-success
|
||
var handleFetchSuccess = function(el, url, verb, extraParams, getHeader, text) { return (function() {
|
||
var respHeaders = processResponseHeaders(getHeader);
|
||
(function() {
|
||
var newHash = get(respHeaders, "css-hash");
|
||
return (isSxTruthy(newHash) ? (_cssHash = newHash) : NIL);
|
||
})();
|
||
dispatchTriggerEvents(el, get(respHeaders, "trigger"));
|
||
processCacheDirectives(el, respHeaders, text);
|
||
return (isSxTruthy(get(respHeaders, "redirect")) ? browserNavigate(get(respHeaders, "redirect")) : (isSxTruthy(get(respHeaders, "refresh")) ? browserReload() : (isSxTruthy(get(respHeaders, "location")) ? fetchLocation(get(respHeaders, "location")) : (function() {
|
||
var targetEl = (isSxTruthy(get(respHeaders, "retarget")) ? domQuery(get(respHeaders, "retarget")) : resolveTarget(el));
|
||
var swapSpec = parseSwapSpec(sxOr(get(respHeaders, "reswap"), domGetAttr(el, "sx-swap")), domHasClass(domBody(), "sx-transitions"));
|
||
var swapStyle = get(swapSpec, "style");
|
||
var useTransition = get(swapSpec, "transition");
|
||
var ct = sxOr(get(respHeaders, "content-type"), "");
|
||
(isSxTruthy(contains(ct, "text/sx")) ? handleSxResponse(el, targetEl, text, swapStyle, useTransition) : handleHtmlResponse(el, targetEl, text, swapStyle, useTransition));
|
||
dispatchTriggerEvents(el, get(respHeaders, "trigger-swap"));
|
||
handleHistory(el, url, respHeaders);
|
||
setTimeout_(function() { if (isSxTruthy(get(respHeaders, "trigger-settle"))) {
|
||
dispatchTriggerEvents(el, get(respHeaders, "trigger-settle"));
|
||
}
|
||
return processSettleHooks(el); }, 20);
|
||
return domDispatch(el, "sx:afterSwap", {["target"]: targetEl, ["swap"]: swapStyle});
|
||
})())));
|
||
})(); };
|
||
|
||
// handle-sx-response
|
||
var handleSxResponse = function(el, target, text, swapStyle, useTransition) { return (function() {
|
||
var cleaned = stripComponentScripts(text);
|
||
return (function() {
|
||
var final_ = extractResponseCss(cleaned);
|
||
return (function() {
|
||
var trimmed = trim(final_);
|
||
return (isSxTruthy(!isSxTruthy(isEmpty(trimmed))) ? (function() {
|
||
var rendered = sxRender(trimmed);
|
||
var container = domCreateElement("div", NIL);
|
||
domAppend(container, rendered);
|
||
processOobSwaps(container, function(t, oob, s) { disposeIslandsIn(t);
|
||
swapDomNodes(t, oob, s);
|
||
sxHydrate(t);
|
||
return processElements(t); });
|
||
return (function() {
|
||
var selectSel = domGetAttr(el, "sx-select");
|
||
var content = (isSxTruthy(selectSel) ? selectFromContainer(container, selectSel) : childrenToFragment(container));
|
||
disposeIslandsIn(target);
|
||
return withTransition(useTransition, function() { swapDomNodes(target, content, swapStyle);
|
||
return postSwap(target); });
|
||
})();
|
||
})() : NIL);
|
||
})();
|
||
})();
|
||
})(); };
|
||
|
||
// handle-html-response
|
||
var handleHtmlResponse = function(el, target, text, swapStyle, useTransition) { return (function() {
|
||
var doc = domParseHtmlDocument(text);
|
||
return (isSxTruthy(doc) ? (function() {
|
||
var selectSel = domGetAttr(el, "sx-select");
|
||
disposeIslandsIn(target);
|
||
return (isSxTruthy(selectSel) ? (function() {
|
||
var html = selectHtmlFromDoc(doc, selectSel);
|
||
return withTransition(useTransition, function() { swapHtmlString(target, html, swapStyle);
|
||
return postSwap(target); });
|
||
})() : (function() {
|
||
var container = domCreateElement("div", NIL);
|
||
domSetInnerHtml(container, domBodyInnerHtml(doc));
|
||
processOobSwaps(container, function(t, oob, s) { disposeIslandsIn(t);
|
||
swapDomNodes(t, oob, s);
|
||
return postSwap(t); });
|
||
hoistHeadElements(container);
|
||
return withTransition(useTransition, function() { swapDomNodes(target, childrenToFragment(container), swapStyle);
|
||
return postSwap(target); });
|
||
})());
|
||
})() : NIL);
|
||
})(); };
|
||
|
||
// handle-retry
|
||
var handleRetry = function(el, verb, method, url, extraParams) { return (function() {
|
||
var retryAttr = domGetAttr(el, "sx-retry");
|
||
var spec = parseRetrySpec(retryAttr);
|
||
return (isSxTruthy(spec) ? (function() {
|
||
var currentMs = sxOr(domGetAttr(el, "data-sx-retry-ms"), get(spec, "start-ms"));
|
||
return (function() {
|
||
var ms = parseInt_(currentMs, get(spec, "start-ms"));
|
||
domSetAttr(el, "data-sx-retry-ms", (String(nextRetryMs(ms, get(spec, "cap-ms")))));
|
||
return setTimeout_(function() { return doFetch(el, verb, method, url, extraParams); }, ms);
|
||
})();
|
||
})() : NIL);
|
||
})(); };
|
||
|
||
// bind-triggers
|
||
var bindTriggers = function(el, verbInfo) { return (function() {
|
||
var triggers = sxOr(parseTriggerSpec(domGetAttr(el, "sx-trigger")), defaultTrigger(domTagName(el)));
|
||
return forEach(function(trigger) { return (function() {
|
||
var kind = classifyTrigger(trigger);
|
||
var mods = get(trigger, "modifiers");
|
||
return (isSxTruthy((kind == "poll")) ? setInterval_(function() { return executeRequest(el, NIL, NIL); }, get(mods, "interval")) : (isSxTruthy((kind == "intersect")) ? observeIntersection(el, function() { return executeRequest(el, NIL, NIL); }, false, get(mods, "delay")) : (isSxTruthy((kind == "load")) ? setTimeout_(function() { return executeRequest(el, NIL, NIL); }, sxOr(get(mods, "delay"), 0)) : (isSxTruthy((kind == "revealed")) ? observeIntersection(el, function() { return executeRequest(el, NIL, NIL); }, true, get(mods, "delay")) : (isSxTruthy((kind == "event")) ? bindEvent(el, get(trigger, "event"), mods, verbInfo) : NIL)))));
|
||
})(); }, triggers);
|
||
})(); };
|
||
|
||
// bind-event
|
||
var bindEvent = function(el, eventName, mods, verbInfo) { return (function() {
|
||
var timer = NIL;
|
||
var lastVal = NIL;
|
||
var listenTarget = (isSxTruthy(get(mods, "from")) ? domQuery(get(mods, "from")) : el);
|
||
return (isSxTruthy(listenTarget) ? domAddListener(listenTarget, eventName, function(e) { return (function() {
|
||
var shouldFire = true;
|
||
if (isSxTruthy(get(mods, "changed"))) {
|
||
(function() {
|
||
var val = elementValue(el);
|
||
return (isSxTruthy((val == lastVal)) ? (shouldFire = false) : (lastVal = val));
|
||
})();
|
||
}
|
||
return (isSxTruthy(shouldFire) ? ((isSxTruthy(sxOr((eventName == "submit"), (isSxTruthy((eventName == "click")) && domHasAttr(el, "href")))) ? preventDefault_(e) : NIL), (function() {
|
||
var liveInfo = sxOr(getVerbInfo(el), verbInfo);
|
||
var isGetLink = (isSxTruthy((eventName == "click")) && isSxTruthy((get(liveInfo, "method") == "GET")) && isSxTruthy(domHasAttr(el, "href")) && !isSxTruthy(get(mods, "delay")));
|
||
var clientRouted = false;
|
||
if (isSxTruthy(isGetLink)) {
|
||
clientRouted = tryClientRoute(urlPathname(get(liveInfo, "url")), domGetAttr(el, "sx-target"));
|
||
}
|
||
return (isSxTruthy(clientRouted) ? (browserPushState(get(liveInfo, "url")), browserScrollTo(0, 0)) : ((isSxTruthy(isGetLink) ? logInfo((String("sx:route server fetch ") + String(get(liveInfo, "url")))) : NIL), (isSxTruthy(get(mods, "delay")) ? (clearTimeout_(timer), (timer = setTimeout_(function() { return executeRequest(el, NIL, NIL); }, get(mods, "delay")))) : executeRequest(el, NIL, NIL))));
|
||
})()) : NIL);
|
||
})(); }, (isSxTruthy(get(mods, "once")) ? {["once"]: true} : NIL)) : NIL);
|
||
})(); };
|
||
|
||
// post-swap
|
||
var postSwap = function(root) { activateScripts(root);
|
||
sxProcessScripts(root);
|
||
sxHydrate(root);
|
||
sxHydrateIslands(root);
|
||
return processElements(root); };
|
||
|
||
// process-settle-hooks
|
||
var processSettleHooks = function(el) { return (function() {
|
||
var settleExpr = domGetAttr(el, "sx-on-settle");
|
||
return (isSxTruthy((isSxTruthy(settleExpr) && !isSxTruthy(isEmpty(settleExpr)))) ? (function() {
|
||
var exprs = sxParse(settleExpr);
|
||
return forEach(function(expr) { return evalExpr(expr, envExtend({})); }, exprs);
|
||
})() : NIL);
|
||
})(); };
|
||
|
||
// activate-scripts
|
||
var activateScripts = function(root) { return (isSxTruthy(root) ? (function() {
|
||
var scripts = domQueryAll(root, "script");
|
||
return forEach(function(dead) { return (isSxTruthy((isSxTruthy(!isSxTruthy(domHasAttr(dead, "data-components"))) && !isSxTruthy(domHasAttr(dead, "data-sx-activated")))) ? (function() {
|
||
var live = createScriptClone(dead);
|
||
domSetAttr(live, "data-sx-activated", "true");
|
||
return domReplaceChild(domParent(dead), live, dead);
|
||
})() : NIL); }, scripts);
|
||
})() : NIL); };
|
||
|
||
// process-oob-swaps
|
||
var processOobSwaps = function(container, swapFn) { return (function() {
|
||
var oobs = findOobSwaps(container);
|
||
return forEach(function(oob) { return (function() {
|
||
var targetId = get(oob, "target-id");
|
||
var target = domQueryById(targetId);
|
||
var oobEl = get(oob, "element");
|
||
var swapType = get(oob, "swap-type");
|
||
if (isSxTruthy(domParent(oobEl))) {
|
||
domRemoveChild(domParent(oobEl), oobEl);
|
||
}
|
||
return (isSxTruthy(target) ? swapFn(target, oobEl, swapType) : NIL);
|
||
})(); }, oobs);
|
||
})(); };
|
||
|
||
// hoist-head-elements
|
||
var hoistHeadElements = function(container) { { var _c = domQueryAll(container, "style[data-sx-css]"); for (var _i = 0; _i < _c.length; _i++) { var style = _c[_i]; if (isSxTruthy(domParent(style))) {
|
||
domRemoveChild(domParent(style), style);
|
||
}
|
||
domAppendToHead(style); } }
|
||
return forEach(function(link) { if (isSxTruthy(domParent(link))) {
|
||
domRemoveChild(domParent(link), link);
|
||
}
|
||
return domAppendToHead(link); }, domQueryAll(container, "link[rel=\"stylesheet\"]")); };
|
||
|
||
// process-boosted
|
||
var processBoosted = function(root) { return forEach(function(container) { return boostDescendants(container); }, domQueryAll(sxOr(root, domBody()), "[sx-boost]")); };
|
||
|
||
// boost-descendants
|
||
var boostDescendants = function(container) { return (function() {
|
||
var boostTarget = domGetAttr(container, "sx-boost");
|
||
{ var _c = domQueryAll(container, "a[href]"); for (var _i = 0; _i < _c.length; _i++) { var link = _c[_i]; if (isSxTruthy((isSxTruthy(!isSxTruthy(isProcessed(link, "boost"))) && shouldBoostLink(link)))) {
|
||
markProcessed(link, "boost");
|
||
if (isSxTruthy((isSxTruthy(!isSxTruthy(domHasAttr(link, "sx-target"))) && isSxTruthy(boostTarget) && !isSxTruthy((boostTarget == "true"))))) {
|
||
domSetAttr(link, "sx-target", boostTarget);
|
||
}
|
||
if (isSxTruthy(!isSxTruthy(domHasAttr(link, "sx-swap")))) {
|
||
domSetAttr(link, "sx-swap", "innerHTML");
|
||
}
|
||
if (isSxTruthy(!isSxTruthy(domHasAttr(link, "sx-push-url")))) {
|
||
domSetAttr(link, "sx-push-url", "true");
|
||
}
|
||
bindClientRouteLink(link, domGetAttr(link, "href"));
|
||
} } }
|
||
return forEach(function(form) { return (isSxTruthy((isSxTruthy(!isSxTruthy(isProcessed(form, "boost"))) && shouldBoostForm(form))) ? (markProcessed(form, "boost"), (function() {
|
||
var method = upper(sxOr(domGetAttr(form, "method"), "GET"));
|
||
var action = sxOr(domGetAttr(form, "action"), browserLocationHref());
|
||
if (isSxTruthy((isSxTruthy(!isSxTruthy(domHasAttr(form, "sx-target"))) && isSxTruthy(boostTarget) && !isSxTruthy((boostTarget == "true"))))) {
|
||
domSetAttr(form, "sx-target", boostTarget);
|
||
}
|
||
if (isSxTruthy(!isSxTruthy(domHasAttr(form, "sx-swap")))) {
|
||
domSetAttr(form, "sx-swap", "innerHTML");
|
||
}
|
||
return bindBoostForm(form, method, action);
|
||
})()) : NIL); }, domQueryAll(container, "form"));
|
||
})(); };
|
||
|
||
// _page-data-cache
|
||
var _pageDataCache = {};
|
||
|
||
// _page-data-cache-ttl
|
||
var _pageDataCacheTtl = 30000;
|
||
|
||
// page-data-cache-key
|
||
var pageDataCacheKey = function(pageName, params) { return (function() {
|
||
var base = pageName;
|
||
return (isSxTruthy(sxOr(isNil(params), isEmpty(keys(params)))) ? base : (function() {
|
||
var parts = [];
|
||
{ var _c = keys(params); for (var _i = 0; _i < _c.length; _i++) { var k = _c[_i]; parts.push((String(k) + String("=") + String(get(params, k)))); } }
|
||
return (String(base) + String(":") + String(join("&", parts)));
|
||
})());
|
||
})(); };
|
||
|
||
// page-data-cache-get
|
||
var pageDataCacheGet = function(cacheKey) { return (function() {
|
||
var entry = get(_pageDataCache, cacheKey);
|
||
return (isSxTruthy(isNil(entry)) ? NIL : (isSxTruthy(((nowMs() - get(entry, "ts")) > _pageDataCacheTtl)) ? (dictSet(_pageDataCache, cacheKey, NIL), NIL) : get(entry, "data")));
|
||
})(); };
|
||
|
||
// page-data-cache-set
|
||
var pageDataCacheSet = function(cacheKey, data) { return dictSet(_pageDataCache, cacheKey, {"data": data, "ts": nowMs()}); };
|
||
|
||
// invalidate-page-cache
|
||
var invalidatePageCache = function(pageName) { { var _c = keys(_pageDataCache); for (var _i = 0; _i < _c.length; _i++) { var k = _c[_i]; if (isSxTruthy(sxOr((k == pageName), startsWith(k, (String(pageName) + String(":")))))) {
|
||
_pageDataCache[k] = NIL;
|
||
} } }
|
||
swPostMessage({"type": "invalidate", "page": pageName});
|
||
return logInfo((String("sx:cache invalidate ") + String(pageName))); };
|
||
|
||
// invalidate-all-page-cache
|
||
var invalidateAllPageCache = function() { _pageDataCache = {};
|
||
swPostMessage({"type": "invalidate", "page": "*"});
|
||
return logInfo("sx:cache invalidate *"); };
|
||
|
||
// update-page-cache
|
||
var updatePageCache = function(pageName, data) { return (function() {
|
||
var cacheKey = pageDataCacheKey(pageName, {});
|
||
pageDataCacheSet(cacheKey, data);
|
||
return logInfo((String("sx:cache update ") + String(pageName)));
|
||
})(); };
|
||
|
||
// process-cache-directives
|
||
var processCacheDirectives = function(el, respHeaders, responseText) { (function() {
|
||
var elInvalidate = domGetAttr(el, "sx-cache-invalidate");
|
||
return (isSxTruthy(elInvalidate) ? (isSxTruthy((elInvalidate == "*")) ? invalidateAllPageCache() : invalidatePageCache(elInvalidate)) : NIL);
|
||
})();
|
||
(function() {
|
||
var hdrInvalidate = get(respHeaders, "cache-invalidate");
|
||
return (isSxTruthy(hdrInvalidate) ? (isSxTruthy((hdrInvalidate == "*")) ? invalidateAllPageCache() : invalidatePageCache(hdrInvalidate)) : NIL);
|
||
})();
|
||
return (function() {
|
||
var hdrUpdate = get(respHeaders, "cache-update");
|
||
return (isSxTruthy(hdrUpdate) ? (function() {
|
||
var data = parseSxData(responseText);
|
||
return (isSxTruthy(data) ? updatePageCache(hdrUpdate, data) : NIL);
|
||
})() : NIL);
|
||
})(); };
|
||
|
||
// _optimistic-snapshots
|
||
var _optimisticSnapshots = {};
|
||
|
||
// optimistic-cache-update
|
||
var optimisticCacheUpdate = function(cacheKey, mutator) { return (function() {
|
||
var cached = pageDataCacheGet(cacheKey);
|
||
return (isSxTruthy(cached) ? (function() {
|
||
var predicted = mutator(cached);
|
||
_optimisticSnapshots[cacheKey] = cached;
|
||
pageDataCacheSet(cacheKey, predicted);
|
||
return predicted;
|
||
})() : NIL);
|
||
})(); };
|
||
|
||
// optimistic-cache-revert
|
||
var optimisticCacheRevert = function(cacheKey) { return (function() {
|
||
var snapshot = get(_optimisticSnapshots, cacheKey);
|
||
return (isSxTruthy(snapshot) ? (pageDataCacheSet(cacheKey, snapshot), dictDelete(_optimisticSnapshots, cacheKey), snapshot) : NIL);
|
||
})(); };
|
||
|
||
// optimistic-cache-confirm
|
||
var optimisticCacheConfirm = function(cacheKey) { return dictDelete(_optimisticSnapshots, cacheKey); };
|
||
|
||
// submit-mutation
|
||
var submitMutation = function(pageName, params, actionName, payload, mutatorFn, onComplete) { return (function() {
|
||
var cacheKey = pageDataCacheKey(pageName, params);
|
||
var predicted = optimisticCacheUpdate(cacheKey, mutatorFn);
|
||
if (isSxTruthy(predicted)) {
|
||
tryRerenderPage(pageName, params, predicted);
|
||
}
|
||
return executeAction(actionName, payload, function(result) { if (isSxTruthy(result)) {
|
||
pageDataCacheSet(cacheKey, result);
|
||
}
|
||
optimisticCacheConfirm(cacheKey);
|
||
if (isSxTruthy(result)) {
|
||
tryRerenderPage(pageName, params, result);
|
||
}
|
||
logInfo((String("sx:optimistic confirmed ") + String(pageName)));
|
||
return (isSxTruthy(onComplete) ? onComplete("confirmed") : NIL); }, function(error) { return (function() {
|
||
var reverted = optimisticCacheRevert(cacheKey);
|
||
if (isSxTruthy(reverted)) {
|
||
tryRerenderPage(pageName, params, reverted);
|
||
}
|
||
logWarn((String("sx:optimistic reverted ") + String(pageName) + String(": ") + String(error)));
|
||
return (isSxTruthy(onComplete) ? onComplete("reverted") : NIL);
|
||
})(); });
|
||
})(); };
|
||
|
||
// _is-online
|
||
var _isOnline = true;
|
||
|
||
// _offline-queue
|
||
var _offlineQueue = [];
|
||
|
||
// offline-is-online?
|
||
var offlineIsOnline_p = function() { return _isOnline; };
|
||
|
||
// offline-set-online!
|
||
var offlineSetOnline_b = function(val) { return (_isOnline = val); };
|
||
|
||
// offline-queue-mutation
|
||
var offlineQueueMutation = function(actionName, payload, pageName, params, mutatorFn) { return (function() {
|
||
var cacheKey = pageDataCacheKey(pageName, params);
|
||
var entry = {["action"]: actionName, ["payload"]: payload, ["page"]: pageName, ["params"]: params, ["timestamp"]: nowMs(), ["status"]: "pending"};
|
||
_offlineQueue.push(entry);
|
||
(function() {
|
||
var predicted = optimisticCacheUpdate(cacheKey, mutatorFn);
|
||
return (isSxTruthy(predicted) ? tryRerenderPage(pageName, params, predicted) : NIL);
|
||
})();
|
||
logInfo((String("sx:offline queued ") + String(actionName) + String(" (") + String(len(_offlineQueue)) + String(" pending)")));
|
||
return entry;
|
||
})(); };
|
||
|
||
// offline-sync
|
||
var offlineSync = function() { return (function() {
|
||
var pending = filter(function(e) { return (get(e, "status") == "pending"); }, _offlineQueue);
|
||
return (isSxTruthy(!isSxTruthy(isEmpty(pending))) ? (logInfo((String("sx:offline syncing ") + String(len(pending)) + String(" mutations"))), forEach(function(entry) { return executeAction(get(entry, "action"), get(entry, "payload"), function(result) { entry["status"] = "synced";
|
||
return logInfo((String("sx:offline synced ") + String(get(entry, "action")))); }, function(error) { entry["status"] = "failed";
|
||
return logWarn((String("sx:offline sync failed ") + String(get(entry, "action")) + String(": ") + String(error))); }); }, pending)) : NIL);
|
||
})(); };
|
||
|
||
// offline-pending-count
|
||
var offlinePendingCount = function() { return len(filter(function(e) { return (get(e, "status") == "pending"); }, _offlineQueue)); };
|
||
|
||
// offline-aware-mutation
|
||
var offlineAwareMutation = function(pageName, params, actionName, payload, mutatorFn, onComplete) { return (isSxTruthy(_isOnline) ? submitMutation(pageName, params, actionName, payload, mutatorFn, onComplete) : (offlineQueueMutation(actionName, payload, pageName, params, mutatorFn), (isSxTruthy(onComplete) ? onComplete("queued") : NIL))); };
|
||
|
||
// current-page-layout
|
||
var currentPageLayout = function() { return (function() {
|
||
var pathname = urlPathname(browserLocationHref());
|
||
var match = findMatchingRoute(pathname, _pageRoutes);
|
||
return (isSxTruthy(isNil(match)) ? "" : sxOr(get(match, "layout"), ""));
|
||
})(); };
|
||
|
||
// swap-rendered-content
|
||
var swapRenderedContent = function(target, rendered, pathname) { return (disposeIslandsIn(target), domSetTextContent(target, ""), domAppend(target, rendered), hoistHeadElementsFull(target), processElements(target), sxHydrateElements(target), domDispatch(target, "sx:clientRoute", {["pathname"]: pathname}), logInfo((String("sx:route client ") + String(pathname)))); };
|
||
|
||
// resolve-route-target
|
||
var resolveRouteTarget = function(targetSel) { return (isSxTruthy((isSxTruthy(targetSel) && !isSxTruthy((targetSel == "true")))) ? domQuery(targetSel) : NIL); };
|
||
|
||
// deps-satisfied?
|
||
var depsSatisfied_p = function(match) { return (function() {
|
||
var deps = get(match, "deps");
|
||
var loaded = loadedComponentNames();
|
||
return (isSxTruthy(sxOr(isNil(deps), isEmpty(deps))) ? true : isEvery(function(dep) { return contains(loaded, dep); }, deps));
|
||
})(); };
|
||
|
||
// try-client-route
|
||
var tryClientRoute = function(pathname, targetSel) { return (function() {
|
||
var match = findMatchingRoute(pathname, _pageRoutes);
|
||
return (isSxTruthy(isNil(match)) ? (logInfo((String("sx:route no match (") + String(len(_pageRoutes)) + String(" routes) ") + String(pathname))), false) : (function() {
|
||
var targetLayout = sxOr(get(match, "layout"), "");
|
||
var curLayout = currentPageLayout();
|
||
return (isSxTruthy(!isSxTruthy((targetLayout == curLayout))) ? (logInfo((String("sx:route server (layout: ") + String(curLayout) + String(" -> ") + String(targetLayout) + String(") ") + String(pathname))), false) : (function() {
|
||
var contentSrc = get(match, "content");
|
||
var closure = sxOr(get(match, "closure"), {});
|
||
var params = get(match, "params");
|
||
var pageName = get(match, "name");
|
||
return (isSxTruthy(sxOr(isNil(contentSrc), isEmpty(contentSrc))) ? (logWarn((String("sx:route no content for ") + String(pathname))), false) : (function() {
|
||
var target = resolveRouteTarget(targetSel);
|
||
return (isSxTruthy(isNil(target)) ? (logWarn((String("sx:route target not found: ") + String(targetSel))), false) : (isSxTruthy(!isSxTruthy(depsSatisfied_p(match))) ? (logInfo((String("sx:route deps miss for ") + String(pageName))), false) : (function() {
|
||
var ioDeps = get(match, "io-deps");
|
||
var hasIo = (isSxTruthy(ioDeps) && !isSxTruthy(isEmpty(ioDeps)));
|
||
var renderPlan = get(match, "render-plan");
|
||
if (isSxTruthy(renderPlan)) {
|
||
(function() {
|
||
var srv = sxOr(get(renderPlan, "server"), []);
|
||
var cli = sxOr(get(renderPlan, "client"), []);
|
||
return logInfo((String("sx:route plan ") + String(pageName) + String(" — ") + String(len(srv)) + String(" server, ") + String(len(cli)) + String(" client")));
|
||
})();
|
||
}
|
||
if (isSxTruthy(hasIo)) {
|
||
registerIoDeps(ioDeps);
|
||
}
|
||
return (isSxTruthy(get(match, "stream")) ? (logInfo((String("sx:route streaming ") + String(pathname))), fetchStreaming(target, pathname, buildRequestHeaders(target, loadedComponentNames(), _cssHash)), true) : (isSxTruthy(get(match, "has-data")) ? (function() {
|
||
var cacheKey = pageDataCacheKey(pageName, params);
|
||
var cached = pageDataCacheGet(cacheKey);
|
||
return (isSxTruthy(cached) ? (function() {
|
||
var env = merge(closure, params, cached);
|
||
return (isSxTruthy(hasIo) ? (logInfo((String("sx:route client+cache+async ") + String(pathname))), tryAsyncEvalContent(contentSrc, env, function(rendered) { return (isSxTruthy(isNil(rendered)) ? (logWarn((String("sx:route cache+async eval failed for ") + String(pathname) + String(" — server fallback"))), fetchAndRestore(target, pathname, buildRequestHeaders(target, loadedComponentNames(), _cssHash), 0)) : swapRenderedContent(target, rendered, pathname)); }), true) : (function() {
|
||
var rendered = tryEvalContent(contentSrc, env);
|
||
return (isSxTruthy(isNil(rendered)) ? (logWarn((String("sx:route cached eval failed for ") + String(pathname))), false) : (logInfo((String("sx:route client+cache ") + String(pathname))), swapRenderedContent(target, rendered, pathname), true));
|
||
})());
|
||
})() : (logInfo((String("sx:route client+data ") + String(pathname))), resolvePageData(pageName, params, function(data) { pageDataCacheSet(cacheKey, data);
|
||
return (function() {
|
||
var env = merge(closure, params, data);
|
||
return (isSxTruthy(hasIo) ? tryAsyncEvalContent(contentSrc, env, function(rendered) { return (isSxTruthy(isNil(rendered)) ? (logWarn((String("sx:route data+async eval failed for ") + String(pathname) + String(" — server fallback"))), fetchAndRestore(target, pathname, buildRequestHeaders(target, loadedComponentNames(), _cssHash), 0)) : swapRenderedContent(target, rendered, pathname)); }) : (function() {
|
||
var rendered = tryEvalContent(contentSrc, env);
|
||
return (isSxTruthy(isNil(rendered)) ? (logWarn((String("sx:route data eval failed for ") + String(pathname) + String(" — server fallback"))), fetchAndRestore(target, pathname, buildRequestHeaders(target, loadedComponentNames(), _cssHash), 0)) : swapRenderedContent(target, rendered, pathname));
|
||
})());
|
||
})(); }), true));
|
||
})() : (isSxTruthy(hasIo) ? (logInfo((String("sx:route client+async ") + String(pathname))), tryAsyncEvalContent(contentSrc, merge(closure, params), function(rendered) { return (isSxTruthy(isNil(rendered)) ? (logWarn((String("sx:route async eval failed for ") + String(pathname) + String(" — server fallback"))), fetchAndRestore(target, pathname, buildRequestHeaders(target, loadedComponentNames(), _cssHash), 0)) : swapRenderedContent(target, rendered, pathname)); }), true) : (function() {
|
||
var env = merge(closure, params);
|
||
var rendered = tryEvalContent(contentSrc, env);
|
||
return (isSxTruthy(isNil(rendered)) ? (logInfo((String("sx:route server (eval failed) ") + String(pathname))), false) : (swapRenderedContent(target, rendered, pathname), true));
|
||
})())));
|
||
})()));
|
||
})());
|
||
})());
|
||
})());
|
||
})(); };
|
||
|
||
// bind-client-route-link
|
||
var bindClientRouteLink = function(link, href) { return bindClientRouteClick(link, href, function() { return bindBoostLink(link, href); }); };
|
||
|
||
// process-sse
|
||
var processSse = function(root) { return forEach(function(el) { return (isSxTruthy(!isSxTruthy(isProcessed(el, "sse"))) ? (markProcessed(el, "sse"), bindSse(el)) : NIL); }, domQueryAll(sxOr(root, domBody()), "[sx-sse]")); };
|
||
|
||
// bind-sse
|
||
var bindSse = function(el) { return (function() {
|
||
var url = domGetAttr(el, "sx-sse");
|
||
return (isSxTruthy(url) ? (function() {
|
||
var source = eventSourceConnect(url, el);
|
||
var eventName = parseSseSwap(el);
|
||
return eventSourceListen(source, eventName, function(data) { return bindSseSwap(el, data); });
|
||
})() : NIL);
|
||
})(); };
|
||
|
||
// bind-sse-swap
|
||
var bindSseSwap = function(el, data) { return (function() {
|
||
var target = resolveTarget(el);
|
||
var swapSpec = parseSwapSpec(domGetAttr(el, "sx-swap"), domHasClass(domBody(), "sx-transitions"));
|
||
var swapStyle = get(swapSpec, "style");
|
||
var useTransition = get(swapSpec, "transition");
|
||
var trimmed = trim(data);
|
||
return (isSxTruthy(!isSxTruthy(isEmpty(trimmed))) ? (disposeIslandsIn(target), (isSxTruthy(startsWith(trimmed, "(")) ? (function() {
|
||
var rendered = sxRender(trimmed);
|
||
var container = domCreateElement("div", NIL);
|
||
domAppend(container, rendered);
|
||
return withTransition(useTransition, function() { swapDomNodes(target, childrenToFragment(container), swapStyle);
|
||
return postSwap(target); });
|
||
})() : withTransition(useTransition, function() { swapHtmlString(target, trimmed, swapStyle);
|
||
return postSwap(target); }))) : NIL);
|
||
})(); };
|
||
|
||
// bind-inline-handlers
|
||
var bindInlineHandlers = function(root) { return forEach(function(el) { return forEach(function(attr) { return (function() {
|
||
var name = first(attr);
|
||
var body = nth(attr, 1);
|
||
return (isSxTruthy(startsWith(name, "sx-on:")) ? (function() {
|
||
var eventName = slice(name, 6);
|
||
return (isSxTruthy(!isSxTruthy(isProcessed(el, (String("on:") + String(eventName))))) ? (markProcessed(el, (String("on:") + String(eventName))), (function() {
|
||
var exprs = sxParse(body);
|
||
return domListen(el, eventName, function(e) { return (function() {
|
||
var handlerEnv = envExtend({});
|
||
envSet(handlerEnv, "event", e);
|
||
envSet(handlerEnv, "this", el);
|
||
envSet(handlerEnv, "detail", eventDetail(e));
|
||
return forEach(function(expr) { return evalExpr(expr, handlerEnv); }, exprs);
|
||
})(); });
|
||
})()) : NIL);
|
||
})() : NIL);
|
||
})(); }, domAttrList(el)); }, domQueryAll(sxOr(root, domBody()), "[sx-on\\:]")); };
|
||
|
||
// bind-preload-for
|
||
var bindPreloadFor = function(el) { return (function() {
|
||
var preloadAttr = domGetAttr(el, "sx-preload");
|
||
return (isSxTruthy(preloadAttr) ? (function() {
|
||
var events = (isSxTruthy((preloadAttr == "mousedown")) ? ["mousedown", "touchstart"] : ["mouseover"]);
|
||
var debounceMs = (isSxTruthy((preloadAttr == "mousedown")) ? 0 : 100);
|
||
return bindPreload(el, events, debounceMs, function() { return (function() {
|
||
var info = getVerbInfo(el);
|
||
return (isSxTruthy(info) ? doPreload(get(info, "url"), buildRequestHeaders(el, loadedComponentNames(), _cssHash)) : NIL);
|
||
})(); });
|
||
})() : NIL);
|
||
})(); };
|
||
|
||
// do-preload
|
||
var doPreload = function(url, headers) { return (isSxTruthy(isNil(preloadCacheGet(_preloadCache, url))) ? fetchPreload(url, headers, _preloadCache) : NIL); };
|
||
|
||
// VERB_SELECTOR
|
||
var VERB_SELECTOR = (String("[sx-get],[sx-post],[sx-put],[sx-delete],[sx-patch]"));
|
||
|
||
// process-elements
|
||
var processElements = function(root) { (function() {
|
||
var els = domQueryAll(sxOr(root, domBody()), VERB_SELECTOR);
|
||
return forEach(function(el) { return (isSxTruthy(!isSxTruthy(isProcessed(el, "verb"))) ? (markProcessed(el, "verb"), processOne(el)) : NIL); }, els);
|
||
})();
|
||
processBoosted(root);
|
||
processSse(root);
|
||
bindInlineHandlers(root);
|
||
return processEmitElements(root); };
|
||
|
||
// process-one
|
||
var processOne = function(el) { return (function() {
|
||
var verbInfo = getVerbInfo(el);
|
||
return (isSxTruthy(verbInfo) ? (isSxTruthy(!isSxTruthy(domHasAttr(el, "sx-disable"))) ? (bindTriggers(el, verbInfo), bindPreloadFor(el)) : NIL) : NIL);
|
||
})(); };
|
||
|
||
// process-emit-elements
|
||
var processEmitElements = function(root) { return (function() {
|
||
var els = domQueryAll(sxOr(root, domBody()), "[data-sx-emit]");
|
||
return forEach(function(el) { return (isSxTruthy(!isSxTruthy(isProcessed(el, "emit"))) ? (markProcessed(el, "emit"), (function() {
|
||
var eventName = domGetAttr(el, "data-sx-emit");
|
||
return (isSxTruthy(eventName) ? domListen(el, "click", function(e) { return (function() {
|
||
var detailJson = domGetAttr(el, "data-sx-emit-detail");
|
||
var detail = (isSxTruthy(detailJson) ? jsonParse(detailJson) : {});
|
||
return domDispatch(el, eventName, detail);
|
||
})(); }) : NIL);
|
||
})()) : NIL); }, els);
|
||
})(); };
|
||
|
||
// handle-popstate
|
||
var handlePopstate = function(scrollY) { return (function() {
|
||
var url = browserLocationHref();
|
||
var boostEl = domQuery("[sx-boost]");
|
||
var targetSel = (isSxTruthy(boostEl) ? (function() {
|
||
var attr = domGetAttr(boostEl, "sx-boost");
|
||
return (isSxTruthy((isSxTruthy(attr) && !isSxTruthy((attr == "true")))) ? attr : NIL);
|
||
})() : NIL);
|
||
var targetSel = sxOr(targetSel, "#main-panel");
|
||
var target = domQuery(targetSel);
|
||
var pathname = urlPathname(url);
|
||
return (isSxTruthy(target) ? (isSxTruthy(tryClientRoute(pathname, targetSel)) ? browserScrollTo(0, scrollY) : (function() {
|
||
var headers = buildRequestHeaders(target, loadedComponentNames(), _cssHash);
|
||
return fetchAndRestore(target, url, headers, scrollY);
|
||
})()) : NIL);
|
||
})(); };
|
||
|
||
// engine-init
|
||
var engineInit = function() { return (initCssTracking(), sxProcessScripts(NIL), sxHydrate(NIL), processElements(NIL)); };
|
||
|
||
|
||
// === Transpiled from boot ===
|
||
|
||
// HEAD_HOIST_SELECTOR
|
||
var HEAD_HOIST_SELECTOR = "meta, title, link[rel='canonical'], script[type='application/ld+json']";
|
||
|
||
// hoist-head-elements-full
|
||
var hoistHeadElementsFull = function(root) { return (function() {
|
||
var els = domQueryAll(root, HEAD_HOIST_SELECTOR);
|
||
return forEach(function(el) { return (function() {
|
||
var tag = lower(domTagName(el));
|
||
return (isSxTruthy((tag == "title")) ? (setDocumentTitle(domTextContent(el)), domRemoveChild(domParent(el), el)) : (isSxTruthy((tag == "meta")) ? ((function() {
|
||
var name = domGetAttr(el, "name");
|
||
var prop = domGetAttr(el, "property");
|
||
if (isSxTruthy(name)) {
|
||
removeHeadElement((String("meta[name=\"") + String(name) + String("\"]")));
|
||
}
|
||
return (isSxTruthy(prop) ? removeHeadElement((String("meta[property=\"") + String(prop) + String("\"]"))) : NIL);
|
||
})(), domRemoveChild(domParent(el), el), domAppendToHead(el)) : (isSxTruthy((isSxTruthy((tag == "link")) && (domGetAttr(el, "rel") == "canonical"))) ? (removeHeadElement("link[rel=\"canonical\"]"), domRemoveChild(domParent(el), el), domAppendToHead(el)) : (domRemoveChild(domParent(el), el), domAppendToHead(el)))));
|
||
})(); }, els);
|
||
})(); };
|
||
|
||
// sx-mount
|
||
var sxMount = function(target, source, extraEnv) { return (function() {
|
||
var el = resolveMountTarget(target);
|
||
return (isSxTruthy(el) ? (function() {
|
||
var node = sxRenderWithEnv(source, extraEnv);
|
||
domSetTextContent(el, "");
|
||
domAppend(el, node);
|
||
hoistHeadElementsFull(el);
|
||
processElements(el);
|
||
sxHydrateElements(el);
|
||
return sxHydrateIslands(el);
|
||
})() : NIL);
|
||
})(); };
|
||
|
||
// resolve-suspense
|
||
var resolveSuspense = function(id, sx) { processSxScripts(NIL);
|
||
return (function() {
|
||
var el = domQuery((String("[data-suspense=\"") + String(id) + String("\"]")));
|
||
return (isSxTruthy(el) ? (function() {
|
||
var exprs = parse(sx);
|
||
var env = getRenderEnv(NIL);
|
||
domSetTextContent(el, "");
|
||
{ var _c = exprs; for (var _i = 0; _i < _c.length; _i++) { var expr = _c[_i]; domAppend(el, renderToDom(expr, env, NIL)); } }
|
||
processElements(el);
|
||
sxHydrateElements(el);
|
||
sxHydrateIslands(el);
|
||
return domDispatch(el, "sx:resolved", {"id": id});
|
||
})() : logWarn((String("resolveSuspense: no element for id=") + String(id))));
|
||
})(); };
|
||
|
||
// sx-hydrate-elements
|
||
var sxHydrateElements = function(root) { return (function() {
|
||
var els = domQueryAll(sxOr(root, domBody()), "[data-sx]");
|
||
return forEach(function(el) { return (isSxTruthy(!isSxTruthy(isProcessed(el, "hydrated"))) ? (markProcessed(el, "hydrated"), sxUpdateElement(el, NIL)) : NIL); }, els);
|
||
})(); };
|
||
|
||
// sx-update-element
|
||
var sxUpdateElement = function(el, newEnv) { return (function() {
|
||
var target = resolveMountTarget(el);
|
||
return (isSxTruthy(target) ? (function() {
|
||
var source = domGetAttr(target, "data-sx");
|
||
return (isSxTruthy(source) ? (function() {
|
||
var baseEnv = parseEnvAttr(target);
|
||
var env = mergeEnvs(baseEnv, newEnv);
|
||
return (function() {
|
||
var node = sxRenderWithEnv(source, env);
|
||
domSetTextContent(target, "");
|
||
domAppend(target, node);
|
||
return (isSxTruthy(newEnv) ? storeEnvAttr(target, baseEnv, newEnv) : NIL);
|
||
})();
|
||
})() : NIL);
|
||
})() : NIL);
|
||
})(); };
|
||
|
||
// sx-render-component
|
||
var sxRenderComponent = function(name, kwargs, extraEnv) { return (function() {
|
||
var fullName = (isSxTruthy(startsWith(name, "~")) ? name : (String("~") + String(name)));
|
||
return (function() {
|
||
var env = getRenderEnv(extraEnv);
|
||
var comp = envGet(env, fullName);
|
||
return (isSxTruthy(!isSxTruthy(isComponent(comp))) ? error((String("Unknown component: ") + String(fullName))) : (function() {
|
||
var callExpr = [makeSymbol(fullName)];
|
||
{ var _c = keys(kwargs); for (var _i = 0; _i < _c.length; _i++) { var k = _c[_i]; callExpr.push(makeKeyword(toKebab(k)));
|
||
callExpr.push(dictGet(kwargs, k)); } }
|
||
return renderToDom(callExpr, env, NIL);
|
||
})());
|
||
})();
|
||
})(); };
|
||
|
||
// process-sx-scripts
|
||
var processSxScripts = function(root) { return (function() {
|
||
var scripts = querySxScripts(root);
|
||
return forEach(function(s) { return (isSxTruthy(!isSxTruthy(isProcessed(s, "script"))) ? (markProcessed(s, "script"), (function() {
|
||
var text = domTextContent(s);
|
||
return (isSxTruthy(domHasAttr(s, "data-components")) ? processComponentScript(s, text) : (isSxTruthy(sxOr(isNil(text), isEmpty(trim(text)))) ? NIL : (isSxTruthy(domHasAttr(s, "data-init")) ? (function() {
|
||
var exprs = sxParse(text);
|
||
return forEach(function(expr) { return evalExpr(expr, envExtend({})); }, exprs);
|
||
})() : (isSxTruthy(domHasAttr(s, "data-mount")) ? (function() {
|
||
var mountSel = domGetAttr(s, "data-mount");
|
||
var target = domQuery(mountSel);
|
||
return (isSxTruthy(target) ? sxMount(target, text, NIL) : NIL);
|
||
})() : sxLoadComponents(text)))));
|
||
})()) : NIL); }, scripts);
|
||
})(); };
|
||
|
||
// process-component-script
|
||
var processComponentScript = function(script, text) { return (function() {
|
||
var hash = domGetAttr(script, "data-hash");
|
||
return (isSxTruthy(isNil(hash)) ? (isSxTruthy((isSxTruthy(text) && !isSxTruthy(isEmpty(trim(text))))) ? sxLoadComponents(text) : NIL) : (function() {
|
||
var hasInline = (isSxTruthy(text) && !isSxTruthy(isEmpty(trim(text))));
|
||
(function() {
|
||
var cachedHash = localStorageGet("sx-components-hash");
|
||
return (isSxTruthy((cachedHash == hash)) ? (isSxTruthy(hasInline) ? (localStorageSet("sx-components-hash", hash), localStorageSet("sx-components-src", text), sxLoadComponents(text), logInfo("components: downloaded (cookie stale)")) : (function() {
|
||
var cached = localStorageGet("sx-components-src");
|
||
return (isSxTruthy(cached) ? (sxLoadComponents(cached), logInfo((String("components: cached (") + String(hash) + String(")")))) : (clearSxCompCookie(), browserReload()));
|
||
})()) : (isSxTruthy(hasInline) ? (localStorageSet("sx-components-hash", hash), localStorageSet("sx-components-src", text), sxLoadComponents(text), logInfo((String("components: downloaded (") + String(hash) + String(")")))) : (localStorageRemove("sx-components-hash"), localStorageRemove("sx-components-src"), clearSxCompCookie(), browserReload())));
|
||
})();
|
||
return setSxCompCookie(hash);
|
||
})());
|
||
})(); };
|
||
|
||
// _page-routes
|
||
var _pageRoutes = [];
|
||
|
||
// process-page-scripts
|
||
var processPageScripts = function() { return (function() {
|
||
var scripts = queryPageScripts();
|
||
logInfo((String("pages: found ") + String(len(scripts)) + String(" script tags")));
|
||
{ var _c = scripts; for (var _i = 0; _i < _c.length; _i++) { var s = _c[_i]; if (isSxTruthy(!isSxTruthy(isProcessed(s, "pages")))) {
|
||
markProcessed(s, "pages");
|
||
(function() {
|
||
var text = domTextContent(s);
|
||
logInfo((String("pages: script text length=") + String((isSxTruthy(text) ? len(text) : 0))));
|
||
return (isSxTruthy((isSxTruthy(text) && !isSxTruthy(isEmpty(trim(text))))) ? (function() {
|
||
var pages = parse(text);
|
||
logInfo((String("pages: parsed ") + String(len(pages)) + String(" entries")));
|
||
return forEach(function(page) { return append_b(_pageRoutes, merge(page, {"parsed": parseRoutePattern(get(page, "path"))})); }, pages);
|
||
})() : logWarn("pages: script tag is empty"));
|
||
})();
|
||
} } }
|
||
return logInfo((String("pages: ") + String(len(_pageRoutes)) + String(" routes loaded")));
|
||
})(); };
|
||
|
||
// sx-hydrate-islands
|
||
var sxHydrateIslands = function(root) { return (function() {
|
||
var els = domQueryAll(sxOr(root, domBody()), "[data-sx-island]");
|
||
return forEach(function(el) { return (isSxTruthy(!isSxTruthy(isProcessed(el, "island-hydrated"))) ? (markProcessed(el, "island-hydrated"), hydrateIsland(el)) : NIL); }, els);
|
||
})(); };
|
||
|
||
// hydrate-island
|
||
var hydrateIsland = function(el) { return (function() {
|
||
var name = domGetAttr(el, "data-sx-island");
|
||
var stateSx = sxOr(domGetAttr(el, "data-sx-state"), "{}");
|
||
return (function() {
|
||
var compName = (String("~") + String(name));
|
||
var env = getRenderEnv(NIL);
|
||
return (function() {
|
||
var comp = envGet(env, compName);
|
||
return (isSxTruthy(!isSxTruthy(sxOr(isComponent(comp), isIsland(comp)))) ? logWarn((String("hydrate-island: unknown island ") + String(compName))) : (function() {
|
||
var kwargs = sxOr(first(sxParse(stateSx)), {});
|
||
var disposers = [];
|
||
var local = envMerge(componentClosure(comp), env);
|
||
{ var _c = componentParams(comp); for (var _i = 0; _i < _c.length; _i++) { var p = _c[_i]; envSet(local, p, (isSxTruthy(dictHas(kwargs, p)) ? dictGet(kwargs, p) : NIL)); } }
|
||
return (function() {
|
||
var bodyDom = withIslandScope(function(disposable) { return append_b(disposers, disposable); }, function() { return renderToDom(componentBody(comp), local, NIL); });
|
||
domSetTextContent(el, "");
|
||
domAppend(el, bodyDom);
|
||
domSetData(el, "sx-disposers", disposers);
|
||
processElements(el);
|
||
return logInfo((String("hydrated island: ") + String(compName) + String(" (") + String(len(disposers)) + String(" disposers)")));
|
||
})();
|
||
})());
|
||
})();
|
||
})();
|
||
})(); };
|
||
|
||
// dispose-island
|
||
var disposeIsland = function(el) { return (function() {
|
||
var disposers = domGetData(el, "sx-disposers");
|
||
return (isSxTruthy(disposers) ? (forEach(function(d) { return (isSxTruthy(isCallable(d)) ? d() : NIL); }, disposers), domSetData(el, "sx-disposers", NIL)) : NIL);
|
||
})(); };
|
||
|
||
// dispose-islands-in
|
||
var disposeIslandsIn = function(root) { return (isSxTruthy(root) ? (function() {
|
||
var islands = domQueryAll(root, "[data-sx-island]");
|
||
return (isSxTruthy((isSxTruthy(islands) && !isSxTruthy(isEmpty(islands)))) ? (function() {
|
||
var toDispose = filter(function(el) { return !isSxTruthy(isProcessed(el, "island-hydrated")); }, islands);
|
||
return (isSxTruthy(!isSxTruthy(isEmpty(toDispose))) ? (logInfo((String("disposing ") + String(len(toDispose)) + String(" island(s)"))), forEach(disposeIsland, toDispose)) : NIL);
|
||
})() : NIL);
|
||
})() : NIL); };
|
||
|
||
// boot-init
|
||
var bootInit = function() { return (logInfo((String("sx-browser ") + String(SX_VERSION))), initCssTracking(), processPageScripts(), processSxScripts(NIL), sxHydrateElements(NIL), sxHydrateIslands(NIL), processElements(NIL)); };
|
||
|
||
|
||
// === Transpiled from deps (component dependency analysis) ===
|
||
|
||
// scan-refs
|
||
var scanRefs = function(node) { return (function() {
|
||
var refs = [];
|
||
scanRefsWalk(node, refs);
|
||
return refs;
|
||
})(); };
|
||
|
||
// scan-refs-walk
|
||
var scanRefsWalk = function(node, refs) { return (isSxTruthy((typeOf(node) == "symbol")) ? (function() {
|
||
var name = symbolName(node);
|
||
return (isSxTruthy(startsWith(name, "~")) ? (isSxTruthy(!isSxTruthy(contains(refs, name))) ? append_b(refs, name) : NIL) : NIL);
|
||
})() : (isSxTruthy((typeOf(node) == "list")) ? forEach(function(item) { return scanRefsWalk(item, refs); }, node) : (isSxTruthy((typeOf(node) == "dict")) ? forEach(function(key) { return scanRefsWalk(dictGet(node, key), refs); }, keys(node)) : NIL))); };
|
||
|
||
// transitive-deps-walk
|
||
var transitiveDepsWalk = function(n, seen, env) { return (isSxTruthy(!isSxTruthy(contains(seen, n))) ? (append_b(seen, n), (function() {
|
||
var val = envGet(env, n);
|
||
return (isSxTruthy((typeOf(val) == "component")) ? forEach(function(ref) { return transitiveDepsWalk(ref, seen, env); }, scanRefs(componentBody(val))) : (isSxTruthy((typeOf(val) == "macro")) ? forEach(function(ref) { return transitiveDepsWalk(ref, seen, env); }, scanRefs(macroBody(val))) : NIL));
|
||
})()) : NIL); };
|
||
|
||
// transitive-deps
|
||
var transitiveDeps = function(name, env) { return (function() {
|
||
var seen = [];
|
||
var key = (isSxTruthy(startsWith(name, "~")) ? name : (String("~") + String(name)));
|
||
transitiveDepsWalk(key, seen, env);
|
||
return filter(function(x) { return !isSxTruthy((x == key)); }, seen);
|
||
})(); };
|
||
|
||
// compute-all-deps
|
||
var computeAllDeps = function(env) { return forEach(function(name) { return (function() {
|
||
var val = envGet(env, name);
|
||
return (isSxTruthy((typeOf(val) == "component")) ? componentSetDeps(val, transitiveDeps(name, env)) : NIL);
|
||
})(); }, envComponents(env)); };
|
||
|
||
// scan-components-from-source
|
||
var scanComponentsFromSource = function(source) { return (function() {
|
||
var matches = regexFindAll("\\(~([a-zA-Z_][a-zA-Z0-9_\\-:/]*)", source);
|
||
return map(function(m) { return (String("~") + String(m)); }, matches);
|
||
})(); };
|
||
|
||
// components-needed
|
||
var componentsNeeded = function(pageSource, env) { return (function() {
|
||
var direct = scanComponentsFromSource(pageSource);
|
||
var allNeeded = [];
|
||
{ var _c = direct; for (var _i = 0; _i < _c.length; _i++) { var name = _c[_i]; if (isSxTruthy(!isSxTruthy(contains(allNeeded, name)))) {
|
||
allNeeded.push(name);
|
||
}
|
||
(function() {
|
||
var val = envGet(env, name);
|
||
return (function() {
|
||
var deps = (isSxTruthy((isSxTruthy((typeOf(val) == "component")) && !isSxTruthy(isEmpty(componentDeps(val))))) ? componentDeps(val) : transitiveDeps(name, env));
|
||
return forEach(function(dep) { return (isSxTruthy(!isSxTruthy(contains(allNeeded, dep))) ? append_b(allNeeded, dep) : NIL); }, deps);
|
||
})();
|
||
})(); } }
|
||
return allNeeded;
|
||
})(); };
|
||
|
||
// page-component-bundle
|
||
var pageComponentBundle = function(pageSource, env) { return componentsNeeded(pageSource, env); };
|
||
|
||
// page-css-classes
|
||
var pageCssClasses = function(pageSource, env) { return (function() {
|
||
var needed = componentsNeeded(pageSource, env);
|
||
var classes = [];
|
||
{ var _c = needed; for (var _i = 0; _i < _c.length; _i++) { var name = _c[_i]; (function() {
|
||
var val = envGet(env, name);
|
||
return (isSxTruthy((typeOf(val) == "component")) ? forEach(function(cls) { return (isSxTruthy(!isSxTruthy(contains(classes, cls))) ? append_b(classes, cls) : NIL); }, componentCssClasses(val)) : NIL);
|
||
})(); } }
|
||
{ var _c = scanCssClasses(pageSource); for (var _i = 0; _i < _c.length; _i++) { var cls = _c[_i]; if (isSxTruthy(!isSxTruthy(contains(classes, cls)))) {
|
||
classes.push(cls);
|
||
} } }
|
||
return classes;
|
||
})(); };
|
||
|
||
// scan-io-refs-walk
|
||
var scanIoRefsWalk = function(node, ioNames, refs) { return (isSxTruthy((typeOf(node) == "symbol")) ? (function() {
|
||
var name = symbolName(node);
|
||
return (isSxTruthy(contains(ioNames, name)) ? (isSxTruthy(!isSxTruthy(contains(refs, name))) ? append_b(refs, name) : NIL) : NIL);
|
||
})() : (isSxTruthy((typeOf(node) == "list")) ? forEach(function(item) { return scanIoRefsWalk(item, ioNames, refs); }, node) : (isSxTruthy((typeOf(node) == "dict")) ? forEach(function(key) { return scanIoRefsWalk(dictGet(node, key), ioNames, refs); }, keys(node)) : NIL))); };
|
||
|
||
// scan-io-refs
|
||
var scanIoRefs = function(node, ioNames) { return (function() {
|
||
var refs = [];
|
||
scanIoRefsWalk(node, ioNames, refs);
|
||
return refs;
|
||
})(); };
|
||
|
||
// transitive-io-refs-walk
|
||
var transitiveIoRefsWalk = function(n, seen, allRefs, env, ioNames) { return (isSxTruthy(!isSxTruthy(contains(seen, n))) ? (append_b(seen, n), (function() {
|
||
var val = envGet(env, n);
|
||
return (isSxTruthy((typeOf(val) == "component")) ? (forEach(function(ref) { return (isSxTruthy(!isSxTruthy(contains(allRefs, ref))) ? append_b(allRefs, ref) : NIL); }, scanIoRefs(componentBody(val), ioNames)), forEach(function(dep) { return transitiveIoRefsWalk(dep, seen, allRefs, env, ioNames); }, scanRefs(componentBody(val)))) : (isSxTruthy((typeOf(val) == "macro")) ? (forEach(function(ref) { return (isSxTruthy(!isSxTruthy(contains(allRefs, ref))) ? append_b(allRefs, ref) : NIL); }, scanIoRefs(macroBody(val), ioNames)), forEach(function(dep) { return transitiveIoRefsWalk(dep, seen, allRefs, env, ioNames); }, scanRefs(macroBody(val)))) : NIL));
|
||
})()) : NIL); };
|
||
|
||
// transitive-io-refs
|
||
var transitiveIoRefs = function(name, env, ioNames) { return (function() {
|
||
var allRefs = [];
|
||
var seen = [];
|
||
var key = (isSxTruthy(startsWith(name, "~")) ? name : (String("~") + String(name)));
|
||
transitiveIoRefsWalk(key, seen, allRefs, env, ioNames);
|
||
return allRefs;
|
||
})(); };
|
||
|
||
// compute-all-io-refs
|
||
var computeAllIoRefs = function(env, ioNames) { return forEach(function(name) { return (function() {
|
||
var val = envGet(env, name);
|
||
return (isSxTruthy((typeOf(val) == "component")) ? componentSetIoRefs(val, transitiveIoRefs(name, env, ioNames)) : NIL);
|
||
})(); }, envComponents(env)); };
|
||
|
||
// component-io-refs-cached
|
||
var componentIoRefsCached = function(name, env, ioNames) { return (function() {
|
||
var key = (isSxTruthy(startsWith(name, "~")) ? name : (String("~") + String(name)));
|
||
return (function() {
|
||
var val = envGet(env, key);
|
||
return (isSxTruthy((isSxTruthy((typeOf(val) == "component")) && isSxTruthy(!isSxTruthy(isNil(componentIoRefs(val)))) && !isSxTruthy(isEmpty(componentIoRefs(val))))) ? componentIoRefs(val) : transitiveIoRefs(name, env, ioNames));
|
||
})();
|
||
})(); };
|
||
|
||
// component-pure?
|
||
var componentPure_p = function(name, env, ioNames) { return (function() {
|
||
var key = (isSxTruthy(startsWith(name, "~")) ? name : (String("~") + String(name)));
|
||
return (function() {
|
||
var val = envGet(env, key);
|
||
return (isSxTruthy((isSxTruthy((typeOf(val) == "component")) && !isSxTruthy(isNil(componentIoRefs(val))))) ? isEmpty(componentIoRefs(val)) : isEmpty(transitiveIoRefs(name, env, ioNames)));
|
||
})();
|
||
})(); };
|
||
|
||
// render-target
|
||
var renderTarget = function(name, env, ioNames) { return (function() {
|
||
var key = (isSxTruthy(startsWith(name, "~")) ? name : (String("~") + String(name)));
|
||
return (function() {
|
||
var val = envGet(env, key);
|
||
return (isSxTruthy(!isSxTruthy((typeOf(val) == "component"))) ? "server" : (function() {
|
||
var affinity = componentAffinity(val);
|
||
return (isSxTruthy((affinity == "server")) ? "server" : (isSxTruthy((affinity == "client")) ? "client" : (isSxTruthy(!isSxTruthy(componentPure_p(name, env, ioNames))) ? "server" : "client")));
|
||
})());
|
||
})();
|
||
})(); };
|
||
|
||
// page-render-plan
|
||
var pageRenderPlan = function(pageSource, env, ioNames) { return (function() {
|
||
var needed = componentsNeeded(pageSource, env);
|
||
var compTargets = {};
|
||
var serverList = [];
|
||
var clientList = [];
|
||
var ioDeps = [];
|
||
{ var _c = needed; for (var _i = 0; _i < _c.length; _i++) { var name = _c[_i]; (function() {
|
||
var target = renderTarget(name, env, ioNames);
|
||
compTargets[name] = target;
|
||
return (isSxTruthy((target == "server")) ? (append_b(serverList, name), forEach(function(ioRef) { return (isSxTruthy(!isSxTruthy(contains(ioDeps, ioRef))) ? append_b(ioDeps, ioRef) : NIL); }, componentIoRefsCached(name, env, ioNames))) : append_b(clientList, name));
|
||
})(); } }
|
||
return {"components": compTargets, "server": serverList, "client": clientList, "io-deps": ioDeps};
|
||
})(); };
|
||
|
||
// env-components
|
||
var envComponents = function(env) { return filter(function(k) { return (function() {
|
||
var v = envGet(env, k);
|
||
return sxOr(isComponent(v), isMacro(v));
|
||
})(); }, keys(env)); };
|
||
|
||
|
||
// === Transpiled from page-helpers (pure data transformation helpers) ===
|
||
|
||
// special-form-category-map
|
||
var specialFormCategoryMap = {"if": "Control Flow", "when": "Control Flow", "cond": "Control Flow", "case": "Control Flow", "and": "Control Flow", "or": "Control Flow", "let": "Binding", "let*": "Binding", "letrec": "Binding", "define": "Binding", "set!": "Binding", "lambda": "Functions & Components", "fn": "Functions & Components", "defcomp": "Functions & Components", "defmacro": "Functions & Components", "begin": "Sequencing & Threading", "do": "Sequencing & Threading", "->": "Sequencing & Threading", "quote": "Quoting", "quasiquote": "Quoting", "reset": "Continuations", "shift": "Continuations", "dynamic-wind": "Guards", "map": "Higher-Order Forms", "map-indexed": "Higher-Order Forms", "filter": "Higher-Order Forms", "reduce": "Higher-Order Forms", "some": "Higher-Order Forms", "every?": "Higher-Order Forms", "for-each": "Higher-Order Forms", "defstyle": "Domain Definitions", "defhandler": "Domain Definitions", "defpage": "Domain Definitions", "defquery": "Domain Definitions", "defaction": "Domain Definitions"};
|
||
|
||
// extract-define-kwargs
|
||
var extractDefineKwargs = function(expr) { return (function() {
|
||
var result = {};
|
||
var items = slice(expr, 2);
|
||
var n = len(items);
|
||
{ var _c = range(0, n); for (var _i = 0; _i < _c.length; _i++) { var idx = _c[_i]; if (isSxTruthy((isSxTruthy(((idx + 1) < n)) && (typeOf(nth(items, idx)) == "keyword")))) {
|
||
(function() {
|
||
var key = keywordName(nth(items, idx));
|
||
var val = nth(items, (idx + 1));
|
||
return dictSet(result, key, (isSxTruthy((typeOf(val) == "list")) ? (String("(") + String(join(" ", map(serialize, val))) + String(")")) : (String(val))));
|
||
})();
|
||
} } }
|
||
return result;
|
||
})(); };
|
||
|
||
// categorize-special-forms
|
||
var categorizeSpecialForms = function(parsedExprs) { return (function() {
|
||
var categories = {};
|
||
{ var _c = parsedExprs; for (var _i = 0; _i < _c.length; _i++) { var expr = _c[_i]; if (isSxTruthy((isSxTruthy((typeOf(expr) == "list")) && isSxTruthy((len(expr) >= 2)) && isSxTruthy((typeOf(first(expr)) == "symbol")) && (symbolName(first(expr)) == "define-special-form")))) {
|
||
(function() {
|
||
var name = nth(expr, 1);
|
||
var kwargs = extractDefineKwargs(expr);
|
||
var category = sxOr(get(specialFormCategoryMap, name), "Other");
|
||
if (isSxTruthy(!isSxTruthy(dictHas(categories, category)))) {
|
||
categories[category] = [];
|
||
}
|
||
return append_b(get(categories, category), {"name": name, "syntax": sxOr(get(kwargs, "syntax"), ""), "doc": sxOr(get(kwargs, "doc"), ""), "tail-position": sxOr(get(kwargs, "tail-position"), ""), "example": sxOr(get(kwargs, "example"), "")});
|
||
})();
|
||
} } }
|
||
return categories;
|
||
})(); };
|
||
|
||
// build-ref-items-with-href
|
||
var buildRefItemsWithHref = function(items, basePath, detailKeys, nFields) { return map(function(item) { return (isSxTruthy((nFields == 3)) ? (function() {
|
||
var name = nth(item, 0);
|
||
var field2 = nth(item, 1);
|
||
var field3 = nth(item, 2);
|
||
return {"name": name, "desc": field2, "exists": field3, "href": (isSxTruthy((isSxTruthy(field3) && some(function(k) { return (k == name); }, detailKeys))) ? (String(basePath) + String(name)) : NIL)};
|
||
})() : (function() {
|
||
var name = nth(item, 0);
|
||
var desc = nth(item, 1);
|
||
return {"name": name, "desc": desc, "href": (isSxTruthy(some(function(k) { return (k == name); }, detailKeys)) ? (String(basePath) + String(name)) : NIL)};
|
||
})()); }, items); };
|
||
|
||
// build-reference-data
|
||
var buildReferenceData = function(slug, rawData, detailKeys) { return (function() { var _m = slug; if (_m == "attributes") return {"req-attrs": buildRefItemsWithHref(get(rawData, "req-attrs"), "/geography/hypermedia/reference/attributes/", detailKeys, 3), "beh-attrs": buildRefItemsWithHref(get(rawData, "beh-attrs"), "/geography/hypermedia/reference/attributes/", detailKeys, 3), "uniq-attrs": buildRefItemsWithHref(get(rawData, "uniq-attrs"), "/geography/hypermedia/reference/attributes/", detailKeys, 3)}; if (_m == "headers") return {"req-headers": buildRefItemsWithHref(get(rawData, "req-headers"), "/geography/hypermedia/reference/headers/", detailKeys, 3), "resp-headers": buildRefItemsWithHref(get(rawData, "resp-headers"), "/geography/hypermedia/reference/headers/", detailKeys, 3)}; if (_m == "events") return {"events-list": buildRefItemsWithHref(get(rawData, "events-list"), "/geography/hypermedia/reference/events/", detailKeys, 2)}; if (_m == "js-api") return {"js-api-list": map(function(item) { return {"name": nth(item, 0), "desc": nth(item, 1)}; }, get(rawData, "js-api-list"))}; return {"req-attrs": buildRefItemsWithHref(get(rawData, "req-attrs"), "/geography/hypermedia/reference/attributes/", detailKeys, 3), "beh-attrs": buildRefItemsWithHref(get(rawData, "beh-attrs"), "/geography/hypermedia/reference/attributes/", detailKeys, 3), "uniq-attrs": buildRefItemsWithHref(get(rawData, "uniq-attrs"), "/geography/hypermedia/reference/attributes/", detailKeys, 3)}; })(); };
|
||
|
||
// build-attr-detail
|
||
var buildAttrDetail = function(slug, detail) { return (isSxTruthy(isNil(detail)) ? {"attr-not-found": true} : {"attr-not-found": NIL, "attr-title": slug, "attr-description": get(detail, "description"), "attr-example": get(detail, "example"), "attr-handler": get(detail, "handler"), "attr-demo": get(detail, "demo"), "attr-wire-id": (isSxTruthy(dictHas(detail, "handler")) ? (String("ref-wire-") + String(replace_(replace_(slug, ":", "-"), "*", "star"))) : NIL)}); };
|
||
|
||
// build-header-detail
|
||
var buildHeaderDetail = function(slug, detail) { return (isSxTruthy(isNil(detail)) ? {"header-not-found": true} : {"header-not-found": NIL, "header-title": slug, "header-direction": get(detail, "direction"), "header-description": get(detail, "description"), "header-example": get(detail, "example"), "header-demo": get(detail, "demo")}); };
|
||
|
||
// build-event-detail
|
||
var buildEventDetail = function(slug, detail) { return (isSxTruthy(isNil(detail)) ? {"event-not-found": true} : {"event-not-found": NIL, "event-title": slug, "event-description": get(detail, "description"), "event-example": get(detail, "example"), "event-demo": get(detail, "demo")}); };
|
||
|
||
// build-component-source
|
||
var buildComponentSource = function(compData) { return (function() {
|
||
var compType = get(compData, "type");
|
||
var name = get(compData, "name");
|
||
var params = get(compData, "params");
|
||
var hasChildren = get(compData, "has-children");
|
||
var bodySx = get(compData, "body-sx");
|
||
var affinity = get(compData, "affinity");
|
||
return (isSxTruthy((compType == "not-found")) ? (String(";; component ") + String(name) + String(" not found")) : (function() {
|
||
var paramStrs = (isSxTruthy(isEmpty(params)) ? (isSxTruthy(hasChildren) ? ["&rest", "children"] : []) : (isSxTruthy(hasChildren) ? append(cons("&key", params), ["&rest", "children"]) : cons("&key", params)));
|
||
var paramsSx = (String("(") + String(join(" ", paramStrs)) + String(")"));
|
||
var formName = (isSxTruthy((compType == "island")) ? "defisland" : "defcomp");
|
||
var affinityStr = (isSxTruthy((isSxTruthy((compType == "component")) && isSxTruthy(!isSxTruthy(isNil(affinity))) && !isSxTruthy((affinity == "auto")))) ? (String(" :affinity ") + String(affinity)) : "");
|
||
return (String("(") + String(formName) + String(" ") + String(name) + String(" ") + String(paramsSx) + String(affinityStr) + String("\n ") + String(bodySx) + String(")"));
|
||
})());
|
||
})(); };
|
||
|
||
// build-bundle-analysis
|
||
var buildBundleAnalysis = function(pagesRaw, componentsRaw, totalComponents, totalMacros, pureCount, ioCount) { return (function() {
|
||
var pagesData = [];
|
||
{ var _c = pagesRaw; for (var _i = 0; _i < _c.length; _i++) { var page = _c[_i]; (function() {
|
||
var neededNames = get(page, "needed-names");
|
||
var n = len(neededNames);
|
||
var pct = (isSxTruthy((totalComponents > 0)) ? round(((n / totalComponents) * 100)) : 0);
|
||
var savings = (100 - pct);
|
||
var pureInPage = 0;
|
||
var ioInPage = 0;
|
||
var pageIoRefs = [];
|
||
var compDetails = [];
|
||
{ var _c = neededNames; for (var _i = 0; _i < _c.length; _i++) { var compName = _c[_i]; (function() {
|
||
var info = get(componentsRaw, compName);
|
||
return (isSxTruthy(!isSxTruthy(isNil(info))) ? ((isSxTruthy(get(info, "is-pure")) ? (pureInPage = (pureInPage + 1)) : ((ioInPage = (ioInPage + 1)), forEach(function(ref) { return (isSxTruthy(!isSxTruthy(some(function(r) { return (r == ref); }, pageIoRefs))) ? append_b(pageIoRefs, ref) : NIL); }, sxOr(get(info, "io-refs"), [])))), append_b(compDetails, {"name": compName, "is-pure": get(info, "is-pure"), "affinity": get(info, "affinity"), "render-target": get(info, "render-target"), "io-refs": sxOr(get(info, "io-refs"), []), "deps": sxOr(get(info, "deps"), []), "source": get(info, "source")})) : NIL);
|
||
})(); } }
|
||
return append_b(pagesData, {"name": get(page, "name"), "path": get(page, "path"), "direct": get(page, "direct"), "needed": n, "pct": pct, "savings": savings, "io-refs": len(pageIoRefs), "pure-in-page": pureInPage, "io-in-page": ioInPage, "components": compDetails});
|
||
})(); } }
|
||
return {"pages": pagesData, "total-components": totalComponents, "total-macros": totalMacros, "pure-count": pureCount, "io-count": ioCount};
|
||
})(); };
|
||
|
||
// build-routing-analysis
|
||
var buildRoutingAnalysis = function(pagesRaw) { return (function() {
|
||
var pagesData = [];
|
||
var clientCount = 0;
|
||
var serverCount = 0;
|
||
{ var _c = pagesRaw; for (var _i = 0; _i < _c.length; _i++) { var page = _c[_i]; (function() {
|
||
var hasData = get(page, "has-data");
|
||
var contentSrc = sxOr(get(page, "content-src"), "");
|
||
var mode = NIL;
|
||
var reason = "";
|
||
(isSxTruthy(hasData) ? ((mode = "server"), (reason = "Has :data expression — needs server IO"), (serverCount = (serverCount + 1))) : (isSxTruthy(isEmpty(contentSrc)) ? ((mode = "server"), (reason = "No content expression"), (serverCount = (serverCount + 1))) : ((mode = "client"), (clientCount = (clientCount + 1)))));
|
||
return append_b(pagesData, {"name": get(page, "name"), "path": get(page, "path"), "mode": mode, "has-data": hasData, "content-expr": (isSxTruthy((len(contentSrc) > 80)) ? (String(slice(contentSrc, 0, 80)) + String("...")) : contentSrc), "reason": reason});
|
||
})(); } }
|
||
return {"pages": pagesData, "total-pages": (clientCount + serverCount), "client-count": clientCount, "server-count": serverCount};
|
||
})(); };
|
||
|
||
// build-affinity-analysis
|
||
var buildAffinityAnalysis = function(demoComponents, pagePlans) { return {"components": demoComponents, "page-plans": pagePlans}; };
|
||
|
||
|
||
// === Transpiled from router (client-side route matching) ===
|
||
|
||
// split-path-segments
|
||
var splitPathSegments = function(path) { return (function() {
|
||
var trimmed = (isSxTruthy(startsWith(path, "/")) ? slice(path, 1) : path);
|
||
return (function() {
|
||
var trimmed2 = (isSxTruthy((isSxTruthy(!isSxTruthy(isEmpty(trimmed))) && endsWith(trimmed, "/"))) ? slice(trimmed, 0, (len(trimmed) - 1)) : trimmed);
|
||
return (isSxTruthy(isEmpty(trimmed2)) ? [] : split(trimmed2, "/"));
|
||
})();
|
||
})(); };
|
||
|
||
// make-route-segment
|
||
var makeRouteSegment = function(seg) { return (isSxTruthy((isSxTruthy(startsWith(seg, "<")) && endsWith(seg, ">"))) ? (function() {
|
||
var paramName = slice(seg, 1, (len(seg) - 1));
|
||
return (function() {
|
||
var d = {};
|
||
d["type"] = "param";
|
||
d["value"] = paramName;
|
||
return d;
|
||
})();
|
||
})() : (function() {
|
||
var d = {};
|
||
d["type"] = "literal";
|
||
d["value"] = seg;
|
||
return d;
|
||
})()); };
|
||
|
||
// parse-route-pattern
|
||
var parseRoutePattern = function(pattern) { return (function() {
|
||
var segments = splitPathSegments(pattern);
|
||
return map(makeRouteSegment, segments);
|
||
})(); };
|
||
|
||
// match-route-segments
|
||
var matchRouteSegments = function(pathSegs, parsedSegs) { return (isSxTruthy(!isSxTruthy((len(pathSegs) == len(parsedSegs)))) ? NIL : (function() {
|
||
var params = {};
|
||
var matched = true;
|
||
forEachIndexed(function(i, parsedSeg) { return (isSxTruthy(matched) ? (function() {
|
||
var pathSeg = nth(pathSegs, i);
|
||
var segType = get(parsedSeg, "type");
|
||
return (isSxTruthy((segType == "literal")) ? (isSxTruthy(!isSxTruthy((pathSeg == get(parsedSeg, "value")))) ? (matched = false) : NIL) : (isSxTruthy((segType == "param")) ? dictSet(params, get(parsedSeg, "value"), pathSeg) : (matched = false)));
|
||
})() : NIL); }, parsedSegs);
|
||
return (isSxTruthy(matched) ? params : NIL);
|
||
})()); };
|
||
|
||
// match-route
|
||
var matchRoute = function(path, pattern) { return (function() {
|
||
var pathSegs = splitPathSegments(path);
|
||
var parsedSegs = parseRoutePattern(pattern);
|
||
return matchRouteSegments(pathSegs, parsedSegs);
|
||
})(); };
|
||
|
||
// find-matching-route
|
||
var findMatchingRoute = function(path, routes) { return (function() {
|
||
var matchPath = (isSxTruthy(startsWith(path, "/(")) ? sxOr(sxUrlToPath(path), path) : path);
|
||
return (function() {
|
||
var pathSegs = splitPathSegments(matchPath);
|
||
var result = NIL;
|
||
{ var _c = routes; for (var _i = 0; _i < _c.length; _i++) { var route = _c[_i]; if (isSxTruthy(isNil(result))) {
|
||
(function() {
|
||
var params = matchRouteSegments(pathSegs, get(route, "parsed"));
|
||
return (isSxTruthy(!isSxTruthy(isNil(params))) ? (function() {
|
||
var matched = merge(route, {});
|
||
matched["params"] = params;
|
||
return (result = matched);
|
||
})() : NIL);
|
||
})();
|
||
} } }
|
||
return result;
|
||
})();
|
||
})(); };
|
||
|
||
// _fn-to-segment
|
||
var _fnToSegment = function(name) { return (function() { var _m = name; if (_m == "doc") return "docs"; if (_m == "spec") return "specs"; if (_m == "bootstrapper") return "bootstrappers"; if (_m == "test") return "testing"; if (_m == "example") return "examples"; if (_m == "protocol") return "protocols"; if (_m == "essay") return "essays"; if (_m == "plan") return "plans"; if (_m == "reference-detail") return "reference"; return name; })(); };
|
||
|
||
// sx-url-to-path
|
||
var sxUrlToPath = function(url) { return (isSxTruthy(!isSxTruthy((isSxTruthy(startsWith(url, "/(")) && endsWith(url, ")")))) ? NIL : (function() {
|
||
var inner = slice(url, 2, (len(url) - 1));
|
||
return (function() {
|
||
var s = replace_(replace_(replace_(inner, ".", "/"), "(", ""), ")", "");
|
||
return (function() {
|
||
var segs = filter(function(s) { return !isSxTruthy(isEmpty(s)); }, split(s, "/"));
|
||
return (String("/") + String(join("/", map(_fnToSegment, segs))));
|
||
})();
|
||
})();
|
||
})()); };
|
||
|
||
// _count-leading-dots
|
||
var _countLeadingDots = function(s) { return (isSxTruthy(isEmpty(s)) ? 0 : (isSxTruthy(startsWith(s, ".")) ? (1 + _countLeadingDots(slice(s, 1))) : 0)); };
|
||
|
||
// _strip-trailing-close
|
||
var _stripTrailingClose = function(s) { return (isSxTruthy(endsWith(s, ")")) ? _stripTrailingClose(slice(s, 0, (len(s) - 1))) : s); };
|
||
|
||
// _index-of-safe
|
||
var _indexOfSafe = function(s, needle) { return (function() {
|
||
var idx = indexOf_(s, needle);
|
||
return (isSxTruthy(sxOr(isNil(idx), (idx < 0))) ? NIL : idx);
|
||
})(); };
|
||
|
||
// _last-index-of
|
||
var _lastIndexOf = function(s, needle) { return (function() {
|
||
var idx = _indexOfSafe(s, needle);
|
||
return (isSxTruthy(isNil(idx)) ? NIL : (function() {
|
||
var restIdx = _lastIndexOf(slice(s, (idx + 1)), needle);
|
||
return (isSxTruthy(isNil(restIdx)) ? idx : ((idx + 1) + restIdx));
|
||
})());
|
||
})(); };
|
||
|
||
// _pop-sx-url-level
|
||
var _popSxUrlLevel = function(url) { return (function() {
|
||
var stripped = _stripTrailingClose(url);
|
||
var closeCount = (len(url) - len(_stripTrailingClose(url)));
|
||
return (isSxTruthy((closeCount <= 1)) ? "/" : (function() {
|
||
var lastDp = _lastIndexOf(stripped, ".(");
|
||
return (isSxTruthy(isNil(lastDp)) ? "/" : (String(slice(stripped, 0, lastDp)) + String(slice(url, (len(url) - (closeCount - 1))))));
|
||
})());
|
||
})(); };
|
||
|
||
// _pop-sx-url-levels
|
||
var _popSxUrlLevels = function(url, n) { return (isSxTruthy((n <= 0)) ? url : _popSxUrlLevels(_popSxUrlLevel(url), (n - 1))); };
|
||
|
||
// _split-pos-kw
|
||
var _splitPosKw = function(tokens, i, pos, kw) { return (isSxTruthy((i >= len(tokens))) ? {"positional": join(".", pos), "keywords": kw} : (function() {
|
||
var tok = nth(tokens, i);
|
||
return (isSxTruthy(startsWith(tok, ":")) ? (function() {
|
||
var val = (isSxTruthy(((i + 1) < len(tokens))) ? nth(tokens, (i + 1)) : "");
|
||
return _splitPosKw(tokens, (i + 2), pos, append(kw, [[tok, val]]));
|
||
})() : _splitPosKw(tokens, (i + 1), append(pos, [tok]), kw));
|
||
})()); };
|
||
|
||
// _parse-relative-body
|
||
var _parseRelativeBody = function(body) { return (isSxTruthy(isEmpty(body)) ? {"positional": "", "keywords": []} : _splitPosKw(split(body, "."), 0, [], [])); };
|
||
|
||
// _extract-innermost
|
||
var _extractInnermost = function(url) { return (function() {
|
||
var stripped = _stripTrailingClose(url);
|
||
var suffix = slice(url, len(_stripTrailingClose(url)));
|
||
return (function() {
|
||
var lastDp = _lastIndexOf(stripped, ".(");
|
||
return (isSxTruthy(isNil(lastDp)) ? {"before": "/(", "content": slice(stripped, 2), "suffix": suffix} : {"before": slice(stripped, 0, (lastDp + 2)), "content": slice(stripped, (lastDp + 2)), "suffix": suffix});
|
||
})();
|
||
})(); };
|
||
|
||
// _find-kw-in-tokens
|
||
var _findKwInTokens = function(tokens, i, kw) { return (isSxTruthy((i >= len(tokens))) ? NIL : (isSxTruthy((isSxTruthy((nth(tokens, i) == kw)) && ((i + 1) < len(tokens)))) ? nth(tokens, (i + 1)) : _findKwInTokens(tokens, (i + 1), kw))); };
|
||
|
||
// _find-keyword-value
|
||
var _findKeywordValue = function(content, kw) { return _findKwInTokens(split(content, "."), 0, kw); };
|
||
|
||
// _replace-kw-in-tokens
|
||
var _replaceKwInTokens = function(tokens, i, kw, value) { return (isSxTruthy((i >= len(tokens))) ? [] : (isSxTruthy((isSxTruthy((nth(tokens, i) == kw)) && ((i + 1) < len(tokens)))) ? append([kw, value], _replaceKwInTokens(tokens, (i + 2), kw, value)) : cons(nth(tokens, i), _replaceKwInTokens(tokens, (i + 1), kw, value)))); };
|
||
|
||
// _set-keyword-in-content
|
||
var _setKeywordInContent = function(content, kw, value) { return (function() {
|
||
var current = _findKeywordValue(content, kw);
|
||
return (isSxTruthy(isNil(current)) ? (String(content) + String(".") + String(kw) + String(".") + String(value)) : join(".", _replaceKwInTokens(split(content, "."), 0, kw, value)));
|
||
})(); };
|
||
|
||
// _is-delta-value?
|
||
var _isDeltaValue_p = function(s) { return (isSxTruthy(!isSxTruthy(isEmpty(s))) && isSxTruthy((len(s) > 1)) && sxOr(startsWith(s, "+"), startsWith(s, "-"))); };
|
||
|
||
// _apply-delta
|
||
var _applyDelta = function(currentStr, deltaStr) { return (function() {
|
||
var cur = parseInt_(currentStr, NIL);
|
||
var delta = parseInt_(deltaStr, NIL);
|
||
return (isSxTruthy(sxOr(isNil(cur), isNil(delta))) ? deltaStr : (String((cur + delta))));
|
||
})(); };
|
||
|
||
// _apply-kw-pairs
|
||
var _applyKwPairs = function(content, kwPairs) { return (isSxTruthy(isEmpty(kwPairs)) ? content : (function() {
|
||
var pair = first(kwPairs);
|
||
var kw = first(pair);
|
||
var rawVal = nth(pair, 1);
|
||
return (function() {
|
||
var actualVal = (isSxTruthy(_isDeltaValue_p(rawVal)) ? (function() {
|
||
var current = _findKeywordValue(content, kw);
|
||
return (isSxTruthy(isNil(current)) ? rawVal : _applyDelta(current, rawVal));
|
||
})() : rawVal);
|
||
return _applyKwPairs(_setKeywordInContent(content, kw, actualVal), rest(kwPairs));
|
||
})();
|
||
})()); };
|
||
|
||
// _apply-keywords-to-url
|
||
var _applyKeywordsToUrl = function(url, kwPairs) { return (isSxTruthy(isEmpty(kwPairs)) ? url : (function() {
|
||
var parts = _extractInnermost(url);
|
||
return (function() {
|
||
var newContent = _applyKwPairs(get(parts, "content"), kwPairs);
|
||
return (String(get(parts, "before")) + String(newContent) + String(get(parts, "suffix")));
|
||
})();
|
||
})()); };
|
||
|
||
// _normalize-relative
|
||
var _normalizeRelative = function(url) { return (isSxTruthy(startsWith(url, "(")) ? url : (String("(") + String(url) + String(")"))); };
|
||
|
||
// resolve-relative-url
|
||
var resolveRelativeUrl = function(current, relative) { return (function() {
|
||
var canonical = _normalizeRelative(relative);
|
||
return (function() {
|
||
var relInner = slice(canonical, 1, (len(canonical) - 1));
|
||
return (function() {
|
||
var dots = _countLeadingDots(relInner);
|
||
var body = slice(relInner, _countLeadingDots(relInner));
|
||
return (isSxTruthy((dots == 0)) ? current : (function() {
|
||
var parsed = _parseRelativeBody(body);
|
||
var posBody = get(parsed, "positional");
|
||
var kwPairs = get(parsed, "keywords");
|
||
return (function() {
|
||
var afterNav = (isSxTruthy((dots == 1)) ? (isSxTruthy(isEmpty(posBody)) ? current : (function() {
|
||
var stripped = _stripTrailingClose(current);
|
||
var suffix = slice(current, len(_stripTrailingClose(current)));
|
||
return (String(stripped) + String(".") + String(posBody) + String(suffix));
|
||
})()) : (function() {
|
||
var base = _popSxUrlLevels(current, (dots - 1));
|
||
return (isSxTruthy(isEmpty(posBody)) ? base : (isSxTruthy((base == "/")) ? (String("/(") + String(posBody) + String(")")) : (function() {
|
||
var stripped = _stripTrailingClose(base);
|
||
var suffix = slice(base, len(_stripTrailingClose(base)));
|
||
return (String(stripped) + String(".(") + String(posBody) + String(")") + String(suffix));
|
||
})()));
|
||
})());
|
||
return _applyKeywordsToUrl(afterNav, kwPairs);
|
||
})();
|
||
})());
|
||
})();
|
||
})();
|
||
})(); };
|
||
|
||
// relative-sx-url?
|
||
var relativeSxUrl_p = function(url) { return sxOr((isSxTruthy(startsWith(url, "(")) && !isSxTruthy(startsWith(url, "/("))), startsWith(url, ".")); };
|
||
|
||
// _url-special-forms
|
||
var _urlSpecialForms = function() { return ["!source", "!inspect", "!diff", "!search", "!raw", "!json"]; };
|
||
|
||
// url-special-form?
|
||
var urlSpecialForm_p = function(name) { return (isSxTruthy(startsWith(name, "!")) && contains(_urlSpecialForms(), name)); };
|
||
|
||
// parse-sx-url
|
||
var parseSxUrl = function(url) { return (isSxTruthy((url == "/")) ? {"type": "home", "raw": url} : (isSxTruthy(relativeSxUrl_p(url)) ? {"type": "relative", "raw": url} : (isSxTruthy((isSxTruthy(startsWith(url, "/(!")) && endsWith(url, ")"))) ? (function() {
|
||
var inner = slice(url, 2, (len(url) - 1));
|
||
return (function() {
|
||
var dotPos = _indexOfSafe(inner, ".");
|
||
var parenPos = _indexOfSafe(inner, "(");
|
||
return (function() {
|
||
var endPos = (isSxTruthy((isSxTruthy(isNil(dotPos)) && isNil(parenPos))) ? len(inner) : (isSxTruthy(isNil(dotPos)) ? parenPos : (isSxTruthy(isNil(parenPos)) ? dotPos : min(dotPos, parenPos))));
|
||
return (function() {
|
||
var formName = slice(inner, 0, endPos);
|
||
var restPart = slice(inner, endPos);
|
||
return (function() {
|
||
var innerExpr = (isSxTruthy(startsWith(restPart, ".")) ? slice(restPart, 1) : restPart);
|
||
return {"type": "special-form", "form": formName, "inner": innerExpr, "raw": url};
|
||
})();
|
||
})();
|
||
})();
|
||
})();
|
||
})() : (isSxTruthy((isSxTruthy(startsWith(url, "/(~")) && endsWith(url, ")"))) ? (function() {
|
||
var name = slice(url, 2, (len(url) - 1));
|
||
return {"type": "direct-component", "name": name, "raw": url};
|
||
})() : (isSxTruthy((isSxTruthy(startsWith(url, "/(")) && endsWith(url, ")"))) ? {"type": "absolute", "raw": url} : {"type": "path", "raw": url}))))); };
|
||
|
||
// url-special-form-name
|
||
var urlSpecialFormName = function(url) { return (function() {
|
||
var parsed = parseSxUrl(url);
|
||
return (isSxTruthy((get(parsed, "type") == "special-form")) ? get(parsed, "form") : NIL);
|
||
})(); };
|
||
|
||
// url-special-form-inner
|
||
var urlSpecialFormInner = function(url) { return (function() {
|
||
var parsed = parseSxUrl(url);
|
||
return (isSxTruthy((get(parsed, "type") == "special-form")) ? get(parsed, "inner") : NIL);
|
||
})(); };
|
||
|
||
// url-to-expr
|
||
var urlToExpr = function(urlPath) { return (isSxTruthy(sxOr((urlPath == "/"), isEmpty(urlPath))) ? [] : (function() {
|
||
var trimmed = (isSxTruthy(startsWith(urlPath, "/")) ? slice(urlPath, 1) : urlPath);
|
||
return (function() {
|
||
var sxSource = replace_(trimmed, ".", " ");
|
||
return (function() {
|
||
var exprs = sxParse(sxSource);
|
||
return (isSxTruthy(isEmpty(exprs)) ? [] : first(exprs));
|
||
})();
|
||
})();
|
||
})()); };
|
||
|
||
// auto-quote-unknowns
|
||
var autoQuoteUnknowns = function(expr, env) { return (isSxTruthy(!isSxTruthy(isList(expr))) ? expr : (isSxTruthy(isEmpty(expr)) ? expr : cons(first(expr), map(function(child) { return (isSxTruthy(isList(child)) ? autoQuoteUnknowns(child, env) : (isSxTruthy((typeOf(child) == "symbol")) ? (function() {
|
||
var name = symbolName(child);
|
||
return (isSxTruthy(sxOr(envHas(env, name), startsWith(name, ":"), startsWith(name, "~"), startsWith(name, "!"))) ? child : name);
|
||
})() : child)); }, rest(expr))))); };
|
||
|
||
// prepare-url-expr
|
||
var prepareUrlExpr = function(urlPath, env) { return (function() {
|
||
var expr = urlToExpr(urlPath);
|
||
return (isSxTruthy(isEmpty(expr)) ? expr : autoQuoteUnknowns(expr, env));
|
||
})(); };
|
||
|
||
|
||
// === Transpiled from signals (reactive signal runtime) ===
|
||
|
||
// signal
|
||
var signal = function(initialValue) { return makeSignal(initialValue); };
|
||
|
||
// deref
|
||
var deref = function(s) { return (isSxTruthy(!isSxTruthy(isSignal(s))) ? s : (function() {
|
||
var ctx = getTrackingContext();
|
||
if (isSxTruthy(ctx)) {
|
||
trackingContextAddDep(ctx, s);
|
||
signalAddSub(s, trackingContextNotifyFn(ctx));
|
||
}
|
||
return signalValue(s);
|
||
})()); };
|
||
|
||
// reset!
|
||
var reset_b = function(s, value) { return (isSxTruthy(isSignal(s)) ? (function() {
|
||
var old = signalValue(s);
|
||
return (isSxTruthy(!isSxTruthy(isIdentical(old, value))) ? (signalSetValue(s, value), notifySubscribers(s)) : NIL);
|
||
})() : NIL); };
|
||
|
||
// swap!
|
||
var swap_b = function(s, f) { var args = Array.prototype.slice.call(arguments, 2); return (isSxTruthy(isSignal(s)) ? (function() {
|
||
var old = signalValue(s);
|
||
var newVal = apply(f, cons(old, args));
|
||
return (isSxTruthy(!isSxTruthy(isIdentical(old, newVal))) ? (signalSetValue(s, newVal), notifySubscribers(s)) : NIL);
|
||
})() : NIL); };
|
||
|
||
// computed
|
||
var computed = function(computeFn) { return (function() {
|
||
var s = makeSignal(NIL);
|
||
var deps = [];
|
||
var computeCtx = NIL;
|
||
return (function() {
|
||
var recompute = function() { { var _c = signalDeps(s); for (var _i = 0; _i < _c.length; _i++) { var dep = _c[_i]; signalRemoveSub(dep, recompute); } }
|
||
signalSetDeps(s, []);
|
||
return (function() {
|
||
var ctx = makeTrackingContext(recompute);
|
||
return (function() {
|
||
var prev = getTrackingContext();
|
||
setTrackingContext(ctx);
|
||
return (function() {
|
||
var newVal = invoke(computeFn);
|
||
setTrackingContext(prev);
|
||
signalSetDeps(s, trackingContextDeps(ctx));
|
||
return (function() {
|
||
var old = signalValue(s);
|
||
signalSetValue(s, newVal);
|
||
return (isSxTruthy(!isSxTruthy(isIdentical(old, newVal))) ? notifySubscribers(s) : NIL);
|
||
})();
|
||
})();
|
||
})();
|
||
})(); };
|
||
recompute();
|
||
registerInScope(function() { return disposeComputed(s); });
|
||
return s;
|
||
})();
|
||
})(); };
|
||
|
||
// effect
|
||
var effect = function(effectFn) { return (function() {
|
||
var deps = [];
|
||
var disposed = false;
|
||
var cleanupFn = NIL;
|
||
return (function() {
|
||
var runEffect = function() { return (isSxTruthy(!isSxTruthy(disposed)) ? ((isSxTruthy(cleanupFn) ? invoke(cleanupFn) : NIL), forEach(function(dep) { return signalRemoveSub(dep, runEffect); }, deps), (deps = []), (function() {
|
||
var ctx = makeTrackingContext(runEffect);
|
||
return (function() {
|
||
var prev = getTrackingContext();
|
||
setTrackingContext(ctx);
|
||
return (function() {
|
||
var result = invoke(effectFn);
|
||
setTrackingContext(prev);
|
||
deps = trackingContextDeps(ctx);
|
||
return (isSxTruthy(isCallable(result)) ? (cleanupFn = result) : NIL);
|
||
})();
|
||
})();
|
||
})()) : NIL); };
|
||
runEffect();
|
||
return (function() {
|
||
var disposeFn = function() { disposed = true;
|
||
if (isSxTruthy(cleanupFn)) {
|
||
invoke(cleanupFn);
|
||
}
|
||
{ var _c = deps; for (var _i = 0; _i < _c.length; _i++) { var dep = _c[_i]; signalRemoveSub(dep, runEffect); } }
|
||
return (deps = []); };
|
||
registerInScope(disposeFn);
|
||
return disposeFn;
|
||
})();
|
||
})();
|
||
})(); };
|
||
|
||
// *batch-depth*
|
||
var _batchDepth = 0;
|
||
|
||
// *batch-queue*
|
||
var _batchQueue = [];
|
||
|
||
// batch
|
||
var batch = function(thunk) { _batchDepth = (_batchDepth + 1);
|
||
invoke(thunk);
|
||
_batchDepth = (_batchDepth - 1);
|
||
return (isSxTruthy((_batchDepth == 0)) ? (function() {
|
||
var queue = _batchQueue;
|
||
_batchQueue = [];
|
||
return (function() {
|
||
var seen = [];
|
||
var pending = [];
|
||
{ var _c = queue; for (var _i = 0; _i < _c.length; _i++) { var s = _c[_i]; { var _c = signalSubscribers(s); for (var _i = 0; _i < _c.length; _i++) { var sub = _c[_i]; if (isSxTruthy(!isSxTruthy(contains(seen, sub)))) {
|
||
seen.push(sub);
|
||
pending.push(sub);
|
||
} } } } }
|
||
return forEach(function(sub) { return sub(); }, pending);
|
||
})();
|
||
})() : NIL); };
|
||
|
||
// notify-subscribers
|
||
var notifySubscribers = function(s) { return (isSxTruthy((_batchDepth > 0)) ? (isSxTruthy(!isSxTruthy(contains(_batchQueue, s))) ? append_b(_batchQueue, s) : NIL) : flushSubscribers(s)); };
|
||
|
||
// flush-subscribers
|
||
var flushSubscribers = function(s) { return forEach(function(sub) { return sub(); }, signalSubscribers(s)); };
|
||
|
||
// dispose-computed
|
||
var disposeComputed = function(s) { return (isSxTruthy(isSignal(s)) ? (forEach(function(dep) { return signalRemoveSub(dep, NIL); }, signalDeps(s)), signalSetDeps(s, [])) : NIL); };
|
||
|
||
// *island-scope*
|
||
var _islandScope = NIL;
|
||
|
||
// with-island-scope
|
||
var withIslandScope = function(scopeFn, bodyFn) { return (function() {
|
||
var prev = _islandScope;
|
||
_islandScope = scopeFn;
|
||
return (function() {
|
||
var result = bodyFn();
|
||
_islandScope = prev;
|
||
return result;
|
||
})();
|
||
})(); };
|
||
|
||
// register-in-scope
|
||
var registerInScope = function(disposable) { return (isSxTruthy(_islandScope) ? _islandScope(disposable) : NIL); };
|
||
|
||
// with-marsh-scope
|
||
var withMarshScope = function(marshEl, bodyFn) { return (function() {
|
||
var disposers = [];
|
||
withIslandScope(function(d) { return append_b(disposers, d); }, bodyFn);
|
||
return domSetData(marshEl, "sx-marsh-disposers", disposers);
|
||
})(); };
|
||
|
||
// dispose-marsh-scope
|
||
var disposeMarshScope = function(marshEl) { return (function() {
|
||
var disposers = domGetData(marshEl, "sx-marsh-disposers");
|
||
return (isSxTruthy(disposers) ? (forEach(function(d) { return invoke(d); }, disposers), domSetData(marshEl, "sx-marsh-disposers", NIL)) : NIL);
|
||
})(); };
|
||
|
||
// *store-registry*
|
||
var _storeRegistry = {};
|
||
|
||
// def-store
|
||
var defStore = function(name, initFn) { return (function() {
|
||
var registry = _storeRegistry;
|
||
if (isSxTruthy(!isSxTruthy(dictHas(registry, name)))) {
|
||
_storeRegistry = assoc(registry, name, invoke(initFn));
|
||
}
|
||
return get(_storeRegistry, name);
|
||
})(); };
|
||
|
||
// use-store
|
||
var useStore = function(name) { return (isSxTruthy(dictHas(_storeRegistry, name)) ? get(_storeRegistry, name) : error((String("Store not found: ") + String(name) + String(". Call (def-store ...) before (use-store ...).")))); };
|
||
|
||
// clear-stores
|
||
var clearStores = function() { return (_storeRegistry = {}); };
|
||
|
||
// emit-event
|
||
var emitEvent = function(el, eventName, detail) { return domDispatch(el, eventName, detail); };
|
||
|
||
// on-event
|
||
var onEvent = function(el, eventName, handler) { return domListen(el, eventName, handler); };
|
||
|
||
// bridge-event
|
||
var bridgeEvent = function(el, eventName, targetSignal, transformFn) { return effect(function() { return (function() {
|
||
var remove = domListen(el, eventName, function(e) { return (function() {
|
||
var detail = eventDetail(e);
|
||
var newVal = (isSxTruthy(transformFn) ? invoke(transformFn, detail) : detail);
|
||
return reset_b(targetSignal, newVal);
|
||
})(); });
|
||
return remove;
|
||
})(); }); };
|
||
|
||
// resource
|
||
var resource = function(fetchFn) { return (function() {
|
||
var state = signal({["loading"]: true, ["data"]: NIL, ["error"]: NIL});
|
||
promiseThen(invoke(fetchFn), function(data) { return reset_b(state, {["loading"]: false, ["data"]: data, ["error"]: NIL}); }, function(err) { return reset_b(state, {["loading"]: false, ["data"]: NIL, ["error"]: err}); });
|
||
return state;
|
||
})(); };
|
||
|
||
|
||
// =========================================================================
|
||
// 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) 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) {
|
||
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 { invoke(handler); } catch(err) { console.error("[sx-ref] domListen handler error:", name, err); } }
|
||
: function(e) { try { invoke(handler, e); } catch(err) { console.error("[sx-ref] domListen handler error:", name, err); } })
|
||
: 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 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 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 = "<script>window.__sxResolve&&window.__sxResolve(";
|
||
var RESOLVE_END = ")</script>";
|
||
|
||
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("<script>window.__sxResolve");
|
||
// If we found a script tag, or the stream is done, process OOB
|
||
var oobEnd = scriptIdx >= 0 ? scriptIdx : (result.done ? buffer.length : -1);
|
||
if (oobEnd >= 0) {
|
||
var oobContent = buffer.substring(0, oobEnd);
|
||
buffer = buffer.substring(oobEnd);
|
||
initialSwapDone = true;
|
||
|
||
// Process OOB SX content (same as fetchAndRestore)
|
||
oobContent = stripComponentScripts(oobContent);
|
||
// Also strip bare <script type="text/sx"> (extra defs from resolve chunks)
|
||
oobContent = stripSxScripts(oobContent);
|
||
oobContent = extractResponseCss(oobContent);
|
||
oobContent = oobContent.trim();
|
||
if (oobContent.charAt(0) === "(") {
|
||
try {
|
||
var dom = sxRender(oobContent);
|
||
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);
|
||
// Dispatch clientRoute so nav links update active state
|
||
domDispatch(target, "sx:clientRoute",
|
||
{ pathname: new URL(url, location.href).pathname });
|
||
} catch (err) {
|
||
console.error("[sx-ref] streaming OOB swap error:", err);
|
||
}
|
||
}
|
||
// Process any resolve scripts already in buffer
|
||
processResolveScripts();
|
||
}
|
||
} else {
|
||
// Process resolve scripts as they arrive
|
||
processResolveScripts();
|
||
}
|
||
|
||
if (!result.done) return pump();
|
||
});
|
||
}
|
||
|
||
return pump();
|
||
}).catch(function(err) {
|
||
console.error("[sx-ref] streaming fetch error:", err);
|
||
location.reload();
|
||
});
|
||
}
|
||
|
||
function fetchPreload(url, headers, cache) {
|
||
fetch(url, { headers: headers }).then(function(resp) {
|
||
if (!resp.ok) return;
|
||
var ct = resp.headers.get("Content-Type") || "";
|
||
return resp.text().then(function(text) {
|
||
preloadCacheSet(cache, url, text, ct);
|
||
});
|
||
}).catch(function() { /* ignore */ });
|
||
}
|
||
|
||
// --- Request body building ---
|
||
|
||
function buildRequestBody(el, method, url) {
|
||
if (!_hasDom) return { body: null, url: url, "content-type": NIL };
|
||
var body = null;
|
||
var ct = NIL;
|
||
var finalUrl = url;
|
||
var isJson = el.getAttribute("sx-encoding") === "json";
|
||
|
||
if (method !== "GET") {
|
||
var form = el.closest("form") || (el.tagName === "FORM" ? el : null);
|
||
if (form) {
|
||
if (isJson) {
|
||
var fd = new FormData(form);
|
||
var obj = {};
|
||
fd.forEach(function(v, k) {
|
||
if (obj[k] !== undefined) {
|
||
if (!Array.isArray(obj[k])) obj[k] = [obj[k]];
|
||
obj[k].push(v);
|
||
} else { obj[k] = v; }
|
||
});
|
||
body = JSON.stringify(obj);
|
||
ct = "application/json";
|
||
} else {
|
||
body = new URLSearchParams(new FormData(form));
|
||
ct = "application/x-www-form-urlencoded";
|
||
}
|
||
}
|
||
}
|
||
|
||
// sx-params
|
||
var paramsSpec = el.getAttribute("sx-params");
|
||
if (paramsSpec && body instanceof URLSearchParams) {
|
||
if (paramsSpec === "none") {
|
||
body = new URLSearchParams();
|
||
} else if (paramsSpec.indexOf("not ") === 0) {
|
||
paramsSpec.substring(4).split(",").forEach(function(k) { body.delete(k.trim()); });
|
||
} else if (paramsSpec !== "*") {
|
||
var allowed = paramsSpec.split(",").map(function(s) { return s.trim(); });
|
||
var filtered = new URLSearchParams();
|
||
allowed.forEach(function(k) {
|
||
body.getAll(k).forEach(function(v) { filtered.append(k, v); });
|
||
});
|
||
body = filtered;
|
||
}
|
||
}
|
||
|
||
// sx-include
|
||
var includeSel = el.getAttribute("sx-include");
|
||
if (includeSel && method !== "GET") {
|
||
if (!body) body = new URLSearchParams();
|
||
document.querySelectorAll(includeSel).forEach(function(inp) {
|
||
if (inp.name) body.append(inp.name, inp.value);
|
||
});
|
||
}
|
||
|
||
// sx-vals
|
||
var valsAttr = el.getAttribute("sx-vals");
|
||
if (valsAttr) {
|
||
try {
|
||
var vals = valsAttr.charAt(0) === "{" && valsAttr.charAt(1) === ":" ? parse(valsAttr) : JSON.parse(valsAttr);
|
||
if (method === "GET") {
|
||
for (var vk in vals) finalUrl += (finalUrl.indexOf("?") >= 0 ? "&" : "?") + encodeURIComponent(vk) + "=" + encodeURIComponent(vals[vk]);
|
||
} else if (body instanceof URLSearchParams) {
|
||
for (var vk2 in vals) body.append(vk2, vals[vk2]);
|
||
} else if (!body) {
|
||
body = new URLSearchParams();
|
||
for (var vk3 in vals) body.append(vk3, vals[vk3]);
|
||
ct = "application/x-www-form-urlencoded";
|
||
}
|
||
} catch (e) {}
|
||
}
|
||
|
||
// GET form data → URL
|
||
if (method === "GET") {
|
||
var form2 = el.closest("form") || (el.tagName === "FORM" ? el : null);
|
||
if (form2) {
|
||
var qs = new URLSearchParams(new FormData(form2)).toString();
|
||
if (qs) finalUrl += (finalUrl.indexOf("?") >= 0 ? "&" : "?") + qs;
|
||
}
|
||
if ((el.tagName === "INPUT" || el.tagName === "SELECT" || el.tagName === "TEXTAREA") && el.name) {
|
||
finalUrl += (finalUrl.indexOf("?") >= 0 ? "&" : "?") + encodeURIComponent(el.name) + "=" + encodeURIComponent(el.value);
|
||
}
|
||
}
|
||
|
||
return { body: body, url: finalUrl, "content-type": ct };
|
||
}
|
||
|
||
// --- Loading state ---
|
||
|
||
function showIndicator(el) {
|
||
if (!_hasDom) return NIL;
|
||
var sel = el.getAttribute("sx-indicator");
|
||
var ind = sel ? (document.querySelector(sel) || el.closest(sel)) : null;
|
||
if (ind) { ind.classList.add("sx-request"); ind.style.display = ""; }
|
||
return ind || NIL;
|
||
}
|
||
|
||
function disableElements(el) {
|
||
if (!_hasDom) return [];
|
||
var sel = el.getAttribute("sx-disabled-elt");
|
||
if (!sel) return [];
|
||
var elts = Array.prototype.slice.call(document.querySelectorAll(sel));
|
||
elts.forEach(function(e) { e.disabled = true; });
|
||
return elts;
|
||
}
|
||
|
||
function clearLoadingState(el, indicator, disabledElts) {
|
||
el.classList.remove("sx-request");
|
||
el.removeAttribute("aria-busy");
|
||
if (indicator && !isNil(indicator)) {
|
||
indicator.classList.remove("sx-request");
|
||
indicator.style.display = "none";
|
||
}
|
||
if (disabledElts) {
|
||
for (var i = 0; i < disabledElts.length; i++) disabledElts[i].disabled = false;
|
||
}
|
||
}
|
||
|
||
// --- DOM extras ---
|
||
|
||
function domQueryById(id) {
|
||
return _hasDom ? document.getElementById(id) : null;
|
||
}
|
||
|
||
function domMatches(el, sel) {
|
||
return el && el.matches ? el.matches(sel) : false;
|
||
}
|
||
|
||
function domClosest(el, sel) {
|
||
return el && el.closest ? el.closest(sel) : null;
|
||
}
|
||
|
||
function domBody() {
|
||
return _hasDom ? document.body : null;
|
||
}
|
||
|
||
function domHasClass(el, cls) {
|
||
return el && el.classList ? el.classList.contains(cls) : false;
|
||
}
|
||
|
||
function domAppendToHead(el) {
|
||
if (_hasDom && document.head) document.head.appendChild(el);
|
||
}
|
||
|
||
function domParseHtmlDocument(text) {
|
||
if (!_hasDom) return null;
|
||
return new DOMParser().parseFromString(text, "text/html");
|
||
}
|
||
|
||
function domOuterHtml(el) {
|
||
return el ? el.outerHTML : "";
|
||
}
|
||
|
||
function domBodyInnerHtml(doc) {
|
||
return doc && doc.body ? doc.body.innerHTML : "";
|
||
}
|
||
|
||
// --- Events ---
|
||
|
||
function preventDefault_(e) { if (e && e.preventDefault) e.preventDefault(); }
|
||
function stopPropagation_(e) { if (e && e.stopPropagation) e.stopPropagation(); }
|
||
function domFocus(el) { if (el && el.focus) el.focus(); }
|
||
function tryCatch(tryFn, catchFn) {
|
||
var t = _wrapSxFn(tryFn);
|
||
var c = catchFn && catchFn._lambda
|
||
? function(e) { return trampoline(callLambda(catchFn, [e], lambdaClosure(catchFn))); }
|
||
: catchFn;
|
||
try { return t(); } catch (e) { return c(e); }
|
||
}
|
||
function errorMessage(e) {
|
||
return e && e.message ? e.message : String(e);
|
||
}
|
||
function scheduleIdle(fn) {
|
||
var cb = _wrapSxFn(fn);
|
||
if (typeof requestIdleCallback !== "undefined") requestIdleCallback(cb);
|
||
else setTimeout(cb, 0);
|
||
}
|
||
function elementValue(el) { return el && el.value !== undefined ? el.value : NIL; }
|
||
|
||
function domAddListener(el, event, fn, opts) {
|
||
if (!el || !el.addEventListener) return;
|
||
var o = {};
|
||
if (opts && !isNil(opts)) {
|
||
if (opts.once || opts["once"]) o.once = true;
|
||
}
|
||
el.addEventListener(event, function(e) {
|
||
try { fn(e); } catch (err) { logInfo("EVENT ERROR: " + event + " " + (err && err.message ? err.message : err)); console.error("[sx-ref] event handler error:", event, err); }
|
||
}, o);
|
||
}
|
||
|
||
// --- Validation ---
|
||
|
||
function validateForRequest(el) {
|
||
if (!_hasDom) return true;
|
||
var attr = el.getAttribute("sx-validate");
|
||
if (attr === null) {
|
||
var vForm = el.closest("[sx-validate]");
|
||
if (vForm) attr = vForm.getAttribute("sx-validate");
|
||
}
|
||
if (attr === null) return true; // no validation configured
|
||
var form = el.tagName === "FORM" ? el : el.closest("form");
|
||
if (form && !form.reportValidity()) return false;
|
||
if (attr && attr !== "true" && attr !== "") {
|
||
var fn = window[attr];
|
||
if (typeof fn === "function" && !fn(el)) return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
// --- View Transitions ---
|
||
|
||
function withTransition(enabled, fn) {
|
||
if (enabled && _hasDom && document.startViewTransition) {
|
||
document.startViewTransition(fn);
|
||
} else {
|
||
fn();
|
||
}
|
||
}
|
||
|
||
// --- IntersectionObserver ---
|
||
|
||
function observeIntersection(el, fn, once, delay) {
|
||
if (!_hasDom || !("IntersectionObserver" in window)) { fn(); return; }
|
||
var fired = false;
|
||
var d = isNil(delay) ? 0 : delay;
|
||
var obs = new IntersectionObserver(function(entries) {
|
||
entries.forEach(function(entry) {
|
||
if (!entry.isIntersecting) return;
|
||
if (once && fired) return;
|
||
fired = true;
|
||
if (once) obs.unobserve(el);
|
||
if (d) setTimeout(fn, d); else fn();
|
||
});
|
||
});
|
||
obs.observe(el);
|
||
}
|
||
|
||
// --- EventSource ---
|
||
|
||
function eventSourceConnect(url, el) {
|
||
var source = new EventSource(url);
|
||
source.addEventListener("error", function() { domDispatch(el, "sx:sseError", {}); });
|
||
source.addEventListener("open", function() { domDispatch(el, "sx:sseOpen", {}); });
|
||
if (typeof MutationObserver !== "undefined") {
|
||
var obs = new MutationObserver(function() {
|
||
if (!document.body.contains(el)) { source.close(); obs.disconnect(); }
|
||
});
|
||
obs.observe(document.body, { childList: true, subtree: true });
|
||
}
|
||
return source;
|
||
}
|
||
|
||
function eventSourceListen(source, event, fn) {
|
||
source.addEventListener(event, function(e) { fn(e.data); });
|
||
}
|
||
|
||
// --- Boost bindings ---
|
||
|
||
function bindBoostLink(el, _href) {
|
||
el.addEventListener("click", function(e) {
|
||
e.preventDefault();
|
||
// Re-read href from element at click time (not closed-over value)
|
||
var liveHref = el.getAttribute("href") || _href;
|
||
executeRequest(el, { method: "GET", url: liveHref }).then(function() {
|
||
try { history.pushState({ sxUrl: liveHref, scrollY: window.scrollY }, "", liveHref); } catch (err) {}
|
||
});
|
||
});
|
||
}
|
||
|
||
function bindBoostForm(form, _method, _action) {
|
||
form.addEventListener("submit", function(e) {
|
||
e.preventDefault();
|
||
// Re-read from element at submit time
|
||
var liveMethod = (form.getAttribute("method") || _method || "GET").toUpperCase();
|
||
var liveAction = form.getAttribute("action") || _action || location.href;
|
||
executeRequest(form, { method: liveMethod, url: liveAction }).then(function() {
|
||
try { history.pushState({ sxUrl: liveAction, scrollY: window.scrollY }, "", liveAction); } catch (err) {}
|
||
});
|
||
});
|
||
}
|
||
|
||
// --- Client-side route bindings ---
|
||
|
||
function bindClientRouteClick(link, _href, fallbackFn) {
|
||
link.addEventListener("click", function(e) {
|
||
e.preventDefault();
|
||
// Re-read href from element at click time (not closed-over value)
|
||
var liveHref = link.getAttribute("href") || _href;
|
||
var pathname = urlPathname(liveHref);
|
||
// Find target selector: sx-boost ancestor, explicit sx-target, or #main-panel
|
||
var boostEl = link.closest("[sx-boost]");
|
||
var targetSel = boostEl ? boostEl.getAttribute("sx-boost") : null;
|
||
if (!targetSel || targetSel === "true") {
|
||
targetSel = link.getAttribute("sx-target") || "#main-panel";
|
||
}
|
||
if (tryClientRoute(pathname, targetSel)) {
|
||
try { history.pushState({ sxUrl: liveHref, scrollY: window.scrollY }, "", liveHref); } catch (err) {}
|
||
if (typeof window !== "undefined") window.scrollTo(0, 0);
|
||
} else {
|
||
logInfo("sx:route server " + pathname);
|
||
executeRequest(link, { method: "GET", url: liveHref }).then(function() {
|
||
try { history.pushState({ sxUrl: liveHref, scrollY: window.scrollY }, "", liveHref); } catch (err) {}
|
||
}).catch(function(err) {
|
||
logWarn("sx:route server fetch error: " + (err && err.message ? err.message : err));
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
function tryEvalContent(source, env) {
|
||
try {
|
||
var merged = merge(componentEnv);
|
||
if (env && !isNil(env)) {
|
||
var ks = Object.keys(env);
|
||
for (var i = 0; i < ks.length; i++) merged[ks[i]] = env[ks[i]];
|
||
}
|
||
return sxRenderWithEnv(source, merged);
|
||
} catch (e) {
|
||
logInfo("sx:route eval miss: " + (e && e.message ? e.message : e));
|
||
return NIL;
|
||
}
|
||
}
|
||
|
||
// Async eval with callback — used for pages with IO deps.
|
||
// Calls callback(rendered) when done, callback(null) on failure.
|
||
function tryAsyncEvalContent(source, env, callback) {
|
||
var merged = merge(componentEnv);
|
||
if (env && !isNil(env)) {
|
||
var ks = Object.keys(env);
|
||
for (var i = 0; i < ks.length; i++) merged[ks[i]] = env[ks[i]];
|
||
}
|
||
try {
|
||
var result = asyncSxRenderWithEnv(source, merged);
|
||
if (isPromise(result)) {
|
||
result.then(function(rendered) {
|
||
callback(rendered);
|
||
}).catch(function(e) {
|
||
logWarn("sx:async eval miss: " + (e && e.message ? e.message : e));
|
||
callback(null);
|
||
});
|
||
} else {
|
||
callback(result);
|
||
}
|
||
} catch (e) {
|
||
logInfo("sx:async eval miss: " + (e && e.message ? e.message : e));
|
||
callback(null);
|
||
}
|
||
}
|
||
|
||
function resolvePageData(pageName, params, callback) {
|
||
// Platform implementation: fetch page data via HTTP from /sx/data/ endpoint.
|
||
// The spec only knows about resolve-page-data(name, params, callback) —
|
||
// this function provides the concrete transport.
|
||
var url = "/sx/data/" + encodeURIComponent(pageName);
|
||
if (params && !isNil(params)) {
|
||
var qs = [];
|
||
var ks = Object.keys(params);
|
||
for (var i = 0; i < ks.length; i++) {
|
||
var v = params[ks[i]];
|
||
if (v !== null && v !== undefined && v !== NIL) {
|
||
qs.push(encodeURIComponent(ks[i]) + "=" + encodeURIComponent(v));
|
||
}
|
||
}
|
||
if (qs.length) url += "?" + qs.join("&");
|
||
}
|
||
var headers = { "SX-Request": "true" };
|
||
fetch(url, { headers: headers }).then(function(resp) {
|
||
if (!resp.ok) {
|
||
logWarn("sx:data resolve failed " + resp.status + " for " + pageName);
|
||
return;
|
||
}
|
||
return resp.text().then(function(text) {
|
||
try {
|
||
var exprs = parse(text);
|
||
var data = exprs.length === 1 ? exprs[0] : {};
|
||
callback(data || {});
|
||
} catch (e) {
|
||
logWarn("sx:data parse error for " + pageName + ": " + (e && e.message ? e.message : e));
|
||
}
|
||
});
|
||
}).catch(function(err) {
|
||
logWarn("sx:data resolve error for " + pageName + ": " + (err && err.message ? err.message : err));
|
||
});
|
||
}
|
||
|
||
function parseSxData(text) {
|
||
// Parse SX text into a data value. Returns the first parsed expression,
|
||
// or NIL on error. Used by cache update directives.
|
||
try {
|
||
var exprs = parse(text);
|
||
return exprs.length >= 1 ? exprs[0] : NIL;
|
||
} catch (e) {
|
||
logWarn("sx:cache parse error: " + (e && e.message ? e.message : e));
|
||
return NIL;
|
||
}
|
||
}
|
||
|
||
function swPostMessage(msg) {
|
||
// Send a message to the active service worker (if registered).
|
||
// Used to notify SW of cache invalidation.
|
||
if (typeof navigator !== "undefined" && navigator.serviceWorker &&
|
||
navigator.serviceWorker.controller) {
|
||
navigator.serviceWorker.controller.postMessage(msg);
|
||
}
|
||
}
|
||
|
||
function urlPathname(href) {
|
||
try {
|
||
return new URL(href, location.href).pathname;
|
||
} catch (e) {
|
||
// Fallback: strip query/hash
|
||
var idx = href.indexOf("?");
|
||
if (idx >= 0) href = href.substring(0, idx);
|
||
idx = href.indexOf("#");
|
||
if (idx >= 0) href = href.substring(0, idx);
|
||
return href;
|
||
}
|
||
}
|
||
|
||
// --- Preload binding ---
|
||
|
||
function bindPreload(el, events, debounceMs, fn) {
|
||
var timer = null;
|
||
events.forEach(function(evt) {
|
||
el.addEventListener(evt, function() {
|
||
if (debounceMs) {
|
||
clearTimeout(timer);
|
||
timer = setTimeout(fn, debounceMs);
|
||
} else {
|
||
fn();
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
// --- Processing markers ---
|
||
|
||
var PROCESSED = "_sxBound";
|
||
|
||
function markProcessed(el, key) { el[PROCESSED + key] = true; }
|
||
function isProcessed(el, key) { return !!el[PROCESSED + key]; }
|
||
|
||
// --- Script cloning ---
|
||
|
||
function createScriptClone(dead) {
|
||
var live = document.createElement("script");
|
||
for (var i = 0; i < dead.attributes.length; i++)
|
||
live.setAttribute(dead.attributes[i].name, dead.attributes[i].value);
|
||
live.textContent = dead.textContent;
|
||
return live;
|
||
}
|
||
|
||
// --- SX API references ---
|
||
|
||
function sxRender(source) {
|
||
var SxObj = typeof Sx !== "undefined" ? Sx : null;
|
||
if (SxObj && SxObj.render) return SxObj.render(source);
|
||
throw new Error("No SX renderer available");
|
||
}
|
||
|
||
function sxProcessScripts(root) {
|
||
var SxObj = typeof Sx !== "undefined" ? Sx : null;
|
||
var r = (root && root !== NIL) ? root : undefined;
|
||
if (SxObj && SxObj.processScripts) SxObj.processScripts(r);
|
||
}
|
||
|
||
function sxHydrate(root) {
|
||
var SxObj = typeof Sx !== "undefined" ? Sx : null;
|
||
var r = (root && root !== NIL) ? root : undefined;
|
||
if (SxObj && SxObj.hydrate) SxObj.hydrate(r);
|
||
}
|
||
|
||
function loadedComponentNames() {
|
||
var SxObj = typeof Sx !== "undefined" ? Sx : null;
|
||
if (!SxObj) return [];
|
||
var env = SxObj.componentEnv || (SxObj.getEnv ? SxObj.getEnv() : {});
|
||
return Object.keys(env).filter(function(k) { return k.charAt(0) === "~"; });
|
||
}
|
||
|
||
// --- Response processing ---
|
||
|
||
function stripComponentScripts(text) {
|
||
var SxObj = typeof Sx !== "undefined" ? Sx : null;
|
||
return text.replace(/<script[^>]*type="text\/sx"[^>]*data-components[^>]*>([\s\S]*?)<\/script>/gi,
|
||
function(_, defs) { if (SxObj && SxObj.loadComponents) SxObj.loadComponents(defs); return ""; });
|
||
}
|
||
|
||
function stripSxScripts(text) {
|
||
// Strip <script type="text/sx">...</script> (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(/<script[^>]*type="text\/sx"[^>]*>[\s\S]*?<\/script>/gi,
|
||
function(match) {
|
||
if (/data-init/.test(match)) return match; // preserve data-init scripts
|
||
var m = match.match(/<script[^>]*>([\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(/<style[^>]*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 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) 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) {}
|
||
}
|
||
|
||
// --- 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);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
// =========================================================================
|
||
// 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 (typeof renderToHtml === "function") PRIMITIVES["render-to-html"] = renderToHtml;
|
||
if (typeof renderToSx === "function") PRIMITIVES["render-to-sx"] = renderToSx;
|
||
if (typeof aser === "function") PRIMITIVES["aser"] = aser;
|
||
if (typeof renderToDom === "function") PRIMITIVES["render-to-dom"] = renderToDom;
|
||
|
||
// 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["invoke"] = invoke;
|
||
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 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; };
|
||
|
||
// 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;
|
||
|
||
// 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;
|
||
|
||
// =========================================================================
|
||
// 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<Node> 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) {
|
||
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) {
|
||
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) {
|
||
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) {
|
||
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<DocumentFragment>
|
||
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/<name>
|
||
// 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 += " |