|
|
|
|
@@ -135,6 +135,8 @@ class JSEmitter:
|
|
|
|
|
"eval-expr": "evalExpr",
|
|
|
|
|
"eval-list": "evalList",
|
|
|
|
|
"eval-call": "evalCall",
|
|
|
|
|
"is-render-expr?": "isRenderExpr",
|
|
|
|
|
"render-expr": "renderExpr",
|
|
|
|
|
"call-lambda": "callLambda",
|
|
|
|
|
"call-component": "callComponent",
|
|
|
|
|
"parse-keyword-args": "parseKeywordArgs",
|
|
|
|
|
@@ -559,7 +561,7 @@ class JSEmitter:
|
|
|
|
|
|
|
|
|
|
def _emit_fn(self, expr) -> str:
|
|
|
|
|
params = expr[1]
|
|
|
|
|
body = expr[2]
|
|
|
|
|
body = expr[2:]
|
|
|
|
|
param_names = []
|
|
|
|
|
for p in params:
|
|
|
|
|
if isinstance(p, Symbol):
|
|
|
|
|
@@ -567,8 +569,16 @@ class JSEmitter:
|
|
|
|
|
else:
|
|
|
|
|
param_names.append(str(p))
|
|
|
|
|
params_str = ", ".join(param_names)
|
|
|
|
|
body_js = self.emit(body)
|
|
|
|
|
return f"function({params_str}) {{ return {body_js}; }}"
|
|
|
|
|
if len(body) == 1:
|
|
|
|
|
body_js = self.emit(body[0])
|
|
|
|
|
return f"function({params_str}) {{ return {body_js}; }}"
|
|
|
|
|
# Multi-expression body: statements then return last
|
|
|
|
|
parts = []
|
|
|
|
|
for b in body[:-1]:
|
|
|
|
|
parts.append(self.emit_statement(b))
|
|
|
|
|
parts.append(f"return {self.emit(body[-1])};")
|
|
|
|
|
inner = "\n".join(parts)
|
|
|
|
|
return f"function({params_str}) {{ {inner} }}"
|
|
|
|
|
|
|
|
|
|
def _emit_let(self, expr) -> str:
|
|
|
|
|
bindings = expr[1]
|
|
|
|
|
@@ -717,10 +727,10 @@ class JSEmitter:
|
|
|
|
|
# If fn is an inline lambda, emit a for loop
|
|
|
|
|
if isinstance(fn_expr, list) and fn_expr[0] == Symbol("fn"):
|
|
|
|
|
params = fn_expr[1]
|
|
|
|
|
body = fn_expr[2]
|
|
|
|
|
body = fn_expr[2:]
|
|
|
|
|
p = params[0].name if isinstance(params[0], Symbol) else str(params[0])
|
|
|
|
|
p_js = self._mangle(p)
|
|
|
|
|
body_js = self.emit_statement(body)
|
|
|
|
|
body_js = "\n".join(self.emit_statement(b) for b in body)
|
|
|
|
|
return f"{{ var _c = {coll}; for (var _i = 0; _i < _c.length; _i++) {{ var {p_js} = _c[_i]; {body_js} }} }}"
|
|
|
|
|
fn = self.emit(fn_expr)
|
|
|
|
|
return f"{{ var _c = {coll}; for (var _i = 0; _i < _c.length; _i++) {{ {fn}(_c[_i]); }} }}"
|
|
|
|
|
@@ -978,6 +988,7 @@ PLATFORM_JS = '''
|
|
|
|
|
if (x._macro) return "macro";
|
|
|
|
|
if (x._raw) return "raw-html";
|
|
|
|
|
if (x._styleValue) return "style-value";
|
|
|
|
|
if (typeof Node !== "undefined" && x instanceof Node) return "dom-node";
|
|
|
|
|
if (Array.isArray(x)) return "list";
|
|
|
|
|
if (typeof x === "object") return "dict";
|
|
|
|
|
return "unknown";
|
|
|
|
|
@@ -1053,6 +1064,29 @@ PLATFORM_JS = '''
|
|
|
|
|
function dictSet(d, k, v) { d[k] = 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.
|
|
|
|
|
function isRenderExpr(expr) {
|
|
|
|
|
if (!Array.isArray(expr) || !expr.length) return false;
|
|
|
|
|
var h = expr[0];
|
|
|
|
|
if (!h || !h._sym) return false;
|
|
|
|
|
var n = h.name;
|
|
|
|
|
return !!(n === "<>" || n === "raw!" ||
|
|
|
|
|
n.charAt(0) === "~" || n.indexOf("html:") === 0 ||
|
|
|
|
|
(typeof HTML_TAGS !== "undefined" && HTML_TAGS.indexOf(n) >= 0) ||
|
|
|
|
|
(typeof SVG_TAGS !== "undefined" && SVG_TAGS.indexOf(n) >= 0) ||
|
|
|
|
|
(n.indexOf("-") > 0 && expr.length > 1 && expr[1] && expr[1]._kw));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Render dispatch — call the active adapter's render function.
|
|
|
|
|
// Set by each adapter when loaded; defaults to identity (no rendering).
|
|
|
|
|
var _renderExprFn = null;
|
|
|
|
|
function renderExpr(expr, env) {
|
|
|
|
|
if (_renderExprFn) return _renderExprFn(expr, env);
|
|
|
|
|
// No adapter loaded — just return the expression as-is
|
|
|
|
|
return expr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function stripPrefix(s, prefix) {
|
|
|
|
|
return s.indexOf(prefix) === 0 ? s.slice(prefix.length) : s;
|
|
|
|
|
}
|
|
|
|
|
@@ -1366,6 +1400,9 @@ PLATFORM_DOM_JS = """
|
|
|
|
|
|
|
|
|
|
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); };
|
|
|
|
|
|
|
|
|
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
|
|
|
var MATH_NS = "http://www.w3.org/1998/Math/MathML";
|
|
|
|
|
|
|
|
|
|
@@ -1649,7 +1686,7 @@ PLATFORM_ORCHESTRATION_JS = """
|
|
|
|
|
if (config.body && config.method !== "GET") opts.body = config.body;
|
|
|
|
|
if (config["cross-origin"]) opts.credentials = "include";
|
|
|
|
|
|
|
|
|
|
var p = config.preloaded
|
|
|
|
|
var p = (config.preloaded && config.preloaded !== NIL)
|
|
|
|
|
? Promise.resolve({
|
|
|
|
|
ok: true, status: 200,
|
|
|
|
|
headers: new Headers({ "Content-Type": config.preloaded["content-type"] || "" }),
|
|
|
|
|
@@ -2045,23 +2082,25 @@ PLATFORM_ORCHESTRATION_JS = """
|
|
|
|
|
// --- SX API references ---
|
|
|
|
|
|
|
|
|
|
function sxRender(source) {
|
|
|
|
|
var SxObj = typeof Sx !== "undefined" ? Sx : (typeof SxRef !== "undefined" ? SxRef : null);
|
|
|
|
|
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 : (typeof SxRef !== "undefined" ? SxRef : null);
|
|
|
|
|
if (SxObj && SxObj.processScripts) SxObj.processScripts(root || undefined);
|
|
|
|
|
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 : (typeof SxRef !== "undefined" ? SxRef : null);
|
|
|
|
|
if (SxObj && SxObj.hydrate) SxObj.hydrate(root || undefined);
|
|
|
|
|
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 : (typeof SxRef !== "undefined" ? SxRef : null);
|
|
|
|
|
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) === "~"; });
|
|
|
|
|
@@ -2070,7 +2109,7 @@ PLATFORM_ORCHESTRATION_JS = """
|
|
|
|
|
// --- Response processing ---
|
|
|
|
|
|
|
|
|
|
function stripComponentScripts(text) {
|
|
|
|
|
var SxObj = typeof Sx !== "undefined" ? Sx : (typeof SxRef !== "undefined" ? SxRef : null);
|
|
|
|
|
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 ""; });
|
|
|
|
|
}
|
|
|
|
|
@@ -2269,8 +2308,9 @@ PLATFORM_BOOT_JS = """
|
|
|
|
|
|
|
|
|
|
function querySxScripts(root) {
|
|
|
|
|
if (!_hasDom) return [];
|
|
|
|
|
var r = (root && root !== NIL) ? root : document;
|
|
|
|
|
return Array.prototype.slice.call(
|
|
|
|
|
(root || document).querySelectorAll('script[type="text/sx"]'));
|
|
|
|
|
r.querySelectorAll('script[type="text/sx"]'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function queryStyleScripts() {
|
|
|
|
|
@@ -2556,11 +2596,13 @@ def public_api_js(has_html, has_sx, has_dom, has_engine, has_orch, has_cssx, has
|
|
|
|
|
return parts.join("");
|
|
|
|
|
}''')
|
|
|
|
|
|
|
|
|
|
# Build SxRef object
|
|
|
|
|
# Build Sx object
|
|
|
|
|
version = f"ref-2.0 ({adapter_label}, bootstrap-compiled)"
|
|
|
|
|
api_lines.append(f'''
|
|
|
|
|
var SxRef = {{
|
|
|
|
|
var Sx = {{
|
|
|
|
|
VERSION: "ref-2.0",
|
|
|
|
|
parse: parse,
|
|
|
|
|
parseAll: parse,
|
|
|
|
|
eval: function(expr, env) {{ return trampoline(evalExpr(expr, env || merge(componentEnv))); }},
|
|
|
|
|
loadComponents: loadComponents,
|
|
|
|
|
render: render,{"" if has_html else ""}
|
|
|
|
|
@@ -2569,6 +2611,8 @@ def public_api_js(has_html, has_sx, has_dom, has_engine, has_orch, has_cssx, has
|
|
|
|
|
NIL: NIL,
|
|
|
|
|
Symbol: Symbol,
|
|
|
|
|
Keyword: Keyword,
|
|
|
|
|
isTruthy: isSxTruthy,
|
|
|
|
|
isNil: isNil,
|
|
|
|
|
componentEnv: componentEnv,''')
|
|
|
|
|
|
|
|
|
|
if has_html:
|
|
|
|
|
@@ -2612,27 +2656,27 @@ def public_api_js(has_html, has_sx, has_dom, has_engine, has_orch, has_cssx, has
|
|
|
|
|
api_lines.append('''
|
|
|
|
|
// --- Auto-init ---
|
|
|
|
|
if (typeof document !== "undefined") {
|
|
|
|
|
var _sxRefInit = function() { bootInit(); };
|
|
|
|
|
var _sxInit = function() { bootInit(); };
|
|
|
|
|
if (document.readyState === "loading") {
|
|
|
|
|
document.addEventListener("DOMContentLoaded", _sxRefInit);
|
|
|
|
|
document.addEventListener("DOMContentLoaded", _sxInit);
|
|
|
|
|
} else {
|
|
|
|
|
_sxRefInit();
|
|
|
|
|
_sxInit();
|
|
|
|
|
}
|
|
|
|
|
}''')
|
|
|
|
|
elif has_orch:
|
|
|
|
|
api_lines.append('''
|
|
|
|
|
// --- Auto-init ---
|
|
|
|
|
if (typeof document !== "undefined") {
|
|
|
|
|
var _sxRefInit = function() { engineInit(); };
|
|
|
|
|
var _sxInit = function() { engineInit(); };
|
|
|
|
|
if (document.readyState === "loading") {
|
|
|
|
|
document.addEventListener("DOMContentLoaded", _sxRefInit);
|
|
|
|
|
document.addEventListener("DOMContentLoaded", _sxInit);
|
|
|
|
|
} else {
|
|
|
|
|
_sxRefInit();
|
|
|
|
|
_sxInit();
|
|
|
|
|
}
|
|
|
|
|
}''')
|
|
|
|
|
|
|
|
|
|
api_lines.append(' if (typeof module !== "undefined" && module.exports) module.exports = SxRef;')
|
|
|
|
|
api_lines.append(' else global.SxRef = SxRef;')
|
|
|
|
|
api_lines.append(' if (typeof module !== "undefined" && module.exports) module.exports = Sx;')
|
|
|
|
|
api_lines.append(' else global.Sx = Sx;')
|
|
|
|
|
|
|
|
|
|
return "\n".join(api_lines)
|
|
|
|
|
|
|
|
|
|
|