htmx demos working: activation, fetch, swap, OOB filtering, test runner page

- htmx-boot-subtree! wired into process-elements for auto-activation
- Fixed cond compilation bug in hx-verb-info (Clojure-style flat cond)
- Platform io-fetch upgraded: method/body/headers support, full response dict
- Replaced perform IO ops with browser primitives (set-timeout, browser-confirm, etc)
- SX→HTML rendering in hx-do-swap with OOB section filtering
- hx-collect-params: collects input name/value for all methods
- Handler naming: ex-{slug} convention, removed perform IO dependencies
- Test runner page at (test.(applications.(htmx))) with iframe-based runner
- Header "test" link on every page linking to test URL
- Page file restructure: 285 files moved to URL-matching paths (a/b/c/index.sx)
- page-functions.sx: ~100 component name references updated
- _test added to skip_dirs, test- file prefix convention for test files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-15 11:56:15 +00:00
parent 4f02f82f4e
commit 4aa49e42e8
16 changed files with 3201 additions and 1562 deletions

View File

@@ -1,257 +1,223 @@
// sx-test-runner.js — Run SX test specs in the browser using sx-browser.js.
// Supports both legacy (monolithic test.sx) and modular (per-spec) modes.
/**
* SX Test Runner — drives tests in an iframe, reports results.
* Updates [data-test] elements in-place with pass/fail icons.
* Expects: #run-btn, #test-status, #test-summary, #test-iframe, [data-test]
*/
(function() {
var NIL = Sx.NIL;
function isNil(x) { return x === NIL || x === null || x === undefined; }
function deepEqual(a, b) {
if (a === b) return true;
if (isNil(a) && isNil(b)) return true;
if (typeof a !== typeof b) return false;
if (Array.isArray(a) && Array.isArray(b)) {
if (a.length !== b.length) return false;
for (var i = 0; i < a.length; i++) if (!deepEqual(a[i], b[i])) return false;
return true;
"use strict";
var TESTS = [
{ name: "click-to-load", actions: [
{ type: "click", selector: "button[hx-get]" },
{ type: "wait", ms: 2000 },
{ type: "assert-text", selector: "#click-result", contains: "Content loaded!" }
]},
{ name: "click-no-oob-leak", actions: [
{ type: "click", selector: "button[hx-get]" },
{ type: "wait", ms: 2000 },
{ type: "assert-text", selector: "#click-result", notContains: "defcomp" }
]},
{ name: "search-debounce", actions: [
{ type: "fill", selector: "input[hx-get]", value: "hx-get" },
{ type: "wait", ms: 1500 },
{ type: "assert-text", selector: "#search-results", contains: "GET request" }
]},
{ name: "search-no-results", actions: [
{ type: "fill", selector: "input[hx-get]", value: "xyznonexistent" },
{ type: "wait", ms: 1500 },
{ type: "assert-text", selector: "#search-results", contains: "No results" }
]},
{ name: "tab-overview", actions: [
{ type: "click", selector: "button[hx-get*='tab=overview']" },
{ type: "wait", ms: 2000 },
{ type: "assert-text", selector: "#htmx-tab-content", contains: "htmx gives you access" }
]},
{ name: "tab-features", actions: [
{ type: "click", selector: "button[hx-get*='tab=features']" },
{ type: "wait", ms: 2000 },
{ type: "assert-text", selector: "#htmx-tab-content", contains: "Any element" }
]},
{ name: "append-item", actions: [
{ type: "click", selector: "button[hx-post*='api.append']" },
{ type: "wait", ms: 2000 },
{ type: "assert-count", selector: "#item-list > *", gte: 1 }
]},
{ name: "form-submit", actions: [
{ type: "fill", selector: "form[hx-post] input[name='name']", value: "Alice" },
{ type: "fill", selector: "form[hx-post] input[name='email']", value: "alice@test.com" },
{ type: "click", selector: "form[hx-post] button[type='submit']" },
{ type: "wait", ms: 2000 },
{ type: "assert-text", selector: "#form-result", contains: "Alice" }
]}
];
if (window.__sxTests) TESTS = window.__sxTests;
var runBtn, statusEl, summaryEl, iframe;
function init() {
runBtn = document.getElementById("run-btn");
statusEl = document.getElementById("test-status");
summaryEl = document.getElementById("test-summary");
iframe = document.getElementById("test-iframe");
if (runBtn) {
console.log("[sx-test] Runner initialized, " + TESTS.length + " tests");
runBtn.addEventListener("click", function() {
console.log("[sx-test] Run clicked");
runAll();
});
} else {
console.warn("[sx-test] #run-btn not found");
}
if (a && typeof a === "object" && b && typeof b === "object") {
var ka = Object.keys(a), kb = Object.keys(b);
if (ka.length !== kb.length) return false;
for (var j = 0; j < ka.length; j++) if (!deepEqual(a[ka[j]], b[ka[j]])) return false;
return true;
}
return false;
}
// --- Platform functions shared across all specs ---
function makeEnv() {
var stack = [], passed = 0, failed = 0, num = 0, lines = [];
var env = {
"try-call": function(thunk) {
try {
Sx.eval([thunk], env);
return { ok: true };
} catch(e) {
return { ok: false, error: e.message || String(e) };
function sleep(ms) { return new Promise(function(r) { setTimeout(r, ms); }); }
function waitForReady(doc, timeout) {
return new Promise(function(resolve, reject) {
var start = Date.now();
(function check() {
try { if (doc.documentElement.getAttribute("data-sx-ready") === "true") return resolve(); } catch(e) {}
if (Date.now() - start > timeout) return reject(new Error("Timeout"));
setTimeout(check, 200);
})();
});
}
function reloadIframe() {
return new Promise(function(resolve) {
iframe.addEventListener("load", function onLoad() {
iframe.removeEventListener("load", onLoad);
resolve();
});
iframe.contentWindow.location.reload();
});
}
function updateTestItem(name, state, error) {
var item = document.querySelector('[data-test="' + name + '"]');
if (!item) return;
var icon = item.querySelector('[data-role="test-icon"]');
if (!icon) return;
if (state === "running") {
icon.textContent = "⟳";
icon.style.color = "#7c3aed";
item.style.borderColor = "#c4b5fd";
} else if (state === "pass") {
icon.textContent = "✓";
icon.style.color = "#16a34a";
item.style.borderColor = "#bbf7d0";
item.style.backgroundColor = "#f0fdf4";
} else if (state === "fail") {
icon.textContent = "✗";
icon.style.color = "#dc2626";
item.style.borderColor = "#fecaca";
item.style.backgroundColor = "#fef2f2";
if (error) {
var errEl = item.querySelector('[data-role="test-error"]');
if (!errEl) {
errEl = document.createElement("div");
errEl.setAttribute("data-role", "test-error");
errEl.style.cssText = "padding:8px 16px;font-size:12px;color:#dc2626;border-top:1px solid #fecaca;background:#fef2f2";
item.querySelector("summary").after(errEl);
}
},
"report-pass": function(name) {
num++; passed++;
lines.push("ok " + num + " - " + stack.concat([name]).join(" > "));
},
"report-fail": function(name, error) {
num++; failed++;
lines.push("not ok " + num + " - " + stack.concat([name]).join(" > "));
lines.push(" # " + error);
},
"push-suite": function(name) { stack.push(name); },
"pop-suite": function() { stack.pop(); },
// Primitives that sx-browser.js may not expose in env
"equal?": function(a, b) { return deepEqual(a, b); },
"eq?": function(a, b) { return a === b; },
"boolean?": function(x) { return typeof x === "boolean"; },
"string-length": function(s) { return String(s).length; },
"substring": function(s, start, end) { return String(s).slice(start, end); },
"string-contains?": function(s, n) { return String(s).indexOf(n) !== -1; },
"upcase": function(s) { return String(s).toUpperCase(); },
"downcase": function(s) { return String(s).toLowerCase(); },
"reverse": function(c) { return c ? c.slice().reverse() : []; },
"flatten": function(c) {
var r = [];
for (var i = 0; i < (c||[]).length; i++) {
if (Array.isArray(c[i])) for (var j = 0; j < c[i].length; j++) r.push(c[i][j]);
else r.push(c[i]);
}
return r;
},
"has-key?": function(d, k) { return d && typeof d === "object" && k in d; },
"append": function(c, x) { return Array.isArray(x) ? (c||[]).concat(x) : (c||[]).concat([x]); },
"for-each-indexed": function(f, coll) {
for (var i = 0; i < (coll||[]).length; i++) Sx.eval([f, i, coll[i]], env);
},
"for-each": function(f, coll) {
for (var i = 0; i < (coll||[]).length; i++) Sx.eval([f, coll[i]], env);
},
"dict-set!": function(d, k, v) { if (d) d[k] = v; },
"dict-has?": function(d, k) { return d && typeof d === "object" && k in d; },
"dict-get": function(d, k) { return d ? d[k] : undefined; },
"starts-with?": function(s, prefix) { return String(s).indexOf(prefix) === 0; },
"ends-with?": function(s, suffix) { var str = String(s); return str.indexOf(suffix) === str.length - suffix.length; },
"slice": function(s, start, end) { return end !== undefined ? s.slice(start, end) : s.slice(start); },
"inc": function(n) { return n + 1; },
"append!": function(arr, item) { if (Array.isArray(arr)) arr.push(item); },
"dict": function() { return {}; },
// --- Parser platform functions ---
"sx-parse": function(source) { return Sx.parseAll(source); },
"sx-serialize": function(val) {
if (val === NIL || val === null || val === undefined) return "nil";
if (typeof val === "boolean") return val ? "true" : "false";
if (typeof val === "number") return String(val);
if (typeof val === "string") return '"' + val.replace(/\\/g, "\\\\").replace(/"/g, '\\"') + '"';
if (val && (val._sym || val._sx_symbol)) return val.name;
if (val && (val._kw || val._sx_keyword)) return ":" + val.name;
if (Array.isArray(val)) return "(" + val.map(function(x) { return env["sx-serialize"](x); }).join(" ") + ")";
if (val && typeof val === "object") {
var parts = [];
Object.keys(val).forEach(function(k) { parts.push(":" + k); parts.push(env["sx-serialize"](val[k])); });
return "{" + parts.join(" ") + "}";
}
return String(val);
},
"make-symbol": function(name) { return Sx.sym ? Sx.sym(name) : { _sx_symbol: true, name: name, toString: function() { return name; } }; },
"make-keyword": function(name) { return Sx.kw ? Sx.kw(name) : { _sx_keyword: true, name: name, toString: function() { return name; } }; },
"symbol-name": function(s) { return s && s.name ? s.name : String(s); },
"keyword-name": function(k) { return k && k.name ? k.name : String(k); },
// --- Render platform function ---
"render-html": function(sxSource) {
if (!Sx.renderToHtml) throw new Error("render-to-html not available");
var exprs = Sx.parseAll(sxSource);
var result = "";
for (var i = 0; i < exprs.length; i++) result += Sx.renderToHtml(exprs[i], env);
return result;
},
};
return { env: env, getResults: function() { return { passed: passed, failed: failed, num: num, lines: lines }; } };
}
function evalSource(src, env) {
var exprs = Sx.parseAll(src);
for (var i = 0; i < exprs.length; i++) Sx.eval(exprs[i], env);
}
function loadRouterFromBootstrap(env) {
if (Sx.splitPathSegments) {
env["split-path-segments"] = Sx.splitPathSegments;
env["parse-route-pattern"] = Sx.parseRoutePattern;
env["match-route-segments"] = Sx.matchRouteSegments;
env["match-route"] = Sx.matchRoute;
env["find-matching-route"] = Sx.findMatchingRoute;
env["make-route-segment"] = Sx.makeRouteSegment;
errEl.textContent = error;
}
}
}
function loadDepsFromBootstrap(env) {
if (Sx.scanRefs) {
env["scan-refs"] = Sx.scanRefs;
env["scan-components-from-source"] = Sx.scanComponentsFromSource;
env["transitive-deps"] = Sx.transitiveDeps;
env["compute-all-deps"] = Sx.computeAllDeps;
env["components-needed"] = Sx.componentsNeeded;
env["page-component-bundle"] = Sx.pageComponentBundle;
env["page-css-classes"] = Sx.pageCssClasses;
env["scan-io-refs"] = Sx.scanIoRefs;
env["transitive-io-refs"] = Sx.transitiveIoRefs;
env["compute-all-io-refs"] = Sx.computeAllIoRefs;
env["component-pure?"] = Sx.componentPure_p;
env["test-env"] = function() { return env; };
function resetAllItems() {
var items = document.querySelectorAll("[data-test]");
for (var i = 0; i < items.length; i++) {
var icon = items[i].querySelector('[data-role="test-icon"]');
if (icon) { icon.textContent = "○"; icon.style.color = ""; }
items[i].style.borderColor = "";
items[i].style.backgroundColor = "";
var err = items[i].querySelector('[data-role="test-error"]');
if (err) err.remove();
}
}
function loadEngineFromBootstrap(env) {
if (Sx.parseTime) {
env["parse-time"] = Sx.parseTime;
env["parse-trigger-spec"] = Sx.parseTriggerSpec;
env["default-trigger"] = Sx.defaultTrigger;
env["parse-swap-spec"] = Sx.parseSwapSpec;
env["parse-retry-spec"] = Sx.parseRetrySpec;
env["next-retry-ms"] = function(cur, cap) { return Math.min(cur * 2, cap); };
env["filter-params"] = Sx.filterParams;
async function runOneTest(test) {
var doc = iframe.contentDocument;
for (var j = 0; j < test.actions.length; j++) {
var a = test.actions[j];
if (a.type === "click") {
var el = doc.querySelector(a.selector);
if (!el) throw new Error("Not found: " + a.selector);
el.click();
} else if (a.type === "fill") {
var el = doc.querySelector(a.selector);
if (!el) throw new Error("Not found: " + a.selector);
el.focus();
el.value = "";
el.value = a.value;
el.dispatchEvent(new Event("input", { bubbles: true }));
el.dispatchEvent(new Event("change", { bubbles: true }));
} else if (a.type === "wait") {
await sleep(a.ms);
} else if (a.type === "assert-text") {
var el = doc.querySelector(a.selector);
if (!el) throw new Error("Not found: " + a.selector);
var txt = el.textContent || "";
if (a.contains && txt.indexOf(a.contains) === -1)
throw new Error("Expected '" + a.contains + "' in '" + txt.substring(0, 60) + "'");
if (a.notContains && txt.indexOf(a.notContains) !== -1)
throw new Error("Unexpected '" + a.notContains + "'");
} else if (a.type === "assert-count") {
var els = doc.querySelectorAll(a.selector);
if (a.gte !== undefined && els.length < a.gte)
throw new Error("Expected >=" + a.gte + ", got " + els.length);
}
}
}
// --- Legacy runner (monolithic test.sx) ---
window.sxRunTests = function(srcId, outId, btnId) {
var src = document.getElementById(srcId).textContent;
var out = document.getElementById(outId);
var btn = document.getElementById(btnId);
var ctx = makeEnv();
async function runAll() {
resetAllItems();
summaryEl.innerHTML = "";
runBtn.disabled = true;
runBtn.style.opacity = "0.5";
var passed = 0, failed = 0;
try {
var t0 = performance.now();
evalSource(src, ctx.env);
var elapsed = Math.round(performance.now() - t0);
var r = ctx.getResults();
r.lines.push("");
r.lines.push("1.." + r.num);
r.lines.push("# tests " + (r.passed + r.failed));
r.lines.push("# pass " + r.passed);
if (r.failed > 0) r.lines.push("# fail " + r.failed);
r.lines.push("# time " + elapsed + "ms");
} catch(e) {
var r = ctx.getResults();
r.lines.push("");
r.lines.push("FATAL: " + (e.message || String(e)));
}
for (var i = 0; i < TESTS.length; i++) {
var test = TESTS[i];
statusEl.textContent = test.name + " (" + (i+1) + "/" + TESTS.length + ")";
updateTestItem(test.name, "running");
out.textContent = r.lines.join("\n");
out.style.display = "block";
btn.textContent = r.passed + "/" + (r.passed + r.failed) + " passed" + (r.failed === 0 ? "" : " (" + r.failed + " failed)");
btn.className = r.failed > 0
? "px-4 py-2 rounded-md bg-red-600 text-white font-medium text-sm cursor-default"
: "px-4 py-2 rounded-md bg-green-600 text-white font-medium text-sm cursor-default";
};
if (i > 0) await reloadIframe();
// --- Modular runner (per-spec or all) ---
var SPECS = {
"eval": { needs: [] },
"parser": { needs: ["sx-parse"] },
"router": { needs: [] },
"render": { needs: ["render-html"] },
"deps": { needs: [] },
"engine": { needs: [] },
};
window.sxRunModularTests = function(specName, outId, btnId) {
var out = document.getElementById(outId);
var btn = document.getElementById(btnId);
var ctx = makeEnv();
var specs = specName === "all" ? Object.keys(SPECS) : [specName];
try {
var t0 = performance.now();
// Load framework
var fwEl = document.getElementById("test-framework-source");
if (fwEl) {
evalSource(fwEl.textContent, ctx.env);
try {
await waitForReady(iframe.contentDocument, 15000);
await sleep(500);
} catch(e) {
updateTestItem(test.name, "fail", "Page load timeout");
failed++;
continue;
}
for (var si = 0; si < specs.length; si++) {
var sn = specs[si];
if (!SPECS[sn]) continue;
// Load module functions from bootstrap
if (sn === "router") loadRouterFromBootstrap(ctx.env);
if (sn === "deps") loadDepsFromBootstrap(ctx.env);
if (sn === "engine") loadEngineFromBootstrap(ctx.env);
// Find spec source — either per-spec textarea or embedded in overview
var specEl = document.getElementById("test-spec-" + sn);
if (specEl) {
evalSource(specEl.textContent, ctx.env);
}
try {
await runOneTest(test);
updateTestItem(test.name, "pass");
passed++;
} catch(err) {
updateTestItem(test.name, "fail", err.message);
failed++;
}
var elapsed = Math.round(performance.now() - t0);
var r = ctx.getResults();
r.lines.push("");
r.lines.push("1.." + r.num);
r.lines.push("# tests " + (r.passed + r.failed));
r.lines.push("# pass " + r.passed);
if (r.failed > 0) r.lines.push("# fail " + r.failed);
r.lines.push("# time " + elapsed + "ms");
} catch(e) {
var r = ctx.getResults();
r.lines.push("");
r.lines.push("FATAL: " + (e.message || String(e)));
}
out.textContent = r.lines.join("\n");
out.style.display = "block";
btn.textContent = r.passed + "/" + (r.passed + r.failed) + " passed" + (r.failed === 0 ? "" : " (" + r.failed + " failed)");
btn.className = r.failed > 0
? "px-4 py-2 rounded-md bg-red-600 text-white font-medium text-sm cursor-default"
: "px-4 py-2 rounded-md bg-green-600 text-white font-medium text-sm cursor-default";
};
runBtn.disabled = false;
runBtn.style.opacity = "1";
statusEl.textContent = "Done";
var total = passed + failed;
summaryEl.innerHTML = '<div style="padding:12px;border-radius:8px;font-weight:600;' +
(failed === 0 ? 'background:#f0fdf4;color:#166534' : 'background:#fef2f2;color:#991b1b') +
'">' + passed + '/' + total + ' tests passed</div>';
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
init();
}
})();

View File

@@ -98,8 +98,33 @@
try { driveAsync(result.resume(null)); } catch(e) { console.error("[sx] driveAsync:", e.message); }
}, typeof arg === "number" ? arg : 0);
} else if (opName === "io-fetch") {
fetch(typeof arg === "string" ? arg : "").then(function(r) { return r.text(); }).then(function(t) {
try { driveAsync(result.resume({ok: true, text: t})); } catch(e) { console.error("[sx] driveAsync:", e.message); }
var fetchUrl = typeof arg === "string" ? arg : "";
var fetchMethod = (items && items[2]) || "GET";
var fetchBody = items && items[3];
var fetchHeaders = items && items[4];
var fetchOpts = { method: typeof fetchMethod === "string" ? fetchMethod : "GET" };
if (fetchBody && typeof fetchBody !== "boolean") {
fetchOpts.body = typeof fetchBody === "string" ? fetchBody : JSON.stringify(fetchBody);
}
if (fetchHeaders && typeof fetchHeaders === "object") {
var h = {};
var keys = fetchHeaders._keys || Object.keys(fetchHeaders);
for (var fi = 0; fi < keys.length; fi++) {
var k = keys[fi], v = fetchHeaders[k];
if (typeof k === "string" && typeof v === "string") h[k] = v;
}
fetchOpts.headers = h;
}
fetch(fetchUrl, fetchOpts).then(function(r) {
var hdrs = {};
try { r.headers.forEach(function(v, k) { hdrs[k] = v; }); } catch(e) {}
return r.text().then(function(t) {
return { status: r.status, body: t, headers: hdrs, ok: r.ok };
});
}).then(function(resp) {
try { driveAsync(result.resume(resp)); } catch(e) { console.error("[sx] driveAsync:", e.message); }
}).catch(function(e) {
try { driveAsync(result.resume({status: 0, body: "", headers: {}, ok: false})); } catch(e2) { console.error("[sx] driveAsync:", e2.message); }
});
} else if (opName === "io-navigate") {
// navigation — don't resume
@@ -273,7 +298,7 @@
}
}
// Content-addressed boot: script loaded from /sx/h/{hash}, not /static/wasm/.
// Fall back to /static/wasm/ base URL for module-manifest.json and .sx sources.
// Fall back to /static/wasm/ base URL for module-manifest.sx and .sx sources.
if (!_baseUrl || _baseUrl.indexOf("/sx/h/") !== -1) {
_baseUrl = "/static/wasm/";
}
@@ -522,6 +547,22 @@
var _manifest = null;
var _loadedLibs = {};
/**
* Convert K.parse output (tagged {_type, ...} objects) to plain JS.
* SX nil (from empty lists `()`) becomes [].
*/
function sxDataToJs(v) {
if (v === null || v === undefined) return [];
if (typeof v !== "object") return v;
if (v._type === "list") return (v.items || []).map(sxDataToJs);
if (v._type === "dict") {
var out = {};
for (var k in v) if (k !== "_type") out[k] = sxDataToJs(v[k]);
return out;
}
return v;
}
/**
* Fetch and parse the module manifest (library deps + file paths).
*/
@@ -529,11 +570,14 @@
if (_manifest) return _manifest;
try {
var xhr = new XMLHttpRequest();
xhr.open("GET", _baseUrl + "sx/module-manifest.json" + _cacheBust, false);
xhr.open("GET", _baseUrl + "sx/module-manifest.sx" + _cacheBust, false);
xhr.send();
if (xhr.status === 200) {
_manifest = JSON.parse(xhr.responseText);
return _manifest;
var parsed = K.parse(xhr.responseText);
if (parsed && parsed.length > 0) {
_manifest = sxDataToJs(parsed[0]);
return _manifest;
}
}
} catch(e) {}
console.warn("[sx-platform] No manifest found, falling back to full load");
@@ -699,6 +743,32 @@
}
}
// Merge definitions from a new page's manifest (called during navigation)
function mergeManifest(el) {
if (!el) return;
try {
var incoming = JSON.parse(el.textContent);
var newDefs = incoming.defs || {};
// Ensure base manifest is loaded
if (!_pageManifest) loadPageManifest();
if (!_pageManifest) _pageManifest = { defs: {} };
if (!_pageManifest.defs) _pageManifest.defs = {};
for (var name in newDefs) {
_pageManifest.defs[name] = newDefs[name];
_hashToName[newDefs[name]] = name;
}
// Merge hash store entries
if (incoming.store) {
if (!_pageManifest.store) _pageManifest.store = {};
for (var h in incoming.store) {
_pageManifest.store[h] = incoming.store[h];
}
}
} catch(e) {
console.warn("[sx] Failed to merge manifest:", e);
}
}
function resolveHash(hash) {
// 1. In-memory cache
if (_hashCache[hash]) return _hashCache[hash];
@@ -833,6 +903,7 @@
renderToHtml: function(expr) { return K.renderToHtml(expr); },
callFn: function(fn, args) { return K.callFn(fn, args); },
engine: function() { return K.engine(); },
mergeManifest: function(el) { return mergeManifest(el); },
// Boot entry point (called by auto-init or manually)
init: function() {
if (typeof K.eval === "function") {

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -415,6 +415,14 @@
(swap-dom-nodes t oob s)
(post-swap t)))
(hoist-head-elements container)
(let
((manifest-el (dom-query-in container "script[data-sx-manifest]")))
(when
manifest-el
(host-call
(host-global "Sx")
"mergeManifest"
manifest-el)))
(let
((html (select-from-container container select-sel)))
(with-transition
@@ -1547,7 +1555,8 @@
(process-sse root)
(bind-inline-handlers root)
(process-emit-elements root)
(hs-boot-subtree! (or root (host-global "document")))))
(hs-boot-subtree! (or root (host-global "document")))
(htmx-boot-subtree! (or root (host-global "document")))))
(define
process-one
:effects (mutation io)
@@ -1622,9 +1631,11 @@
(pathname (url-pathname url)))
(when
target
(let
((headers (dict "SX-Request" "true")))
(fetch-and-restore target url headers scrollY))))))
(when
(not (try-client-route pathname target-sel))
(let
((headers (build-request-headers target (loaded-component-names))))
(fetch-and-restore target url headers scrollY)))))))
(define
engine-init
:effects (mutation io)

File diff suppressed because one or more lines are too long

View File

@@ -1792,7 +1792,7 @@
blake2_js_for_wasm_create: blake2_js_for_wasm_create};
}
(globalThis))
({"link":[["runtime-0db9b496",0],["prelude-d7e4b000",0],["stdlib-23ce0836",[]],["re-9a0de245",[2]],["sx-80a20737",[2,3]],["jsoo_runtime-f96b44a8",[2]],["js_of_ocaml-651f6707",[2,5]],["dune__exe__Sx_browser-653fa705",[2,4,6]],["std_exit-10fb8830",[2]],["start-f808dbe1",0]],"generated":(b=>{var
({"link":[["runtime-0db9b496",0],["prelude-d7e4b000",0],["stdlib-23ce0836",[]],["re-9a0de245",[2]],["sx-faa4f9b6",[2,3]],["jsoo_runtime-f96b44a8",[2]],["js_of_ocaml-651f6707",[2,5]],["dune__exe__Sx_browser-efe9c27c",[2,4,6]],["std_exit-10fb8830",[2]],["start-f808dbe1",0]],"generated":(b=>{var
c=b,a=b?.module?.export||b;return{"env":{"caml_ba_kind_of_typed_array":()=>{throw new
Error("caml_ba_kind_of_typed_array not implemented")},"caml_exn_with_js_backtrace":()=>{throw new
Error("caml_exn_with_js_backtrace not implemented")},"caml_int64_create_lo_mi_hi":()=>{throw new
@@ -1818,4 +1818,4 @@ a()},"Js_of_ocaml__Json.fragments":{"get_JSON":a=>a.JSON,"get_constructor":a=>a.
a(b)},"Js_of_ocaml__Dom_svg.fragments":{"get_SVGElement":a=>a.SVGElement,"get_document":a=>a.document,"get_tagName":a=>a.tagName,"meth_call_0_toLowerCase":a=>a.toLowerCase(),"meth_call_1_getElementById":(a,b)=>a.getElementById(b),"meth_call_2_createElementNS":(a,b,c)=>a.createElementNS(b,c)},"Js_of_ocaml__EventSource.fragments":{"get_EventSource":a=>a.EventSource,"obj_9":()=>({}),"set_withCredentials":(a,b)=>a.withCredentials=b},"Js_of_ocaml__Geolocation.fragments":{"get_geolocation":a=>a.geolocation,"get_navigator":a=>a.navigator,"obj_10":()=>({})},"Js_of_ocaml__IntersectionObserver.fragments":{"get_IntersectionObserver":a=>a.IntersectionObserver,"obj_11":()=>({})},"Js_of_ocaml__Intl.fragments":{"get_Collator":a=>a.Collator,"get_DateTimeFormat":a=>a.DateTimeFormat,"get_Intl":a=>a.Intl,"get_NumberFormat":a=>a.NumberFormat,"get_PluralRules":a=>a.PluralRules,"obj_12":a=>({localeMatcher:a}),"obj_13":(a,b,c,d,e,f)=>({localeMatcher:a,usage:b,sensitivity:c,ignorePunctuation:d,numeric:e,caseFirst:f}),"obj_14":(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t)=>({dateStyle:a,timeStyle:b,calendar:c,dayPeriod:d,numberingSystem:e,localeMatcher:f,timeZone:g,hour12:h,hourCycle:i,formatMatcher:j,weekday:k,era:l,year:m,month:n,day:o,hour:p,minute:q,second:r,fractionalSecondDigits:s,timeZoneName:t}),"obj_15":(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u)=>({compactDisplay:a,currency:b,currencyDisplay:c,currencySign:d,localeMatcher:e,notation:f,numberingSystem:g,signDisplay:h,style:i,unit:j,unitDisplay:k,useGrouping:l,roundingMode:m,roundingPriority:n,roundingIncrement:o,trailingZeroDisplay:p,minimumIntegerDigits:q,minimumFractionDigits:r,maximumFractionDigits:s,minimumSignificantDigits:t,maximumSignificantDigits:u}),"obj_16":(a,b)=>({localeMatcher:a,type:b})},"Dune__exe__Sx_browser.fragments":{"fun_call_1":(a,b)=>a(b),"fun_call_3":(a,b,c,d)=>a(b,c,d),"get_Array":a=>a.Array,"get_Object":a=>a.Object,"get___sx_handle":a=>a.__sx_handle,"get__driveAsync":a=>a._driveAsync,"get__type":a=>a._type,"get_console":a=>a.console,"get_items":a=>a.items,"get_length":a=>a.length,"get_name":a=>a.name,"js_expr_10d25c5c":()=>function(a){return function(){b.__sxR=undefined;var
c=a.apply(null,arguments);return b.__sxR!==undefined?b.__sxR:c}},"js_expr_1ab4fffb":()=>function(){var
b={},d=0;return{put:function(a){var
c=d++;b[c]=a;return c},get:function(a){return b[a]}}}(),"js_expr_36506fc1":()=>function(a,b,c){a.__sx_handle=b;a._type=c;return a},"meth_call_1_error":(a,b)=>a.error(b),"meth_call_1_get":(a,b)=>a.get(b),"meth_call_1_isArray":(a,b)=>a.isArray(b),"meth_call_1_keys":(a,b)=>a.keys(b),"meth_call_1_put":(a,b)=>a.put(b),"obj_0":()=>({}),"obj_1":()=>({}),"obj_2":(a,b)=>({_type:a,items:b}),"obj_3":(a,b)=>({_type:a,name:b}),"obj_4":(a,b)=>({_type:a,name:b}),"obj_5":(a,b)=>({_type:a,__sx_handle:b}),"obj_6":()=>({}),"obj_7":()=>({}),"obj_8":()=>({}),"set_SxKernel":(a,b)=>a.SxKernel=b,"set___sxR":(a,b)=>a.__sxR=b,"set__type":(a,b)=>a._type=b,"set_beginModuleLoad":(a,b)=>a.beginModuleLoad=b,"set_callFn":(a,b)=>a.callFn=b,"set_compileModule":(a,b)=>a.compileModule=b,"set_debugEnv":(a,b)=>a.debugEnv=b,"set_endModuleLoad":(a,b)=>a.endModuleLoad=b,"set_engine":(a,b)=>a.engine=b,"set_eval":(a,b)=>a.eval=b,"set_evalExpr":(a,b)=>a.evalExpr=b,"set_evalVM":(a,b)=>a.evalVM=b,"set_fnArity":(a,b)=>a.fnArity=b,"set_inspect":(a,b)=>a.inspect=b,"set_isCallable":(a,b)=>a.isCallable=b,"set_load":(a,b)=>a.load=b,"set_loadModule":(a,b)=>a.loadModule=b,"set_loadSource":(a,b)=>a.loadSource=b,"set_op":(a,b)=>a.op=b,"set_parse":(a,b)=>a.parse=b,"set_registerNative":(a,b)=>a.registerNative=b,"set_renderToHtml":(a,b)=>a.renderToHtml=b,"set_request":(a,b)=>a.request=b,"set_resume":(a,b)=>a.resume=b,"set_scopeTraceDrain":(a,b)=>a.scopeTraceDrain=b,"set_scopeTraceOff":(a,b)=>a.scopeTraceOff=b,"set_scopeTraceOn":(a,b)=>a.scopeTraceOn=b,"set_stringify":(a,b)=>a.stringify=b,"set_suspended":(a,b)=>a.suspended=b,"set_typeOf":(a,b)=>a.typeOf=b}}})(globalThis),"src":"sx_browser.bc.wasm.assets"});
c=d++;b[c]=a;return c},get:function(a){return b[a]}}}(),"js_expr_36506fc1":()=>function(a,b,c){a.__sx_handle=b;a._type=c;return a},"meth_call_1_error":(a,b)=>a.error(b),"meth_call_1_get":(a,b)=>a.get(b),"meth_call_1_isArray":(a,b)=>a.isArray(b),"meth_call_1_keys":(a,b)=>a.keys(b),"meth_call_1_put":(a,b)=>a.put(b),"obj_0":()=>({}),"obj_1":()=>({}),"obj_10":(a,b)=>({__sx_error:a,message:b}),"obj_2":(a,b)=>({_type:a,items:b}),"obj_3":(a,b)=>({_type:a,name:b}),"obj_4":(a,b)=>({_type:a,name:b}),"obj_5":(a,b)=>({_type:a,__sx_handle:b}),"obj_6":()=>({}),"obj_7":()=>({}),"obj_8":()=>({}),"obj_9":(a,b)=>({__sx_error:a,message:b}),"set_SxKernel":(a,b)=>a.SxKernel=b,"set___sxR":(a,b)=>a.__sxR=b,"set__type":(a,b)=>a._type=b,"set_beginModuleLoad":(a,b)=>a.beginModuleLoad=b,"set_callFn":(a,b)=>a.callFn=b,"set_compileModule":(a,b)=>a.compileModule=b,"set_debugEnv":(a,b)=>a.debugEnv=b,"set_endModuleLoad":(a,b)=>a.endModuleLoad=b,"set_engine":(a,b)=>a.engine=b,"set_eval":(a,b)=>a.eval=b,"set_evalExpr":(a,b)=>a.evalExpr=b,"set_evalVM":(a,b)=>a.evalVM=b,"set_fnArity":(a,b)=>a.fnArity=b,"set_inspect":(a,b)=>a.inspect=b,"set_isCallable":(a,b)=>a.isCallable=b,"set_load":(a,b)=>a.load=b,"set_loadModule":(a,b)=>a.loadModule=b,"set_loadSource":(a,b)=>a.loadSource=b,"set_op":(a,b)=>a.op=b,"set_parse":(a,b)=>a.parse=b,"set_registerNative":(a,b)=>a.registerNative=b,"set_renderToHtml":(a,b)=>a.renderToHtml=b,"set_request":(a,b)=>a.request=b,"set_resetStepCount":(a,b)=>a.resetStepCount=b,"set_resume":(a,b)=>a.resume=b,"set_scopeTraceDrain":(a,b)=>a.scopeTraceDrain=b,"set_scopeTraceOff":(a,b)=>a.scopeTraceOff=b,"set_scopeTraceOn":(a,b)=>a.scopeTraceOn=b,"set_setStepLimit":(a,b)=>a.setStepLimit=b,"set_stringify":(a,b)=>a.stringify=b,"set_suspended":(a,b)=>a.suspended=b,"set_typeOf":(a,b)=>a.typeOf=b}}})(globalThis),"src":"sx_browser.bc.wasm.assets"});