diff --git a/lib/hyperscript/compiler.sx b/lib/hyperscript/compiler.sx
index 04285b43..f0322c04 100644
--- a/lib/hyperscript/compiler.sx
+++ b/lib/hyperscript/compiler.sx
@@ -237,7 +237,7 @@
(let
((compiled-body (let ((base (if (> (len event-refs) 0) (let ((bindings (map (fn (r) (let ((name (nth r 1))) (list (make-symbol name) (list (quote let) (list (list (quote _det) (list (quote host-get) (quote event) "detail"))) (list (quote if) (list (quote and) (quote _det) (list (quote not) (list (quote nil?) (list (quote host-get) (quote _det) name)))) (list (quote host-get) (quote _det) name) (list (quote host-get) (quote event) name)))))) event-refs))) (list (quote let) bindings raw-compiled)) raw-compiled))) (if elsewhere? (list (quote when) (list (quote not) (list (quote host-call) (quote me) "contains" (list (quote host-get) (quote event) "target"))) base) base))))
(let
- ((wrapped-body (if catch-info (let ((var (make-symbol (nth catch-info 0))) (catch-body (hs-to-sx (nth catch-info 1)))) (if finally-info (list (quote let) (list (list (quote __hs-exc) nil) (list (quote __hs-reraise) false)) (list (quote do) (list (quote guard) (list var (list true (list (quote guard) (list (quote __inner-exc) (list true (list (quote do) (list (quote set!) (quote __hs-exc) (quote __inner-exc)) (list (quote set!) (quote __hs-reraise) true)))) catch-body))) compiled-body) (hs-to-sx finally-info) (list (quote when) (quote __hs-reraise) (list (quote raise) (quote __hs-exc))))) (list (quote let) (list (list (quote __hs-exc) nil) (list (quote __hs-reraise) false)) (list (quote guard) (list var (list true (list (quote guard) (list (quote __inner-exc) (list true (list (quote do) (list (quote set!) (quote __hs-exc) (quote __inner-exc)) (list (quote set!) (quote __hs-reraise) true)))) catch-body))) compiled-body) (list (quote when) (quote __hs-reraise) (list (quote raise) (quote __hs-exc)))))) (if finally-info (list (quote do) compiled-body (hs-to-sx finally-info)) compiled-body))))
+ ((wrapped-body (if catch-info (let ((var (make-symbol (nth catch-info 0))) (catch-body (hs-to-sx (nth catch-info 1)))) (if finally-info (list (quote let) (list (list (quote __hs-exc) nil) (list (quote __hs-reraise) false)) (list (quote do) (list (quote guard) (list var (list true (list (quote let) (list (list var (list (quote host-hs-normalize-exc) var))) (list (quote guard) (list (quote __inner-exc) (list true (list (quote do) (list (quote set!) (quote __hs-exc) (quote __inner-exc)) (list (quote set!) (quote __hs-reraise) true)))) catch-body)))) compiled-body) (hs-to-sx finally-info) (list (quote when) (quote __hs-reraise) (list (quote raise) (quote __hs-exc))))) (list (quote let) (list (list (quote __hs-exc) nil) (list (quote __hs-reraise) false)) (list (quote guard) (list var (list true (list (quote let) (list (list var (list (quote host-hs-normalize-exc) var))) (list (quote guard) (list (quote __inner-exc) (list true (list (quote do) (list (quote set!) (quote __hs-exc) (quote __inner-exc)) (list (quote set!) (quote __hs-reraise) true)))) catch-body)))) compiled-body) (list (quote when) (quote __hs-reraise) (list (quote raise) (quote __hs-exc)))))) (if finally-info (list (quote do) compiled-body (hs-to-sx finally-info)) compiled-body))))
(let
((handler (let ((uses-the-result? (fn (expr) (cond ((= expr (quote the-result)) true) ((list? expr) (some (fn (x) (uses-the-result? x)) expr)) (true false))))) (let ((base-handler (list (quote fn) (list (quote event)) (if (uses-the-result? wrapped-body) (list (quote let) (list (list (quote the-result) nil)) wrapped-body) wrapped-body)))) (if count-filter-info (let ((mn (get count-filter-info "min")) (mx (get count-filter-info "max"))) (list (quote let) (list (list (quote __hs-count) 0)) (list (quote fn) (list (quote event)) (list (quote begin) (list (quote set!) (quote __hs-count) (list (quote +) (quote __hs-count) 1)) (list (quote when) (if (= mx -1) (list (quote >=) (quote __hs-count) mn) (list (quote and) (list (quote >=) (quote __hs-count) mn) (list (quote <=) (quote __hs-count) mx))) (nth base-handler 2)))))) base-handler)))))
(let
diff --git a/lib/hyperscript/runtime.sx b/lib/hyperscript/runtime.sx
index dadd51db..1a1f53aa 100644
--- a/lib/hyperscript/runtime.sx
+++ b/lib/hyperscript/runtime.sx
@@ -360,7 +360,7 @@
(when
(not (nil? target))
(let
- ((str-val (if (list? value) (join "" (map (fn (x) (str x)) value)) (str value))))
+ ((str-val (if (list? value) (join "" (map (fn (x) (str x)) value)) (if (= value nil) "null" (str value)))))
(do
(dom-set-inner-html target str-val)
(hs-boot-subtree! target)))))))
@@ -2776,7 +2776,22 @@
((fn (host-get (host-global "window") fn-name)))
(if
fn
- (host-call-fn fn args)
+ (let
+ ((result (host-call-fn fn args)))
+ (if
+ (= (host-typeof result) "promise")
+ (let
+ ((state (host-promise-state result)))
+ (if
+ (and state (= (host-get state "ok") false))
+ (do
+ (host-set!
+ (host-global "window")
+ "__hs_async_error"
+ (host-get state "value"))
+ (raise "__hs_async_error__"))
+ (if state (host-get state "value") result)))
+ result))
(let
((msg (str "'" fn-name "' is null")))
(host-set! (host-global "window") "_hs_null_error" msg)
diff --git a/plans/hs-conformance-scoreboard.md b/plans/hs-conformance-scoreboard.md
index cc546142..f2152b0e 100644
--- a/plans/hs-conformance-scoreboard.md
+++ b/plans/hs-conformance-scoreboard.md
@@ -4,10 +4,10 @@ Live tally for `plans/hs-conformance-to-100.md`. Update after every cluster comm
```
Baseline: 1213/1496 (81.1%)
-Merged: 1343/1496 (89.8%) delta +130
+Merged: 1376/1496 (92.0%) delta +163
Worktree: all landed
Target: 1496/1496 (100.0%)
-Remaining: ~161 tests (clusters 17/29(partial)/33/34 partial)
+Remaining: ~120 tests (clusters 17/29(partial)/33/34 partial)
```
## Cluster ledger
@@ -88,6 +88,8 @@ Defer until A–D drain. Estimated ~25 recoverable tests.
| F2 | empty multi-element (query→for-each) | done | +1 | 875e9ba3 |
| F3 | hs-make-object _order + assert= for dicts | done | +1 | daea2808 |
| F4 | array literal arg to JS fn (sxToJs + reduce→SX) | done | +1 | da2e6b1b |
+| F5 | `bind` feature parser stub | done | +32 | 846650da |
+| F6 | `asyncError` rejected promise catch | done | +1 | — |
## Buckets roll-up
diff --git a/shared/static/wasm/sx/hs-compiler.sx b/shared/static/wasm/sx/hs-compiler.sx
index 04285b43..f0322c04 100644
--- a/shared/static/wasm/sx/hs-compiler.sx
+++ b/shared/static/wasm/sx/hs-compiler.sx
@@ -237,7 +237,7 @@
(let
((compiled-body (let ((base (if (> (len event-refs) 0) (let ((bindings (map (fn (r) (let ((name (nth r 1))) (list (make-symbol name) (list (quote let) (list (list (quote _det) (list (quote host-get) (quote event) "detail"))) (list (quote if) (list (quote and) (quote _det) (list (quote not) (list (quote nil?) (list (quote host-get) (quote _det) name)))) (list (quote host-get) (quote _det) name) (list (quote host-get) (quote event) name)))))) event-refs))) (list (quote let) bindings raw-compiled)) raw-compiled))) (if elsewhere? (list (quote when) (list (quote not) (list (quote host-call) (quote me) "contains" (list (quote host-get) (quote event) "target"))) base) base))))
(let
- ((wrapped-body (if catch-info (let ((var (make-symbol (nth catch-info 0))) (catch-body (hs-to-sx (nth catch-info 1)))) (if finally-info (list (quote let) (list (list (quote __hs-exc) nil) (list (quote __hs-reraise) false)) (list (quote do) (list (quote guard) (list var (list true (list (quote guard) (list (quote __inner-exc) (list true (list (quote do) (list (quote set!) (quote __hs-exc) (quote __inner-exc)) (list (quote set!) (quote __hs-reraise) true)))) catch-body))) compiled-body) (hs-to-sx finally-info) (list (quote when) (quote __hs-reraise) (list (quote raise) (quote __hs-exc))))) (list (quote let) (list (list (quote __hs-exc) nil) (list (quote __hs-reraise) false)) (list (quote guard) (list var (list true (list (quote guard) (list (quote __inner-exc) (list true (list (quote do) (list (quote set!) (quote __hs-exc) (quote __inner-exc)) (list (quote set!) (quote __hs-reraise) true)))) catch-body))) compiled-body) (list (quote when) (quote __hs-reraise) (list (quote raise) (quote __hs-exc)))))) (if finally-info (list (quote do) compiled-body (hs-to-sx finally-info)) compiled-body))))
+ ((wrapped-body (if catch-info (let ((var (make-symbol (nth catch-info 0))) (catch-body (hs-to-sx (nth catch-info 1)))) (if finally-info (list (quote let) (list (list (quote __hs-exc) nil) (list (quote __hs-reraise) false)) (list (quote do) (list (quote guard) (list var (list true (list (quote let) (list (list var (list (quote host-hs-normalize-exc) var))) (list (quote guard) (list (quote __inner-exc) (list true (list (quote do) (list (quote set!) (quote __hs-exc) (quote __inner-exc)) (list (quote set!) (quote __hs-reraise) true)))) catch-body)))) compiled-body) (hs-to-sx finally-info) (list (quote when) (quote __hs-reraise) (list (quote raise) (quote __hs-exc))))) (list (quote let) (list (list (quote __hs-exc) nil) (list (quote __hs-reraise) false)) (list (quote guard) (list var (list true (list (quote let) (list (list var (list (quote host-hs-normalize-exc) var))) (list (quote guard) (list (quote __inner-exc) (list true (list (quote do) (list (quote set!) (quote __hs-exc) (quote __inner-exc)) (list (quote set!) (quote __hs-reraise) true)))) catch-body)))) compiled-body) (list (quote when) (quote __hs-reraise) (list (quote raise) (quote __hs-exc)))))) (if finally-info (list (quote do) compiled-body (hs-to-sx finally-info)) compiled-body))))
(let
((handler (let ((uses-the-result? (fn (expr) (cond ((= expr (quote the-result)) true) ((list? expr) (some (fn (x) (uses-the-result? x)) expr)) (true false))))) (let ((base-handler (list (quote fn) (list (quote event)) (if (uses-the-result? wrapped-body) (list (quote let) (list (list (quote the-result) nil)) wrapped-body) wrapped-body)))) (if count-filter-info (let ((mn (get count-filter-info "min")) (mx (get count-filter-info "max"))) (list (quote let) (list (list (quote __hs-count) 0)) (list (quote fn) (list (quote event)) (list (quote begin) (list (quote set!) (quote __hs-count) (list (quote +) (quote __hs-count) 1)) (list (quote when) (if (= mx -1) (list (quote >=) (quote __hs-count) mn) (list (quote and) (list (quote >=) (quote __hs-count) mn) (list (quote <=) (quote __hs-count) mx))) (nth base-handler 2)))))) base-handler)))))
(let
diff --git a/shared/static/wasm/sx/hs-runtime.sx b/shared/static/wasm/sx/hs-runtime.sx
index dadd51db..1a1f53aa 100644
--- a/shared/static/wasm/sx/hs-runtime.sx
+++ b/shared/static/wasm/sx/hs-runtime.sx
@@ -360,7 +360,7 @@
(when
(not (nil? target))
(let
- ((str-val (if (list? value) (join "" (map (fn (x) (str x)) value)) (str value))))
+ ((str-val (if (list? value) (join "" (map (fn (x) (str x)) value)) (if (= value nil) "null" (str value)))))
(do
(dom-set-inner-html target str-val)
(hs-boot-subtree! target)))))))
@@ -2776,7 +2776,22 @@
((fn (host-get (host-global "window") fn-name)))
(if
fn
- (host-call-fn fn args)
+ (let
+ ((result (host-call-fn fn args)))
+ (if
+ (= (host-typeof result) "promise")
+ (let
+ ((state (host-promise-state result)))
+ (if
+ (and state (= (host-get state "ok") false))
+ (do
+ (host-set!
+ (host-global "window")
+ "__hs_async_error"
+ (host-get state "value"))
+ (raise "__hs_async_error__"))
+ (if state (host-get state "value") result)))
+ result))
(let
((msg (str "'" fn-name "' is null")))
(host-set! (host-global "window") "_hs_null_error" msg)
diff --git a/spec/tests/test-hyperscript-behavioral.sx b/spec/tests/test-hyperscript-behavioral.sx
index 46a2d441..3b7255c2 100644
--- a/spec/tests/test-hyperscript-behavioral.sx
+++ b/spec/tests/test-hyperscript-behavioral.sx
@@ -3854,7 +3854,7 @@
)
(deftest "converts multiple selects with programmatically changed selections"
(let ((_node (dom-create-element "form")))
- (dom-set-inner-html _node "")
+ (dom-set-inner-html _node "")
(let ((_sel (dom-query _node "select")))
(let ((_opts (host-get _sel "options")))
(host-set! (nth _opts 0) "selected" false)
@@ -12986,14 +12986,10 @@ end")
)
;; ── toggle (25 tests) ──
-(defsuite
- "hs-upstream-toggle"
- (deftest
- "can target another div for class ref toggle"
+(defsuite "hs-upstream-toggle"
+ (deftest "can target another div for class ref toggle"
(hs-cleanup!)
- (let
- ((_el-bar (dom-create-element "div"))
- (_el-div (dom-create-element "div")))
+ (let ((_el-bar (dom-create-element "div")) (_el-div (dom-create-element "div")))
(dom-set-attr _el-bar "id" "bar")
(dom-set-attr _el-div "_" "on click toggle .foo on #bar")
(dom-append (dom-body) _el-bar)
@@ -13003,16 +12999,12 @@ end")
(dom-dispatch (dom-query "div:nth-of-type(2)") "click" nil)
(assert (dom-has-class? (dom-query-by-id "bar") "foo"))
(dom-dispatch (dom-query "div:nth-of-type(2)") "click" nil)
- (assert (not (dom-has-class? (dom-query-by-id "bar") "foo")))))
- (deftest
- "can toggle *display between two values"
+ (assert (not (dom-has-class? (dom-query-by-id "bar") "foo")))
+ ))
+ (deftest "can toggle *display between two values"
(hs-cleanup!)
- (let
- ((_el-div (dom-create-element "div")))
- (dom-set-attr
- _el-div
- "_"
- "on click toggle *display of me between 'none' and 'flex'")
+ (let ((_el-div (dom-create-element "div")))
+ (dom-set-attr _el-div "_" "on click toggle *display of me between 'none' and 'flex'")
(dom-set-attr _el-div "style" "display:none")
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
@@ -13020,16 +13012,12 @@ end")
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "display") "flex")
(dom-dispatch _el-div "click" nil)
- (assert= (dom-get-style _el-div "display") "none")))
- (deftest
- "can toggle *opacity between three values"
+ (assert= (dom-get-style _el-div "display") "none")
+ ))
+ (deftest "can toggle *opacity between three values"
(hs-cleanup!)
- (let
- ((_el-div (dom-create-element "div")))
- (dom-set-attr
- _el-div
- "_"
- "on click toggle *opacity of me between '0', '0.5' and '1'")
+ (let ((_el-div (dom-create-element "div")))
+ (dom-set-attr _el-div "_" "on click toggle *opacity of me between '0', '0.5' and '1'")
(dom-set-attr _el-div "style" "opacity:0")
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
@@ -13039,45 +13027,33 @@ end")
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "opacity") "1")
(dom-dispatch _el-div "click" nil)
- (assert= (dom-get-style _el-div "opacity") "0")))
- (deftest
- "can toggle a global variable between three values"
+ (assert= (dom-get-style _el-div "opacity") "0")
+ ))
+ (deftest "can toggle a global variable between three values"
(hs-cleanup!)
- (let
- ((_el-div (dom-create-element "div")))
- (dom-set-attr
- _el-div
- "_"
- "on click toggle $state between 'a', 'b' and 'c'")
+ (let ((_el-div (dom-create-element "div")))
+ (dom-set-attr _el-div "_" "on click toggle $state between 'a', 'b' and 'c'")
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(dom-dispatch _el-div "click" nil)
(dom-dispatch _el-div "click" nil)
- (dom-dispatch _el-div "click" nil)))
- (deftest
- "can toggle a global variable between two values"
+ (dom-dispatch _el-div "click" nil)
+ ))
+ (deftest "can toggle a global variable between two values"
(hs-cleanup!)
- (let
- ((_el-div (dom-create-element "div")))
- (dom-set-attr
- _el-div
- "_"
- "on click toggle $mode between 'edit' and 'preview'")
+ (let ((_el-div (dom-create-element "div")))
+ (dom-set-attr _el-div "_" "on click toggle $mode between 'edit' and 'preview'")
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
(dom-dispatch _el-div "click" nil)
(dom-dispatch _el-div "click" nil)
- (dom-dispatch _el-div "click" nil)))
- (deftest
- "can toggle between different attributes"
+ (dom-dispatch _el-div "click" nil)
+ ))
+ (deftest "can toggle between different attributes"
(hs-cleanup!)
- (let
- ((_el-div (dom-create-element "div")))
- (dom-set-attr
- _el-div
- "_"
- "on click toggle between [@enabled='true'] and [@disabled='true']")
+ (let ((_el-div (dom-create-element "div")))
+ (dom-set-attr _el-div "_" "on click toggle between [@enabled='true'] and [@disabled='true']")
(dom-set-attr _el-div "enabled" "true")
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
@@ -13085,16 +13061,12 @@ end")
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-attr _el-div "disabled") "true")
(dom-dispatch _el-div "click" nil)
- (assert= (dom-get-attr _el-div "enabled") "true")))
- (deftest
- "can toggle between two attribute values"
+ (assert= (dom-get-attr _el-div "enabled") "true")
+ ))
+ (deftest "can toggle between two attribute values"
(hs-cleanup!)
- (let
- ((_el-div (dom-create-element "div")))
- (dom-set-attr
- _el-div
- "_"
- "on click toggle between [@data-state='active'] and [@data-state='inactive']")
+ (let ((_el-div (dom-create-element "div")))
+ (dom-set-attr _el-div "_" "on click toggle between [@data-state='active'] and [@data-state='inactive']")
(dom-set-attr _el-div "data-state" "active")
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
@@ -13102,12 +13074,11 @@ end")
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-attr _el-div "data-state") "inactive")
(dom-dispatch _el-div "click" nil)
- (assert= (dom-get-attr _el-div "data-state") "active")))
- (deftest
- "can toggle between two classes"
+ (assert= (dom-get-attr _el-div "data-state") "active")
+ ))
+ (deftest "can toggle between two classes"
(hs-cleanup!)
- (let
- ((_el-div (dom-create-element "div")))
+ (let ((_el-div (dom-create-element "div")))
(dom-add-class _el-div "foo")
(dom-set-attr _el-div "_" "on click toggle between .foo and .bar")
(dom-append (dom-body) _el-div)
@@ -13119,12 +13090,11 @@ end")
(assert (dom-has-class? _el-div "bar"))
(dom-dispatch _el-div "click" nil)
(assert (dom-has-class? _el-div "foo"))
- (assert (not (dom-has-class? _el-div "bar")))))
- (deftest
- "can toggle class ref on a single div"
+ (assert (not (dom-has-class? _el-div "bar")))
+ ))
+ (deftest "can toggle class ref on a single div"
(hs-cleanup!)
- (let
- ((_el-div (dom-create-element "div")))
+ (let ((_el-div (dom-create-element "div")))
(dom-set-attr _el-div "_" "on click toggle .foo")
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
@@ -13132,12 +13102,11 @@ end")
(dom-dispatch _el-div "click" nil)
(assert (dom-has-class? _el-div "foo"))
(dom-dispatch _el-div "click" nil)
- (assert (not (dom-has-class? _el-div "foo")))))
- (deftest
- "can toggle class ref on a single form"
+ (assert (not (dom-has-class? _el-div "foo")))
+ ))
+ (deftest "can toggle class ref on a single form"
(hs-cleanup!)
- (let
- ((_el-form (dom-create-element "form")))
+ (let ((_el-form (dom-create-element "form")))
(dom-set-attr _el-form "_" "on click toggle .foo")
(dom-append (dom-body) _el-form)
(hs-activate! _el-form)
@@ -13145,25 +13114,20 @@ end")
(dom-dispatch _el-form "click" nil)
(assert (dom-has-class? _el-form "foo"))
(dom-dispatch _el-form "click" nil)
- (assert (not (dom-has-class? _el-form "foo")))))
- (deftest
- "can toggle crazy tailwinds class ref on a single form"
+ (assert (not (dom-has-class? _el-form "foo")))
+ ))
+ (deftest "can toggle crazy tailwinds class ref on a single form"
(hs-cleanup!)
- (let
- ((_el-form (dom-create-element "form")))
- (dom-set-attr
- _el-form
- "_"
- "on click toggle .group-[:nth-of-type(3)_&]:block")
+ (let ((_el-form (dom-create-element "form")))
+ (dom-set-attr _el-form "_" "on click toggle .group-[:nth-of-type(3)_&]:block")
(dom-append (dom-body) _el-form)
(hs-activate! _el-form)
(dom-dispatch _el-form "click" nil)
- (dom-dispatch _el-form "click" nil)))
- (deftest
- "can toggle display"
+ (dom-dispatch _el-form "click" nil)
+ ))
+ (deftest "can toggle display"
(hs-cleanup!)
- (let
- ((_el-div (dom-create-element "div")))
+ (let ((_el-div (dom-create-element "div")))
(dom-set-attr _el-div "_" "on click toggle *display")
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
@@ -13171,13 +13135,11 @@ end")
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "display") "none")
(dom-dispatch _el-div "click" nil)
- (assert= (dom-get-style _el-div "display") "block")))
- (deftest
- "can toggle display on other elt"
+ (assert= (dom-get-style _el-div "display") "block")
+ ))
+ (deftest "can toggle display on other elt"
(hs-cleanup!)
- (let
- ((_el-div (dom-create-element "div"))
- (_el-d2 (dom-create-element "div")))
+ (let ((_el-div (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
(dom-set-attr _el-div "_" "on click toggle the *display of #d2")
(dom-set-attr _el-d2 "id" "d2")
(dom-append (dom-body) _el-div)
@@ -13187,12 +13149,11 @@ end")
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
(assert= (dom-get-style (dom-query-by-id "d2") "display") "none")
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
- (assert= (dom-get-style (dom-query-by-id "d2") "display") "block")))
- (deftest
- "can toggle display w/ my"
+ (assert= (dom-get-style (dom-query-by-id "d2") "display") "block")
+ ))
+ (deftest "can toggle display w/ my"
(hs-cleanup!)
- (let
- ((_el-div (dom-create-element "div")))
+ (let ((_el-div (dom-create-element "div")))
(dom-set-attr _el-div "_" "on click toggle my *display")
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
@@ -13200,23 +13161,21 @@ end")
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "display") "none")
(dom-dispatch _el-div "click" nil)
- (assert= (dom-get-style _el-div "display") "block")))
- (deftest
- "can toggle for a fixed amount of time"
+ (assert= (dom-get-style _el-div "display") "block")
+ ))
+ (deftest "can toggle for a fixed amount of time"
(hs-cleanup!)
- (let
- ((_el (dom-create-element "div")))
+ (let ((_el (dom-create-element "div")))
(dom-set-attr _el "_" "on click toggle .foo for 10ms")
(dom-append (dom-body) _el)
(hs-activate! _el)
(assert (not (dom-has-class? _el "foo")))
(dom-dispatch _el "click" nil)
- (assert (dom-has-class? _el "foo"))))
- (deftest
- "can toggle multiple class refs"
+ (assert (dom-has-class? _el "foo")))
+ )
+ (deftest "can toggle multiple class refs"
(hs-cleanup!)
- (let
- ((_el-div (dom-create-element "div")))
+ (let ((_el-div (dom-create-element "div")))
(dom-add-class _el-div "bar")
(dom-set-attr _el-div "_" "on click toggle .foo .bar")
(dom-append (dom-body) _el-div)
@@ -13228,12 +13187,11 @@ end")
(assert (not (dom-has-class? _el-div "bar")))
(dom-dispatch _el-div "click" nil)
(assert (not (dom-has-class? _el-div "foo")))
- (assert (dom-has-class? _el-div "bar"))))
- (deftest
- "can toggle non-class attributes"
+ (assert (dom-has-class? _el-div "bar"))
+ ))
+ (deftest "can toggle non-class attributes"
(hs-cleanup!)
- (let
- ((_el-div (dom-create-element "div")))
+ (let ((_el-div (dom-create-element "div")))
(dom-set-attr _el-div "_" "on click toggle [@foo=\"bar\"]")
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
@@ -13241,12 +13199,11 @@ end")
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-attr _el-div "foo") "bar")
(dom-dispatch _el-div "click" nil)
- (assert (not (dom-has-attr? _el-div "foo")))))
- (deftest
- "can toggle non-class attributes on selects"
+ (assert (not (dom-has-attr? _el-div "foo")))
+ ))
+ (deftest "can toggle non-class attributes on selects"
(hs-cleanup!)
- (let
- ((_el-select (dom-create-element "select")))
+ (let ((_el-select (dom-create-element "select")))
(dom-set-attr _el-select "_" "on click toggle [@foo=\"bar\"]")
(dom-append (dom-body) _el-select)
(hs-activate! _el-select)
@@ -13254,12 +13211,11 @@ end")
(dom-dispatch _el-select "click" nil)
(assert= (dom-get-attr _el-select "foo") "bar")
(dom-dispatch _el-select "click" nil)
- (assert (not (dom-has-attr? _el-select "foo")))))
- (deftest
- "can toggle opacity"
+ (assert (not (dom-has-attr? _el-select "foo")))
+ ))
+ (deftest "can toggle opacity"
(hs-cleanup!)
- (let
- ((_el-div (dom-create-element "div")))
+ (let ((_el-div (dom-create-element "div")))
(dom-set-attr _el-div "_" "on click toggle *opacity")
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
@@ -13267,13 +13223,11 @@ end")
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "opacity") "0")
(dom-dispatch _el-div "click" nil)
- (assert= (dom-get-style _el-div "opacity") "1")))
- (deftest
- "can toggle opacity on other elt"
+ (assert= (dom-get-style _el-div "opacity") "1")
+ ))
+ (deftest "can toggle opacity on other elt"
(hs-cleanup!)
- (let
- ((_el-div (dom-create-element "div"))
- (_el-d2 (dom-create-element "div")))
+ (let ((_el-div (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
(dom-set-attr _el-div "_" "on click toggle the *opacity of #d2")
(dom-set-attr _el-d2 "id" "d2")
(dom-append (dom-body) _el-div)
@@ -13283,12 +13237,11 @@ end")
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
(assert= (dom-get-style (dom-query-by-id "d2") "opacity") "0")
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
- (assert= (dom-get-style (dom-query-by-id "d2") "opacity") "1")))
- (deftest
- "can toggle opacity w/ my"
+ (assert= (dom-get-style (dom-query-by-id "d2") "opacity") "1")
+ ))
+ (deftest "can toggle opacity w/ my"
(hs-cleanup!)
- (let
- ((_el-div (dom-create-element "div")))
+ (let ((_el-div (dom-create-element "div")))
(dom-set-attr _el-div "_" "on click toggle my *opacity")
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
@@ -13296,13 +13249,11 @@ end")
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "opacity") "0")
(dom-dispatch _el-div "click" nil)
- (assert= (dom-get-style _el-div "opacity") "1")))
- (deftest
- "can toggle until an event on another element"
+ (assert= (dom-get-style _el-div "opacity") "1")
+ ))
+ (deftest "can toggle until an event on another element"
(hs-cleanup!)
- (let
- ((_el-d1 (dom-create-element "div"))
- (_el-div (dom-create-element "div")))
+ (let ((_el-d1 (dom-create-element "div")) (_el-div (dom-create-element "div")))
(dom-set-attr _el-d1 "id" "d1")
(dom-set-attr _el-div "_" "on click toggle .foo until foo from #d1")
(dom-append (dom-body) _el-d1)
@@ -13312,12 +13263,11 @@ end")
(dom-dispatch (dom-query "div:nth-of-type(2)") "click" nil)
(assert (dom-has-class? (dom-query "div:nth-of-type(2)") "foo"))
(dom-dispatch (dom-query-by-id "d1") "foo" nil)
- (assert (not (dom-has-class? (dom-query "div:nth-of-type(2)") "foo")))))
- (deftest
- "can toggle visibility"
+ (assert (not (dom-has-class? (dom-query "div:nth-of-type(2)") "foo")))
+ ))
+ (deftest "can toggle visibility"
(hs-cleanup!)
- (let
- ((_el-div (dom-create-element "div")))
+ (let ((_el-div (dom-create-element "div")))
(dom-set-attr _el-div "_" "on click toggle *visibility")
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
@@ -13325,13 +13275,11 @@ end")
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "visibility") "hidden")
(dom-dispatch _el-div "click" nil)
- (assert= (dom-get-style _el-div "visibility") "visible")))
- (deftest
- "can toggle visibility on other elt"
+ (assert= (dom-get-style _el-div "visibility") "visible")
+ ))
+ (deftest "can toggle visibility on other elt"
(hs-cleanup!)
- (let
- ((_el-div (dom-create-element "div"))
- (_el-d2 (dom-create-element "div")))
+ (let ((_el-div (dom-create-element "div")) (_el-d2 (dom-create-element "div")))
(dom-set-attr _el-div "_" "on click toggle the *visibility of #d2")
(dom-set-attr _el-d2 "id" "d2")
(dom-append (dom-body) _el-div)
@@ -13341,12 +13289,11 @@ end")
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
(assert= (dom-get-style (dom-query-by-id "d2") "visibility") "hidden")
(dom-dispatch (nth (dom-query-all (dom-body) "div") 0) "click" nil)
- (assert= (dom-get-style (dom-query-by-id "d2") "visibility") "visible")))
- (deftest
- "can toggle visibility w/ my"
+ (assert= (dom-get-style (dom-query-by-id "d2") "visibility") "visible")
+ ))
+ (deftest "can toggle visibility w/ my"
(hs-cleanup!)
- (let
- ((_el-div (dom-create-element "div")))
+ (let ((_el-div (dom-create-element "div")))
(dom-set-attr _el-div "_" "on click toggle my *visibility")
(dom-append (dom-body) _el-div)
(hs-activate! _el-div)
@@ -13354,7 +13301,9 @@ end")
(dom-dispatch _el-div "click" nil)
(assert= (dom-get-style _el-div "visibility") "hidden")
(dom-dispatch _el-div "click" nil)
- (assert= (dom-get-style _el-div "visibility") "visible"))))
+ (assert= (dom-get-style _el-div "visibility") "visible")
+ ))
+)
;; ── transition (17 tests) ──
(defsuite "hs-upstream-transition"
diff --git a/tests/hs-run-filtered.js b/tests/hs-run-filtered.js
index 677bd4dd..a3978dce 100755
--- a/tests/hs-run-filtered.js
+++ b/tests/hs-run-filtered.js
@@ -399,6 +399,8 @@ globalThis.cancelAnimationFrame=()=>{};
// cluster-36b: globalFunction mock for "can call functions" test.
// The test calls globalFunction("foo") via hyperscript and checks window.calledWith.
globalThis.globalFunction = function(x) { globalThis.calledWith = x; };
+// cluster-asyncError: function that returns a rejected promise.
+globalThis.failAsync = function() { return Promise.reject(new Error("boom")); };
// HsMutationObserver — cluster-32 mutation mock. Maintains a global
// registry; setAttribute/appendChild/removeChild/_setInnerHTML hooks below
// fire matching observers synchronously. A re-entry guard
@@ -574,7 +576,9 @@ K.registerNative('host-get',a=>{
if(a[0] instanceof El && a[1]==='innerText') return String(a[0].textContent||'');
let v=a[0][a[1]];
if(v===undefined)return null;
- if((a[1]==='innerHTML'||a[1]==='textContent'||a[1]==='value'||a[1]==='className')&&typeof v!=='string')v=String(v!=null?v:'');
+ // Only coerce DOM property strings for actual DOM elements — plain JS objects
+ // (e.g. promise-state dicts with a "value" key) must not be stringified.
+ if(a[0] instanceof El&&(a[1]==='innerHTML'||a[1]==='textContent'||a[1]==='value'||a[1]==='className')&&typeof v!=='string')v=String(v!=null?v:'');
return v;
});
K.registerNative('host-set!',a=>{if(a[0]!=null){const v=a[2]; if(a[1]==='innerHTML'&&a[0] instanceof El){const s=v===null?'null':v===undefined?'':String(v);a[0]._setInnerHTML(s);a[0][a[1]]=a[0].innerHTML;} else if(a[1]==='textContent'&&a[0] instanceof El){const s=v===null?'null':v===undefined?'':String(v);a[0].textContent=s;a[0].innerHTML=s;for(const c of a[0].children){c.parentElement=null;c.parentNode=null;}a[0].children=[];a[0].childNodes=[];} else{a[0][a[1]]=v;}} return a[2];});
@@ -623,7 +627,25 @@ K.registerNative('host-promise-state', a => {
if (!p || typeof p.then !== 'function') return null;
const s = _promiseStates.get(p);
if (!s) return null;
- return {ok: s.ok, value: s.value};
+ // Wrap Error objects as plain dicts — the WASM bridge serializes arbitrary
+ // JS objects to strings, so we extract message before crossing the boundary.
+ const val = s.value instanceof Error
+ ? {message: s.value.message}
+ : (s.value != null ? s.value : null);
+ return {ok: s.ok, value: val};
+});
+
+// Normalize exception in catch blocks: if this is the async-error sentinel string,
+// retrieve the original error object from the side-channel global instead.
+K.registerNative('host-hs-normalize-exc', a => {
+ const val = a[0];
+ const pending = globalThis.__hs_async_error;
+ if (pending !== undefined && pending !== null && val === '__hs_async_error__') {
+ globalThis.__hs_async_error = null;
+ return pending;
+ }
+ globalThis.__hs_async_error = null;
+ return val;
});
let _testDeadline = 0;
diff --git a/tests/playwright/generate-sx-tests.py b/tests/playwright/generate-sx-tests.py
index ea0a1617..718a9131 100644
--- a/tests/playwright/generate-sx-tests.py
+++ b/tests/playwright/generate-sx-tests.py
@@ -141,7 +141,7 @@ MANUAL_TEST_BODIES = {
],
"converts multiple selects with programmatically changed selections": [
' (let ((_node (dom-create-element "form")))',
- ' (dom-set-inner-html _node "")',
+ ' (dom-set-inner-html _node "")',
' (let ((_sel (dom-query _node "select")))',
' (let ((_opts (host-get _sel "options")))',
' (host-set! (nth _opts 0) "selected" false)',