@@ -11,7 +11,6 @@ module Yoga.JSON
1111 , parseJSON
1212 , undefined
1313 , unsafeStringify
14−
1514 , class ReadForeign
1615 , readImpl
1716 , class ReadForeignFields
@@ -21,25 +20,25 @@ module Yoga.JSON
2120 , class ReadTuple
2221 , readTupleImpl
2322 , tupleSize
24−
2523 , class WriteForeign
2624 , writeImpl
2725 , class WriteForeignFields
2826 , writeImplFields
2927 , class WriteForeignVariant
3028 , writeVariantImpl
31−
3229 ) where
3330
3431import Prelude
3532
3633import Control.Alt ((<|>))
3734import Control.Apply (lift2)
35+import Control.Comonad.Cofree as Cofree
3836import Control.Monad.Except (ExceptT(..), except, runExcept, throwError, withExcept)
3937import Data.Array as Array
4038import Data.Array.NonEmpty (NonEmptyArray, fromArray, toArray)
4139import Data.Bifunctor (lmap)
4240import Data.DateTime (DateTime)
41+import Data.DateTime.Instant (Instant, instant, unInstant)
4342import Data.Either (Either(..), hush, note)
4443import Data.Foldable (class Foldable, foldl)
4544import Data.FoldableWithIndex (foldrWithIndex)
@@ -52,12 +51,13 @@ import Data.List.NonEmpty (NonEmptyList, singleton)
5251import Data.Map (Map)
5352import Data.Map as Map
5453import Data.Maybe (Maybe(..), fromMaybe, fromMaybe', maybe)
55−import Data.Newtype (class Newtype)
54+import Data.Newtype (class Newtype, unwrap, wrap)
5655import Data.Nullable (Nullable, toMaybe, toNullable)
5756import Data.Number as Number
5857import Data.String.NonEmpty.Internal (NonEmptyString)
5958import Data.String.NonEmpty.Internal as NonEmptyString
6059import Data.Symbol (class IsSymbol, reflectSymbol)
60+import Data.Time.Duration (Milliseconds(..))
6161import Data.Traversable (traverse)
6262import Data.Tuple (Tuple(..))
6363import Data.Variant (Variant, inj, on)
@@ -78,6 +78,8 @@ import Record.Builder (Builder)
7878import Record.Builder as Builder
7979import Type.Prelude (Proxy(..))
8080import Unsafe.Coerce (unsafeCoerce)
81+import Yoga.Tree (Tree)
82+import Yoga.Tree as Tree
8183
8284-- | An alias for the Either result of decoding
8385type E a = Either MultipleErrors a
@@ -573,6 +575,22 @@ instance ReadForeign DateTime where
573575 >>> note (pure $ ForeignError "Invalid date time")
574576 >>> except
575577
578+instance WriteForeign Instant where
579+ writeImpl = unInstant >>> writeImpl
580+
581+instance ReadForeign Instant where
582+ readImpl f = do
583+ millis ← readImpl f
584+ case instant millis of
585+ Nothing → except $ Left (pure $ ForeignError "Invalid instant")
586+ Just ins → pure ins
587+
588+instance WriteForeign Milliseconds where
589+ writeImpl = unwrap >>> writeImpl
590+
591+instance ReadForeign Milliseconds where
592+ readImpl = readImpl >>> map wrap
593+
576594unsafeStringToInt ∷ String → Int
577595unsafeStringToInt = Int.fromString >>>
578596 (fromMaybe' \_ → unsafeCrashWith "impossible")
@@ -593,3 +611,17 @@ sequenceCombining = foldl fn (Right mempty) >>> except
593611 Left errs, Right _ → Left errs
594612 Right values, Right value → Right (values <> pure value)
595613 Right _, Left errs → Left errs
614+
615+instance WriteForeign a ⇒ WriteForeign (Tree a) where
616+ writeImpl ∷ Tree a → Foreign
617+ writeImpl t = write { value: Cofree.head t, children }
618+ where
619+ tail = Cofree.tail t
620+ children = if Array.null tail then Nothing else Just (writeImpl <$> tail)
621+
622+instance ReadForeign a ⇒ ReadForeign (Tree a) where
623+ readImpl f = do
624+ { value, children } ∷ { value ∷ a, children ∷ Maybe (Array Foreign) } ← readImpl f
625+ case children of
626+ Nothing → pure (Tree.leaf value)
627+ Just cs → traverse readImpl cs <#> Tree.mkTree value