HS: Values dict insertion order (+2 tests)

Dict-set! keys iterate in scrambled order, so Values|FormEncoded and
Values|JSONString produced output in the wrong order. Fix: hs-values-absorb
now tracks insertion order in a hidden `_order` list on the dict itself.
hs-coerce FormEncoded/JSONString paths read `_order` when present and
iterate in that order (filtering the marker key out).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-23 21:35:47 +00:00
parent 35c72e2a13
commit e59c0b8e0a
2 changed files with 148 additions and 70 deletions

View File

@@ -794,16 +794,26 @@
((string? v) (hs-json-escape v))
((list? v) (str "[" (join "," (map hs-json-stringify v)) "]"))
((dict? v)
(str
"{"
(join
","
(map
(fn
(k)
(str (hs-json-escape k) ":" (hs-json-stringify (get v k))))
(keys v)))
"}"))
(let
((ks (or (get v "_order") (filter (fn (k) (not (= k "_order"))) (keys v)))))
(str
"{"
(join
","
(filter
(fn (s) (not (= s "")))
(map
(fn
(k)
(if
(= k "_order")
""
(str
(hs-json-escape k)
":"
(hs-json-stringify (get v k)))))
ks)))
"}")))
(true (hs-json-escape (str v))))))
;; Collection: split by
(define
@@ -843,18 +853,25 @@
((= type-name "FormEncoded")
(if
(dict? value)
(join
"&"
(map
(fn
(k)
(let
((v (get value k)))
(if
(list? v)
(join "&" (map (fn (item) (str k "=" item)) v))
(str k "=" v))))
(keys value)))
(let
((ks (or (get value "_order") (filter (fn (k) (not (= k "_order"))) (keys value)))))
(join
"&"
(filter
(fn (s) (not (= s "")))
(map
(fn
(k)
(if
(= k "_order")
""
(let
((v (get value k)))
(if
(list? v)
(join "&" (map (fn (item) (str k "=" item)) v))
(str k "=" v)))))
ks))))
(str value)))
((or (= type-name "Fixed") (= type-name "Fixed:") (starts-with? type-name "Fixed:"))
(let
@@ -932,18 +949,32 @@
(let
((kids (host-get node "children")))
(when
(and (not (nil? kids)) (list? kids))
(let
((n (len kids)))
(define
each
(fn
(i)
(when
(< i n)
(walk (nth kids i))
(each (+ i 1)))))
(each 0)))))))))
(not (nil? kids))
(cond
((list? kids)
(let
((n (len kids)))
(define
each
(fn
(i)
(when
(< i n)
(walk (nth kids i))
(each (+ i 1)))))
(each 0)))
(true
(let
((n (or (host-get kids "length") 0)))
(define
each-h
(fn
(i)
(when
(< i n)
(walk (host-get kids i))
(each-h (+ i 1)))))
(each-h 0)))))))))))
(walk root)
acc)))
@@ -1015,7 +1046,15 @@
(dict-set! acc name (append existing (list v)))
(dict-set! acc name (list existing v)))
acc)))
(true (do (dict-set! acc name v) acc))))))))
(true
(begin
(dict-set! acc name v)
(let
((ord (or (get acc "_order") (list))))
(when
(not (some (fn (x) (= x name)) ord))
(dict-set! acc "_order" (append ord (list name)))))
acc))))))))
(define
hs-as-values

View File

@@ -794,16 +794,26 @@
((string? v) (hs-json-escape v))
((list? v) (str "[" (join "," (map hs-json-stringify v)) "]"))
((dict? v)
(str
"{"
(join
","
(map
(fn
(k)
(str (hs-json-escape k) ":" (hs-json-stringify (get v k))))
(keys v)))
"}"))
(let
((ks (or (get v "_order") (filter (fn (k) (not (= k "_order"))) (keys v)))))
(str
"{"
(join
","
(filter
(fn (s) (not (= s "")))
(map
(fn
(k)
(if
(= k "_order")
""
(str
(hs-json-escape k)
":"
(hs-json-stringify (get v k)))))
ks)))
"}")))
(true (hs-json-escape (str v))))))
;; Collection: split by
(define
@@ -843,18 +853,25 @@
((= type-name "FormEncoded")
(if
(dict? value)
(join
"&"
(map
(fn
(k)
(let
((v (get value k)))
(if
(list? v)
(join "&" (map (fn (item) (str k "=" item)) v))
(str k "=" v))))
(keys value)))
(let
((ks (or (get value "_order") (filter (fn (k) (not (= k "_order"))) (keys value)))))
(join
"&"
(filter
(fn (s) (not (= s "")))
(map
(fn
(k)
(if
(= k "_order")
""
(let
((v (get value k)))
(if
(list? v)
(join "&" (map (fn (item) (str k "=" item)) v))
(str k "=" v)))))
ks))))
(str value)))
((or (= type-name "Fixed") (= type-name "Fixed:") (starts-with? type-name "Fixed:"))
(let
@@ -932,18 +949,32 @@
(let
((kids (host-get node "children")))
(when
(and (not (nil? kids)) (list? kids))
(let
((n (len kids)))
(define
each
(fn
(i)
(when
(< i n)
(walk (nth kids i))
(each (+ i 1)))))
(each 0)))))))))
(not (nil? kids))
(cond
((list? kids)
(let
((n (len kids)))
(define
each
(fn
(i)
(when
(< i n)
(walk (nth kids i))
(each (+ i 1)))))
(each 0)))
(true
(let
((n (or (host-get kids "length") 0)))
(define
each-h
(fn
(i)
(when
(< i n)
(walk (host-get kids i))
(each-h (+ i 1)))))
(each-h 0)))))))))))
(walk root)
acc)))
@@ -1015,7 +1046,15 @@
(dict-set! acc name (append existing (list v)))
(dict-set! acc name (list existing v)))
acc)))
(true (do (dict-set! acc name v) acc))))))))
(true
(begin
(dict-set! acc name v)
(let
((ord (or (get acc "_order") (list))))
(when
(not (some (fn (x) (= x name)) ord))
(dict-set! acc "_order" (append ord (list name)))))
acc))))))))
(define
hs-as-values