git.iko.soy/rowtype-yoga/purescript-yoga-json
on main help sign in
Fix variant branch decoding and release v5.2.2
commit0581d65eee9f7dc9e39cff149739f9992b9d7dfd authorMark <mark.eibes@gmail.com> dateSun 27 Sep 2026, 16:38 (2 weeks ago) parent1b638bd
4 files changed+35−7
unifiedsplit
CHANGELOG.md+4 spago.yaml+1−1 src/Yoga/JSON.purs+7−4 test/BasicsSpec.purs+23−2
CHANGELOG.md+4
@@ -1,5 +1,9 @@
11# Changelog
22
3+## v5.2.2
4+
5+- Fix variant decoding selecting absent branches whose payload decoders accept missing values, such as empty records and `Maybe`. Branches now require an own property matching their label.
6+
37## v4.0.1
48
59- Allow the type of `read*` functions to be visibly applied (#24 by @postsolar)
spago.yaml+1−1
@@ -42,7 +42,7 @@ package:
4242 - strings-extra
4343
4444 publish:
45− version: 5.2.1
45+ version: 5.2.2
4646 license: MIT
4747 location:
4848 githubOwner: rowtype-yoga
src/Yoga/JSON.purs+7−4
@@ -68,7 +68,7 @@ import Effect.Exception (message, try)
6868import Effect.Uncurried as EU
6969import Effect.Unsafe (unsafePerformEffect)
7070import Foreign (F, Foreign, ForeignError(..), MultipleErrors, fail, isNull, isUndefined, readArray, readBoolean, readChar, readInt, readNull, readNumber, readString, tagOf, unsafeFromForeign, unsafeReadTagged, unsafeToForeign)
71−import Foreign.Index (readProp)
71+import Foreign.Index (hasOwnProperty, readProp)
7272import Foreign.Object (Object)
7373import Foreign.Object as Object
7474import JS.BigInt (BigInt)
@@ -403,10 +403,13 @@ instance
403403 , ReadForeignVariant tail row
404404 ) ⇒
405405 ReadForeignVariant (Cons name ty tail) row where
406− readVariantImpl _ o = readVariantImpl (Proxy ∷ Proxy tail) o <|> ado
407− value ∷ ty ← readProp name o >>= readImpl
408− in inj namep value
406+ readVariantImpl _ o =
407+ if hasOwnProperty @String @Identity name o then rest <|> ado
408+ value ∷ ty ← readProp name o >>= readImpl
409+ in inj namep value
410+ else rest
409411 where
412+ rest = readVariantImpl (Proxy ∷ Proxy tail) o
410413 namep = Proxy ∷ Proxy name
411414 name = reflectSymbol namep
412415
test/BasicsSpec.purs+23−2
@@ -3,7 +3,7 @@ module Test.BasicsSpec where
33import Prelude
44
55import Data.Array.NonEmpty as NEA
6−import Data.Either (Either(..))
6+import Data.Either (Either(..), isLeft)
77import Data.Foldable (traverse_)
88import Data.JSDate as JSDate
99import Data.List as List
@@ -144,9 +144,30 @@ spec = describe "En- and decoding" do
144144
145145 describe "works on variant types" do
146146 it "roundtrips" do
147− roundtrips (inj (Proxy ∷ _ "erwin") "e" ∷ Variant ("erwin" ∷ String))
147+ let input = inj (Proxy ∷ _ "a") {} ∷ Variant (a ∷ {}, b ∷ {})
148+ let asJSON = writeJSON input
149+ readJSON asJSON `shouldEqual` Right input
150+
151+ let input2 = inj (Proxy ∷ _ "b") {} ∷ Variant (a ∷ {}, b ∷ {})
152+ let asJSON2 = writeJSON input2
153+ readJSON asJSON2 `shouldEqual` Right input2
154+
155+ roundtrips (inj (Proxy ∷ _ "erwin") "e" ∷ Variant (erwin ∷ String))
148156 roundtrips (inj (Proxy ∷ _ "jackie") 7 ∷ Variant ExampleVariant)
149157
158+ it "does not select an absent optional branch" do
159+ let expected = inj (Proxy ∷ _ "a") 42 ∷ Variant (a ∷ Int, b ∷ Maybe Int)
160+ readJSON """{"a":42}""" `shouldEqual` Right expected
161+
162+ it "accepts an explicitly null optional branch" do
163+ let expected = inj (Proxy ∷ _ "b") Nothing ∷ Variant (a ∷ Int, b ∷ Maybe Int)
164+ readJSON """{"b":null}""" `shouldEqual` Right expected
165+
166+ it "rejects objects without a matching variant key" do
167+ traverse_
168+ (\json → isLeft (readJSON json ∷ _ (Variant (a ∷ {}, b ∷ {}))) `shouldEqual` true)
169+ [ "{}", """{"unknown":{}}""" ]
170+
150171 describe "works on tagged variant types" do
151172 it "roundtrips" do
152173 roundtrips (TaggedVariant (erwin "e") ∷ TaggedVariant "super" "hans" (Erwin ()))