@@ -11,7 +11,6 @@ module Yoga.JSON
11 , parseJSON
11 , parseJSON
12 , undefined
12 , undefined
13 , unsafeStringify
13 , unsafeStringify
15 , class ReadForeign
14 , class ReadForeign
16 , readImpl
15 , readImpl
17 , class ReadForeignFields
16 , class ReadForeignFields
@@ -21,25 +20,25 @@ module Yoga.JSON
21 , class ReadTuple
20 , class ReadTuple
22 , readTupleImpl
21 , readTupleImpl
23 , tupleSize
22 , tupleSize
25 , class WriteForeign
23 , class WriteForeign
26 , writeImpl
24 , writeImpl
27 , class WriteForeignFields
25 , class WriteForeignFields
28 , writeImplFields
26 , writeImplFields
29 , class WriteForeignVariant
27 , class WriteForeignVariant
30 , writeVariantImpl
28 , writeVariantImpl
34import Prelude
31import Prelude
36import Control.Alt ((<|>))
33import Control.Alt ((<|>))
37import Control.Apply (lift2)
34import Control.Apply (lift2)
35+import Control.Comonad.Cofree as Cofree
38import Control.Monad.Except (ExceptT(..), except, runExcept, throwError, withExcept)
36import Control.Monad.Except (ExceptT(..), except, runExcept, throwError, withExcept)
39import Data.Array as Array
37import Data.Array as Array
40import Data.Array.NonEmpty (NonEmptyArray, fromArray, toArray)
38import Data.Array.NonEmpty (NonEmptyArray, fromArray, toArray)
41import Data.Bifunctor (lmap)
39import Data.Bifunctor (lmap)
42import Data.DateTime (DateTime)
40import Data.DateTime (DateTime)
41+import Data.DateTime.Instant (Instant, instant, unInstant)
43import Data.Either (Either(..), hush, note)
42import Data.Either (Either(..), hush, note)
44import Data.Foldable (class Foldable, foldl)
43import Data.Foldable (class Foldable, foldl)
45import Data.FoldableWithIndex (foldrWithIndex)
44import Data.FoldableWithIndex (foldrWithIndex)
@@ -52,12 +51,13 @@ import Data.List.NonEmpty (NonEmptyList, singleton)
52import Data.Map (Map)
51import Data.Map (Map)
53import Data.Map as Map
52import Data.Map as Map
54import Data.Maybe (Maybe(..), fromMaybe, fromMaybe', maybe)
53import Data.Maybe (Maybe(..), fromMaybe, fromMaybe', maybe)
55−import Data.Newtype (class Newtype)
54+import Data.Newtype (class Newtype, unwrap, wrap)
56import Data.Nullable (Nullable, toMaybe, toNullable)
55import Data.Nullable (Nullable, toMaybe, toNullable)
57import Data.Number as Number
56import Data.Number as Number
58import Data.String.NonEmpty.Internal (NonEmptyString)
57import Data.String.NonEmpty.Internal (NonEmptyString)
59import Data.String.NonEmpty.Internal as NonEmptyString
58import Data.String.NonEmpty.Internal as NonEmptyString
60import Data.Symbol (class IsSymbol, reflectSymbol)
59import Data.Symbol (class IsSymbol, reflectSymbol)
60+import Data.Time.Duration (Milliseconds(..))
61import Data.Traversable (traverse)
61import Data.Traversable (traverse)
62import Data.Tuple (Tuple(..))
62import Data.Tuple (Tuple(..))
63import Data.Variant (Variant, inj, on)
63import Data.Variant (Variant, inj, on)
@@ -78,6 +78,8 @@ import Record.Builder (Builder)
78import Record.Builder as Builder
78import Record.Builder as Builder
79import Type.Prelude (Proxy(..))
79import Type.Prelude (Proxy(..))
80import Unsafe.Coerce (unsafeCoerce)
80import Unsafe.Coerce (unsafeCoerce)
81+import Yoga.Tree (Tree)
82+import Yoga.Tree as Tree
82-- | An alias for the Either result of decoding
84-- | An alias for the Either result of decoding
83type E a = Either MultipleErrors a
85type E a = Either MultipleErrors a
@@ -573,6 +575,22 @@ instance ReadForeign DateTime where
573 >>> note (pure $ ForeignError "Invalid date time")
575 >>> note (pure $ ForeignError "Invalid date time")
574 >>> except
576 >>> except
578+instance WriteForeign Instant where
579+ writeImpl = unInstant >>> writeImpl
581+instance ReadForeign Instant where
584+ case instant millis of
585+ Nothing → except $ Left (pure $ ForeignError "Invalid instant")
588+instance WriteForeign Milliseconds where
589+ writeImpl = unwrap >>> writeImpl
591+instance ReadForeign Milliseconds where
592+ readImpl = readImpl >>> map wrap
576unsafeStringToInt ∷ String → Int
594unsafeStringToInt ∷ String → Int
577unsafeStringToInt = Int.fromString >>>
595unsafeStringToInt = Int.fromString >>>
578 (fromMaybe' \_ → unsafeCrashWith "impossible")
596 (fromMaybe' \_ → unsafeCrashWith "impossible")
@@ -593,3 +611,17 @@ sequenceCombining = foldl fn (Right mempty) >>> except
593 Left errs, Right _ → Left errs
611 Left errs, Right _ → Left errs
594 Right values, Right value → Right (values <> pure value)
612 Right values, Right value → Right (values <> pure value)
595 Right _, Left errs → Left errs
613 Right _, Left errs → Left errs
615+instance WriteForeign a ⇒ WriteForeign (Tree a) where
616+ writeImpl ∷ Tree a → Foreign
617+ writeImpl t = write { value: Cofree.head t, children }
619+ tail = Cofree.tail t
620+ children = if Array.null tail then Nothing else Just (writeImpl <$> tail)
622+instance ReadForeign a ⇒ ReadForeign (Tree a) where
624+ { value, children } ∷ { value ∷ a, children ∷ Maybe (Array Foreign) } ← readImpl f
626+ Nothing → pure (Tree.leaf value)
627+ Just cs → traverse readImpl cs <#> Tree.mkTree value