Step 17: streaming render — hyperscript enhancements, WASM builds, live server tests

Streaming chunked transfer with shell-first suspense and resolve scripts.
Hyperscript parser/compiler/runtime expanded for conformance. WASM static
assets added to OCaml host. Playwright streaming and page-level test suites.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-12 08:41:38 +00:00
parent 7aefe4da8f
commit 6e27442d57
29 changed files with 65959 additions and 628 deletions

View File

@@ -70,17 +70,38 @@
((target (if source (hs-to-sx source) (quote me))))
(let
((compiled-body (hs-to-sx body))
(wrapped-body
(if catch-info
(let ((var (make-symbol (first catch-info)))
(catch-body (hs-to-sx (nth catch-info 1))))
(if finally-info
(list (quote do) (list (quote guard) (list var (list true catch-body)) compiled-body) (hs-to-sx finally-info))
(list (quote guard) (list var (list true catch-body)) compiled-body)))
(if finally-info
(list (quote do) compiled-body (hs-to-sx finally-info))
compiled-body)))
(handler (list (quote fn) (list (quote event)) wrapped-body)))
(wrapped-body
(if
catch-info
(let
((var (make-symbol (first catch-info)))
(catch-body
(hs-to-sx (nth catch-info 1))))
(if
finally-info
(list
(quote do)
(list
(quote guard)
(list var (list true catch-body))
compiled-body)
(hs-to-sx finally-info))
(list
(quote guard)
(list var (list true catch-body))
compiled-body)))
(if
finally-info
(list
(quote do)
compiled-body
(hs-to-sx finally-info))
compiled-body)))
(handler
(list
(quote fn)
(list (quote event))
wrapped-body)))
(if
every?
(list
@@ -106,12 +127,37 @@
catch-info
finally-info))
((= (first items) :every)
(scan-on (rest (rest items)) source filter true catch-info finally-info))
(scan-on
(rest (rest items))
source
filter
true
catch-info
finally-info))
((= (first items) :catch)
(scan-on (rest (rest items)) source filter every? (nth items 1) finally-info))
(scan-on
(rest (rest items))
source
filter
every?
(nth items 1)
finally-info))
((= (first items) :finally)
(scan-on (rest (rest items)) source filter every? catch-info (nth items 1)))
(true (scan-on (rest items) source filter every? catch-info finally-info)))))
(scan-on
(rest (rest items))
source
filter
every?
catch-info
(nth items 1)))
(true
(scan-on
(rest items)
source
filter
every?
catch-info
finally-info)))))
(scan-on (rest parts) nil nil false nil nil)))))
(define
emit-send
@@ -223,13 +269,11 @@
(define
emit-inc
(fn
(expr tgt-override)
(let
((t (hs-to-sx expr)))
(if
(and (list? expr) (= (first expr) (quote attr)))
(expr amount tgt-override)
(cond
((and (list? expr) (= (first expr) (quote attr)))
(let
((el (if tgt-override (hs-to-sx tgt-override) (hs-to-sx (nth expr 2)))))
((el (if tgt-override (hs-to-sx tgt-override) (quote me))))
(list
(quote dom-set-attr)
el
@@ -239,18 +283,46 @@
(list
(quote parse-number)
(list (quote dom-get-attr) el (nth expr 1)))
1)))
(list (quote set!) t (list (quote +) t 1))))))
amount))))
((and (list? expr) (= (first expr) dot-sym))
(let
((obj (hs-to-sx (nth expr 1))) (prop (nth expr 2)))
(list
(quote host-set)
obj
prop
(list
(quote +)
(list
(quote parse-number)
(list (quote host-get) obj prop))
amount))))
((and (list? expr) (= (first expr) (quote style)))
(let
((el (if tgt-override (hs-to-sx tgt-override) (quote me)))
(prop (nth expr 1)))
(list
(quote dom-set-style)
el
prop
(list
(quote +)
(list
(quote parse-number)
(list (quote dom-get-style) el prop))
amount))))
(true
(let
((t (hs-to-sx expr)))
(list (quote set!) t (list (quote +) t amount)))))))
(define
emit-dec
(fn
(expr tgt-override)
(let
((t (hs-to-sx expr)))
(if
(and (list? expr) (= (first expr) (quote attr)))
(expr amount tgt-override)
(cond
((and (list? expr) (= (first expr) (quote attr)))
(let
((el (if tgt-override (hs-to-sx tgt-override) (hs-to-sx (nth expr 2)))))
((el (if tgt-override (hs-to-sx tgt-override) (quote me))))
(list
(quote dom-set-attr)
el
@@ -260,8 +332,38 @@
(list
(quote parse-number)
(list (quote dom-get-attr) el (nth expr 1)))
1)))
(list (quote set!) t (list (quote -) t 1))))))
amount))))
((and (list? expr) (= (first expr) dot-sym))
(let
((obj (hs-to-sx (nth expr 1))) (prop (nth expr 2)))
(list
(quote host-set)
obj
prop
(list
(quote -)
(list
(quote parse-number)
(list (quote host-get) obj prop))
amount))))
((and (list? expr) (= (first expr) (quote style)))
(let
((el (if tgt-override (hs-to-sx tgt-override) (quote me)))
(prop (nth expr 1)))
(list
(quote dom-set-style)
el
prop
(list
(quote -)
(list
(quote parse-number)
(list (quote dom-get-style) el prop))
amount))))
(true
(let
((t (hs-to-sx expr)))
(list (quote set!) t (list (quote -) t amount)))))))
(define
emit-behavior
(fn
@@ -654,13 +756,23 @@
(hs-to-sx (nth ast 2))
(nth ast 1)))
((= head (quote multi-add-class))
(let ((target (hs-to-sx (nth ast 1)))
(classes (rest (rest ast))))
(cons (quote do) (map (fn (cls) (list (quote dom-add-class) target cls)) classes))))
(let
((target (hs-to-sx (nth ast 1)))
(classes (rest (rest ast))))
(cons
(quote do)
(map
(fn (cls) (list (quote dom-add-class) target cls))
classes))))
((= head (quote multi-remove-class))
(let ((target (hs-to-sx (nth ast 1)))
(classes (rest (rest ast))))
(cons (quote do) (map (fn (cls) (list (quote dom-remove-class) target cls)) classes))))
(let
((target (hs-to-sx (nth ast 1)))
(classes (rest (rest ast))))
(cons
(quote do)
(map
(fn (cls) (list (quote dom-remove-class) target cls))
classes))))
((= head (quote remove-class))
(list
(quote dom-remove-class)
@@ -677,6 +789,30 @@
(hs-to-sx (nth ast 3))
(nth ast 1)
(nth ast 2)))
((= head (quote toggle-style))
(list
(quote hs-toggle-style!)
(hs-to-sx (nth ast 2))
(nth ast 1)))
((= head (quote toggle-style-between))
(list
(quote hs-toggle-style-between!)
(hs-to-sx (nth ast 4))
(nth ast 1)
(hs-to-sx (nth ast 2))
(hs-to-sx (nth ast 3))))
((= head (quote toggle-attr))
(list
(quote hs-toggle-attr!)
(hs-to-sx (nth ast 2))
(nth ast 1)))
((= head (quote toggle-attr-between))
(list
(quote hs-toggle-attr-between!)
(hs-to-sx (nth ast 4))
(nth ast 1)
(hs-to-sx (nth ast 2))
(hs-to-sx (nth ast 3))))
((= head (quote set!))
(emit-set (nth ast 1) (hs-to-sx (nth ast 2))))
((= head (quote put!))
@@ -749,8 +885,21 @@
(list (list (quote me) (hs-to-sx (nth ast 1))))
(hs-to-sx (nth ast 2))))
((= head (quote for)) (emit-for ast))
((= head (quote take))
(list (quote hs-take!) (hs-to-sx (nth ast 2)) (nth ast 1)))
((= head (quote take!))
(let
((kind (nth ast 1))
(name (nth ast 2))
(from-sel (if (> (len ast) 3) (nth ast 3) nil))
(for-tgt (if (> (len ast) 4) (nth ast 4) nil)))
(let
((target (if for-tgt (hs-to-sx for-tgt) (quote me)))
(scope
(cond
((nil? from-sel) nil)
((and (list? from-sel) (= (first from-sel) (quote query)))
(list (quote hs-query-all) (nth from-sel 1)))
(true (hs-to-sx from-sel)))))
(list (quote hs-take!) target kind name scope))))
((= head (quote make)) (emit-make ast))
((= head (quote install))
(cons (quote hs-install) (map hs-to-sx (rest ast))))
@@ -759,11 +908,13 @@
((= head (quote increment!))
(emit-inc
(nth ast 1)
(if (> (len ast) 2) (nth ast 2) nil)))
(nth ast 2)
(if (> (len ast) 3) (nth ast 3) nil)))
((= head (quote decrement!))
(emit-dec
(nth ast 1)
(if (> (len ast) 2) (nth ast 2) nil)))
(nth ast 2)
(if (> (len ast) 3) (nth ast 3) nil)))
((= head (quote on)) (emit-on ast))
((= head (quote init))
(list
@@ -860,6 +1011,23 @@
(list (make-symbol (nth ast 1)))
(hs-to-sx (nth ast 3)))
(hs-to-sx (nth ast 2))))
((= head (quote scroll!))
(list
(quote hs-scroll!)
(hs-to-sx (nth ast 1))
(nth ast 2)))
((= head (quote select!))
(list (quote hs-select!) (hs-to-sx (nth ast 1))))
((= head (quote reset!))
(list (quote hs-reset!) (hs-to-sx (nth ast 1))))
((= head (quote default!))
(let
((t (hs-to-sx (nth ast 1))) (v (hs-to-sx (nth ast 2))))
(list
(quote when)
(list (quote nil?) t)
(list (quote set!) t v))))
((= head (quote halt!)) (list (quote hs-halt!) (nth ast 1)))
(true ast))))))))
;; ── Convenience: source → SX ─────────────────────────────────