HS: extend parser/runtime + new node test runner; ignore test-results/
- Parser: `--` line comments, `|` op, `result` → `the-result`, query-scoped `<sel> in <expr>`, `is a/an <type>` predicate, multi-`as` chaining with `|`, `match`/`precede` keyword aliases, `[attr]` add/toggle, between attr forms - Runtime: per-element listener registry + hs-deactivate!, attr toggle variants, set-inner-html boots subtree, hs-append polymorphic on string/list/element, default? / array-set! / query-all-in / list-set via take+drop, hs-script idempotence guard - Integration: skip reserved (me/it/event/you/yourself) when collecting vars - Tokenizer: emit `--` comments and `|` op - Test framework + conformance runner updates; new tests/hs-run-filtered.js (single-process Node runner using OCaml VM step-limit to bound infinite loops); generate-sx-conformance-dev.py improvements - mcp_tree.ml + run_tests.ml: harness extensions - .gitignore: top-level test-results/ (Playwright artifacts) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -22,7 +22,13 @@
|
||||
;; Stock hyperscript queues by default; "every" disables queuing.
|
||||
(define
|
||||
hs-on
|
||||
(fn (target event-name handler) (dom-listen target event-name handler)))
|
||||
(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)))
|
||||
|
||||
;; Run an initializer function immediately.
|
||||
;; (hs-init thunk) — called at element boot time
|
||||
@@ -88,7 +94,7 @@
|
||||
((or (= prop "display") (= prop "opacity"))
|
||||
(if
|
||||
(or (= cur "none") (= cur "0"))
|
||||
(dom-set-style target prop (if (= prop "opacity") "1" ""))
|
||||
(dom-set-style target prop (if (= prop "opacity") "1" "block"))
|
||||
(dom-set-style target prop (if (= prop "display") "none" "0"))))
|
||||
(true
|
||||
(if
|
||||
@@ -167,6 +173,45 @@
|
||||
(fn
|
||||
(el name val)
|
||||
(if (nil? val) (dom-remove-attr el name) (dom-set-attr el name val))))
|
||||
(define
|
||||
hs-toggle-attr!
|
||||
(fn
|
||||
(el name)
|
||||
(if
|
||||
(dom-has-attr? el name)
|
||||
(dom-remove-attr el name)
|
||||
(dom-set-attr el name ""))))
|
||||
(define
|
||||
hs-toggle-attr-val!
|
||||
(fn
|
||||
(el name val)
|
||||
(if
|
||||
(= (dom-get-attr el name) val)
|
||||
(dom-remove-attr el name)
|
||||
(dom-set-attr el name val))))
|
||||
(define
|
||||
hs-toggle-attr-between!
|
||||
(fn
|
||||
(el name val1 val2)
|
||||
(if
|
||||
(= (dom-get-attr el name) val1)
|
||||
(dom-set-attr el name val2)
|
||||
(dom-set-attr el name val1))))
|
||||
(define
|
||||
hs-toggle-attr-diff!
|
||||
(fn
|
||||
(el n1 v1 n2 v2)
|
||||
(if
|
||||
(dom-has-attr? el n1)
|
||||
(do (dom-remove-attr el n1) (dom-set-attr el n2 v2))
|
||||
(do
|
||||
(when (dom-has-attr? el n2) (dom-remove-attr el n2))
|
||||
(dom-set-attr el n1 v1)))))
|
||||
(define
|
||||
hs-set-inner-html!
|
||||
(fn
|
||||
(target value)
|
||||
(do (dom-set-inner-html target value) (hs-boot-subtree! target))))
|
||||
(define
|
||||
hs-put!
|
||||
(fn
|
||||
@@ -407,19 +452,24 @@
|
||||
hs-query-all
|
||||
(fn (sel) (host-call (dom-body) "querySelectorAll" sel)))
|
||||
|
||||
(define
|
||||
hs-query-all-in
|
||||
(fn
|
||||
(sel target)
|
||||
(if
|
||||
(nil? target)
|
||||
(hs-query-all sel)
|
||||
(host-call target "querySelectorAll" sel))))
|
||||
|
||||
(define
|
||||
hs-list-set
|
||||
(fn (lst idx val) (map-indexed (fn (i x) (if (= i idx) val x)) lst)))
|
||||
(fn
|
||||
(lst idx val)
|
||||
(append (take lst idx) (cons val (drop lst (+ idx 1))))))
|
||||
|
||||
(define
|
||||
hs-to-number
|
||||
(fn
|
||||
(v)
|
||||
(cond
|
||||
((number? v) v)
|
||||
((string? v) (or (parse-number v) 0))
|
||||
((nil? v) 0)
|
||||
(true (or (parse-number (str v)) 0)))))
|
||||
(fn (v) (if (number? v) v (or (parse-number (str v)) 0))))
|
||||
|
||||
(define
|
||||
hs-query-first
|
||||
@@ -490,6 +540,10 @@
|
||||
((= signal "hs-continue") (hs-repeat-while cond-fn thunk))
|
||||
(true (hs-repeat-while cond-fn thunk)))))))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(define
|
||||
hs-repeat-until
|
||||
(fn
|
||||
@@ -502,10 +556,6 @@
|
||||
(if (cond-fn) nil (hs-repeat-until cond-fn thunk)))
|
||||
(true (if (cond-fn) nil (hs-repeat-until cond-fn thunk)))))))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(define
|
||||
hs-for-each
|
||||
(fn
|
||||
@@ -525,27 +575,38 @@
|
||||
((= signal "hs-continue") (do-loop (rest remaining)))
|
||||
(true (do-loop (rest remaining))))))))
|
||||
(do-loop items))))
|
||||
|
||||
;; ── Sandbox/test runtime additions ──────────────────────────────
|
||||
;; Property access — dot notation and .length
|
||||
(begin
|
||||
(define
|
||||
hs-append
|
||||
(fn
|
||||
(target value)
|
||||
(cond
|
||||
((nil? target) value)
|
||||
((string? target) (str target value))
|
||||
((list? target) (append target (list value)))
|
||||
((hs-element? target)
|
||||
(do
|
||||
(dom-insert-adjacent-html target "beforeend" (str value))
|
||||
target))
|
||||
(true (str target value)))))
|
||||
(define
|
||||
hs-append!
|
||||
(fn (value target) (dom-insert-adjacent-html target "beforeend" value))))
|
||||
;; ── Sandbox/test runtime additions ──────────────────────────────
|
||||
;; Property access — dot notation and .length
|
||||
(fn
|
||||
(value target)
|
||||
(cond
|
||||
((nil? target) nil)
|
||||
((hs-element? target)
|
||||
(dom-insert-adjacent-html target "beforeend" (str value)))
|
||||
(true nil)))))
|
||||
;; DOM query stub — sandbox returns empty list
|
||||
(define
|
||||
hs-fetch
|
||||
(fn
|
||||
(url format)
|
||||
(perform (list "io-fetch" url (if format format "text")))))
|
||||
;; DOM query stub — sandbox returns empty list
|
||||
;; Method dispatch — obj.method(args)
|
||||
(define
|
||||
hs-coerce
|
||||
(fn
|
||||
@@ -636,7 +697,24 @@
|
||||
(map (fn (k) (list k (get value k))) (keys value))
|
||||
value))
|
||||
(true value))))
|
||||
;; Method dispatch — obj.method(args)
|
||||
|
||||
;; ── 0.9.90 features ─────────────────────────────────────────────
|
||||
;; beep! — debug logging, returns value unchanged
|
||||
(define
|
||||
hs-default?
|
||||
(fn
|
||||
(v)
|
||||
(cond
|
||||
((nil? v) true)
|
||||
((and (string? v) (= v "")) true)
|
||||
(true false))))
|
||||
;; Property-based is — check obj.key truthiness
|
||||
(define
|
||||
hs-array-set!
|
||||
(fn
|
||||
(arr i v)
|
||||
(if (list? arr) (do (set-nth! arr i v) v) (host-set! arr i v))))
|
||||
;; Array slicing (inclusive both ends)
|
||||
(define
|
||||
hs-add
|
||||
(fn
|
||||
@@ -646,9 +724,7 @@
|
||||
((list? b) (cons a b))
|
||||
((or (string? a) (string? b)) (str a b))
|
||||
(true (+ a b)))))
|
||||
|
||||
;; ── 0.9.90 features ─────────────────────────────────────────────
|
||||
;; beep! — debug logging, returns value unchanged
|
||||
;; Collection: sorted by
|
||||
(define
|
||||
hs-make
|
||||
(fn
|
||||
@@ -659,13 +735,13 @@
|
||||
((= type-name "Set") (list))
|
||||
((= type-name "Map") (dict))
|
||||
(true (dict)))))
|
||||
;; Property-based is — check obj.key truthiness
|
||||
;; Collection: sorted by descending
|
||||
(define hs-install (fn (behavior-fn) (behavior-fn me)))
|
||||
;; Array slicing (inclusive both ends)
|
||||
;; Collection: split by
|
||||
(define
|
||||
hs-measure
|
||||
(fn (target) (perform (list (quote io-measure) target))))
|
||||
;; Collection: sorted by
|
||||
;; Collection: joined by
|
||||
(define
|
||||
hs-transition
|
||||
(fn
|
||||
@@ -678,7 +754,7 @@
|
||||
(str prop " " (/ duration 1000) "s")))
|
||||
(dom-set-style target prop value)
|
||||
(when duration (hs-settle target))))
|
||||
;; Collection: sorted by descending
|
||||
|
||||
(define
|
||||
hs-transition-from
|
||||
(fn
|
||||
@@ -692,7 +768,7 @@
|
||||
(str prop " " (/ duration 1000) "s")))
|
||||
(dom-set-style target prop (str to-val))
|
||||
(when duration (hs-settle target))))
|
||||
;; Collection: split by
|
||||
|
||||
(define
|
||||
hs-type-check
|
||||
(fn
|
||||
@@ -712,7 +788,7 @@
|
||||
(= (host-typeof value) "element")
|
||||
(= (host-typeof value) "text")))
|
||||
(true (= (host-typeof value) (downcase type-name)))))))
|
||||
;; Collection: joined by
|
||||
|
||||
(define
|
||||
hs-type-check-strict
|
||||
(fn
|
||||
@@ -745,11 +821,26 @@
|
||||
((nil? suffix) false)
|
||||
(true (ends-with? (str s) (str suffix))))))
|
||||
|
||||
(define
|
||||
hs-scoped-set!
|
||||
(fn (el name val) (dom-set-data el (str "hs-local-" name) val)))
|
||||
|
||||
(define
|
||||
hs-scoped-get
|
||||
(fn (el name) (dom-get-data el (str "hs-local-" name))))
|
||||
|
||||
(define
|
||||
hs-precedes?
|
||||
(fn
|
||||
(a b)
|
||||
(cond ((nil? a) false) ((nil? b) false) (true (< (str a) (str b))))))
|
||||
(cond
|
||||
((nil? a) false)
|
||||
((nil? b) false)
|
||||
((and (dict? a) (dict? b))
|
||||
(let
|
||||
((pos (host-call a "compareDocumentPosition" b)))
|
||||
(if (number? pos) (not (= 0 (mod (/ pos 4) 2))) false)))
|
||||
(true (< (str a) (str b))))))
|
||||
|
||||
(define
|
||||
hs-follows?
|
||||
@@ -840,7 +931,18 @@
|
||||
(= obj (nth r 1))
|
||||
(= obj nil)))))))
|
||||
|
||||
(define precedes? (fn (a b) (< (str a) (str b))))
|
||||
(define
|
||||
precedes?
|
||||
(fn
|
||||
(a b)
|
||||
(cond
|
||||
((nil? a) false)
|
||||
((nil? b) false)
|
||||
((and (dict? a) (dict? b))
|
||||
(let
|
||||
((pos (host-call a "compareDocumentPosition" b)))
|
||||
(if (number? pos) (not (= 0 (mod (/ pos 4) 2))) false)))
|
||||
(true (< (str a) (str b))))))
|
||||
|
||||
(define
|
||||
hs-empty?
|
||||
@@ -1124,33 +1226,109 @@
|
||||
(host-call el "removeAttribute" "open")
|
||||
(dom-set-prop el "open" false)))))))
|
||||
|
||||
(define
|
||||
hs-hide!
|
||||
(fn
|
||||
(el strategy)
|
||||
(let
|
||||
((tag (dom-get-prop el "tagName")))
|
||||
(cond
|
||||
((= tag "DIALOG")
|
||||
(when (dom-has-attr? el "open") (host-call el "close")))
|
||||
((= tag "DETAILS") (dom-set-prop el "open" false))
|
||||
((= strategy "opacity") (dom-set-style el "opacity" "0"))
|
||||
((= strategy "visibility") (dom-set-style el "visibility" "hidden"))
|
||||
(true (dom-set-style el "display" "none"))))))
|
||||
(begin
|
||||
(define
|
||||
hs-hide-one!
|
||||
(fn
|
||||
(el strategy)
|
||||
(let
|
||||
((parts (split strategy ":")) (tag (dom-get-prop el "tagName")))
|
||||
(let
|
||||
((prop (first parts))
|
||||
(val (if (> (len parts) 1) (nth parts 1) nil)))
|
||||
(cond
|
||||
((= tag "DIALOG")
|
||||
(when (dom-has-attr? el "open") (host-call el "close")))
|
||||
((= tag "DETAILS") (dom-set-prop el "open" false))
|
||||
((= prop "opacity")
|
||||
(dom-set-style el "opacity" (if val val "0")))
|
||||
((= prop "visibility")
|
||||
(dom-set-style el "visibility" (if val val "hidden")))
|
||||
((= prop "hidden") (dom-set-attr el "hidden" ""))
|
||||
((= prop "twDisplay") (dom-add-class el "hidden"))
|
||||
((= prop "twVisibility") (dom-add-class el "invisible"))
|
||||
((= prop "twOpacity") (dom-add-class el "opacity-0"))
|
||||
(true (dom-set-style el "display" (if val val "none"))))))))
|
||||
(define
|
||||
hs-hide!
|
||||
(fn
|
||||
(target strategy)
|
||||
(if
|
||||
(list? target)
|
||||
(do (for-each (fn (el) (hs-hide-one! el strategy)) target) target)
|
||||
(do (hs-hide-one! target strategy) target)))))
|
||||
|
||||
(begin
|
||||
(define
|
||||
hs-show-one!
|
||||
(fn
|
||||
(el strategy)
|
||||
(let
|
||||
((parts (split strategy ":")) (tag (dom-get-prop el "tagName")))
|
||||
(let
|
||||
((prop (first parts))
|
||||
(val (if (> (len parts) 1) (nth parts 1) nil)))
|
||||
(cond
|
||||
((= tag "DIALOG")
|
||||
(when
|
||||
(not (dom-has-attr? el "open"))
|
||||
(host-call el "showModal")))
|
||||
((= tag "DETAILS") (dom-set-prop el "open" true))
|
||||
((= prop "opacity")
|
||||
(dom-set-style el "opacity" (if val val "1")))
|
||||
((= prop "visibility")
|
||||
(dom-set-style el "visibility" (if val val "visible")))
|
||||
((= prop "hidden") (dom-remove-attr el "hidden"))
|
||||
((= prop "twDisplay") (dom-remove-class el "hidden"))
|
||||
((= prop "twVisibility") (dom-remove-class el "invisible"))
|
||||
((= prop "twOpacity") (dom-remove-class el "opacity-0"))
|
||||
(true (dom-set-style el "display" (if val val "block"))))))))
|
||||
(define
|
||||
hs-show!
|
||||
(fn
|
||||
(target strategy)
|
||||
(if
|
||||
(list? target)
|
||||
(do (for-each (fn (el) (hs-show-one! el strategy)) target) target)
|
||||
(do (hs-show-one! target strategy) target)))))
|
||||
|
||||
(define
|
||||
hs-show!
|
||||
hs-show-when!
|
||||
(fn
|
||||
(el strategy)
|
||||
(target strategy pred)
|
||||
(let
|
||||
((tag (dom-get-prop el "tagName")))
|
||||
(cond
|
||||
((= tag "DIALOG")
|
||||
(when (not (dom-has-attr? el "open")) (host-call el "showModal")))
|
||||
((= tag "DETAILS") (dom-set-prop el "open" true))
|
||||
((= strategy "opacity") (dom-set-style el "opacity" "1"))
|
||||
((= strategy "visibility") (dom-set-style el "visibility" "visible"))
|
||||
(true (dom-set-style el "display" ""))))))
|
||||
((items (if (list? target) target (list target))))
|
||||
(let
|
||||
((matched (list)))
|
||||
(do
|
||||
(for-each
|
||||
(fn
|
||||
(el)
|
||||
(if
|
||||
(pred el)
|
||||
(do (hs-show-one! el strategy) (append! matched el))
|
||||
(hs-hide-one! el strategy)))
|
||||
items)
|
||||
matched)))))
|
||||
|
||||
(define
|
||||
hs-hide-when!
|
||||
(fn
|
||||
(target strategy pred)
|
||||
(let
|
||||
((items (if (list? target) target (list target))))
|
||||
(let
|
||||
((matched (list)))
|
||||
(do
|
||||
(for-each
|
||||
(fn
|
||||
(el)
|
||||
(if
|
||||
(pred el)
|
||||
(do (hs-hide-one! el strategy) (append! matched el))
|
||||
(hs-show-one! el strategy)))
|
||||
items)
|
||||
matched)))))
|
||||
|
||||
(define hs-first (fn (lst) (first lst)))
|
||||
|
||||
@@ -1390,7 +1568,7 @@
|
||||
false
|
||||
(let
|
||||
((store (host-get el "__hs_vars")))
|
||||
(if (nil? store) false (has-key? store name))))))
|
||||
(if (nil? store) false (host-call store "hasOwnProperty" name))))))
|
||||
|
||||
(define
|
||||
hs-dom-get-var-raw
|
||||
@@ -1409,7 +1587,7 @@
|
||||
(do
|
||||
(when
|
||||
(nil? (host-get el "__hs_vars"))
|
||||
(host-set! el "__hs_vars" (dict)))
|
||||
(host-set! el "__hs_vars" (host-new "Object")))
|
||||
(host-set! (host-get el "__hs_vars") name val)
|
||||
(when changed (hs-dom-fire-watchers! el name val))))))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user