HS behavioral tests: 478→509/831 (57%→61%), parser/compiler/runtime fixes
Parser: am-a/am-not-a type checks, transition element/selector targeting, take @attr=value with replacement, toggle my/the possessive, <selector/> syntax in parse-atom, the-of for style/attr/class/selector, when-clause filtering for add, starts/ends-with ignoring case. Compiler: take attr passthrough, toggle-style nil→me default, scoped querySelectorAll for add/remove/toggle-class, has-class? entry, matches? extracts selector from (query sel), add-class-when with for-each filter, starts/ends-with-ic entries, hs-add replaces + for polymorphic add. Runtime: hs-take! proper attr values, hs-type-check Element/Node via host-typeof, hs-toggle-style! opacity 0↔1, hs-coerce +8 coercions (Keys/Values/Entries/Reversed/Unique/Flat/JSON/Object), hs-query-all bypasses broken dom-query-all (WASM auto-converts arrays), hs-matches? handles DOM el.matches(selector), hs-add list+string+number polymorphic, hs-starts/ends-with-ic for case-insensitive comparison. DOM mock: mkStyle() with setProperty/getPropertyValue, fndAll.item(). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -56,32 +56,39 @@
|
|||||||
(hs-to-sx (nth target 2))
|
(hs-to-sx (nth target 2))
|
||||||
value))
|
value))
|
||||||
((= th (quote of))
|
((= th (quote of))
|
||||||
;; Decompose (of prop-expr target) into a set operation
|
(let
|
||||||
;; e.g. (of (. (ref "parentNode") "innerHTML") (query "#d1"))
|
((prop-ast (nth target 1)) (obj-ast (nth target 2)))
|
||||||
;; → set parentNode.innerHTML of #d1 → need to navigate target, then set final prop
|
(if
|
||||||
(let ((prop-ast (nth target 1))
|
(and (list? prop-ast) (= (first prop-ast) dot-sym))
|
||||||
(obj-ast (nth target 2)))
|
(let
|
||||||
(if (and (list? prop-ast) (= (first prop-ast) dot-sym))
|
((base (nth prop-ast 1))
|
||||||
;; (. base "prop") of obj → (dom-set-prop (host-get (compiled-obj) (compiled-base-name)) "prop" value)
|
(prop-name (nth prop-ast 2)))
|
||||||
(let ((base (nth prop-ast 1))
|
(list
|
||||||
(prop-name (nth prop-ast 2)))
|
(quote dom-set-prop)
|
||||||
(list (quote dom-set-prop)
|
(list
|
||||||
(list (quote host-get) (hs-to-sx obj-ast) (nth base 1))
|
(quote host-get)
|
||||||
|
(hs-to-sx obj-ast)
|
||||||
|
(nth base 1))
|
||||||
prop-name
|
prop-name
|
||||||
value))
|
value))
|
||||||
;; (attr "name") of obj → (dom-set-attr (compiled-obj) "name" value)
|
(if
|
||||||
(if (and (list? prop-ast) (= (first prop-ast) (quote attr)))
|
(and
|
||||||
(list (quote dom-set-attr)
|
(list? prop-ast)
|
||||||
|
(= (first prop-ast) (quote attr)))
|
||||||
|
(list
|
||||||
|
(quote dom-set-attr)
|
||||||
(hs-to-sx obj-ast)
|
(hs-to-sx obj-ast)
|
||||||
(nth prop-ast 1)
|
(nth prop-ast 1)
|
||||||
value)
|
value)
|
||||||
;; Simple: (ref "prop") of obj → (dom-set-prop (compiled-obj) "prop" value)
|
(if
|
||||||
(if (and (list? prop-ast) (= (first prop-ast) (quote ref)))
|
(and
|
||||||
(list (quote dom-set-prop)
|
(list? prop-ast)
|
||||||
|
(= (first prop-ast) (quote ref)))
|
||||||
|
(list
|
||||||
|
(quote dom-set-prop)
|
||||||
(hs-to-sx obj-ast)
|
(hs-to-sx obj-ast)
|
||||||
(nth prop-ast 1)
|
(nth prop-ast 1)
|
||||||
value)
|
value)
|
||||||
;; Fallback
|
|
||||||
(list (quote set!) (hs-to-sx target) value))))))
|
(list (quote set!) (hs-to-sx target) value))))))
|
||||||
(true (list (quote set!) (hs-to-sx target) value)))))))
|
(true (list (quote set!) (hs-to-sx target) value)))))))
|
||||||
(define
|
(define
|
||||||
@@ -427,7 +434,7 @@
|
|||||||
((= head (quote null-literal)) nil)
|
((= head (quote null-literal)) nil)
|
||||||
((= head (quote not))
|
((= head (quote not))
|
||||||
(list (quote not) (hs-to-sx (nth ast 1))))
|
(list (quote not) (hs-to-sx (nth ast 1))))
|
||||||
((or (= head (quote starts-with?)) (= head (quote ends-with?)) (= head (quote contains?)) (= head (quote matches?)) (= head (quote precedes?)) (= head (quote follows?)) (= head (quote exists?)))
|
((or (= head (quote starts-with?)) (= head (quote ends-with?)) (= head (quote contains?)) (= head (quote precedes?)) (= head (quote follows?)) (= head (quote exists?)))
|
||||||
(cons head (map hs-to-sx (rest ast))))
|
(cons head (map hs-to-sx (rest ast))))
|
||||||
((= head (quote object-literal))
|
((= head (quote object-literal))
|
||||||
(let
|
(let
|
||||||
@@ -656,6 +663,11 @@
|
|||||||
(quote dom-get-style)
|
(quote dom-get-style)
|
||||||
(hs-to-sx (nth ast 2))
|
(hs-to-sx (nth ast 2))
|
||||||
(nth ast 1)))
|
(nth ast 1)))
|
||||||
|
((= head (quote has-class?))
|
||||||
|
(list
|
||||||
|
(quote dom-has-class?)
|
||||||
|
(hs-to-sx (nth ast 1))
|
||||||
|
(nth ast 2)))
|
||||||
((= head (quote local)) (make-symbol (nth ast 1)))
|
((= head (quote local)) (make-symbol (nth ast 1)))
|
||||||
((= head (quote array))
|
((= head (quote array))
|
||||||
(cons (quote list) (map hs-to-sx (rest ast))))
|
(cons (quote list) (map hs-to-sx (rest ast))))
|
||||||
@@ -713,15 +725,30 @@
|
|||||||
(quote not)
|
(quote not)
|
||||||
(list (quote nil?) (hs-to-sx (nth ast 1)))))
|
(list (quote nil?) (hs-to-sx (nth ast 1)))))
|
||||||
((= head (quote matches?))
|
((= head (quote matches?))
|
||||||
(list
|
(let
|
||||||
(quote hs-matches?)
|
((left (nth ast 1)) (right (nth ast 2)))
|
||||||
(hs-to-sx (nth ast 1))
|
(if
|
||||||
(hs-to-sx (nth ast 2))))
|
(and (list? right) (= (first right) (quote query)))
|
||||||
|
(list (quote hs-matches?) (hs-to-sx left) (nth right 1))
|
||||||
|
(list
|
||||||
|
(quote hs-matches?)
|
||||||
|
(hs-to-sx left)
|
||||||
|
(hs-to-sx right)))))
|
||||||
((= head (quote matches-ignore-case?))
|
((= head (quote matches-ignore-case?))
|
||||||
(list
|
(list
|
||||||
(quote hs-matches-ignore-case?)
|
(quote hs-matches-ignore-case?)
|
||||||
(hs-to-sx (nth ast 1))
|
(hs-to-sx (nth ast 1))
|
||||||
(hs-to-sx (nth ast 2))))
|
(hs-to-sx (nth ast 2))))
|
||||||
|
((= head (quote starts-with-ic?))
|
||||||
|
(list
|
||||||
|
(quote hs-starts-with-ic?)
|
||||||
|
(hs-to-sx (nth ast 1))
|
||||||
|
(hs-to-sx (nth ast 2))))
|
||||||
|
((= head (quote ends-with-ic?))
|
||||||
|
(list
|
||||||
|
(quote hs-ends-with-ic?)
|
||||||
|
(hs-to-sx (nth ast 1))
|
||||||
|
(hs-to-sx (nth ast 2))))
|
||||||
((= head (quote contains?))
|
((= head (quote contains?))
|
||||||
(list
|
(list
|
||||||
(quote hs-contains?)
|
(quote hs-contains?)
|
||||||
@@ -824,6 +851,23 @@
|
|||||||
(map
|
(map
|
||||||
(fn (cls) (list (quote dom-add-class) target cls))
|
(fn (cls) (list (quote dom-add-class) target cls))
|
||||||
classes))))
|
classes))))
|
||||||
|
((= head (quote add-class-when))
|
||||||
|
(let
|
||||||
|
((cls (nth ast 1))
|
||||||
|
(raw-tgt (nth ast 2))
|
||||||
|
(when-cond (nth ast 3)))
|
||||||
|
(let
|
||||||
|
((tgt-expr (cond ((and (list? raw-tgt) (= (first raw-tgt) (quote query))) (list (quote hs-query-all) (nth raw-tgt 1))) ((and (list? raw-tgt) (= (first raw-tgt) (quote in?)) (list? (nth raw-tgt 1)) (= (first (nth raw-tgt 1)) (quote query))) (list (quote host-call) (hs-to-sx (nth raw-tgt 2)) "querySelectorAll" (nth (nth raw-tgt 1) 1))) (true (hs-to-sx raw-tgt)))))
|
||||||
|
(list
|
||||||
|
(quote for-each)
|
||||||
|
(list
|
||||||
|
(quote fn)
|
||||||
|
(list (quote it))
|
||||||
|
(list
|
||||||
|
(quote when)
|
||||||
|
(hs-to-sx when-cond)
|
||||||
|
(list (quote dom-add-class) (quote it) cls)))
|
||||||
|
tgt-expr))))
|
||||||
((= head (quote multi-remove-class))
|
((= head (quote multi-remove-class))
|
||||||
(let
|
(let
|
||||||
((target (hs-to-sx (nth ast 1)))
|
((target (hs-to-sx (nth ast 1)))
|
||||||
@@ -895,10 +939,12 @@
|
|||||||
(nth ast 1)
|
(nth ast 1)
|
||||||
(nth ast 2)))
|
(nth ast 2)))
|
||||||
((= head (quote toggle-style))
|
((= head (quote toggle-style))
|
||||||
(list
|
(let
|
||||||
(quote hs-toggle-style!)
|
((raw-tgt (nth ast 2)))
|
||||||
(hs-to-sx (nth ast 2))
|
(list
|
||||||
(nth ast 1)))
|
(quote hs-toggle-style!)
|
||||||
|
(if (nil? raw-tgt) (quote me) (hs-to-sx raw-tgt))
|
||||||
|
(nth ast 1))))
|
||||||
((= head (quote toggle-style-between))
|
((= head (quote toggle-style-between))
|
||||||
(list
|
(list
|
||||||
(quote hs-toggle-style-between!)
|
(quote hs-toggle-style-between!)
|
||||||
|
|||||||
@@ -513,12 +513,26 @@
|
|||||||
(do
|
(do
|
||||||
(adv!)
|
(adv!)
|
||||||
(match-kw "with")
|
(match-kw "with")
|
||||||
(list (quote starts-with?) left (parse-expr))))
|
(let
|
||||||
|
((rhs (parse-atom)))
|
||||||
|
(if
|
||||||
|
(match-kw "ignoring")
|
||||||
|
(do
|
||||||
|
(match-kw "case")
|
||||||
|
(list (quote starts-with-ic?) left rhs))
|
||||||
|
(list (quote starts-with?) left rhs)))))
|
||||||
((and (or (= typ "keyword") (= typ "ident")) (= val "ends"))
|
((and (or (= typ "keyword") (= typ "ident")) (= val "ends"))
|
||||||
(do
|
(do
|
||||||
(adv!)
|
(adv!)
|
||||||
(match-kw "with")
|
(match-kw "with")
|
||||||
(list (quote ends-with?) left (parse-expr))))
|
(let
|
||||||
|
((rhs (parse-atom)))
|
||||||
|
(if
|
||||||
|
(match-kw "ignoring")
|
||||||
|
(do
|
||||||
|
(match-kw "case")
|
||||||
|
(list (quote ends-with-ic?) left rhs))
|
||||||
|
(list (quote ends-with?) left rhs)))))
|
||||||
((and (= typ "keyword") (= val "matches"))
|
((and (= typ "keyword") (= val "matches"))
|
||||||
(do
|
(do
|
||||||
(adv!)
|
(adv!)
|
||||||
@@ -607,11 +621,17 @@
|
|||||||
(quote not)
|
(quote not)
|
||||||
(list (quote contains?) left (parse-expr))))
|
(list (quote contains?) left (parse-expr))))
|
||||||
((match-kw "start")
|
((match-kw "start")
|
||||||
(do (match-kw "with")
|
(do
|
||||||
(list (quote not) (list (quote starts-with?) left (parse-expr)))))
|
(match-kw "with")
|
||||||
|
(list
|
||||||
|
(quote not)
|
||||||
|
(list (quote starts-with?) left (parse-expr)))))
|
||||||
((match-kw "end")
|
((match-kw "end")
|
||||||
(do (match-kw "with")
|
(do
|
||||||
(list (quote not) (list (quote ends-with?) left (parse-expr)))))
|
(match-kw "with")
|
||||||
|
(list
|
||||||
|
(quote not)
|
||||||
|
(list (quote ends-with?) left (parse-expr)))))
|
||||||
(true left))))
|
(true left))))
|
||||||
((and (= typ "keyword") (= val "equals"))
|
((and (= typ "keyword") (= val "equals"))
|
||||||
(do (adv!) (list (quote =) left (parse-expr))))
|
(do (adv!) (list (quote =) left (parse-expr))))
|
||||||
@@ -693,12 +713,20 @@
|
|||||||
nil
|
nil
|
||||||
(do
|
(do
|
||||||
(when
|
(when
|
||||||
(and (number? left) (= (tp-type) "ident")
|
(and
|
||||||
(not (or (= (tp-val) "starts") (= (tp-val) "ends")
|
(number? left)
|
||||||
(= (tp-val) "contains") (= (tp-val) "matches")
|
(= (tp-type) "ident")
|
||||||
(= (tp-val) "is") (= (tp-val) "does")
|
(not
|
||||||
(= (tp-val) "in") (= (tp-val) "precedes")
|
(or
|
||||||
(= (tp-val) "follows"))))
|
(= (tp-val) "starts")
|
||||||
|
(= (tp-val) "ends")
|
||||||
|
(= (tp-val) "contains")
|
||||||
|
(= (tp-val) "matches")
|
||||||
|
(= (tp-val) "is")
|
||||||
|
(= (tp-val) "does")
|
||||||
|
(= (tp-val) "in")
|
||||||
|
(= (tp-val) "precedes")
|
||||||
|
(= (tp-val) "follows"))))
|
||||||
(let
|
(let
|
||||||
((unit (tp-val)))
|
((unit (tp-val)))
|
||||||
(do
|
(do
|
||||||
@@ -757,12 +785,25 @@
|
|||||||
(collect-classes!)
|
(collect-classes!)
|
||||||
(let
|
(let
|
||||||
((tgt (parse-tgt-kw "to" (list (quote me)))))
|
((tgt (parse-tgt-kw "to" (list (quote me)))))
|
||||||
(if
|
(let
|
||||||
(empty? extra-classes)
|
((when-clause (if (match-kw "when") (parse-expr) nil)))
|
||||||
(list (quote add-class) cls tgt)
|
(if
|
||||||
(cons
|
(empty? extra-classes)
|
||||||
(quote multi-add-class)
|
(if
|
||||||
(cons tgt (cons cls extra-classes))))))
|
when-clause
|
||||||
|
(list (quote add-class-when) cls tgt when-clause)
|
||||||
|
(list (quote add-class) cls tgt))
|
||||||
|
(if
|
||||||
|
when-clause
|
||||||
|
(list
|
||||||
|
(quote multi-add-class-when)
|
||||||
|
tgt
|
||||||
|
when-clause
|
||||||
|
cls
|
||||||
|
extra-classes)
|
||||||
|
(cons
|
||||||
|
(quote multi-add-class)
|
||||||
|
(cons tgt (cons cls extra-classes))))))))
|
||||||
nil)))
|
nil)))
|
||||||
(define
|
(define
|
||||||
parse-remove-cmd
|
parse-remove-cmd
|
||||||
@@ -893,6 +934,70 @@
|
|||||||
(let
|
(let
|
||||||
((tgt (parse-tgt-kw "on" (list (quote me)))))
|
((tgt (parse-tgt-kw "on" (list (quote me)))))
|
||||||
(list (quote toggle-attr) attr-name tgt)))))
|
(list (quote toggle-attr) attr-name tgt)))))
|
||||||
|
((and (= (tp-type) "keyword") (= (tp-val) "my"))
|
||||||
|
(do
|
||||||
|
(adv!)
|
||||||
|
(cond
|
||||||
|
((= (tp-type) "style")
|
||||||
|
(let
|
||||||
|
((prop (get (adv!) "value")))
|
||||||
|
(if
|
||||||
|
(match-kw "between")
|
||||||
|
(let
|
||||||
|
((val1 (parse-expr)))
|
||||||
|
(expect-kw! "and")
|
||||||
|
(let
|
||||||
|
((val2 (parse-expr)))
|
||||||
|
(let
|
||||||
|
((tgt (if (match-kw "on") (parse-expr) nil)))
|
||||||
|
(list
|
||||||
|
(quote toggle-style-between)
|
||||||
|
prop
|
||||||
|
val1
|
||||||
|
val2
|
||||||
|
tgt))))
|
||||||
|
(let
|
||||||
|
((tgt (if (match-kw "on") (parse-expr) nil)))
|
||||||
|
(list (quote toggle-style) prop tgt)))))
|
||||||
|
((= (tp-type) "attr")
|
||||||
|
(let
|
||||||
|
((attr-name (get (adv!) "value")))
|
||||||
|
(let
|
||||||
|
((tgt (if (match-kw "on") (parse-expr) nil)))
|
||||||
|
(list (quote toggle-attr) attr-name tgt))))
|
||||||
|
(true nil))))
|
||||||
|
((and (= (tp-type) "keyword") (= (tp-val) "the"))
|
||||||
|
(do
|
||||||
|
(adv!)
|
||||||
|
(let
|
||||||
|
((expr (parse-the-expr)))
|
||||||
|
(cond
|
||||||
|
((and (list? expr) (= (first expr) (quote style)))
|
||||||
|
(let
|
||||||
|
((prop (nth expr 1)) (tgt (nth expr 2)))
|
||||||
|
(if
|
||||||
|
(match-kw "between")
|
||||||
|
(let
|
||||||
|
((val1 (parse-expr)))
|
||||||
|
(expect-kw! "and")
|
||||||
|
(let
|
||||||
|
((val2 (parse-expr)))
|
||||||
|
(list
|
||||||
|
(quote toggle-style-between)
|
||||||
|
prop
|
||||||
|
val1
|
||||||
|
val2
|
||||||
|
tgt)))
|
||||||
|
(list (quote toggle-style) prop tgt))))
|
||||||
|
((and (list? expr) (= (first expr) (quote attr)))
|
||||||
|
(let
|
||||||
|
((attr-name (nth expr 1)) (tgt (nth expr 2)))
|
||||||
|
(list (quote toggle-attr) attr-name tgt)))
|
||||||
|
((and (list? expr) (= (first expr) (quote has-class?)))
|
||||||
|
(let
|
||||||
|
((tgt (nth expr 1)) (cls (nth expr 2)))
|
||||||
|
(list (quote toggle-class) cls tgt)))
|
||||||
|
(true nil)))))
|
||||||
(true nil))))
|
(true nil))))
|
||||||
(define
|
(define
|
||||||
parse-set-cmd
|
parse-set-cmd
|
||||||
@@ -1080,21 +1185,26 @@
|
|||||||
(fn
|
(fn
|
||||||
()
|
()
|
||||||
(let
|
(let
|
||||||
((prop (cond ((= (tp-type) "style") (get (adv!) "value")) ((= (tp-val) "my") (do (adv!) (if (= (tp-type) "style") (get (adv!) "value") (get (adv!) "value")))) (true (get (adv!) "value")))))
|
((tgt (cond ((and (= (tp-type) "ident") (= (tp-val) "element")) (do (adv!) (parse-atom))) ((= (tp-type) "id") (parse-atom)) ((= (tp-type) "class") (parse-atom)) ((= (tp-type) "selector") (parse-atom)) (true nil))))
|
||||||
(let
|
(let
|
||||||
((from-val (if (match-kw "from") (parse-expr) nil)))
|
((prop (cond ((= (tp-type) "style") (get (adv!) "value")) ((= (tp-val) "my") (do (adv!) (if (= (tp-type) "style") (get (adv!) "value") (get (adv!) "value")))) (true (get (adv!) "value")))))
|
||||||
(expect-kw! "to")
|
|
||||||
(let
|
(let
|
||||||
((value (parse-expr)))
|
((from-val (if (match-kw "from") (parse-expr) nil)))
|
||||||
|
(expect-kw! "to")
|
||||||
(let
|
(let
|
||||||
((dur (if (match-kw "over") (parse-expr) nil)))
|
((value (parse-expr)))
|
||||||
(if
|
(let
|
||||||
from-val
|
((dur (if (match-kw "over") (parse-expr) nil)))
|
||||||
(list (quote transition-from) prop from-val value dur)
|
|
||||||
(if
|
(if
|
||||||
dur
|
from-val
|
||||||
(list (quote transition) prop value dur nil)
|
(list
|
||||||
(list (quote transition) prop value nil)))))))))
|
(quote transition-from)
|
||||||
|
prop
|
||||||
|
from-val
|
||||||
|
value
|
||||||
|
dur
|
||||||
|
tgt)
|
||||||
|
(list (quote transition) prop value dur tgt)))))))))
|
||||||
(define
|
(define
|
||||||
parse-repeat-cmd
|
parse-repeat-cmd
|
||||||
(fn
|
(fn
|
||||||
@@ -1223,22 +1333,53 @@
|
|||||||
()
|
()
|
||||||
(let
|
(let
|
||||||
((typ (tp-type)) (val (tp-val)))
|
((typ (tp-type)) (val (tp-val)))
|
||||||
(if
|
(cond
|
||||||
(or (= typ "ident") (= typ "keyword"))
|
((= typ "style")
|
||||||
(do
|
(do
|
||||||
(adv!)
|
(adv!)
|
||||||
(if
|
(if
|
||||||
(match-kw "of")
|
(match-kw "of")
|
||||||
(list (make-symbol ".") (parse-expr) val)
|
(list (quote style) val (parse-expr))
|
||||||
(cond
|
(list (quote style) val (list (quote me))))))
|
||||||
((= val "result") (list (quote it)))
|
((= typ "attr")
|
||||||
((= val "first") (parse-pos-kw (quote first)))
|
(do
|
||||||
((= val "last") (parse-pos-kw (quote last)))
|
(adv!)
|
||||||
((= val "closest") (parse-trav (quote closest)))
|
(if
|
||||||
((= val "next") (parse-trav (quote next)))
|
(match-kw "of")
|
||||||
((= val "previous") (parse-trav (quote previous)))
|
(list (quote attr) val (parse-expr))
|
||||||
(true (list (quote ref) val)))))
|
(list (quote attr) val (list (quote me))))))
|
||||||
(parse-atom)))))
|
((= typ "class")
|
||||||
|
(do
|
||||||
|
(adv!)
|
||||||
|
(if
|
||||||
|
(match-kw "of")
|
||||||
|
(list (quote has-class?) (parse-expr) val)
|
||||||
|
(list (quote has-class?) (list (quote me)) val))))
|
||||||
|
((= typ "selector")
|
||||||
|
(do
|
||||||
|
(adv!)
|
||||||
|
(if
|
||||||
|
(match-kw "in")
|
||||||
|
(list
|
||||||
|
(quote in?)
|
||||||
|
(list (quote query) val)
|
||||||
|
(parse-expr))
|
||||||
|
(list (quote query) val))))
|
||||||
|
((or (= typ "ident") (= typ "keyword"))
|
||||||
|
(do
|
||||||
|
(adv!)
|
||||||
|
(if
|
||||||
|
(match-kw "of")
|
||||||
|
(list (make-symbol ".") (parse-expr) val)
|
||||||
|
(cond
|
||||||
|
((= val "result") (list (quote it)))
|
||||||
|
((= val "first") (parse-pos-kw (quote first)))
|
||||||
|
((= val "last") (parse-pos-kw (quote last)))
|
||||||
|
((= val "closest") (parse-trav (quote closest)))
|
||||||
|
((= val "next") (parse-trav (quote next)))
|
||||||
|
((= val "previous") (parse-trav (quote previous)))
|
||||||
|
(true (list (quote ref) val))))))
|
||||||
|
(true (parse-atom))))))
|
||||||
(define
|
(define
|
||||||
parse-array-lit
|
parse-array-lit
|
||||||
(fn
|
(fn
|
||||||
|
|||||||
@@ -88,7 +88,7 @@
|
|||||||
((or (= prop "display") (= prop "opacity"))
|
((or (= prop "display") (= prop "opacity"))
|
||||||
(if
|
(if
|
||||||
(or (= cur "none") (= cur "0"))
|
(or (= cur "none") (= cur "0"))
|
||||||
(dom-set-style target prop "")
|
(dom-set-style target prop (if (= prop "opacity") "1" ""))
|
||||||
(dom-set-style target prop (if (= prop "display") "none" "0"))))
|
(dom-set-style target prop (if (= prop "display") "none" "0"))))
|
||||||
(true
|
(true
|
||||||
(if
|
(if
|
||||||
@@ -102,17 +102,30 @@
|
|||||||
(define
|
(define
|
||||||
hs-take!
|
hs-take!
|
||||||
(fn
|
(fn
|
||||||
(target kind name scope)
|
(target kind name scope &rest extra)
|
||||||
(let
|
(let
|
||||||
((els (if scope (if (list? scope) scope (list scope)) (let ((parent (host-get target "parentNode"))) (if parent (dom-child-list parent) (list))))))
|
((els (if scope (if (list? scope) scope (list scope)) (let ((parent (dom-parent target))) (if parent (dom-child-list parent) (list))))))
|
||||||
(if
|
(if
|
||||||
(= kind "class")
|
(= kind "class")
|
||||||
(do
|
(do
|
||||||
(for-each (fn (el) (dom-remove-class el name)) els)
|
(for-each (fn (el) (dom-remove-class el name)) els)
|
||||||
(dom-add-class target name))
|
(dom-add-class target name))
|
||||||
(do
|
(let
|
||||||
(for-each (fn (el) (dom-remove-attr el name)) els)
|
((attr-val (if (> (len extra) 0) (first extra) nil))
|
||||||
(dom-set-attr target name "true"))))))
|
(with-val (if (> (len extra) 1) (nth extra 1) nil)))
|
||||||
|
(do
|
||||||
|
(for-each
|
||||||
|
(fn
|
||||||
|
(el)
|
||||||
|
(if
|
||||||
|
with-val
|
||||||
|
(dom-set-attr el name with-val)
|
||||||
|
(dom-remove-attr el name)))
|
||||||
|
els)
|
||||||
|
(if
|
||||||
|
attr-val
|
||||||
|
(dom-set-attr target name attr-val)
|
||||||
|
(dom-set-attr target name ""))))))))
|
||||||
|
|
||||||
;; Find next sibling matching a selector (or any sibling).
|
;; Find next sibling matching a selector (or any sibling).
|
||||||
(define
|
(define
|
||||||
@@ -204,7 +217,9 @@
|
|||||||
|
|
||||||
;; Fetch a URL, parse response according to format.
|
;; Fetch a URL, parse response according to format.
|
||||||
;; (hs-fetch url format) — format is "json" | "text" | "html"
|
;; (hs-fetch url format) — format is "json" | "text" | "html"
|
||||||
(define hs-query-all (fn (sel) (dom-query-all (dom-body) sel)))
|
(define
|
||||||
|
hs-query-all
|
||||||
|
(fn (sel) (host-call (dom-body) "querySelectorAll" sel)))
|
||||||
|
|
||||||
;; ── Type coercion ───────────────────────────────────────────────
|
;; ── Type coercion ───────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -290,29 +305,72 @@
|
|||||||
((= type-name "Bool") (not (hs-falsy? value)))
|
((= type-name "Bool") (not (hs-falsy? value)))
|
||||||
((= type-name "Boolean") (not (hs-falsy? value)))
|
((= type-name "Boolean") (not (hs-falsy? value)))
|
||||||
((= type-name "Array") (if (list? value) value (list value)))
|
((= type-name "Array") (if (list? value) value (list value)))
|
||||||
((= type-name "JSON") (str value))
|
((= type-name "HTML") (str value))
|
||||||
((= type-name "Object") (if (string? value) value value))
|
((= type-name "JSON")
|
||||||
((or (= type-name "Fixed") (string-contains? type-name "Fixed:"))
|
(if
|
||||||
|
(string? value)
|
||||||
|
value
|
||||||
|
(host-call (host-global "JSON") "stringify" value)))
|
||||||
|
((= type-name "Object")
|
||||||
|
(if
|
||||||
|
(string? value)
|
||||||
|
(host-call (host-global "JSON") "parse" value)
|
||||||
|
value))
|
||||||
|
((or (= type-name "Fixed") (= type-name "Fixed:"))
|
||||||
(let
|
(let
|
||||||
((digits (if (string-contains? type-name ":") (parse-number (nth (split type-name ":") 1)) 0))
|
((digits (if (> (string-length type-name) 6) (+ (substring type-name 6 (string-length type-name)) 0) 0))
|
||||||
(num (+ value 0)))
|
(num (+ value 0)))
|
||||||
(if
|
(if
|
||||||
(= digits 0)
|
(= digits 0)
|
||||||
(str (floor num))
|
(str (floor num))
|
||||||
(let
|
(let
|
||||||
((factor (reduce (fn (acc _) (* acc 10)) 1 (range 0 digits))))
|
((factor (** 10 digits)))
|
||||||
(let
|
(str (/ (floor (+ (* num factor) 0.5)) factor))))))
|
||||||
((rounded (/ (floor (+ (* num factor) 0.5)) factor)))
|
((= type-name "Selector") (str value))
|
||||||
(str rounded))))))
|
((= type-name "Fragment") value)
|
||||||
((= type-name "HTML") (str value))
|
((= type-name "Values")
|
||||||
((= type-name "Values") value)
|
(if
|
||||||
((= type-name "Fragment") (str value))
|
(dict? value)
|
||||||
((= type-name "Date") (str value))
|
(map (fn (k) (get value k)) (keys value))
|
||||||
|
value))
|
||||||
|
((= type-name "Keys") (if (dict? value) (keys value) value))
|
||||||
|
((= type-name "Entries")
|
||||||
|
(if
|
||||||
|
(dict? value)
|
||||||
|
(map (fn (k) (list k (get value k))) (keys value))
|
||||||
|
value))
|
||||||
|
((= type-name "Reversed") (if (list? value) (reverse value) value))
|
||||||
|
((= type-name "Unique")
|
||||||
|
(if
|
||||||
|
(list? value)
|
||||||
|
(reduce
|
||||||
|
(fn
|
||||||
|
(acc x)
|
||||||
|
(if (some (fn (a) (= a x)) acc) acc (append acc (list x))))
|
||||||
|
(list)
|
||||||
|
value)
|
||||||
|
value))
|
||||||
|
((or (= type-name "Flattened") (= type-name "Flat"))
|
||||||
|
(if
|
||||||
|
(list? value)
|
||||||
|
(reduce
|
||||||
|
(fn
|
||||||
|
(acc x)
|
||||||
|
(if (list? x) (append acc x) (append acc (list x))))
|
||||||
|
(list)
|
||||||
|
value)
|
||||||
|
value))
|
||||||
(true value))))
|
(true value))))
|
||||||
|
|
||||||
(define
|
(define
|
||||||
hs-add
|
hs-add
|
||||||
(fn (a b) (if (or (string? a) (string? b)) (str a b) (+ a b))))
|
(fn
|
||||||
|
(a b)
|
||||||
|
(cond
|
||||||
|
((list? a) (if (list? b) (append a b) (append a (list b))))
|
||||||
|
((list? b) (cons a b))
|
||||||
|
((or (string? a) (string? b)) (str a b))
|
||||||
|
(true (+ a b)))))
|
||||||
|
|
||||||
(define
|
(define
|
||||||
hs-make
|
hs-make
|
||||||
@@ -371,7 +429,12 @@
|
|||||||
((= type-name "Boolean") (or (= value true) (= value false)))
|
((= type-name "Boolean") (or (= value true) (= value false)))
|
||||||
((= type-name "Array") (list? value))
|
((= type-name "Array") (list? value))
|
||||||
((= type-name "Object") (dict? value))
|
((= type-name "Object") (dict? value))
|
||||||
(true true)))))
|
((= type-name "Element") (= (host-typeof value) "element"))
|
||||||
|
((= type-name "Node")
|
||||||
|
(or
|
||||||
|
(= (host-typeof value) "element")
|
||||||
|
(= (host-typeof value) "text")))
|
||||||
|
(true (= (host-typeof value) (downcase type-name)))))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -392,12 +455,18 @@
|
|||||||
hs-eq-ignore-case
|
hs-eq-ignore-case
|
||||||
(fn (a b) (= (downcase (str a)) (downcase (str b)))))
|
(fn (a b) (= (downcase (str a)) (downcase (str b)))))
|
||||||
;; DOM query stub — sandbox returns empty list
|
;; DOM query stub — sandbox returns empty list
|
||||||
|
(define
|
||||||
|
hs-starts-with-ic?
|
||||||
|
(fn (str prefix) (starts-with? (downcase str) (downcase prefix))))
|
||||||
|
;; Method dispatch — obj.method(args)
|
||||||
(define
|
(define
|
||||||
hs-contains-ignore-case?
|
hs-contains-ignore-case?
|
||||||
(fn
|
(fn
|
||||||
(haystack needle)
|
(haystack needle)
|
||||||
(contains? (downcase (str haystack)) (downcase (str needle)))))
|
(contains? (downcase (str haystack)) (downcase (str needle)))))
|
||||||
;; Method dispatch — obj.method(args)
|
|
||||||
|
;; ── 0.9.90 features ─────────────────────────────────────────────
|
||||||
|
;; beep! — debug logging, returns value unchanged
|
||||||
(define
|
(define
|
||||||
hs-falsy?
|
hs-falsy?
|
||||||
(fn
|
(fn
|
||||||
@@ -409,18 +478,18 @@
|
|||||||
((and (list? v) (= (len v) 0)) true)
|
((and (list? v) (= (len v) 0)) true)
|
||||||
((= v 0) true)
|
((= v 0) true)
|
||||||
(true false))))
|
(true false))))
|
||||||
|
;; Property-based is — check obj.key truthiness
|
||||||
;; ── 0.9.90 features ─────────────────────────────────────────────
|
|
||||||
;; beep! — debug logging, returns value unchanged
|
|
||||||
(define
|
(define
|
||||||
hs-matches?
|
hs-matches?
|
||||||
(fn
|
(fn
|
||||||
(target pattern)
|
(target pattern)
|
||||||
(if
|
(cond
|
||||||
(string? target)
|
((string? target)
|
||||||
(if (= pattern ".*") true (string-contains? target pattern))
|
(if (= pattern ".*") true (string-contains? target pattern)))
|
||||||
false)))
|
((= (host-typeof target) "element")
|
||||||
;; Property-based is — check obj.key truthiness
|
(if (string? pattern) (host-call target "matches" pattern) false))
|
||||||
|
(true false))))
|
||||||
|
;; Array slicing (inclusive both ends)
|
||||||
(define
|
(define
|
||||||
hs-contains?
|
hs-contains?
|
||||||
(fn
|
(fn
|
||||||
@@ -440,9 +509,9 @@
|
|||||||
true
|
true
|
||||||
(hs-contains? (rest collection) item)))))
|
(hs-contains? (rest collection) item)))))
|
||||||
(true false))))
|
(true false))))
|
||||||
;; Array slicing (inclusive both ends)
|
|
||||||
(define precedes? (fn (a b) (< (str a) (str b))))
|
|
||||||
;; Collection: sorted by
|
;; Collection: sorted by
|
||||||
|
(define precedes? (fn (a b) (< (str a) (str b))))
|
||||||
|
;; Collection: sorted by descending
|
||||||
(define
|
(define
|
||||||
hs-empty?
|
hs-empty?
|
||||||
(fn
|
(fn
|
||||||
@@ -453,7 +522,7 @@
|
|||||||
((list? v) (= (len v) 0))
|
((list? v) (= (len v) 0))
|
||||||
((dict? v) (= (len (keys v)) 0))
|
((dict? v) (= (len (keys v)) 0))
|
||||||
(true false))))
|
(true false))))
|
||||||
;; Collection: sorted by descending
|
;; Collection: split by
|
||||||
(define
|
(define
|
||||||
hs-empty-target!
|
hs-empty-target!
|
||||||
(fn
|
(fn
|
||||||
@@ -474,7 +543,7 @@
|
|||||||
(dom-set-prop target "value" ""))))
|
(dom-set-prop target "value" ""))))
|
||||||
((= tag "FORM") (dom-set-inner-html target ""))
|
((= tag "FORM") (dom-set-inner-html target ""))
|
||||||
(true (dom-set-inner-html target ""))))))))
|
(true (dom-set-inner-html target ""))))))))
|
||||||
;; Collection: split by
|
;; Collection: joined by
|
||||||
(define
|
(define
|
||||||
hs-open!
|
hs-open!
|
||||||
(fn
|
(fn
|
||||||
@@ -485,7 +554,7 @@
|
|||||||
(= tag "DIALOG")
|
(= tag "DIALOG")
|
||||||
(host-call el "showModal")
|
(host-call el "showModal")
|
||||||
(dom-set-prop el "open" true)))))
|
(dom-set-prop el "open" true)))))
|
||||||
;; Collection: joined by
|
|
||||||
(define
|
(define
|
||||||
hs-close!
|
hs-close!
|
||||||
(fn
|
(fn
|
||||||
|
|||||||
@@ -56,32 +56,39 @@
|
|||||||
(hs-to-sx (nth target 2))
|
(hs-to-sx (nth target 2))
|
||||||
value))
|
value))
|
||||||
((= th (quote of))
|
((= th (quote of))
|
||||||
;; Decompose (of prop-expr target) into a set operation
|
(let
|
||||||
;; e.g. (of (. (ref "parentNode") "innerHTML") (query "#d1"))
|
((prop-ast (nth target 1)) (obj-ast (nth target 2)))
|
||||||
;; → set parentNode.innerHTML of #d1 → need to navigate target, then set final prop
|
(if
|
||||||
(let ((prop-ast (nth target 1))
|
(and (list? prop-ast) (= (first prop-ast) dot-sym))
|
||||||
(obj-ast (nth target 2)))
|
(let
|
||||||
(if (and (list? prop-ast) (= (first prop-ast) dot-sym))
|
((base (nth prop-ast 1))
|
||||||
;; (. base "prop") of obj → (dom-set-prop (host-get (compiled-obj) (compiled-base-name)) "prop" value)
|
(prop-name (nth prop-ast 2)))
|
||||||
(let ((base (nth prop-ast 1))
|
(list
|
||||||
(prop-name (nth prop-ast 2)))
|
(quote dom-set-prop)
|
||||||
(list (quote dom-set-prop)
|
(list
|
||||||
(list (quote host-get) (hs-to-sx obj-ast) (nth base 1))
|
(quote host-get)
|
||||||
|
(hs-to-sx obj-ast)
|
||||||
|
(nth base 1))
|
||||||
prop-name
|
prop-name
|
||||||
value))
|
value))
|
||||||
;; (attr "name") of obj → (dom-set-attr (compiled-obj) "name" value)
|
(if
|
||||||
(if (and (list? prop-ast) (= (first prop-ast) (quote attr)))
|
(and
|
||||||
(list (quote dom-set-attr)
|
(list? prop-ast)
|
||||||
|
(= (first prop-ast) (quote attr)))
|
||||||
|
(list
|
||||||
|
(quote dom-set-attr)
|
||||||
(hs-to-sx obj-ast)
|
(hs-to-sx obj-ast)
|
||||||
(nth prop-ast 1)
|
(nth prop-ast 1)
|
||||||
value)
|
value)
|
||||||
;; Simple: (ref "prop") of obj → (dom-set-prop (compiled-obj) "prop" value)
|
(if
|
||||||
(if (and (list? prop-ast) (= (first prop-ast) (quote ref)))
|
(and
|
||||||
(list (quote dom-set-prop)
|
(list? prop-ast)
|
||||||
|
(= (first prop-ast) (quote ref)))
|
||||||
|
(list
|
||||||
|
(quote dom-set-prop)
|
||||||
(hs-to-sx obj-ast)
|
(hs-to-sx obj-ast)
|
||||||
(nth prop-ast 1)
|
(nth prop-ast 1)
|
||||||
value)
|
value)
|
||||||
;; Fallback
|
|
||||||
(list (quote set!) (hs-to-sx target) value))))))
|
(list (quote set!) (hs-to-sx target) value))))))
|
||||||
(true (list (quote set!) (hs-to-sx target) value)))))))
|
(true (list (quote set!) (hs-to-sx target) value)))))))
|
||||||
(define
|
(define
|
||||||
@@ -427,7 +434,7 @@
|
|||||||
((= head (quote null-literal)) nil)
|
((= head (quote null-literal)) nil)
|
||||||
((= head (quote not))
|
((= head (quote not))
|
||||||
(list (quote not) (hs-to-sx (nth ast 1))))
|
(list (quote not) (hs-to-sx (nth ast 1))))
|
||||||
((or (= head (quote starts-with?)) (= head (quote ends-with?)) (= head (quote contains?)) (= head (quote matches?)) (= head (quote precedes?)) (= head (quote follows?)) (= head (quote exists?)))
|
((or (= head (quote starts-with?)) (= head (quote ends-with?)) (= head (quote contains?)) (= head (quote precedes?)) (= head (quote follows?)) (= head (quote exists?)))
|
||||||
(cons head (map hs-to-sx (rest ast))))
|
(cons head (map hs-to-sx (rest ast))))
|
||||||
((= head (quote object-literal))
|
((= head (quote object-literal))
|
||||||
(let
|
(let
|
||||||
@@ -656,6 +663,11 @@
|
|||||||
(quote dom-get-style)
|
(quote dom-get-style)
|
||||||
(hs-to-sx (nth ast 2))
|
(hs-to-sx (nth ast 2))
|
||||||
(nth ast 1)))
|
(nth ast 1)))
|
||||||
|
((= head (quote has-class?))
|
||||||
|
(list
|
||||||
|
(quote dom-has-class?)
|
||||||
|
(hs-to-sx (nth ast 1))
|
||||||
|
(nth ast 2)))
|
||||||
((= head (quote local)) (make-symbol (nth ast 1)))
|
((= head (quote local)) (make-symbol (nth ast 1)))
|
||||||
((= head (quote array))
|
((= head (quote array))
|
||||||
(cons (quote list) (map hs-to-sx (rest ast))))
|
(cons (quote list) (map hs-to-sx (rest ast))))
|
||||||
@@ -713,15 +725,30 @@
|
|||||||
(quote not)
|
(quote not)
|
||||||
(list (quote nil?) (hs-to-sx (nth ast 1)))))
|
(list (quote nil?) (hs-to-sx (nth ast 1)))))
|
||||||
((= head (quote matches?))
|
((= head (quote matches?))
|
||||||
(list
|
(let
|
||||||
(quote hs-matches?)
|
((left (nth ast 1)) (right (nth ast 2)))
|
||||||
(hs-to-sx (nth ast 1))
|
(if
|
||||||
(hs-to-sx (nth ast 2))))
|
(and (list? right) (= (first right) (quote query)))
|
||||||
|
(list (quote hs-matches?) (hs-to-sx left) (nth right 1))
|
||||||
|
(list
|
||||||
|
(quote hs-matches?)
|
||||||
|
(hs-to-sx left)
|
||||||
|
(hs-to-sx right)))))
|
||||||
((= head (quote matches-ignore-case?))
|
((= head (quote matches-ignore-case?))
|
||||||
(list
|
(list
|
||||||
(quote hs-matches-ignore-case?)
|
(quote hs-matches-ignore-case?)
|
||||||
(hs-to-sx (nth ast 1))
|
(hs-to-sx (nth ast 1))
|
||||||
(hs-to-sx (nth ast 2))))
|
(hs-to-sx (nth ast 2))))
|
||||||
|
((= head (quote starts-with-ic?))
|
||||||
|
(list
|
||||||
|
(quote hs-starts-with-ic?)
|
||||||
|
(hs-to-sx (nth ast 1))
|
||||||
|
(hs-to-sx (nth ast 2))))
|
||||||
|
((= head (quote ends-with-ic?))
|
||||||
|
(list
|
||||||
|
(quote hs-ends-with-ic?)
|
||||||
|
(hs-to-sx (nth ast 1))
|
||||||
|
(hs-to-sx (nth ast 2))))
|
||||||
((= head (quote contains?))
|
((= head (quote contains?))
|
||||||
(list
|
(list
|
||||||
(quote hs-contains?)
|
(quote hs-contains?)
|
||||||
@@ -824,6 +851,23 @@
|
|||||||
(map
|
(map
|
||||||
(fn (cls) (list (quote dom-add-class) target cls))
|
(fn (cls) (list (quote dom-add-class) target cls))
|
||||||
classes))))
|
classes))))
|
||||||
|
((= head (quote add-class-when))
|
||||||
|
(let
|
||||||
|
((cls (nth ast 1))
|
||||||
|
(raw-tgt (nth ast 2))
|
||||||
|
(when-cond (nth ast 3)))
|
||||||
|
(let
|
||||||
|
((tgt-expr (cond ((and (list? raw-tgt) (= (first raw-tgt) (quote query))) (list (quote hs-query-all) (nth raw-tgt 1))) ((and (list? raw-tgt) (= (first raw-tgt) (quote in?)) (list? (nth raw-tgt 1)) (= (first (nth raw-tgt 1)) (quote query))) (list (quote host-call) (hs-to-sx (nth raw-tgt 2)) "querySelectorAll" (nth (nth raw-tgt 1) 1))) (true (hs-to-sx raw-tgt)))))
|
||||||
|
(list
|
||||||
|
(quote for-each)
|
||||||
|
(list
|
||||||
|
(quote fn)
|
||||||
|
(list (quote it))
|
||||||
|
(list
|
||||||
|
(quote when)
|
||||||
|
(hs-to-sx when-cond)
|
||||||
|
(list (quote dom-add-class) (quote it) cls)))
|
||||||
|
tgt-expr))))
|
||||||
((= head (quote multi-remove-class))
|
((= head (quote multi-remove-class))
|
||||||
(let
|
(let
|
||||||
((target (hs-to-sx (nth ast 1)))
|
((target (hs-to-sx (nth ast 1)))
|
||||||
@@ -895,10 +939,12 @@
|
|||||||
(nth ast 1)
|
(nth ast 1)
|
||||||
(nth ast 2)))
|
(nth ast 2)))
|
||||||
((= head (quote toggle-style))
|
((= head (quote toggle-style))
|
||||||
(list
|
(let
|
||||||
(quote hs-toggle-style!)
|
((raw-tgt (nth ast 2)))
|
||||||
(hs-to-sx (nth ast 2))
|
(list
|
||||||
(nth ast 1)))
|
(quote hs-toggle-style!)
|
||||||
|
(if (nil? raw-tgt) (quote me) (hs-to-sx raw-tgt))
|
||||||
|
(nth ast 1))))
|
||||||
((= head (quote toggle-style-between))
|
((= head (quote toggle-style-between))
|
||||||
(list
|
(list
|
||||||
(quote hs-toggle-style-between!)
|
(quote hs-toggle-style-between!)
|
||||||
|
|||||||
@@ -513,12 +513,26 @@
|
|||||||
(do
|
(do
|
||||||
(adv!)
|
(adv!)
|
||||||
(match-kw "with")
|
(match-kw "with")
|
||||||
(list (quote starts-with?) left (parse-expr))))
|
(let
|
||||||
|
((rhs (parse-atom)))
|
||||||
|
(if
|
||||||
|
(match-kw "ignoring")
|
||||||
|
(do
|
||||||
|
(match-kw "case")
|
||||||
|
(list (quote starts-with-ic?) left rhs))
|
||||||
|
(list (quote starts-with?) left rhs)))))
|
||||||
((and (or (= typ "keyword") (= typ "ident")) (= val "ends"))
|
((and (or (= typ "keyword") (= typ "ident")) (= val "ends"))
|
||||||
(do
|
(do
|
||||||
(adv!)
|
(adv!)
|
||||||
(match-kw "with")
|
(match-kw "with")
|
||||||
(list (quote ends-with?) left (parse-expr))))
|
(let
|
||||||
|
((rhs (parse-atom)))
|
||||||
|
(if
|
||||||
|
(match-kw "ignoring")
|
||||||
|
(do
|
||||||
|
(match-kw "case")
|
||||||
|
(list (quote ends-with-ic?) left rhs))
|
||||||
|
(list (quote ends-with?) left rhs)))))
|
||||||
((and (= typ "keyword") (= val "matches"))
|
((and (= typ "keyword") (= val "matches"))
|
||||||
(do
|
(do
|
||||||
(adv!)
|
(adv!)
|
||||||
@@ -607,11 +621,17 @@
|
|||||||
(quote not)
|
(quote not)
|
||||||
(list (quote contains?) left (parse-expr))))
|
(list (quote contains?) left (parse-expr))))
|
||||||
((match-kw "start")
|
((match-kw "start")
|
||||||
(do (match-kw "with")
|
(do
|
||||||
(list (quote not) (list (quote starts-with?) left (parse-expr)))))
|
(match-kw "with")
|
||||||
|
(list
|
||||||
|
(quote not)
|
||||||
|
(list (quote starts-with?) left (parse-expr)))))
|
||||||
((match-kw "end")
|
((match-kw "end")
|
||||||
(do (match-kw "with")
|
(do
|
||||||
(list (quote not) (list (quote ends-with?) left (parse-expr)))))
|
(match-kw "with")
|
||||||
|
(list
|
||||||
|
(quote not)
|
||||||
|
(list (quote ends-with?) left (parse-expr)))))
|
||||||
(true left))))
|
(true left))))
|
||||||
((and (= typ "keyword") (= val "equals"))
|
((and (= typ "keyword") (= val "equals"))
|
||||||
(do (adv!) (list (quote =) left (parse-expr))))
|
(do (adv!) (list (quote =) left (parse-expr))))
|
||||||
@@ -693,12 +713,20 @@
|
|||||||
nil
|
nil
|
||||||
(do
|
(do
|
||||||
(when
|
(when
|
||||||
(and (number? left) (= (tp-type) "ident")
|
(and
|
||||||
(not (or (= (tp-val) "starts") (= (tp-val) "ends")
|
(number? left)
|
||||||
(= (tp-val) "contains") (= (tp-val) "matches")
|
(= (tp-type) "ident")
|
||||||
(= (tp-val) "is") (= (tp-val) "does")
|
(not
|
||||||
(= (tp-val) "in") (= (tp-val) "precedes")
|
(or
|
||||||
(= (tp-val) "follows"))))
|
(= (tp-val) "starts")
|
||||||
|
(= (tp-val) "ends")
|
||||||
|
(= (tp-val) "contains")
|
||||||
|
(= (tp-val) "matches")
|
||||||
|
(= (tp-val) "is")
|
||||||
|
(= (tp-val) "does")
|
||||||
|
(= (tp-val) "in")
|
||||||
|
(= (tp-val) "precedes")
|
||||||
|
(= (tp-val) "follows"))))
|
||||||
(let
|
(let
|
||||||
((unit (tp-val)))
|
((unit (tp-val)))
|
||||||
(do
|
(do
|
||||||
@@ -757,12 +785,25 @@
|
|||||||
(collect-classes!)
|
(collect-classes!)
|
||||||
(let
|
(let
|
||||||
((tgt (parse-tgt-kw "to" (list (quote me)))))
|
((tgt (parse-tgt-kw "to" (list (quote me)))))
|
||||||
(if
|
(let
|
||||||
(empty? extra-classes)
|
((when-clause (if (match-kw "when") (parse-expr) nil)))
|
||||||
(list (quote add-class) cls tgt)
|
(if
|
||||||
(cons
|
(empty? extra-classes)
|
||||||
(quote multi-add-class)
|
(if
|
||||||
(cons tgt (cons cls extra-classes))))))
|
when-clause
|
||||||
|
(list (quote add-class-when) cls tgt when-clause)
|
||||||
|
(list (quote add-class) cls tgt))
|
||||||
|
(if
|
||||||
|
when-clause
|
||||||
|
(list
|
||||||
|
(quote multi-add-class-when)
|
||||||
|
tgt
|
||||||
|
when-clause
|
||||||
|
cls
|
||||||
|
extra-classes)
|
||||||
|
(cons
|
||||||
|
(quote multi-add-class)
|
||||||
|
(cons tgt (cons cls extra-classes))))))))
|
||||||
nil)))
|
nil)))
|
||||||
(define
|
(define
|
||||||
parse-remove-cmd
|
parse-remove-cmd
|
||||||
@@ -893,6 +934,70 @@
|
|||||||
(let
|
(let
|
||||||
((tgt (parse-tgt-kw "on" (list (quote me)))))
|
((tgt (parse-tgt-kw "on" (list (quote me)))))
|
||||||
(list (quote toggle-attr) attr-name tgt)))))
|
(list (quote toggle-attr) attr-name tgt)))))
|
||||||
|
((and (= (tp-type) "keyword") (= (tp-val) "my"))
|
||||||
|
(do
|
||||||
|
(adv!)
|
||||||
|
(cond
|
||||||
|
((= (tp-type) "style")
|
||||||
|
(let
|
||||||
|
((prop (get (adv!) "value")))
|
||||||
|
(if
|
||||||
|
(match-kw "between")
|
||||||
|
(let
|
||||||
|
((val1 (parse-expr)))
|
||||||
|
(expect-kw! "and")
|
||||||
|
(let
|
||||||
|
((val2 (parse-expr)))
|
||||||
|
(let
|
||||||
|
((tgt (if (match-kw "on") (parse-expr) nil)))
|
||||||
|
(list
|
||||||
|
(quote toggle-style-between)
|
||||||
|
prop
|
||||||
|
val1
|
||||||
|
val2
|
||||||
|
tgt))))
|
||||||
|
(let
|
||||||
|
((tgt (if (match-kw "on") (parse-expr) nil)))
|
||||||
|
(list (quote toggle-style) prop tgt)))))
|
||||||
|
((= (tp-type) "attr")
|
||||||
|
(let
|
||||||
|
((attr-name (get (adv!) "value")))
|
||||||
|
(let
|
||||||
|
((tgt (if (match-kw "on") (parse-expr) nil)))
|
||||||
|
(list (quote toggle-attr) attr-name tgt))))
|
||||||
|
(true nil))))
|
||||||
|
((and (= (tp-type) "keyword") (= (tp-val) "the"))
|
||||||
|
(do
|
||||||
|
(adv!)
|
||||||
|
(let
|
||||||
|
((expr (parse-the-expr)))
|
||||||
|
(cond
|
||||||
|
((and (list? expr) (= (first expr) (quote style)))
|
||||||
|
(let
|
||||||
|
((prop (nth expr 1)) (tgt (nth expr 2)))
|
||||||
|
(if
|
||||||
|
(match-kw "between")
|
||||||
|
(let
|
||||||
|
((val1 (parse-expr)))
|
||||||
|
(expect-kw! "and")
|
||||||
|
(let
|
||||||
|
((val2 (parse-expr)))
|
||||||
|
(list
|
||||||
|
(quote toggle-style-between)
|
||||||
|
prop
|
||||||
|
val1
|
||||||
|
val2
|
||||||
|
tgt)))
|
||||||
|
(list (quote toggle-style) prop tgt))))
|
||||||
|
((and (list? expr) (= (first expr) (quote attr)))
|
||||||
|
(let
|
||||||
|
((attr-name (nth expr 1)) (tgt (nth expr 2)))
|
||||||
|
(list (quote toggle-attr) attr-name tgt)))
|
||||||
|
((and (list? expr) (= (first expr) (quote has-class?)))
|
||||||
|
(let
|
||||||
|
((tgt (nth expr 1)) (cls (nth expr 2)))
|
||||||
|
(list (quote toggle-class) cls tgt)))
|
||||||
|
(true nil)))))
|
||||||
(true nil))))
|
(true nil))))
|
||||||
(define
|
(define
|
||||||
parse-set-cmd
|
parse-set-cmd
|
||||||
@@ -1080,21 +1185,26 @@
|
|||||||
(fn
|
(fn
|
||||||
()
|
()
|
||||||
(let
|
(let
|
||||||
((prop (cond ((= (tp-type) "style") (get (adv!) "value")) ((= (tp-val) "my") (do (adv!) (if (= (tp-type) "style") (get (adv!) "value") (get (adv!) "value")))) (true (get (adv!) "value")))))
|
((tgt (cond ((and (= (tp-type) "ident") (= (tp-val) "element")) (do (adv!) (parse-atom))) ((= (tp-type) "id") (parse-atom)) ((= (tp-type) "class") (parse-atom)) ((= (tp-type) "selector") (parse-atom)) (true nil))))
|
||||||
(let
|
(let
|
||||||
((from-val (if (match-kw "from") (parse-expr) nil)))
|
((prop (cond ((= (tp-type) "style") (get (adv!) "value")) ((= (tp-val) "my") (do (adv!) (if (= (tp-type) "style") (get (adv!) "value") (get (adv!) "value")))) (true (get (adv!) "value")))))
|
||||||
(expect-kw! "to")
|
|
||||||
(let
|
(let
|
||||||
((value (parse-expr)))
|
((from-val (if (match-kw "from") (parse-expr) nil)))
|
||||||
|
(expect-kw! "to")
|
||||||
(let
|
(let
|
||||||
((dur (if (match-kw "over") (parse-expr) nil)))
|
((value (parse-expr)))
|
||||||
(if
|
(let
|
||||||
from-val
|
((dur (if (match-kw "over") (parse-expr) nil)))
|
||||||
(list (quote transition-from) prop from-val value dur)
|
|
||||||
(if
|
(if
|
||||||
dur
|
from-val
|
||||||
(list (quote transition) prop value dur nil)
|
(list
|
||||||
(list (quote transition) prop value nil)))))))))
|
(quote transition-from)
|
||||||
|
prop
|
||||||
|
from-val
|
||||||
|
value
|
||||||
|
dur
|
||||||
|
tgt)
|
||||||
|
(list (quote transition) prop value dur tgt)))))))))
|
||||||
(define
|
(define
|
||||||
parse-repeat-cmd
|
parse-repeat-cmd
|
||||||
(fn
|
(fn
|
||||||
@@ -1223,22 +1333,53 @@
|
|||||||
()
|
()
|
||||||
(let
|
(let
|
||||||
((typ (tp-type)) (val (tp-val)))
|
((typ (tp-type)) (val (tp-val)))
|
||||||
(if
|
(cond
|
||||||
(or (= typ "ident") (= typ "keyword"))
|
((= typ "style")
|
||||||
(do
|
(do
|
||||||
(adv!)
|
(adv!)
|
||||||
(if
|
(if
|
||||||
(match-kw "of")
|
(match-kw "of")
|
||||||
(list (make-symbol ".") (parse-expr) val)
|
(list (quote style) val (parse-expr))
|
||||||
(cond
|
(list (quote style) val (list (quote me))))))
|
||||||
((= val "result") (list (quote it)))
|
((= typ "attr")
|
||||||
((= val "first") (parse-pos-kw (quote first)))
|
(do
|
||||||
((= val "last") (parse-pos-kw (quote last)))
|
(adv!)
|
||||||
((= val "closest") (parse-trav (quote closest)))
|
(if
|
||||||
((= val "next") (parse-trav (quote next)))
|
(match-kw "of")
|
||||||
((= val "previous") (parse-trav (quote previous)))
|
(list (quote attr) val (parse-expr))
|
||||||
(true (list (quote ref) val)))))
|
(list (quote attr) val (list (quote me))))))
|
||||||
(parse-atom)))))
|
((= typ "class")
|
||||||
|
(do
|
||||||
|
(adv!)
|
||||||
|
(if
|
||||||
|
(match-kw "of")
|
||||||
|
(list (quote has-class?) (parse-expr) val)
|
||||||
|
(list (quote has-class?) (list (quote me)) val))))
|
||||||
|
((= typ "selector")
|
||||||
|
(do
|
||||||
|
(adv!)
|
||||||
|
(if
|
||||||
|
(match-kw "in")
|
||||||
|
(list
|
||||||
|
(quote in?)
|
||||||
|
(list (quote query) val)
|
||||||
|
(parse-expr))
|
||||||
|
(list (quote query) val))))
|
||||||
|
((or (= typ "ident") (= typ "keyword"))
|
||||||
|
(do
|
||||||
|
(adv!)
|
||||||
|
(if
|
||||||
|
(match-kw "of")
|
||||||
|
(list (make-symbol ".") (parse-expr) val)
|
||||||
|
(cond
|
||||||
|
((= val "result") (list (quote it)))
|
||||||
|
((= val "first") (parse-pos-kw (quote first)))
|
||||||
|
((= val "last") (parse-pos-kw (quote last)))
|
||||||
|
((= val "closest") (parse-trav (quote closest)))
|
||||||
|
((= val "next") (parse-trav (quote next)))
|
||||||
|
((= val "previous") (parse-trav (quote previous)))
|
||||||
|
(true (list (quote ref) val))))))
|
||||||
|
(true (parse-atom))))))
|
||||||
(define
|
(define
|
||||||
parse-array-lit
|
parse-array-lit
|
||||||
(fn
|
(fn
|
||||||
|
|||||||
@@ -88,7 +88,7 @@
|
|||||||
((or (= prop "display") (= prop "opacity"))
|
((or (= prop "display") (= prop "opacity"))
|
||||||
(if
|
(if
|
||||||
(or (= cur "none") (= cur "0"))
|
(or (= cur "none") (= cur "0"))
|
||||||
(dom-set-style target prop "")
|
(dom-set-style target prop (if (= prop "opacity") "1" ""))
|
||||||
(dom-set-style target prop (if (= prop "display") "none" "0"))))
|
(dom-set-style target prop (if (= prop "display") "none" "0"))))
|
||||||
(true
|
(true
|
||||||
(if
|
(if
|
||||||
@@ -102,17 +102,30 @@
|
|||||||
(define
|
(define
|
||||||
hs-take!
|
hs-take!
|
||||||
(fn
|
(fn
|
||||||
(target kind name scope)
|
(target kind name scope &rest extra)
|
||||||
(let
|
(let
|
||||||
((els (if scope (if (list? scope) scope (list scope)) (let ((parent (host-get target "parentNode"))) (if parent (dom-child-list parent) (list))))))
|
((els (if scope (if (list? scope) scope (list scope)) (let ((parent (dom-parent target))) (if parent (dom-child-list parent) (list))))))
|
||||||
(if
|
(if
|
||||||
(= kind "class")
|
(= kind "class")
|
||||||
(do
|
(do
|
||||||
(for-each (fn (el) (dom-remove-class el name)) els)
|
(for-each (fn (el) (dom-remove-class el name)) els)
|
||||||
(dom-add-class target name))
|
(dom-add-class target name))
|
||||||
(do
|
(let
|
||||||
(for-each (fn (el) (dom-remove-attr el name)) els)
|
((attr-val (if (> (len extra) 0) (first extra) nil))
|
||||||
(dom-set-attr target name "true"))))))
|
(with-val (if (> (len extra) 1) (nth extra 1) nil)))
|
||||||
|
(do
|
||||||
|
(for-each
|
||||||
|
(fn
|
||||||
|
(el)
|
||||||
|
(if
|
||||||
|
with-val
|
||||||
|
(dom-set-attr el name with-val)
|
||||||
|
(dom-remove-attr el name)))
|
||||||
|
els)
|
||||||
|
(if
|
||||||
|
attr-val
|
||||||
|
(dom-set-attr target name attr-val)
|
||||||
|
(dom-set-attr target name ""))))))))
|
||||||
|
|
||||||
;; Find next sibling matching a selector (or any sibling).
|
;; Find next sibling matching a selector (or any sibling).
|
||||||
(define
|
(define
|
||||||
@@ -204,7 +217,9 @@
|
|||||||
|
|
||||||
;; Fetch a URL, parse response according to format.
|
;; Fetch a URL, parse response according to format.
|
||||||
;; (hs-fetch url format) — format is "json" | "text" | "html"
|
;; (hs-fetch url format) — format is "json" | "text" | "html"
|
||||||
(define hs-query-all (fn (sel) (dom-query-all (dom-body) sel)))
|
(define
|
||||||
|
hs-query-all
|
||||||
|
(fn (sel) (host-call (dom-body) "querySelectorAll" sel)))
|
||||||
|
|
||||||
;; ── Type coercion ───────────────────────────────────────────────
|
;; ── Type coercion ───────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -287,32 +302,75 @@
|
|||||||
((= type-name "Float") (+ value 0))
|
((= type-name "Float") (+ value 0))
|
||||||
((= type-name "Number") (+ value 0))
|
((= type-name "Number") (+ value 0))
|
||||||
((= type-name "String") (str value))
|
((= type-name "String") (str value))
|
||||||
((= type-name "Bool") (if value true false))
|
((= type-name "Bool") (not (hs-falsy? value)))
|
||||||
((= type-name "Boolean") (if value true false))
|
((= type-name "Boolean") (not (hs-falsy? value)))
|
||||||
((= type-name "Array") (if (list? value) value (list value)))
|
((= type-name "Array") (if (list? value) value (list value)))
|
||||||
((= type-name "JSON") (str value))
|
((= type-name "HTML") (str value))
|
||||||
((= type-name "Object") (if (string? value) value value))
|
((= type-name "JSON")
|
||||||
((or (= type-name "Fixed") (string-contains? type-name "Fixed:"))
|
(if
|
||||||
|
(string? value)
|
||||||
|
value
|
||||||
|
(host-call (host-global "JSON") "stringify" value)))
|
||||||
|
((= type-name "Object")
|
||||||
|
(if
|
||||||
|
(string? value)
|
||||||
|
(host-call (host-global "JSON") "parse" value)
|
||||||
|
value))
|
||||||
|
((or (= type-name "Fixed") (= type-name "Fixed:"))
|
||||||
(let
|
(let
|
||||||
((digits (if (string-contains? type-name ":") (parse-number (nth (split type-name ":") 1)) 0))
|
((digits (if (> (string-length type-name) 6) (+ (substring type-name 6 (string-length type-name)) 0) 0))
|
||||||
(num (+ value 0)))
|
(num (+ value 0)))
|
||||||
(if
|
(if
|
||||||
(= digits 0)
|
(= digits 0)
|
||||||
(str (floor num))
|
(str (floor num))
|
||||||
(let
|
(let
|
||||||
((factor (reduce (fn (acc _) (* acc 10)) 1 (range 0 digits))))
|
((factor (** 10 digits)))
|
||||||
(let
|
(str (/ (floor (+ (* num factor) 0.5)) factor))))))
|
||||||
((rounded (/ (floor (+ (* num factor) 0.5)) factor)))
|
((= type-name "Selector") (str value))
|
||||||
(str rounded))))))
|
((= type-name "Fragment") value)
|
||||||
((= type-name "HTML") (str value))
|
((= type-name "Values")
|
||||||
((= type-name "Values") value)
|
(if
|
||||||
((= type-name "Fragment") (str value))
|
(dict? value)
|
||||||
((= type-name "Date") (str value))
|
(map (fn (k) (get value k)) (keys value))
|
||||||
|
value))
|
||||||
|
((= type-name "Keys") (if (dict? value) (keys value) value))
|
||||||
|
((= type-name "Entries")
|
||||||
|
(if
|
||||||
|
(dict? value)
|
||||||
|
(map (fn (k) (list k (get value k))) (keys value))
|
||||||
|
value))
|
||||||
|
((= type-name "Reversed") (if (list? value) (reverse value) value))
|
||||||
|
((= type-name "Unique")
|
||||||
|
(if
|
||||||
|
(list? value)
|
||||||
|
(reduce
|
||||||
|
(fn
|
||||||
|
(acc x)
|
||||||
|
(if (some (fn (a) (= a x)) acc) acc (append acc (list x))))
|
||||||
|
(list)
|
||||||
|
value)
|
||||||
|
value))
|
||||||
|
((or (= type-name "Flattened") (= type-name "Flat"))
|
||||||
|
(if
|
||||||
|
(list? value)
|
||||||
|
(reduce
|
||||||
|
(fn
|
||||||
|
(acc x)
|
||||||
|
(if (list? x) (append acc x) (append acc (list x))))
|
||||||
|
(list)
|
||||||
|
value)
|
||||||
|
value))
|
||||||
(true value))))
|
(true value))))
|
||||||
|
|
||||||
(define
|
(define
|
||||||
hs-add
|
hs-add
|
||||||
(fn (a b) (if (or (string? a) (string? b)) (str a b) (+ a b))))
|
(fn
|
||||||
|
(a b)
|
||||||
|
(cond
|
||||||
|
((list? a) (if (list? b) (append a b) (append a (list b))))
|
||||||
|
((list? b) (cons a b))
|
||||||
|
((or (string? a) (string? b)) (str a b))
|
||||||
|
(true (+ a b)))))
|
||||||
|
|
||||||
(define
|
(define
|
||||||
hs-make
|
hs-make
|
||||||
@@ -371,7 +429,12 @@
|
|||||||
((= type-name "Boolean") (or (= value true) (= value false)))
|
((= type-name "Boolean") (or (= value true) (= value false)))
|
||||||
((= type-name "Array") (list? value))
|
((= type-name "Array") (list? value))
|
||||||
((= type-name "Object") (dict? value))
|
((= type-name "Object") (dict? value))
|
||||||
(true true)))))
|
((= type-name "Element") (= (host-typeof value) "element"))
|
||||||
|
((= type-name "Node")
|
||||||
|
(or
|
||||||
|
(= (host-typeof value) "element")
|
||||||
|
(= (host-typeof value) "text")))
|
||||||
|
(true (= (host-typeof value) (downcase type-name)))))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -388,6 +451,22 @@
|
|||||||
(fn (a b) (and (= (type-of a) (type-of b)) (= a b))))
|
(fn (a b) (and (= (type-of a) (type-of b)) (= a b))))
|
||||||
;; ── Sandbox/test runtime additions ──────────────────────────────
|
;; ── Sandbox/test runtime additions ──────────────────────────────
|
||||||
;; Property access — dot notation and .length
|
;; Property access — dot notation and .length
|
||||||
|
(define
|
||||||
|
hs-eq-ignore-case
|
||||||
|
(fn (a b) (= (downcase (str a)) (downcase (str b)))))
|
||||||
|
;; DOM query stub — sandbox returns empty list
|
||||||
|
(define
|
||||||
|
hs-starts-with-ic?
|
||||||
|
(fn (str prefix) (starts-with? (downcase str) (downcase prefix))))
|
||||||
|
;; Method dispatch — obj.method(args)
|
||||||
|
(define
|
||||||
|
hs-contains-ignore-case?
|
||||||
|
(fn
|
||||||
|
(haystack needle)
|
||||||
|
(contains? (downcase (str haystack)) (downcase (str needle)))))
|
||||||
|
|
||||||
|
;; ── 0.9.90 features ─────────────────────────────────────────────
|
||||||
|
;; beep! — debug logging, returns value unchanged
|
||||||
(define
|
(define
|
||||||
hs-falsy?
|
hs-falsy?
|
||||||
(fn
|
(fn
|
||||||
@@ -399,16 +478,18 @@
|
|||||||
((and (list? v) (= (len v) 0)) true)
|
((and (list? v) (= (len v) 0)) true)
|
||||||
((= v 0) true)
|
((= v 0) true)
|
||||||
(true false))))
|
(true false))))
|
||||||
;; DOM query stub — sandbox returns empty list
|
;; Property-based is — check obj.key truthiness
|
||||||
(define
|
(define
|
||||||
hs-matches?
|
hs-matches?
|
||||||
(fn
|
(fn
|
||||||
(target pattern)
|
(target pattern)
|
||||||
(if
|
(cond
|
||||||
(string? target)
|
((string? target)
|
||||||
(if (= pattern ".*") true (string-contains? target pattern))
|
(if (= pattern ".*") true (string-contains? target pattern)))
|
||||||
false)))
|
((= (host-typeof target) "element")
|
||||||
;; Method dispatch — obj.method(args)
|
(if (string? pattern) (host-call target "matches" pattern) false))
|
||||||
|
(true false))))
|
||||||
|
;; Array slicing (inclusive both ends)
|
||||||
(define
|
(define
|
||||||
hs-contains?
|
hs-contains?
|
||||||
(fn
|
(fn
|
||||||
@@ -428,11 +509,9 @@
|
|||||||
true
|
true
|
||||||
(hs-contains? (rest collection) item)))))
|
(hs-contains? (rest collection) item)))))
|
||||||
(true false))))
|
(true false))))
|
||||||
|
;; Collection: sorted by
|
||||||
;; ── 0.9.90 features ─────────────────────────────────────────────
|
|
||||||
;; beep! — debug logging, returns value unchanged
|
|
||||||
(define precedes? (fn (a b) (< (str a) (str b))))
|
(define precedes? (fn (a b) (< (str a) (str b))))
|
||||||
;; Property-based is — check obj.key truthiness
|
;; Collection: sorted by descending
|
||||||
(define
|
(define
|
||||||
hs-empty?
|
hs-empty?
|
||||||
(fn
|
(fn
|
||||||
@@ -443,7 +522,7 @@
|
|||||||
((list? v) (= (len v) 0))
|
((list? v) (= (len v) 0))
|
||||||
((dict? v) (= (len (keys v)) 0))
|
((dict? v) (= (len (keys v)) 0))
|
||||||
(true false))))
|
(true false))))
|
||||||
;; Array slicing (inclusive both ends)
|
;; Collection: split by
|
||||||
(define
|
(define
|
||||||
hs-empty-target!
|
hs-empty-target!
|
||||||
(fn
|
(fn
|
||||||
@@ -464,11 +543,61 @@
|
|||||||
(dom-set-prop target "value" ""))))
|
(dom-set-prop target "value" ""))))
|
||||||
((= tag "FORM") (dom-set-inner-html target ""))
|
((= tag "FORM") (dom-set-inner-html target ""))
|
||||||
(true (dom-set-inner-html target ""))))))))
|
(true (dom-set-inner-html target ""))))))))
|
||||||
;; Collection: sorted by
|
;; Collection: joined by
|
||||||
|
(define
|
||||||
|
hs-open!
|
||||||
|
(fn
|
||||||
|
(el)
|
||||||
|
(let
|
||||||
|
((tag (dom-get-prop el "tagName")))
|
||||||
|
(if
|
||||||
|
(= tag "DIALOG")
|
||||||
|
(host-call el "showModal")
|
||||||
|
(dom-set-prop el "open" true)))))
|
||||||
|
|
||||||
|
(define
|
||||||
|
hs-close!
|
||||||
|
(fn
|
||||||
|
(el)
|
||||||
|
(let
|
||||||
|
((tag (dom-get-prop el "tagName")))
|
||||||
|
(if
|
||||||
|
(= tag "DIALOG")
|
||||||
|
(host-call el "close")
|
||||||
|
(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"))))))
|
||||||
|
|
||||||
|
(define
|
||||||
|
hs-show!
|
||||||
|
(fn
|
||||||
|
(el strategy)
|
||||||
|
(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" ""))))))
|
||||||
|
|
||||||
(define hs-first (fn (lst) (first lst)))
|
(define hs-first (fn (lst) (first lst)))
|
||||||
;; Collection: sorted by descending
|
|
||||||
(define hs-last (fn (lst) (last lst)))
|
(define hs-last (fn (lst) (last lst)))
|
||||||
;; Collection: split by
|
|
||||||
(define
|
(define
|
||||||
hs-template
|
hs-template
|
||||||
(fn
|
(fn
|
||||||
@@ -554,7 +683,7 @@
|
|||||||
(set! i (+ i 1))
|
(set! i (+ i 1))
|
||||||
(tpl-loop)))))))
|
(tpl-loop)))))))
|
||||||
(do (tpl-loop) result))))
|
(do (tpl-loop) result))))
|
||||||
;; Collection: joined by
|
|
||||||
(define
|
(define
|
||||||
hs-make-object
|
hs-make-object
|
||||||
(fn
|
(fn
|
||||||
|
|||||||
@@ -21,8 +21,9 @@ function setStepLimit(n) { K.setStepLimit(n); }
|
|||||||
function resetStepCount() { K.resetStepCount(); }
|
function resetStepCount() { K.resetStepCount(); }
|
||||||
|
|
||||||
// ─── DOM mock ──────────────────────────────────────────────────
|
// ─── DOM mock ──────────────────────────────────────────────────
|
||||||
|
function mkStyle() { const s={}; s.setProperty=function(p,v){s[p]=v;}; s.getPropertyValue=function(p){return s[p]||'';}; s.removeProperty=function(p){delete s[p];}; return s; }
|
||||||
class El {
|
class El {
|
||||||
constructor(t) { this.tagName=t.toUpperCase(); this.nodeName=this.tagName; this.nodeType=1; this.id=''; this.className=''; this.classList=new CL(this); this.style={}; this.attributes={}; this.children=[]; this.childNodes=[]; this.parentElement=null; this.parentNode=null; this.textContent=''; this.innerHTML=''; this._listeners={}; this.dataset={}; this.open=false; this.value=''; this.checked=false; this.disabled=false; this.type=''; this.name=''; this.selectedIndex=-1; this.options=[]; }
|
constructor(t) { this.tagName=t.toUpperCase(); this.nodeName=this.tagName; this.nodeType=1; this.id=''; this.className=''; this.classList=new CL(this); this.style=mkStyle(); this.attributes={}; this.children=[]; this.childNodes=[]; this.parentElement=null; this.parentNode=null; this.textContent=''; this.innerHTML=''; this._listeners={}; this.dataset={}; this.open=false; this.value=''; this.checked=false; this.disabled=false; this.type=''; this.name=''; this.selectedIndex=-1; this.options=[]; }
|
||||||
setAttribute(n,v) { this.attributes[n]=String(v); if(n==='id')this.id=v; if(n==='class'){this.className=v;this.classList._sync(v);} if(n==='value')this.value=v; if(n==='disabled')this.disabled=true; }
|
setAttribute(n,v) { this.attributes[n]=String(v); if(n==='id')this.id=v; if(n==='class'){this.className=v;this.classList._sync(v);} if(n==='value')this.value=v; if(n==='disabled')this.disabled=true; }
|
||||||
getAttribute(n) { return this.attributes[n]!==undefined?this.attributes[n]:null; }
|
getAttribute(n) { return this.attributes[n]!==undefined?this.attributes[n]:null; }
|
||||||
removeAttribute(n) { delete this.attributes[n]; if(n==='disabled')this.disabled=false; }
|
removeAttribute(n) { delete this.attributes[n]; if(n==='disabled')this.disabled=false; }
|
||||||
@@ -39,7 +40,7 @@ class El {
|
|||||||
closest(s) { let e=this; while(e){if(mt(e,s))return e; e=e.parentElement;} return null; }
|
closest(s) { let e=this; while(e){if(mt(e,s))return e; e=e.parentElement;} return null; }
|
||||||
matches(s) { return mt(this,s); }
|
matches(s) { return mt(this,s); }
|
||||||
contains(o) { if(o===this)return true; for(const c of this.children)if(c===o||c.contains(o))return true; return false; }
|
contains(o) { if(o===this)return true; for(const c of this.children)if(c===o||c.contains(o))return true; return false; }
|
||||||
cloneNode(d) { const e=new El(this.tagName.toLowerCase()); Object.assign(e.attributes,this.attributes); e.id=this.id; e.className=this.className; e.classList._sync(this.className); Object.assign(e.style,this.style); e.textContent=this.textContent; e.innerHTML=this.innerHTML; e.value=this.value; if(d)for(const c of this.children)e.appendChild(c.cloneNode(true)); return e; }
|
cloneNode(d) { const e=new El(this.tagName.toLowerCase()); Object.assign(e.attributes,this.attributes); e.id=this.id; e.className=this.className; e.classList._sync(this.className); for(const k of Object.keys(this.style)){if(typeof this.style[k]!=='function')e.style[k]=this.style[k];} e.textContent=this.textContent; e.innerHTML=this.innerHTML; e.value=this.value; if(d)for(const c of this.children)e.appendChild(c.cloneNode(true)); return e; }
|
||||||
focus(){} blur(){} click(){this.dispatchEvent(new Ev('click',{bubbles:true}));} remove(){if(this.parentElement)this.parentElement.removeChild(this);}
|
focus(){} blur(){} click(){this.dispatchEvent(new Ev('click',{bubbles:true}));} remove(){if(this.parentElement)this.parentElement.removeChild(this);}
|
||||||
_syncText() {
|
_syncText() {
|
||||||
// Sync textContent from children
|
// Sync textContent from children
|
||||||
@@ -149,7 +150,7 @@ function mt(e,s) {
|
|||||||
return e.tagName.toLowerCase() === s.toLowerCase();
|
return e.tagName.toLowerCase() === s.toLowerCase();
|
||||||
}
|
}
|
||||||
function fnd(e,s) { for(const c of(e.children||[])){if(mt(c,s))return c;const f=fnd(c,s);if(f)return f;} return null; }
|
function fnd(e,s) { for(const c of(e.children||[])){if(mt(c,s))return c;const f=fnd(c,s);if(f)return f;} return null; }
|
||||||
function fndAll(e,s) { const r=[];for(const c of(e.children||[])){if(mt(c,s))r.push(c);r.push(...fndAll(c,s));}return r; }
|
function fndAll(e,s) { const r=[];for(const c of(e.children||[])){if(mt(c,s))r.push(c);r.push(...fndAll(c,s));}r.item=function(i){return r[i]||null;};return r; }
|
||||||
|
|
||||||
const _body = new El('body');
|
const _body = new El('body');
|
||||||
const _html = new El('html');
|
const _html = new El('html');
|
||||||
|
|||||||
Reference in New Issue
Block a user