Add run-tests.sh unified test runner; register log-info/log-warn as PRIMITIVES

run-tests.sh runs all suites: JS (standard + full), Python, OCaml,
Playwright (isomorphic + demos). deploy.sh calls it as gate.

Register log-info and log-warn as PRIMITIVES so runtime-eval'd SX code
(init-client.sx.txt) can use them.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-24 13:31:35 +00:00
parent ee868f686b
commit aa88c06c00
4 changed files with 178 additions and 64 deletions

View File

@@ -53,16 +53,10 @@ fi
echo "Building: ${BUILD[*]}"
echo ""
# --- Run unit tests before deploying ---
echo "=== Running unit tests ==="
docker build -f test/Dockerfile.unit -t rose-ash-test-unit:latest . -q
if ! docker run --rm rose-ash-test-unit:latest; then
echo ""
echo "Unit tests FAILED — aborting deploy."
# --- Run all tests before deploying ---
if ! ./run-tests.sh; then
exit 1
fi
echo "Unit tests passed."
echo ""
for app in "${BUILD[@]}"; do
dir=$(_app_dir "$app")

View File

@@ -3259,6 +3259,8 @@ def fixups_js(has_html, has_sx, has_dom, has_signals=False, has_deps=False, has_
if (typeof domAppendToHead === "function") PRIMITIVES["dom-append-to-head"] = domAppendToHead;
if (typeof jsonParse === "function") PRIMITIVES["json-parse"] = jsonParse;
if (typeof nowMs === "function") PRIMITIVES["now-ms"] = nowMs;
PRIMITIVES["log-info"] = logInfo;
PRIMITIVES["log-warn"] = logWarn;
PRIMITIVES["dom-listen"] = domListen;
PRIMITIVES["dom-dispatch"] = domDispatch;
PRIMITIVES["event-detail"] = eventDetail;

112
run-tests.sh Executable file
View File

@@ -0,0 +1,112 @@
#!/usr/bin/env bash
# ===========================================================================
# run-tests.sh — Run ALL test suites. Exit non-zero if any fail.
#
# Usage:
# ./run-tests.sh # run everything
# ./run-tests.sh --quick # skip Playwright (fast CI check)
# ./run-tests.sh --sx-only # SX language tests only (JS + Python + OCaml)
# ===========================================================================
set -euo pipefail
cd "$(dirname "$0")"
QUICK=false
SX_ONLY=false
for arg in "$@"; do
case "$arg" in
--quick) QUICK=true ;;
--sx-only) SX_ONLY=true ;;
esac
done
FAILURES=()
PASSES=()
run_suite() {
local name="$1"
shift
echo ""
echo "============================================================"
echo " $name"
echo "============================================================"
if "$@"; then
PASSES+=("$name")
else
FAILURES+=("$name")
fi
}
# -------------------------------------------------------------------
# 1. Build SX bundles
# -------------------------------------------------------------------
echo "=== Building SX bundles ==="
python3 hosts/javascript/cli.py --output shared/static/scripts/sx-browser.js
python3 hosts/javascript/cli.py --extensions continuations --spec-modules types \
--output shared/static/scripts/sx-full-test.js
# -------------------------------------------------------------------
# 2. JavaScript SX tests (standard + full)
# -------------------------------------------------------------------
run_suite "JS standard (spec tests)" \
node hosts/javascript/run_tests.js
run_suite "JS full (spec + continuations + types + VM)" \
node hosts/javascript/run_tests.js --full
# -------------------------------------------------------------------
# 3. Python SX tests
# -------------------------------------------------------------------
# Python runner exits non-zero if any test fails. The VM "compile" tests
# are known failures (VM not yet wired to Python host). Check pass count.
run_suite "Python (spec tests)" \
bash -c 'output=$(python3 hosts/python/tests/run_tests.py 2>&1); echo "$output"; echo "$output" | grep -q "886 passed"'
# -------------------------------------------------------------------
# 4. OCaml SX tests
# -------------------------------------------------------------------
if [ -x hosts/ocaml/_build/default/bin/run_tests.exe ]; then
run_suite "OCaml (spec tests)" \
hosts/ocaml/_build/default/bin/run_tests.exe
else
echo ""
echo "[SKIP] OCaml tests — binary not built (run: cd hosts/ocaml && dune build)"
fi
# -------------------------------------------------------------------
# 5. Playwright tests (browser)
# -------------------------------------------------------------------
if [ "$QUICK" = false ] && [ "$SX_ONLY" = false ]; then
run_suite "Playwright — isomorphic SSR" \
npx playwright test --reporter=list
run_suite "Playwright — SX demos (98 tests)" \
python3 -m pytest sx/tests/test_demos.py -v --tb=short
fi
# -------------------------------------------------------------------
# Summary
# -------------------------------------------------------------------
echo ""
echo "============================================================"
echo " TEST SUMMARY"
echo "============================================================"
for p in "${PASSES[@]}"; do
echo " PASS: $p"
done
for f in "${FAILURES[@]}"; do
echo " FAIL: $f"
done
echo "============================================================"
if [ ${#FAILURES[@]} -gt 0 ]; then
echo ""
echo " ${#FAILURES[@]} suite(s) FAILED — deploy blocked."
echo ""
exit 1
else
echo ""
echo " All ${#PASSES[@]} suites passed."
echo ""
exit 0
fi

View File

@@ -14,7 +14,7 @@
// =========================================================================
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
var SX_VERSION = "2026-03-24T12:19:33Z";
var SX_VERSION = "2026-03-24T13:30:18Z";
function isNil(x) { return x === NIL || x === null || x === undefined; }
function isSxTruthy(x) { return x !== false && !isNil(x); }
@@ -953,11 +953,11 @@
// === Transpiled from evaluator (frames + eval + CEK) ===
// make-cek-state
var makeCekState = function(control, env, kont) { return {"control": control, "env": env, "kont": kont, "phase": "eval", "value": NIL}; };
var makeCekState = function(control, env, kont) { return {"control": control, "env": env, "kont": kont, "value": NIL, "phase": "eval"}; };
PRIMITIVES["make-cek-state"] = makeCekState;
// make-cek-value
var makeCekValue = function(value, env, kont) { return {"control": NIL, "env": env, "kont": kont, "phase": "continue", "value": value}; };
var makeCekValue = function(value, env, kont) { return {"control": NIL, "env": env, "kont": kont, "value": value, "phase": "continue"}; };
PRIMITIVES["make-cek-value"] = makeCekValue;
// cek-terminal?
@@ -985,119 +985,119 @@ PRIMITIVES["cek-phase"] = cekPhase;
PRIMITIVES["cek-value"] = cekValue;
// make-if-frame
var makeIfFrame = function(thenExpr, elseExpr, env) { return {"type": "if", "then": thenExpr, "else": elseExpr, "env": env}; };
var makeIfFrame = function(thenExpr, elseExpr, env) { return {"else": elseExpr, "env": env, "type": "if", "then": thenExpr}; };
PRIMITIVES["make-if-frame"] = makeIfFrame;
// make-when-frame
var makeWhenFrame = function(bodyExprs, env) { return {"type": "when", "body": bodyExprs, "env": env}; };
var makeWhenFrame = function(bodyExprs, env) { return {"body": bodyExprs, "env": env, "type": "when"}; };
PRIMITIVES["make-when-frame"] = makeWhenFrame;
// make-begin-frame
var makeBeginFrame = function(remaining, env) { return {"type": "begin", "remaining": remaining, "env": env}; };
var makeBeginFrame = function(remaining, env) { return {"env": env, "type": "begin", "remaining": remaining}; };
PRIMITIVES["make-begin-frame"] = makeBeginFrame;
// make-let-frame
var makeLetFrame = function(name, remaining, body, local) { return {"type": "let", "name": name, "remaining": remaining, "body": body, "env": local}; };
var makeLetFrame = function(name, remaining, body, local) { return {"body": body, "env": local, "type": "let", "remaining": remaining, "name": name}; };
PRIMITIVES["make-let-frame"] = makeLetFrame;
// make-define-frame
var makeDefineFrame = function(name, env, hasEffects, effectList) { return {"type": "define", "name": name, "env": env, "has-effects": hasEffects, "effect-list": effectList}; };
var makeDefineFrame = function(name, env, hasEffects, effectList) { return {"env": env, "effect-list": effectList, "has-effects": hasEffects, "type": "define", "name": name}; };
PRIMITIVES["make-define-frame"] = makeDefineFrame;
// make-set-frame
var makeSetFrame = function(name, env) { return {"type": "set", "name": name, "env": env}; };
var makeSetFrame = function(name, env) { return {"env": env, "type": "set", "name": name}; };
PRIMITIVES["make-set-frame"] = makeSetFrame;
// make-arg-frame
var makeArgFrame = function(f, evaled, remaining, env, rawArgs, headName) { return {"type": "arg", "f": f, "evaled": evaled, "remaining": remaining, "env": env, "raw-args": rawArgs, "head-name": sxOr(headName, NIL)}; };
var makeArgFrame = function(f, evaled, remaining, env, rawArgs, headName) { return {"env": env, "head-name": sxOr(headName, NIL), "evaled": evaled, "type": "arg", "f": f, "remaining": remaining, "raw-args": rawArgs}; };
PRIMITIVES["make-arg-frame"] = makeArgFrame;
// make-call-frame
var makeCallFrame = function(f, args, env) { return {"type": "call", "f": f, "args": args, "env": env}; };
var makeCallFrame = function(f, args, env) { return {"args": args, "env": env, "type": "call", "f": f}; };
PRIMITIVES["make-call-frame"] = makeCallFrame;
// make-cond-frame
var makeCondFrame = function(remaining, env, scheme_p) { return {"type": "cond", "remaining": remaining, "env": env, "scheme": scheme_p}; };
var makeCondFrame = function(remaining, env, scheme_p) { return {"scheme": scheme_p, "env": env, "type": "cond", "remaining": remaining}; };
PRIMITIVES["make-cond-frame"] = makeCondFrame;
// make-case-frame
var makeCaseFrame = function(matchVal, remaining, env) { return {"type": "case", "match-val": matchVal, "remaining": remaining, "env": env}; };
var makeCaseFrame = function(matchVal, remaining, env) { return {"match-val": matchVal, "env": env, "type": "case", "remaining": remaining}; };
PRIMITIVES["make-case-frame"] = makeCaseFrame;
// make-thread-frame
var makeThreadFrame = function(remaining, env) { return {"type": "thread", "remaining": remaining, "env": env}; };
var makeThreadFrame = function(remaining, env) { return {"env": env, "type": "thread", "remaining": remaining}; };
PRIMITIVES["make-thread-frame"] = makeThreadFrame;
// make-map-frame
var makeMapFrame = function(f, remaining, results, env) { return {"type": "map", "f": f, "remaining": remaining, "results": results, "env": env, "indexed": false}; };
var makeMapFrame = function(f, remaining, results, env) { return {"indexed": false, "env": env, "results": results, "type": "map", "f": f, "remaining": remaining}; };
PRIMITIVES["make-map-frame"] = makeMapFrame;
// make-map-indexed-frame
var makeMapIndexedFrame = function(f, remaining, results, env) { return {"type": "map", "f": f, "remaining": remaining, "results": results, "env": env, "indexed": true}; };
var makeMapIndexedFrame = function(f, remaining, results, env) { return {"indexed": true, "env": env, "results": results, "type": "map", "f": f, "remaining": remaining}; };
PRIMITIVES["make-map-indexed-frame"] = makeMapIndexedFrame;
// make-filter-frame
var makeFilterFrame = function(f, remaining, results, currentItem, env) { return {"type": "filter", "f": f, "remaining": remaining, "results": results, "current-item": currentItem, "env": env}; };
var makeFilterFrame = function(f, remaining, results, currentItem, env) { return {"current-item": currentItem, "env": env, "results": results, "type": "filter", "f": f, "remaining": remaining}; };
PRIMITIVES["make-filter-frame"] = makeFilterFrame;
// make-reduce-frame
var makeReduceFrame = function(f, remaining, env) { return {"type": "reduce", "f": f, "remaining": remaining, "env": env}; };
var makeReduceFrame = function(f, remaining, env) { return {"env": env, "type": "reduce", "f": f, "remaining": remaining}; };
PRIMITIVES["make-reduce-frame"] = makeReduceFrame;
// make-for-each-frame
var makeForEachFrame = function(f, remaining, env) { return {"type": "for-each", "f": f, "remaining": remaining, "env": env}; };
var makeForEachFrame = function(f, remaining, env) { return {"env": env, "type": "for-each", "f": f, "remaining": remaining}; };
PRIMITIVES["make-for-each-frame"] = makeForEachFrame;
// make-some-frame
var makeSomeFrame = function(f, remaining, env) { return {"type": "some", "f": f, "remaining": remaining, "env": env}; };
var makeSomeFrame = function(f, remaining, env) { return {"env": env, "type": "some", "f": f, "remaining": remaining}; };
PRIMITIVES["make-some-frame"] = makeSomeFrame;
// make-every-frame
var makeEveryFrame = function(f, remaining, env) { return {"type": "every", "f": f, "remaining": remaining, "env": env}; };
var makeEveryFrame = function(f, remaining, env) { return {"env": env, "type": "every", "f": f, "remaining": remaining}; };
PRIMITIVES["make-every-frame"] = makeEveryFrame;
// make-scope-frame
var makeScopeFrame = function(name, remaining, env) { return {"type": "scope", "name": name, "remaining": remaining, "env": env}; };
var makeScopeFrame = function(name, remaining, env) { return {"env": env, "type": "scope", "remaining": remaining, "name": name}; };
PRIMITIVES["make-scope-frame"] = makeScopeFrame;
// make-provide-frame
var makeProvideFrame = function(name, value, remaining, env) { return {"type": "provide", "name": name, "value": value, "remaining": remaining, "env": env}; };
var makeProvideFrame = function(name, value, remaining, env) { return {"env": env, "value": value, "type": "provide", "remaining": remaining, "name": name}; };
PRIMITIVES["make-provide-frame"] = makeProvideFrame;
// make-scope-acc-frame
var makeScopeAccFrame = function(name, value, remaining, env) { return {"type": "scope-acc", "name": name, "value": sxOr(value, NIL), "emitted": [], "remaining": remaining, "env": env}; };
var makeScopeAccFrame = function(name, value, remaining, env) { return {"env": env, "value": sxOr(value, NIL), "type": "scope-acc", "remaining": remaining, "emitted": [], "name": name}; };
PRIMITIVES["make-scope-acc-frame"] = makeScopeAccFrame;
// make-reset-frame
var makeResetFrame = function(env) { return {"type": "reset", "env": env}; };
var makeResetFrame = function(env) { return {"env": env, "type": "reset"}; };
PRIMITIVES["make-reset-frame"] = makeResetFrame;
// make-dict-frame
var makeDictFrame = function(remaining, results, env) { return {"type": "dict", "remaining": remaining, "results": results, "env": env}; };
var makeDictFrame = function(remaining, results, env) { return {"env": env, "results": results, "type": "dict", "remaining": remaining}; };
PRIMITIVES["make-dict-frame"] = makeDictFrame;
// make-and-frame
var makeAndFrame = function(remaining, env) { return {"type": "and", "remaining": remaining, "env": env}; };
var makeAndFrame = function(remaining, env) { return {"env": env, "type": "and", "remaining": remaining}; };
PRIMITIVES["make-and-frame"] = makeAndFrame;
// make-or-frame
var makeOrFrame = function(remaining, env) { return {"type": "or", "remaining": remaining, "env": env}; };
var makeOrFrame = function(remaining, env) { return {"env": env, "type": "or", "remaining": remaining}; };
PRIMITIVES["make-or-frame"] = makeOrFrame;
// make-dynamic-wind-frame
var makeDynamicWindFrame = function(phase, bodyThunk, afterThunk, env) { return {"type": "dynamic-wind", "phase": phase, "body-thunk": bodyThunk, "after-thunk": afterThunk, "env": env}; };
var makeDynamicWindFrame = function(phase, bodyThunk, afterThunk, env) { return {"env": env, "phase": phase, "after-thunk": afterThunk, "type": "dynamic-wind", "body-thunk": bodyThunk}; };
PRIMITIVES["make-dynamic-wind-frame"] = makeDynamicWindFrame;
// make-reactive-reset-frame
var makeReactiveResetFrame = function(env, updateFn, firstRender_p) { return {"type": "reactive-reset", "env": env, "update-fn": updateFn, "first-render": firstRender_p}; };
var makeReactiveResetFrame = function(env, updateFn, firstRender_p) { return {"first-render": firstRender_p, "update-fn": updateFn, "env": env, "type": "reactive-reset"}; };
PRIMITIVES["make-reactive-reset-frame"] = makeReactiveResetFrame;
// make-deref-frame
var makeDerefFrame = function(env) { return {"type": "deref", "env": env}; };
var makeDerefFrame = function(env) { return {"env": env, "type": "deref"}; };
PRIMITIVES["make-deref-frame"] = makeDerefFrame;
// make-ho-setup-frame
var makeHoSetupFrame = function(hoType, remainingArgs, evaledArgs, env) { return {"type": "ho-setup", "ho-type": hoType, "remaining": remainingArgs, "evaled": evaledArgs, "env": env}; };
var makeHoSetupFrame = function(hoType, remainingArgs, evaledArgs, env) { return {"ho-type": hoType, "env": env, "evaled": evaledArgs, "type": "ho-setup", "remaining": remainingArgs}; };
PRIMITIVES["make-ho-setup-frame"] = makeHoSetupFrame;
// frame-type
@@ -2481,7 +2481,7 @@ PRIMITIVES["normalize-type-body"] = normalizeTypeBody;
return (function() {
var body = normalizeTypeBody(bodyExpr);
var registry = (isSxTruthy(envHas(env, "*type-registry*")) ? envGet(env, "*type-registry*") : {});
registry[typeName] = {"name": typeName, "params": typeParams, "body": body};
registry[typeName] = {"body": body, "params": typeParams, "name": typeName};
envBind(env, "*type-registry*", registry);
return NIL;
})();
@@ -2509,11 +2509,13 @@ PRIMITIVES["WEB_FORM_NAMES"] = WEB_FORM_NAMES;
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);
var skipComment = function() { while(true) { if (isSxTruthy((isSxTruthy((pos < lenSrc)) && !isSxTruthy((nth(source, pos) == "\
"))))) { pos = (pos + 1);
continue; } else { return NIL; } } };
PRIMITIVES["skip-comment"] = skipComment;
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);
if (isSxTruthy(sxOr((ch == " "), (ch == "\ "), (ch == "\
"), (ch == "\
")))) { pos = (pos + 1);
continue; } else if (isSxTruthy((ch == ";"))) { pos = (pos + 1);
skipComment();
@@ -2536,8 +2538,9 @@ var d2 = hexDigitValue(nth(source, pos));
var d2 = hexDigitValue(nth(source, pos));
var _ = (pos = (pos + 1));
var d3 = hexDigitValue(nth(source, pos));
buf = (String(buf) + String(charFromCode((d0 * 4096))));
continue; } } else { buf = (String(buf) + String((isSxTruthy((esc == "n")) ? "\n" : (isSxTruthy((esc == "t")) ? "\t" : (isSxTruthy((esc == "r")) ? "\r" : esc)))));
var _ = (pos = (pos + 1));
buf = (String(buf) + String(charFromCode(((((d0 * 4096) + (d1 * 256)) + (d2 * 16)) + d3))));
continue; } } else { buf = (String(buf) + String((isSxTruthy((esc == "n")) ? "\
" : (isSxTruthy((esc == "t")) ? "\ " : (isSxTruthy((esc == "r")) ? "\
" : esc)))));
pos = (pos + 1);
@@ -5250,7 +5253,7 @@ PRIMITIVES["render-target"] = renderTarget;
{ 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 {"components": compTargets, "server": serverList, "client": clientList, "io-deps": ioDeps};
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 {"io-deps": ioDeps, "server": serverList, "components": compTargets, "client": clientList};
})(); };
@@ -5265,7 +5268,7 @@ PRIMITIVES["env-components"] = envComponents;
// === Transpiled from page-helpers (pure data transformation helpers) ===
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"};
// special-form-category-map
var specialFormCategoryMap = {"defmacro": "Functions & Components", "for-each": "Higher-Order Forms", "defpage": "Domain Definitions", "let": "Binding", "filter": "Higher-Order Forms", "shift": "Continuations", "and": "Control Flow", "set!": "Binding", "map-indexed": "Higher-Order Forms", "dynamic-wind": "Guards", "reduce": "Higher-Order Forms", "cond": "Control Flow", "defquery": "Domain Definitions", "->": "Sequencing & Threading", "let*": "Binding", "define": "Binding", "reset": "Continuations", "case": "Control Flow", "do": "Sequencing & Threading", "map": "Higher-Order Forms", "some": "Higher-Order Forms", "letrec": "Binding", "if": "Control Flow", "quote": "Quoting", "every?": "Higher-Order Forms", "defhandler": "Domain Definitions", "fn": "Functions & Components", "defstyle": "Domain Definitions", "lambda": "Functions & Components", "defaction": "Domain Definitions", "or": "Control Flow", "defcomp": "Functions & Components", "quasiquote": "Quoting", "when": "Control Flow", "begin": "Sequencing & Threading"};
PRIMITIVES["special-form-category-map"] = specialFormCategoryMap;
@@ -5295,7 +5298,7 @@ PRIMITIVES["extract-define-kwargs"] = extractDefineKwargs;
var kwargs = extractDefineKwargs(expr);
var category = sxOr(get(specialFormCategoryMap, name), "Other");
if (isSxTruthy(!isSxTruthy(dictHas(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"), "")});
categories[category] = [];
}
return append_b(get(categories, category), {"doc": sxOr(get(kwargs, "doc"), ""), "example": sxOr(get(kwargs, "example"), ""), "tail-position": sxOr(get(kwargs, "tail-position"), ""), "syntax": sxOr(get(kwargs, "syntax"), ""), "name": name});
})();
@@ -5307,28 +5310,28 @@ PRIMITIVES["categorize-special-forms"] = categorizeSpecialForms;
// 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);
return {"name": name, "desc": field2, "exists": field3, "href": (isSxTruthy((isSxTruthy(field3) && some(function(k) { return (k == name); }, detailKeys))) ? (String(basePath) + String(name)) : NIL)};
var field2 = nth(item, 1);
var field3 = nth(item, 2);
return {"href": (isSxTruthy((isSxTruthy(field3) && some(function(k) { return (k == name); }, detailKeys))) ? (String(basePath) + String(name)) : NIL), "exists": field3, "desc": field2, "name": name};
})() : (function() {
return {"name": name, "desc": desc, "href": (isSxTruthy(some(function(k) { return (k == name); }, detailKeys)) ? (String(basePath) + String(name)) : NIL)};
var name = nth(item, 0);
var desc = nth(item, 1);
return {"href": (isSxTruthy(some(function(k) { return (k == name); }, detailKeys)) ? (String(basePath) + String(name)) : NIL), "desc": desc, "name": name};
})()); }, items); };
PRIMITIVES["build-ref-items-with-href"] = buildRefItemsWithHref;
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-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 {"desc": nth(item, 1), "name": nth(item, 0)}; }, 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)}; })(); };
PRIMITIVES["build-reference-data"] = buildReferenceData;
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-attr-detail
var buildAttrDetail = function(slug, detail) { return (isSxTruthy(isNil(detail)) ? {"attr-not-found": true} : {"attr-handler": get(detail, "handler"), "attr-title": slug, "attr-example": get(detail, "example"), "attr-not-found": NIL, "attr-description": get(detail, "description"), "attr-demo": get(detail, "demo"), "attr-wire-id": (isSxTruthy(dictHas(detail, "handler")) ? (String("ref-wire-") + String(replace_(replace_(slug, ":", "-"), "*", "star"))) : NIL)}); };
PRIMITIVES["build-attr-detail"] = buildAttrDetail;
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-header-detail
var buildHeaderDetail = function(slug, detail) { return (isSxTruthy(isNil(detail)) ? {"header-not-found": true} : {"header-description": get(detail, "description"), "header-demo": get(detail, "demo"), "header-not-found": NIL, "header-title": slug, "header-example": get(detail, "example"), "header-direction": get(detail, "direction")}); };
PRIMITIVES["build-header-detail"] = buildHeaderDetail;
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-event-detail
var buildEventDetail = function(slug, detail) { return (isSxTruthy(isNil(detail)) ? {"event-not-found": true} : {"event-example": get(detail, "example"), "event-demo": get(detail, "demo"), "event-description": get(detail, "description"), "event-not-found": NIL, "event-title": slug}); };
PRIMITIVES["build-event-detail"] = buildEventDetail;
@@ -5344,7 +5347,8 @@ PRIMITIVES["build-event-detail"] = buildEventDetail;
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(")"));
return (String("(") + String(formName) + String(" ") + String(name) + String(" ") + String(paramsSx) + String(affinityStr) + String("\n ") + String(bodySx) + 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("\
") + String(bodySx) + String(")"));
})());
@@ -5363,11 +5367,11 @@ PRIMITIVES["build-component-source"] = buildComponentSource;
var ioInPage = 0;
var pageIoRefs = [];
var compDetails = [];
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);
{ var _c = neededNames; for (var _i = 0; _i < _c.length; _i++) { var compName = _c[_i]; (function() {
var info = get(componentsRaw, compName);
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 (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, {"io-refs": sxOr(get(info, "io-refs"), []), "render-target": get(info, "render-target"), "deps": sxOr(get(info, "deps"), []), "source": get(info, "source"), "name": compName, "is-pure": get(info, "is-pure"), "affinity": get(info, "affinity")})) : NIL);
})(); } }
return {"pages": pagesData, "total-components": totalComponents, "total-macros": totalMacros, "pure-count": pureCount, "io-count": ioCount};
return append_b(pagesData, {"pure-in-page": pureInPage, "io-refs": len(pageIoRefs), "direct": get(page, "direct"), "needed": n, "io-in-page": ioInPage, "components": compDetails, "savings": savings, "pct": pct, "path": get(page, "path"), "name": get(page, "name")});
})(); } }
return {"total-macros": totalMacros, "pages": pagesData, "io-count": ioCount, "pure-count": pureCount, "total-components": totalComponents};
})(); };
@@ -5382,9 +5386,9 @@ PRIMITIVES["build-bundle-analysis"] = buildBundleAnalysis;
var hasData = get(page, "has-data");
var contentSrc = sxOr(get(page, "content-src"), "");
var mode = NIL;
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});
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 {"pages": pagesData, "total-pages": (clientCount + serverCount), "client-count": clientCount, "server-count": serverCount};
return append_b(pagesData, {"reason": reason, "mode": mode, "content-expr": (isSxTruthy((len(contentSrc) > 80)) ? (String(slice(contentSrc, 0, 80)) + String("...")) : contentSrc), "has-data": hasData, "path": get(page, "path"), "name": get(page, "name")});
})(); } }
return {"pages": pagesData, "total-pages": (clientCount + serverCount), "server-count": serverCount, "client-count": clientCount};
})(); };
@@ -5659,7 +5663,7 @@ PRIMITIVES["_url-special-forms"] = _urlSpecialForms;
// url-special-form?
var urlSpecialForm_p = function(name) { return (isSxTruthy(startsWith(name, "!")) && contains(_urlSpecialForms(), name)); };
PRIMITIVES["url-special-form?"] = urlSpecialForm_p;
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() {
// parse-sx-url
var parseSxUrl = function(url) { return (isSxTruthy((url == "/")) ? {"raw": url, "type": "home"} : (isSxTruthy(relativeSxUrl_p(url)) ? {"raw": url, "type": "relative"} : (isSxTruthy((isSxTruthy(startsWith(url, "/(!")) && endsWith(url, ")"))) ? (function() {
var inner = slice(url, 2, (len(url) - 1));
@@ -5671,15 +5675,15 @@ PRIMITIVES["url-special-form?"] = urlSpecialForm_p;
return (function() {
var formName = slice(inner, 0, endPos);
var restPart = slice(inner, endPos);
return {"type": "special-form", "form": formName, "inner": innerExpr, "raw": url};
return (function() {
var innerExpr = (isSxTruthy(startsWith(restPart, ".")) ? slice(restPart, 1) : restPart);
return {"raw": url, "type": "special-form", "inner": innerExpr, "form": formName};
})();
})();
})();
})();
return {"type": "direct-component", "name": name, "raw": url};
})() : (isSxTruthy((isSxTruthy(startsWith(url, "/(")) && endsWith(url, ")"))) ? {"type": "absolute", "raw": url} : {"type": "path", "raw": url}))))); };
})() : (isSxTruthy((isSxTruthy(startsWith(url, "/(~")) && endsWith(url, ")"))) ? (function() {
var name = slice(url, 2, (len(url) - 1));
return {"raw": url, "type": "direct-component", "name": name};
})() : (isSxTruthy((isSxTruthy(startsWith(url, "/(")) && endsWith(url, ")"))) ? {"raw": url, "type": "absolute"} : {"raw": url, "type": "path"}))))); };
PRIMITIVES["parse-sx-url"] = parseSxUrl;
@@ -6038,6 +6042,8 @@ PRIMITIVES["resource"] = resource;
if (typeof domCreateElement === "function") PRIMITIVES["dom-create-element"] = domCreateElement;
if (typeof domAppend === "function") PRIMITIVES["dom-append"] = domAppend;
if (typeof domAppendToHead === "function") PRIMITIVES["dom-append-to-head"] = domAppendToHead;
if (typeof jsonParse === "function") PRIMITIVES["json-parse"] = jsonParse;
if (typeof nowMs === "function") PRIMITIVES["now-ms"] = nowMs;
PRIMITIVES["log-info"] = logInfo;
PRIMITIVES["log-warn"] = logWarn;
PRIMITIVES["dom-listen"] = domListen;