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:
@@ -64,22 +64,50 @@
|
||||
;; Take a class from siblings — add to target, remove from others.
|
||||
;; (hs-take! target cls) — like radio button class behavior
|
||||
(define
|
||||
hs-take!
|
||||
hs-toggle-style!
|
||||
(fn
|
||||
(target cls)
|
||||
(target prop)
|
||||
(let
|
||||
((parent (dom-parent target)))
|
||||
(when
|
||||
parent
|
||||
(for-each
|
||||
(fn (child) (dom-remove-class child cls))
|
||||
(dom-child-list parent)))
|
||||
(dom-add-class target cls))))
|
||||
((cur (dom-get-style target prop)))
|
||||
(cond
|
||||
((= prop "visibility")
|
||||
(if
|
||||
(= cur "hidden")
|
||||
(dom-set-style target prop "visible")
|
||||
(dom-set-style target prop "hidden")))
|
||||
((or (= prop "display") (= prop "opacity"))
|
||||
(if
|
||||
(or (= cur "none") (= cur "0"))
|
||||
(dom-set-style target prop "")
|
||||
(dom-set-style target prop (if (= prop "display") "none" "0"))))
|
||||
(true
|
||||
(if
|
||||
(or (= cur "") (= cur nil))
|
||||
(dom-set-style target prop "hidden")
|
||||
(dom-set-style target prop "")))))))
|
||||
|
||||
;; ── DOM insertion ───────────────────────────────────────────────
|
||||
|
||||
;; Put content at a position relative to a target.
|
||||
;; pos: "into" | "before" | "after"
|
||||
(define
|
||||
hs-take!
|
||||
(fn
|
||||
(target kind name scope)
|
||||
(let
|
||||
((els (if scope (if (list? scope) scope (list scope)) (let ((parent (host-get target "parentNode"))) (if parent (dom-child-list parent) (list))))))
|
||||
(if
|
||||
(= kind "class")
|
||||
(do
|
||||
(for-each (fn (el) (dom-remove-class el name)) els)
|
||||
(dom-add-class target name))
|
||||
(do
|
||||
(for-each (fn (el) (dom-remove-attr el name)) els)
|
||||
(dom-set-attr target name "true"))))))
|
||||
|
||||
;; ── Navigation / traversal ──────────────────────────────────────
|
||||
|
||||
;; Navigate to a URL.
|
||||
(define
|
||||
hs-put!
|
||||
(fn
|
||||
@@ -92,12 +120,38 @@
|
||||
((= pos "start") (dom-insert-adjacent-html target "afterbegin" value))
|
||||
((= pos "end") (dom-insert-adjacent-html target "beforeend" value)))))
|
||||
|
||||
;; ── Navigation / traversal ──────────────────────────────────────
|
||||
|
||||
;; Navigate to a URL.
|
||||
;; Find next sibling matching a selector (or any sibling).
|
||||
(define hs-navigate! (fn (url) (perform (list (quote io-navigate) url))))
|
||||
|
||||
;; Find next sibling matching a selector (or any sibling).
|
||||
;; Find previous sibling matching a selector.
|
||||
(define
|
||||
hs-scroll!
|
||||
(fn
|
||||
(target position)
|
||||
(host-call
|
||||
target
|
||||
"scrollIntoView"
|
||||
(list
|
||||
(cond
|
||||
((= position "bottom") (dict :block "end"))
|
||||
(true (dict :block "start")))))))
|
||||
|
||||
;; First element matching selector within a scope.
|
||||
(define
|
||||
hs-halt!
|
||||
(fn
|
||||
(mode)
|
||||
(when
|
||||
event
|
||||
(host-call event "preventDefault" (list))
|
||||
(when (= mode "event") (host-call event "stopPropagation" (list))))))
|
||||
|
||||
;; Last element matching selector.
|
||||
(define hs-select! (fn (target) (host-call target "select" (list))))
|
||||
|
||||
;; First/last within a specific scope.
|
||||
(define hs-reset! (fn (target) (host-call target "reset" (list))))
|
||||
|
||||
(define
|
||||
hs-next
|
||||
(fn
|
||||
@@ -117,7 +171,9 @@
|
||||
(true (find-next (dom-next-sibling el))))))
|
||||
(find-next sibling)))))
|
||||
|
||||
;; Find previous sibling matching a selector.
|
||||
;; ── Iteration ───────────────────────────────────────────────────
|
||||
|
||||
;; Repeat a thunk N times.
|
||||
(define
|
||||
hs-previous
|
||||
(fn
|
||||
@@ -137,12 +193,27 @@
|
||||
(true (find-prev (dom-get-prop el "previousElementSibling"))))))
|
||||
(find-prev sibling)))))
|
||||
|
||||
;; First element matching selector within a scope.
|
||||
;; Repeat forever (until break — relies on exception/continuation).
|
||||
(define
|
||||
hs-query-all
|
||||
(fn
|
||||
(sel)
|
||||
(dom-query-all
|
||||
(host-call (host-global "document") "querySelector" (list "body"))
|
||||
sel)))
|
||||
|
||||
;; ── Fetch ───────────────────────────────────────────────────────
|
||||
|
||||
;; Fetch a URL, parse response according to format.
|
||||
;; (hs-fetch url format) — format is "json" | "text" | "html"
|
||||
(define
|
||||
hs-query-first
|
||||
(fn (sel) (host-call (host-global "document") "querySelector" sel)))
|
||||
|
||||
;; Last element matching selector.
|
||||
;; ── Type coercion ───────────────────────────────────────────────
|
||||
|
||||
;; Coerce a value to a type by name.
|
||||
;; (hs-coerce value type-name) — type-name is "Int", "Float", "String", etc.
|
||||
(define
|
||||
hs-query-last
|
||||
(fn
|
||||
@@ -151,9 +222,17 @@
|
||||
((all (dom-query-all (dom-body) sel)))
|
||||
(if (> (len all) 0) (nth all (- (len all) 1)) nil))))
|
||||
|
||||
;; First/last within a specific scope.
|
||||
;; ── Object creation ─────────────────────────────────────────────
|
||||
|
||||
;; Make a new object of a given type.
|
||||
;; (hs-make type-name) — creates empty object/collection
|
||||
(define hs-first (fn (scope sel) (dom-query-all scope sel)))
|
||||
|
||||
;; ── Behavior installation ───────────────────────────────────────
|
||||
|
||||
;; Install a behavior on an element.
|
||||
;; A behavior is a function that takes (me ...params) and sets up features.
|
||||
;; (hs-install behavior-fn me ...args)
|
||||
(define
|
||||
hs-last
|
||||
(fn
|
||||
@@ -162,9 +241,10 @@
|
||||
((all (dom-query-all scope sel)))
|
||||
(if (> (len all) 0) (nth all (- (len all) 1)) nil))))
|
||||
|
||||
;; ── Iteration ───────────────────────────────────────────────────
|
||||
;; ── Measurement ─────────────────────────────────────────────────
|
||||
|
||||
;; Repeat a thunk N times.
|
||||
;; Measure an element's bounding rect, store as local variables.
|
||||
;; Returns a dict with x, y, width, height, top, left, right, bottom.
|
||||
(define
|
||||
hs-repeat-times
|
||||
(fn
|
||||
@@ -174,7 +254,10 @@
|
||||
(fn (i) (when (< i n) (do (thunk) (do-repeat (+ i 1))))))
|
||||
(do-repeat 0)))
|
||||
|
||||
;; Repeat forever (until break — relies on exception/continuation).
|
||||
;; ── Transition ──────────────────────────────────────────────────
|
||||
|
||||
;; Transition a CSS property to a value, optionally with duration.
|
||||
;; (hs-transition target prop value duration)
|
||||
(define
|
||||
hs-repeat-forever
|
||||
(fn
|
||||
@@ -182,10 +265,6 @@
|
||||
(define do-forever (fn () (thunk) (do-forever)))
|
||||
(do-forever)))
|
||||
|
||||
;; ── Fetch ───────────────────────────────────────────────────────
|
||||
|
||||
;; Fetch a URL, parse response according to format.
|
||||
;; (hs-fetch url format) — format is "json" | "text" | "html"
|
||||
(define
|
||||
hs-fetch
|
||||
(fn
|
||||
@@ -198,10 +277,6 @@
|
||||
((= format "html") (perform (list (quote io-parse-html) response)))
|
||||
(true response)))))
|
||||
|
||||
;; ── Type coercion ───────────────────────────────────────────────
|
||||
|
||||
;; Coerce a value to a type by name.
|
||||
;; (hs-coerce value type-name) — type-name is "Int", "Float", "String", etc.
|
||||
(define
|
||||
hs-coerce
|
||||
(fn
|
||||
@@ -235,19 +310,10 @@
|
||||
((= type-name "Date") (str value))
|
||||
(true value))))
|
||||
|
||||
;; ── Object creation ─────────────────────────────────────────────
|
||||
|
||||
;; Make a new object of a given type.
|
||||
;; (hs-make type-name) — creates empty object/collection
|
||||
(define
|
||||
hs-add
|
||||
(fn (a b) (if (or (string? a) (string? b)) (str a b) (+ a b))))
|
||||
|
||||
;; ── Behavior installation ───────────────────────────────────────
|
||||
|
||||
;; Install a behavior on an element.
|
||||
;; A behavior is a function that takes (me ...params) and sets up features.
|
||||
;; (hs-install behavior-fn me ...args)
|
||||
(define
|
||||
hs-make
|
||||
(fn
|
||||
@@ -259,16 +325,8 @@
|
||||
((= type-name "Map") (dict))
|
||||
(true (dict)))))
|
||||
|
||||
;; ── Measurement ─────────────────────────────────────────────────
|
||||
|
||||
;; Measure an element's bounding rect, store as local variables.
|
||||
;; Returns a dict with x, y, width, height, top, left, right, bottom.
|
||||
(define hs-install (fn (behavior-fn) (behavior-fn me)))
|
||||
|
||||
;; ── Transition ──────────────────────────────────────────────────
|
||||
|
||||
;; Transition a CSS property to a value, optionally with duration.
|
||||
;; (hs-transition target prop value duration)
|
||||
(define
|
||||
hs-measure
|
||||
(fn (target) (perform (list (quote io-measure) target))))
|
||||
@@ -311,6 +369,10 @@
|
||||
hs-strict-eq
|
||||
(fn (a b) (and (= (type-of a) (type-of b)) (= a b))))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(define
|
||||
hs-falsy?
|
||||
(fn
|
||||
@@ -331,7 +393,8 @@
|
||||
(string? target)
|
||||
(if (= pattern ".*") true (string-contains? target pattern))
|
||||
false)))
|
||||
|
||||
;; ── Sandbox/test runtime additions ──────────────────────────────
|
||||
;; Property access — dot notation and .length
|
||||
(define
|
||||
hs-contains?
|
||||
(fn
|
||||
@@ -351,7 +414,7 @@
|
||||
true
|
||||
(hs-contains? (rest collection) item)))))
|
||||
(true false))))
|
||||
|
||||
;; DOM query stub — sandbox returns empty list
|
||||
(define
|
||||
hs-empty?
|
||||
(fn
|
||||
@@ -362,15 +425,13 @@
|
||||
((list? v) (= (len v) 0))
|
||||
((dict? v) (= (len (keys v)) 0))
|
||||
(true false))))
|
||||
|
||||
;; Method dispatch — obj.method(args)
|
||||
(define hs-first (fn (lst) (first lst)))
|
||||
|
||||
;; ── 0.9.90 features ─────────────────────────────────────────────
|
||||
;; beep! — debug logging, returns value unchanged
|
||||
(define hs-last (fn (lst) (last lst)))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
;; Property-based is — check obj.key truthiness
|
||||
(define
|
||||
hs-template
|
||||
(fn
|
||||
@@ -456,7 +517,7 @@
|
||||
(set! i (+ i 1))
|
||||
(tpl-loop)))))))
|
||||
(do (tpl-loop) result))))
|
||||
|
||||
;; Array slicing (inclusive both ends)
|
||||
(define
|
||||
hs-make-object
|
||||
(fn
|
||||
@@ -468,8 +529,7 @@
|
||||
(fn (pair) (dict-set! d (first pair) (nth pair 1)))
|
||||
pairs)
|
||||
d))))
|
||||
;; ── Sandbox/test runtime additions ──────────────────────────────
|
||||
;; Property access — dot notation and .length
|
||||
;; Collection: sorted by
|
||||
(define
|
||||
hs-method-call
|
||||
(fn
|
||||
@@ -492,13 +552,11 @@
|
||||
(if (= (first lst) item) i (idx-loop (rest lst) (+ i 1))))))
|
||||
(idx-loop obj 0)))
|
||||
(true nil))))
|
||||
;; DOM query stub — sandbox returns empty list
|
||||
;; Collection: sorted by descending
|
||||
(define hs-beep (fn (v) v))
|
||||
;; Method dispatch — obj.method(args)
|
||||
;; Collection: split by
|
||||
(define hs-prop-is (fn (obj key) (not (hs-falsy? (host-get obj key)))))
|
||||
|
||||
;; ── 0.9.90 features ─────────────────────────────────────────────
|
||||
;; beep! — debug logging, returns value unchanged
|
||||
;; Collection: joined by
|
||||
(define
|
||||
hs-slice
|
||||
(fn
|
||||
@@ -507,7 +565,7 @@
|
||||
((s (if (nil? start) 0 start))
|
||||
(e (if (nil? end) (len col) (+ end 1))))
|
||||
(slice col s e))))
|
||||
;; Property-based is — check obj.key truthiness
|
||||
|
||||
(define
|
||||
hs-sorted-by
|
||||
(fn
|
||||
@@ -517,7 +575,7 @@
|
||||
(map
|
||||
(fn (p) (nth p 1))
|
||||
(sort (fn (a b) (if (< (first a) (first b)) true false)) pairs)))))
|
||||
;; Array slicing (inclusive both ends)
|
||||
|
||||
(define
|
||||
hs-sorted-by-desc
|
||||
(fn
|
||||
@@ -527,11 +585,11 @@
|
||||
(map
|
||||
(fn (p) (nth p 1))
|
||||
(sort (fn (a b) (if (> (first a) (first b)) true false)) pairs)))))
|
||||
;; Collection: sorted by
|
||||
|
||||
(define hs-split-by (fn (s sep) (split s sep)))
|
||||
;; Collection: sorted by descending
|
||||
|
||||
(define hs-joined-by (fn (col sep) (join sep col)))
|
||||
;; Collection: split by
|
||||
|
||||
(define
|
||||
hs-sorted-by
|
||||
(fn
|
||||
@@ -567,7 +625,7 @@
|
||||
(append acc (list (nth found 1)))
|
||||
(filter (fn (x) (not (= x found))) remaining)))))))
|
||||
(reorder sorted-dec (list) decorated)))))
|
||||
;; Collection: joined by
|
||||
|
||||
(define
|
||||
hs-sorted-by-desc
|
||||
(fn (col key-fn) (reverse (hs-sorted-by col key-fn))))
|
||||
|
||||
Reference in New Issue
Block a user