@@ -41,13 +41,14 @@ import Data.Array.NonEmpty (NonEmptyArray, fromArray, toArray)
41import Data.Bifunctor (lmap)
41import Data.Bifunctor (lmap)
42import Data.BigInt (BigInt)
42import Data.BigInt (BigInt)
43import Data.BigInt as BigInt
43import Data.BigInt as BigInt
44−import Data.DateTime (DateTime(..))
44+import Data.DateTime (DateTime)
45−import Data.DateTime as DateTime
46−import Data.Either (Either(..), either, hush, note)
45+import Data.Either (Either(..), hush, note)
46+import Data.Foldable (class Foldable, foldl)
47import Data.FoldableWithIndex (foldrWithIndex)
47import Data.FoldableWithIndex (foldrWithIndex)
48+import Data.FunctorWithIndex (mapWithIndex)
48import Data.Identity (Identity(..))
49import Data.Identity (Identity(..))
49import Data.Int as Int
50import Data.Int as Int
50−import Data.JSDate (JSDate, toISOString)
51+import Data.JSDate (JSDate)
51import Data.JSDate as JSDate
52import Data.JSDate as JSDate
52import Data.List.NonEmpty (NonEmptyList, singleton)
53import Data.List.NonEmpty (NonEmptyList, singleton)
53import Data.Map (Map)
54import Data.Map (Map)
@@ -57,8 +58,7 @@ import Data.Newtype (class Newtype)
57import Data.Nullable (Nullable, toMaybe, toNullable)
58import Data.Nullable (Nullable, toMaybe, toNullable)
58import Data.Number as Number
59import Data.Number as Number
59import Data.Symbol (class IsSymbol, reflectSymbol)
60import Data.Symbol (class IsSymbol, reflectSymbol)
60−import Data.Traversable (sequence, traverse)
61+import Data.Traversable (traverse)
61−import Data.TraversableWithIndex (traverseWithIndex)
62import Data.Tuple (Tuple(..))
62import Data.Tuple (Tuple(..))
63import Data.Variant (Variant, inj, on)
63import Data.Variant (Variant, inj, on)
64import Effect.Exception (message, try)
64import Effect.Exception (message, try)
@@ -216,7 +216,7 @@ instance ReadForeign Boolean where
216 readImpl = readBoolean
216 readImpl = readBoolean
218instance ReadForeign a ⇒ ReadForeign (Array a) where
218instance ReadForeign a ⇒ ReadForeign (Array a) where
219− readImpl = traverseWithIndex readAtIdx <=< readArray
219+ readImpl = sequenceCombining <<< mapWithIndex readAtIdx <=< readArray
221instance ReadForeign a ⇒ ReadForeign (Maybe a) where
221instance ReadForeign a ⇒ ReadForeign (Maybe a) where
222 readImpl = readNullOrUndefined readImpl
222 readImpl = readNullOrUndefined readImpl
@@ -242,8 +242,21 @@ instance (ReadForeign a, ReadForeign b) ⇒ ReadForeign (Either a b) where
242 _ -> except $ Left (pure $ ForeignError $ "Invalid Either tag " <> tpe)
242 _ -> except $ Left (pure $ ForeignError $ "Invalid Either tag " <> tpe)
244instance ReadForeign a ⇒ ReadForeign (Object.Object a) where
244instance ReadForeign a ⇒ ReadForeign (Object.Object a) where
245− readImpl = sequence <<< Object.mapWithKey readProp <=< readObject'
245+ readImpl = gatherErrors <<< Object.mapWithKey readProp <=< readObject'
247+ gatherErrors :: Object (F a) -> F (Object a)
248+ gatherErrors = Object.toUnfoldable
249+ >>> Array.foldl fn (Right (Object.empty))
252+ fn :: _ -> _ -> (Either MultipleErrors (Object a))
253+ fn acc (Tuple k v) = do
254+ case acc, runExcept v of
255+ Left errs, Left errsNew -> Left (errs <> errsNew)
256+ Left errs, Right _ -> Left errs
257+ Right obj, Right value -> Right (Object.insert k value obj)
258+ Right _, Left errs -> Left errs
247 readProp key value = except $ lmap (map (ErrorAtProperty key))
260 readProp key value = except $ lmap (map (ErrorAtProperty key))
248 (readImpl value # runExcept)
261 (readImpl value # runExcept)
@@ -321,16 +334,20 @@ instance
321 , Row.Cons name ty from' to
334 , Row.Cons name ty from' to
323 ReadForeignFields (Cons name ty tail) from to where
336 ReadForeignFields (Cons name ty tail) from to where
324− getFields _ obj = do
337+ getFields _ obj = except
325− compose <$> first <*> rest
338+ case runExcept first, runExcept rest of
339+ Right f, Right r -> Right (f <<< r)
340+ Left e1, Left e2 -> Left (e1 <> e2)
341+ Right _, Left es -> Left es
342+ Left es, Right _ -> Left es
327− value = withExcept' (readImpl =<< readProp name obj)
344+ value = enrichErrorWithPropName (readImpl =<< readProp name obj)
328 first = Builder.insert nameP <$> value
345 first = Builder.insert nameP <$> value
329 rest = getFields tailP obj
346 rest = getFields tailP obj
330 nameP = Proxy ∷ Proxy name
347 nameP = Proxy ∷ Proxy name
331 tailP = Proxy ∷ Proxy tail
348 tailP = Proxy ∷ Proxy tail
332 name = reflectSymbol nameP
349 name = reflectSymbol nameP
333− withExcept' = (withExcept <<< map) (ErrorAtProperty name)
350+ enrichErrorWithPropName = (withExcept <<< map) (ErrorAtProperty name)
335readAtIdx ∷ ∀ a. ReadForeign a ⇒ Int → Foreign → F a
352readAtIdx ∷ ∀ a. ReadForeign a ⇒ Int → Foreign → F a
336readAtIdx i f = withExcept (map (ErrorAtIndex i)) (readImpl f)
353readAtIdx i f = withExcept (map (ErrorAtIndex i)) (readImpl f)
@@ -552,3 +569,18 @@ instance ReadForeign DateTime where
552unsafeStringToInt :: String → Int
569unsafeStringToInt :: String → Int
553unsafeStringToInt = Int.fromString >>>
570unsafeStringToInt = Int.fromString >>>
554 (fromMaybe' \_ -> unsafeCrashWith "impossible")
571 (fromMaybe' \_ -> unsafeCrashWith "impossible")
573+sequenceCombining :: forall f a.
578+sequenceCombining = foldl fn (Right mempty) >>> except
580+ fn :: _ -> _ -> (Either MultipleErrors (f a))
582+ case acc, runExcept elem of
583+ Left errs, Left errsNew -> Left (errs <> errsNew)
584+ Left errs, Right _ -> Left errs
585+ Right values, Right value -> Right (values <> pure value)
586+ Right _, Left errs -> Left errs