Split orchestration from engine into separate adapter
engine.sx now contains only pure logic: parsing, morph, swap, headers, retry, target resolution, etc. orchestration.sx contains the browser wiring: request execution, trigger binding, SSE, boost, post-swap lifecycle, and init. Dependency is one-way: orchestration → engine. Bootstrap compiler gains "orchestration" as a separate adapter with deps on engine+dom. Engine-only builds get morph/swap without the full browser runtime. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -705,14 +705,15 @@ def extract_defines(source: str) -> list[tuple[str, list]]:
|
||||
|
||||
|
||||
ADAPTER_FILES = {
|
||||
"html": ("adapter-html.sx", "adapter-html"),
|
||||
"sx": ("adapter-sx.sx", "adapter-sx"),
|
||||
"dom": ("adapter-dom.sx", "adapter-dom"),
|
||||
"engine": ("engine.sx", "engine"),
|
||||
"html": ("adapter-html.sx", "adapter-html"),
|
||||
"sx": ("adapter-sx.sx", "adapter-sx"),
|
||||
"dom": ("adapter-dom.sx", "adapter-dom"),
|
||||
"engine": ("engine.sx", "engine"),
|
||||
"orchestration": ("orchestration.sx","orchestration"),
|
||||
}
|
||||
|
||||
# Dependencies: engine requires dom
|
||||
ADAPTER_DEPS = {"engine": ["dom"]}
|
||||
# Dependencies: orchestration requires engine+dom, engine requires dom
|
||||
ADAPTER_DEPS = {"engine": ["dom"], "orchestration": ["engine", "dom"]}
|
||||
|
||||
|
||||
def compile_ref_to_js(adapters: list[str] | None = None) -> str:
|
||||
@@ -728,8 +729,9 @@ def compile_ref_to_js(adapters: list[str] | None = None) -> str:
|
||||
|
||||
# Platform JS blocks keyed by adapter name
|
||||
adapter_platform = {
|
||||
"dom": PLATFORM_DOM_JS,
|
||||
"engine": PLATFORM_ENGINE_JS,
|
||||
"dom": PLATFORM_DOM_JS,
|
||||
"engine": PLATFORM_ENGINE_PURE_JS,
|
||||
"orchestration": PLATFORM_ORCHESTRATION_JS,
|
||||
}
|
||||
|
||||
# Resolve adapter set
|
||||
@@ -750,7 +752,7 @@ def compile_ref_to_js(adapters: list[str] | None = None) -> str:
|
||||
("eval.sx", "eval"),
|
||||
("render.sx", "render (core)"),
|
||||
]
|
||||
for name in ("html", "sx", "dom", "engine"):
|
||||
for name in ("html", "sx", "dom", "engine", "orchestration"):
|
||||
if name in adapter_set:
|
||||
sx_files.append(ADAPTER_FILES[name])
|
||||
|
||||
@@ -769,6 +771,7 @@ def compile_ref_to_js(adapters: list[str] | None = None) -> str:
|
||||
has_sx = "sx" in adapter_set
|
||||
has_dom = "dom" in adapter_set
|
||||
has_engine = "engine" in adapter_set
|
||||
has_orch = "orchestration" in adapter_set
|
||||
adapter_label = "+".join(sorted(adapter_set)) if adapter_set else "core-only"
|
||||
|
||||
parts = []
|
||||
@@ -784,12 +787,12 @@ def compile_ref_to_js(adapters: list[str] | None = None) -> str:
|
||||
# Platform JS for selected adapters
|
||||
if not has_dom:
|
||||
parts.append("\n var _hasDom = false;\n")
|
||||
for name in ("dom", "engine"):
|
||||
for name in ("dom", "engine", "orchestration"):
|
||||
if name in adapter_set and name in adapter_platform:
|
||||
parts.append(adapter_platform[name])
|
||||
|
||||
parts.append(fixups_js(has_html, has_sx, has_dom))
|
||||
parts.append(public_api_js(has_html, has_sx, has_dom, has_engine, adapter_label))
|
||||
parts.append(public_api_js(has_html, has_sx, has_dom, has_engine, has_orch, adapter_label))
|
||||
parts.append(EPILOGUE)
|
||||
return "\n".join(parts)
|
||||
|
||||
@@ -1441,13 +1444,11 @@ PLATFORM_DOM_JS = """
|
||||
function domTagName(el) { return el && el.tagName ? el.tagName : ""; }
|
||||
"""
|
||||
|
||||
PLATFORM_ENGINE_JS = """
|
||||
PLATFORM_ENGINE_PURE_JS = """
|
||||
// =========================================================================
|
||||
// Platform interface — Engine (browser-only)
|
||||
// Platform interface — Engine pure logic (browser + node compatible)
|
||||
// =========================================================================
|
||||
|
||||
// --- Browser/Network ---
|
||||
|
||||
function browserLocationHref() {
|
||||
return typeof location !== "undefined" ? location.href : "";
|
||||
}
|
||||
@@ -1471,6 +1472,24 @@ PLATFORM_ENGINE_JS = """
|
||||
}
|
||||
}
|
||||
|
||||
function nowMs() { return Date.now(); }
|
||||
|
||||
function parseHeaderValue(s) {
|
||||
if (!s) return null;
|
||||
try {
|
||||
if (s.charAt(0) === "{" && s.charAt(1) === ":") return parse(s);
|
||||
return JSON.parse(s);
|
||||
} catch (e) { return null; }
|
||||
}
|
||||
"""
|
||||
|
||||
PLATFORM_ORCHESTRATION_JS = """
|
||||
// =========================================================================
|
||||
// Platform interface — Orchestration (browser-only)
|
||||
// =========================================================================
|
||||
|
||||
// --- Browser/Network ---
|
||||
|
||||
function browserNavigate(url) {
|
||||
if (typeof location !== "undefined") location.assign(url);
|
||||
}
|
||||
@@ -1499,16 +1518,6 @@ PLATFORM_ENGINE_JS = """
|
||||
return r === null ? NIL : r;
|
||||
}
|
||||
|
||||
function nowMs() { return 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; }
|
||||
}
|
||||
|
||||
function csrfToken() {
|
||||
if (!_hasDom) return NIL;
|
||||
var m = document.querySelector('meta[name="csrf-token"]');
|
||||
@@ -2059,7 +2068,7 @@ def fixups_js(has_html, has_sx, has_dom):
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def public_api_js(has_html, has_sx, has_dom, has_engine, adapter_label):
|
||||
def public_api_js(has_html, has_sx, has_dom, has_engine, has_orch, adapter_label):
|
||||
# Parser is always included
|
||||
parser = r'''
|
||||
// =========================================================================
|
||||
@@ -2255,6 +2264,7 @@ def public_api_js(has_html, has_sx, has_dom, has_engine, adapter_label):
|
||||
api_lines.append(' morphNode: typeof morphNode === "function" ? morphNode : null,')
|
||||
api_lines.append(' morphChildren: typeof morphChildren === "function" ? morphChildren : null,')
|
||||
api_lines.append(' swapDomNodes: typeof swapDomNodes === "function" ? swapDomNodes : null,')
|
||||
if has_orch:
|
||||
api_lines.append(' process: typeof processElements === "function" ? processElements : null,')
|
||||
api_lines.append(' executeRequest: typeof executeRequest === "function" ? executeRequest : null,')
|
||||
api_lines.append(' postSwap: typeof postSwap === "function" ? postSwap : null,')
|
||||
@@ -2263,7 +2273,7 @@ def public_api_js(has_html, has_sx, has_dom, has_engine, adapter_label):
|
||||
api_lines.append(f' _version: "{version}"')
|
||||
api_lines.append(' };')
|
||||
api_lines.append('')
|
||||
if has_engine:
|
||||
if has_orch:
|
||||
api_lines.append('''
|
||||
// --- Popstate listener ---
|
||||
if (typeof window !== "undefined") {
|
||||
|
||||
Reference in New Issue
Block a user