diff --git a/src/jolt/core.janet b/src/jolt/core.janet index 71c3b26..fa78e65 100644 --- a/src/jolt/core.janet +++ b/src/jolt/core.janet @@ -204,7 +204,12 @@ (defn core-fn? [x] (or (function? x) (cfunction? x))) (defn core-keyword? [x] (keyword? x)) (defn core-symbol? [x] (and (struct? x) (= :symbol (x :jolt/type)))) -(defn core-vector? [x] (jvec? x)) +# A record shape-rec is a Janet tuple (jvec? true), but a record is NOT a vector +# in Clojure — `(vector? record)` is false, and so is `(sequential? record)`. +# Excluding it here keeps map-destructuring of a record off the `& {:keys}` kwargs +# coerce path (which does `(apply hash-map x)` for a sequential x). jvec? itself +# stays as-is for internal representation dispatch. +(defn core-vector? [x] (and (jvec? x) (not (shape-rec? x)))) # map? is STRICT: a plain struct map literal, a phm, a sorted map, or a record. # Tagged structs (symbols/chars/uuids — anything with :jolt/type) are VALUES, # not maps. (sorted-map? is defined later, so the table check is inlined.) diff --git a/test/integration/record-declared-shape-test.janet b/test/integration/record-declared-shape-test.janet index 5171f47..7d0cf30 100644 --- a/test/integration/record-declared-shape-test.janet +++ b/test/integration/record-declared-shape-test.janet @@ -29,7 +29,13 @@ ["record? true" "(do (defrecord Rd [x y]) (record? (->Rd 1 2)))"] ["record vs map not=" "(do (defrecord Re [x y]) (not (= (->Re 1 2) {:x 1 :y 2})))"] ["assoc keeps type" "(do (defrecord Rf [x y]) (record? (assoc (->Rf 1 2) :x 9)))"] - ["pr declared order" "(do (defrecord Rg [b a c]) (= \"#user.Rg{:b 10, :a 20, :c 30}\" (pr-str (->Rg 10 20 30))))"]]) + ["pr declared order" "(do (defrecord Rg [b a c]) (= \"#user.Rg{:b 10, :a 20, :c 30}\" (pr-str (->Rg 10 20 30))))"] + # a record shape-rec is a Janet tuple, but a record is NOT a vector/sequential + # in Clojure — else map-destructuring it takes the kwargs coerce path and + # corrupts (reitit router crash, jolt-14k). + ["vector? record false" "(do (defrecord Rh [x y]) (not (vector? (->Rh 1 2))))"] + ["sequential? record false" "(do (defrecord Ri [x y]) (not (sequential? (->Ri 1 2))))"] + ["destructure record :or" "(do (defrecord Rj [a b c d e]) (let [{:keys [a e] :or {a 0}} (->Rj 1 2 3 4 5)] (= 6 (+ a e))))"]]) (each [label prog] cases (check label (eval-string dl prog) true))