diff --git a/lib/hyperscript/runtime.sx b/lib/hyperscript/runtime.sx index 93060e39..cd3edfe9 100644 --- a/lib/hyperscript/runtime.sx +++ b/lib/hyperscript/runtime.sx @@ -470,6 +470,7 @@ (some (fn (x) (= x value)) target) target (append target (list value)))) + ((hs-is-set? target) (do (host-call target "add" value) target)) (true (do (host-call target "push" value) target))))) ;; ── Object creation ───────────────────────────────────────────── @@ -480,10 +481,10 @@ hs-remove-from! (fn (value target) - (if - (list? target) - (filter (fn (x) (not (= x value))) target) - (host-call target "splice" (host-call target "indexOf" value) 1)))) + (cond + ((list? target) (filter (fn (x) (not (= x value))) target)) + ((hs-is-set? target) (do (host-call target "delete" value) target)) + (true (host-call target "splice" (host-call target "indexOf" value) 1))))) ;; ── Behavior installation ─────────────────────────────────────── @@ -965,6 +966,7 @@ (some (fn (x) (= x value)) target) target (append target (list value)))) + ((hs-is-set? target) (do (host-call target "add" value) target)) ((hs-element? target) (do (dom-insert-adjacent-html @@ -1260,22 +1262,24 @@ value) value)) ((= type-name "Set") - (if - (list? value) - (reduce - (fn - (acc x) - (if (some (fn (a) (= a x)) acc) acc (append acc (list x)))) - (list) - value) - value)) + (let + ((s (host-new "Set"))) + (do + (when + (list? value) + (for-each (fn (x) (host-call s "add" x)) value)) + s))) ((= type-name "Map") - (if - (dict? value) - (let - ((ks (if (dict-has? value "_order") (get value "_order") (filter (fn (k) (not (= k "_order"))) (keys value))))) - (map (fn (k) (list k (get value k))) ks)) - value)) + (let + ((m (host-new "Map"))) + (do + (when + (dict? value) + (for-each + (fn (k) (host-call m "set" k (get value k))) + (filter (fn (k) (not (= k "_order"))) (keys value)))) + m))) + ((= type-name "Date") (host-new "Date" value)) (true value)))) (define @@ -1471,8 +1475,8 @@ (cond ((= type-name "Object") (dict)) ((= type-name "Array") (list)) - ((= type-name "Set") (list)) - ((= type-name "Map") (dict)) + ((= type-name "Set") (host-new "Set")) + ((= type-name "Map") (host-new "Map")) (true (dict))) (apply host-new (cons type-name args))))))) (define @@ -1871,6 +1875,8 @@ (cond ((list? v) (list)) ((dict? v) (dict)) + ((hs-is-set? v) (host-new "Set")) + ((hs-is-map? v) (host-new "Map")) ((string? v) "") ((nil? v) nil) (true v)))) diff --git a/spec/tests/test-hyperscript-behavioral.sx b/spec/tests/test-hyperscript-behavioral.sx index 4d9319e4..59b067b7 100644 --- a/spec/tests/test-hyperscript-behavioral.sx +++ b/spec/tests/test-hyperscript-behavioral.sx @@ -3724,7 +3724,9 @@ (deftest "can accept custom dynamic conversions" (error "SKIP (untranslated): can accept custom dynamic conversions")) (deftest "can use the a modifier if you like" - (error "SKIP (untranslated): can use the a modifier if you like")) + (let ((_result (eval-hs "1 as a Date"))) + (assert= (host-call _result "getTime") 1)) + ) (deftest "can use the an modifier if you'd like" (assert= (host-get (eval-hs "'{\"foo\":\"bar\"}' as an Object") "foo") "bar") ) @@ -3828,7 +3830,10 @@ (assert= (eval-hs "[1,2,3] as Reversed") (list 3 2 1)) ) (deftest "converts array as Set" - (error "SKIP (untranslated): converts array as Set")) + (let ((_result (eval-hs "[1,2,2,3] as Set"))) + (assert (hs-is-set? _result)) + (assert= (host-get _result "size") 3)) + ) (deftest "converts array as Unique" (assert= (eval-hs "[1,2,2,3,3] as Unique") (list 1 2 3)) ) @@ -3881,7 +3886,11 @@ (assert= (eval-hs "{a:1, b:2} as Keys") (list "a" "b")) ) (deftest "converts object as Map" - (error "SKIP (untranslated): converts object as Map")) + (let ((_result (eval-hs "{a:1, b:2} as Map"))) + (assert (hs-is-map? _result)) + (assert= (host-call _result "get" "a") 1) + (assert= (host-get _result "size") 2)) + ) (deftest "converts radio buttons into a Value correctly" (let ((_node (dom-create-element "form"))) (dom-set-inner-html _node "
") @@ -3901,7 +3910,9 @@ (assert= (eval-hs "'hello' as Boolean") true) ) (deftest "converts value as Date" - (error "SKIP (untranslated): converts value as Date")) + (let ((_result (eval-hs "1 as Date"))) + (assert= (host-call _result "getTime") 1)) + ) (deftest "converts value as Fixed" (assert= (eval-hs "'10.4' as Fixed") "10") (assert= (eval-hs "'10.4899' as Fixed:2") "10.49") diff --git a/tests/hs-run-filtered.js b/tests/hs-run-filtered.js index ff2b6231..b4f3cef3 100755 --- a/tests/hs-run-filtered.js +++ b/tests/hs-run-filtered.js @@ -593,6 +593,8 @@ K.registerNative('host-iter?',([obj])=>obj!=null&&typeof obj[Symbol.iterator]=== K.registerNative('host-to-list',([obj])=>{try{return[...obj];}catch(e){return[];}}); K.registerNative('host-await',a=>{}); K.registerNative('load-library!',()=>false); +K.registerNative('hs-is-set?',a=>a[0] instanceof Set); +K.registerNative('hs-is-map?',a=>a[0] instanceof Map); // Upstream test fixtures: synchronous stubs matching OCaml run_tests.ml registrations globalThis.promiseAString = () => 'foo'; globalThis.promiseAnInt = () => 42; diff --git a/tests/playwright/generate-sx-tests.py b/tests/playwright/generate-sx-tests.py index fd3c86fb..e8c4596e 100644 --- a/tests/playwright/generate-sx-tests.py +++ b/tests/playwright/generate-sx-tests.py @@ -326,6 +326,26 @@ MANUAL_TEST_BODIES = { ' (list (list (quote record) record)))', ' "
John Connor
"))', ], + # asExpression: Date/Set/Map need real JS host objects + "converts value as Date": [ + ' (let ((_result (eval-hs "1 as Date")))', + ' (assert= (host-call _result "getTime") 1))', + ], + "can use the a modifier if you like": [ + ' (let ((_result (eval-hs "1 as a Date")))', + ' (assert= (host-call _result "getTime") 1))', + ], + "converts array as Set": [ + ' (let ((_result (eval-hs "[1,2,2,3] as Set")))', + ' (assert (hs-is-set? _result))', + ' (assert= (host-get _result "size") 3))', + ], + "converts object as Map": [ + ' (let ((_result (eval-hs "{a:1, b:2} as Map")))', + ' (assert (hs-is-map? _result))', + ' (assert= (host-call _result "get" "a") 1)', + ' (assert= (host-get _result "size") 2))', + ], }