From dda3becbab0c82ab762683166451153ca505f93c Mon Sep 17 00:00:00 2001 From: giles Date: Fri, 24 Apr 2026 06:54:02 +0000 Subject: [PATCH] HS: throw respond via exception event (+2 tests) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `hs-on` now wraps each event handler in a `guard` that catches thrown exceptions and re-dispatches them as an `exception` DOM event on the same target with `{error: e}` as detail. The `on exception(error)` handler, registered the same way, receives the event and destructures `error` from the detail. Wrapping skips `exception`/`error` event handlers to avoid infinite loops — those bubble out as before. Suite hs-upstream-throw: 5/7 → 7/7. Smoke 0-195: 162/195 unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) --- lib/hyperscript/runtime.sx | 10 ++++++---- shared/static/wasm/sx/hs-runtime.sx | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/hyperscript/runtime.sx b/lib/hyperscript/runtime.sx index 125a2e4b..86d3cb91 100644 --- a/lib/hyperscript/runtime.sx +++ b/lib/hyperscript/runtime.sx @@ -25,10 +25,12 @@ (fn (target event-name handler) (let - ((unlisten (dom-listen target event-name handler)) - (prev (or (dom-get-data target "hs-unlisteners") (list)))) - (dom-set-data target "hs-unlisteners" (append prev (list unlisten))) - unlisten))) + ((wrapped (fn (event) (guard (e ((and (not (= event-name "exception")) (not (= event-name "error"))) (dom-dispatch target "exception" {:error e})) (true (raise e))) (handler event))))) + (let + ((unlisten (dom-listen target event-name wrapped)) + (prev (or (dom-get-data target "hs-unlisteners") (list)))) + (dom-set-data target "hs-unlisteners" (append prev (list unlisten))) + unlisten)))) ;; Run an initializer function immediately. ;; (hs-init thunk) — called at element boot time diff --git a/shared/static/wasm/sx/hs-runtime.sx b/shared/static/wasm/sx/hs-runtime.sx index 125a2e4b..86d3cb91 100644 --- a/shared/static/wasm/sx/hs-runtime.sx +++ b/shared/static/wasm/sx/hs-runtime.sx @@ -25,10 +25,12 @@ (fn (target event-name handler) (let - ((unlisten (dom-listen target event-name handler)) - (prev (or (dom-get-data target "hs-unlisteners") (list)))) - (dom-set-data target "hs-unlisteners" (append prev (list unlisten))) - unlisten))) + ((wrapped (fn (event) (guard (e ((and (not (= event-name "exception")) (not (= event-name "error"))) (dom-dispatch target "exception" {:error e})) (true (raise e))) (handler event))))) + (let + ((unlisten (dom-listen target event-name wrapped)) + (prev (or (dom-get-data target "hs-unlisteners") (list)))) + (dom-set-data target "hs-unlisteners" (append prev (list unlisten))) + unlisten)))) ;; Run an initializer function immediately. ;; (hs-init thunk) — called at element boot time