HS parser/compiler/mock: fix put positions, add CSS properties

Parser:
- Skip optional "the" in "at the start/end of" put targets
- Handle "style" token type in parse-add-cmd for *prop:value syntax

Compiler:
- Add set-style dispatch → dom-set-style for CSS property additions

Mock DOM:
- Position-aware insertAdjacentHTML: afterbegin prepends, beforeend appends
- Sync textContent after insertAdjacentHTML mutations

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-18 20:55:58 +00:00
parent be84246961
commit 5a0740d3ce
3 changed files with 87 additions and 53 deletions

View File

@@ -1985,12 +1985,26 @@ let run_spec_tests env test_files =
Hashtbl.replace r "right" (Number 100.0); Hashtbl.replace r "bottom" (Number 100.0); Hashtbl.replace r "right" (Number 100.0); Hashtbl.replace r "bottom" (Number 100.0);
Dict r Dict r
| "insertAdjacentHTML" -> | "insertAdjacentHTML" ->
(* Simplified: coerce value to string and append to innerHTML *) (* Position-aware insertion, coerce value to string *)
(match rest with (match rest with
| [String _pos; value] -> | [String pos; value] ->
let html = match dom_stringify value with String s -> s | _ -> "" in let html = match dom_stringify value with String s -> s | _ -> "" in
let cur = match Hashtbl.find_opt d "innerHTML" with Some (String s) -> s | _ -> "" in let cur = match Hashtbl.find_opt d "innerHTML" with Some (String s) -> s | _ -> "" in
Hashtbl.replace d "innerHTML" (String (cur ^ html)); Nil let new_html = match pos with
| "afterbegin" -> html ^ cur (* prepend *)
| _ -> cur ^ html (* beforeend / default: append *)
in
Hashtbl.replace d "innerHTML" (String new_html);
(* Sync textContent *)
let buf = Buffer.create (String.length new_html) in
let in_tag = ref false in
String.iter (fun c ->
if c = '<' then in_tag := true
else if c = '>' then in_tag := false
else if not !in_tag then Buffer.add_char buf c
) new_html;
Hashtbl.replace d "textContent" (String (Buffer.contents buf));
Nil
| _ -> Nil) | _ -> Nil)
| "showModal" | "show" -> | "showModal" | "show" ->
Hashtbl.replace d "open" (Bool true); Hashtbl.replace d "open" (Bool true);

View File

@@ -856,6 +856,12 @@
(quote dom-add-class) (quote dom-add-class)
(hs-to-sx raw-tgt) (hs-to-sx raw-tgt)
(nth ast 1))))) (nth ast 1)))))
((= head (quote set-style))
(list
(quote dom-set-style)
(hs-to-sx (nth ast 3))
(nth ast 1)
(nth ast 2)))
((= head (quote multi-add-class)) ((= head (quote multi-add-class))
(let (let
((target (hs-to-sx (nth ast 1))) ((target (hs-to-sx (nth ast 1)))

View File

@@ -775,50 +775,62 @@
parse-add-cmd parse-add-cmd
(fn (fn
() ()
(if (cond
(= (tp-type) "class") ((= (tp-type) "class")
(let
((cls (get (adv!) "value")) (extra-classes (list)))
(define
collect-classes!
(fn
()
(when
(= (tp-type) "class")
(set!
extra-classes
(append extra-classes (list (get (adv!) "value"))))
(collect-classes!))))
(collect-classes!)
(let (let
((tgt (parse-tgt-kw "to" (list (quote me))))) ((cls (get (adv!) "value")) (extra-classes (list)))
(define
collect-classes!
(fn
()
(when
(= (tp-type) "class")
(set!
extra-classes
(append extra-classes (list (get (adv!) "value"))))
(collect-classes!))))
(collect-classes!)
(let (let
((when-clause (if (match-kw "when") (parse-expr) nil))) ((tgt (if (match-kw "to") (parse-expr) (list (quote me)))))
(if (let
(empty? extra-classes) ((when-clause (if (match-kw "when") (parse-expr) nil)))
(if (if
when-clause (empty? extra-classes)
(list (quote add-class-when) cls tgt when-clause) (if
(list (quote add-class) cls tgt))
(if
when-clause
(list
(quote multi-add-class-when)
tgt
when-clause when-clause
cls (list (quote add-class-when) cls tgt when-clause)
extra-classes) (list (quote add-class) cls tgt))
(cons (if
(quote multi-add-class) when-clause
(cons tgt (cons cls extra-classes)))))))) (list
(let (quote multi-add-class-when)
((value (parse-expr))) tgt
(if when-clause
(match-kw "to") cls
extra-classes)
(cons
(quote multi-add-class)
(cons tgt (cons cls extra-classes)))))))))
((= (tp-type) "style")
(let
((prop (get (adv!) "value"))
(value
(if
(= (tp-type) "local")
(get (adv!) "value")
(parse-expr))))
(let (let
((tgt (parse-expr))) ((tgt (if (match-kw "to") (parse-expr) (list (quote me)))))
(list (quote add-value) value tgt)) (list (quote set-style) prop value tgt))))
nil))))) (true
(let
((value (parse-expr)))
(if
(match-kw "to")
(let
((tgt (parse-expr)))
(list (quote add-value) value tgt))
nil))))))
(define (define
parse-remove-cmd parse-remove-cmd
(fn (fn
@@ -1050,17 +1062,19 @@
((match-kw "after") ((match-kw "after")
(list (quote put!) value "after" (parse-expr))) (list (quote put!) value "after" (parse-expr)))
((match-kw "at") ((match-kw "at")
(cond (do
((match-kw "start") (match-kw "the")
(do (cond
(expect-kw! "of") ((match-kw "start")
(list (quote put!) value "start" (parse-expr)))) (do
((match-kw "end") (expect-kw! "of")
(do (list (quote put!) value "start" (parse-expr))))
(expect-kw! "of") ((match-kw "end")
(list (quote put!) value "end" (parse-expr)))) (do
(true (expect-kw! "of")
(error (str "Expected start/end after at, position " p))))) (list (quote put!) value "end" (parse-expr))))
(true
(error (str "Expected start/end after at, position " p))))))
(true (true
(error (str "Expected into/before/after/at at position " p))))))) (error (str "Expected into/before/after/at at position " p)))))))
(define (define