packages feed

aeson-flowtyped 0.7.5 → 0.8.0

raw patch · 3 files changed

+153/−75 lines, 3 filesdep +transformersPVP ok

version bump matches the API change (PVP)

Dependencies added: transformers

API changes (from Hackage documentation)

- Data.Aeson.Flow: Poly :: !Var -> !(Vector a) -> FlowTypeF a
- Data.Aeson.Flow: Var :: Text -> Var
- Data.Aeson.Flow: [varName] :: Var -> Text
- Data.Aeson.Flow: instance Data.Aeson.Flow.FlowTyped a => Data.Aeson.Flow.FlowTyped (Data.Tree.Tree a)
- Data.Aeson.Flow: instance GHC.Classes.Eq Data.Aeson.Flow.Var
- Data.Aeson.Flow: instance GHC.Classes.Ord Data.Aeson.Flow.Var
- Data.Aeson.Flow: instance GHC.Read.Read Data.Aeson.Flow.Var
- Data.Aeson.Flow: instance GHC.Show.Show Data.Aeson.Flow.Var
- Data.Aeson.Flow: newtype Var
+ Data.Aeson.Flow: Instantiate :: !TypeRep -> a -> FlowTypeF a
+ Data.Aeson.Flow: PolyApply :: a -> ![TypeRep] -> FlowTypeF a
+ Data.Aeson.Flow: [Var] :: Var a
+ Data.Aeson.Flow: class Typeable k (a :: k)
+ Data.Aeson.Flow: data Var :: Nat -> Type
+ Data.Aeson.Flow: flowTypeVars :: FlowTyped a => Proxy a -> [TypeRep]
+ Data.Aeson.Flow: instance (Data.Typeable.Internal.Typeable a, GHC.TypeLits.KnownNat a, v ~ Data.Aeson.Flow.Var a) => Data.Aeson.Flow.FlowTyped (Data.Tree.Tree v)
+ Data.Aeson.Flow: instance Data.Typeable.Internal.Typeable a => Data.Aeson.Flow.FlowTyped (Data.Aeson.Flow.Var a)
+ Data.Aeson.Flow: typeRep :: Typeable k a => proxy a -> TypeRep
- Data.Aeson.Flow: PolyVar :: !Var -> FlowTypeF a
+ Data.Aeson.Flow: PolyVar :: !TypeRep -> FlowTypeF a
- Data.Aeson.Flow: class Typeable a => FlowTyped a where flowOptions _ = defaultOptions isPrim _ = False flowType p = defaultFlowType (flowOptions p) p flowTypeName = defaultFlowTypeName
+ Data.Aeson.Flow: class Typeable a => FlowTyped a where flowTypeVars _ = [] flowOptions _ = defaultOptions isPrim _ = False flowType p = defaultFlowType (flowOptions p) p flowTypeName = defaultFlowTypeName

Files

aeson-flowtyped.cabal view
@@ -3,7 +3,7 @@ -- see: https://github.com/sol/hpack  name:           aeson-flowtyped-version:        0.7.5+version:        0.8.0 synopsis:       Create Flow type definitions from Haskell data types. description:    Create Flow type definitions from Haskell data types. category:       Web@@ -29,13 +29,14 @@     , vector     , text     , recursion-schemes+    , containers     , time     , unordered-containers-    , containers     , reflection     , wl-pprint     , free     , scientific+    , transformers   exposed-modules:       Data.Aeson.Flow   other-modules:@@ -53,6 +54,7 @@     , vector     , text     , recursion-schemes+    , containers     , aeson-flowtyped     , tasty     , tasty-hunit
src/Data/Aeson/Flow.hs view
@@ -47,41 +47,47 @@   , FlowTypeI   , Info (..)   , Var (..)+  , Typeable+  , typeRep   ) where import           Control.Monad-import qualified Data.Aeson              as A-import           Data.Aeson.Types        (Options (..), SumEncoding (..))-import           Data.Fixed              (Fixed)+import           Control.Monad.Trans.State.Strict+import qualified Data.Aeson                       as A+import           Data.Aeson.Types                 (Options (..),+                                                   SumEncoding (..))+import           Data.Fixed                       (Fixed) import           Data.Foldable import           Data.Functor.Classes import           Data.Functor.Compose-import           Data.Functor.Foldable   hiding (fold)-import           Data.HashMap.Strict     (HashMap)-import qualified Data.HashMap.Strict     as H-import qualified Data.HashSet            as HashSet+import           Data.Functor.Foldable            hiding (fold)+import           Data.HashMap.Strict              (HashMap)+import qualified Data.HashMap.Strict              as H+import qualified Data.HashSet                     as HashSet import           Data.Int-import qualified Data.IntSet             as IntSet+import qualified Data.IntSet                      as IntSet+import           Data.Kind                        (Type)+import           Data.Map.Strict                  (Map)+import qualified Data.Map.Strict                  as M import           Data.Proxy import           Data.Reflection-import           Data.Scientific         (Scientific)-import qualified Data.Set                as Set-import qualified Data.Set                as Set-import           Data.Text               (Text)-import qualified Data.Text               as T-import qualified Data.Text.IO            as TIO-import qualified Data.Text.Lazy          as TL-import           Data.Time               (UTCTime)-import qualified Data.Tree               as Tree+import           Data.Scientific                  (Scientific)+import qualified Data.Set                         as Set+import           Data.Text                        (Text)+import qualified Data.Text                        as T+import qualified Data.Text.IO                     as TIO+import qualified Data.Text.Lazy                   as TL+import           Data.Time                        (UTCTime)+import qualified Data.Tree                        as Tree import           Data.Typeable-import           Data.Vector             (Vector)-import qualified Data.Vector             as V-import qualified Data.Vector.Storable    as VS-import qualified Data.Vector.Unboxed     as VU-import qualified Data.Void               as Void+import           Data.Vector                      (Vector)+import qualified Data.Vector                      as V+import qualified Data.Vector.Storable             as VS+import qualified Data.Vector.Unboxed              as VU+import qualified Data.Void                        as Void import           Data.Word import           GHC.Generics import           GHC.TypeLits-import qualified Text.PrettyPrint.Leijen as PP+import qualified Text.PrettyPrint.Leijen          as PP  -------------------------------------------------------------------------------- -- Magical newtype for injecting showsPrec into any arbitrary Show@@ -110,9 +116,6 @@   | Any   deriving (Show, Read, Eq, Ord) -newtype Var = Var { varName :: Text }-  deriving (Show, Read, Eq, Ord)- -- | A name for a flowtyped data-type. These are returned by 'dependencies'. data FlowName where   FlowName :: (Typeable a, FlowTyped a) => Proxy a -> Text -> FlowName@@ -141,8 +144,9 @@   | Literal !A.Value   | Tag !Text   | Name !FlowName-  | Poly !Var !(Vector a)-  | PolyVar !Var+  | Instantiate !TypeRep a+  | PolyVar !TypeRep+  | PolyApply a ![TypeRep]   deriving (Show, Eq, Functor, Traversable, Foldable) -- XXX: vector >= 0.12 has Eq1 vector which allows us to use eq for Fix FlowTypeF -- and related types@@ -168,10 +172,12 @@ text :: Text -> PP.Doc text = PP.text . T.unpack -ppAlts :: [FlowType] -> FlowType -> PP.Doc+type Poly = State (Map TypeRep Text)++ppAlts :: [FlowType] -> FlowType -> Poly PP.Doc ppAlts alts (Fix f) = case f of   Alt a b -> ppAlts (a:alts) b-  x       -> PP.align (sep (map pp (reverse (Fix x:alts))))+  x       -> PP.align . sep <$> mapM pp (reverse (Fix x:alts))   where     sep [x]    = x     sep (x:xs) = x PP.<+> PP.string "|" PP.<$> sep xs@@ -213,43 +219,65 @@   Array _    -> PP.parens x   _          -> x -ppObject :: HashMap Text FlowType -> [PP.Doc]-ppObject = map-  (\(name, fty') ->-     case fty' of-       Fix (Omitable fty) -> text name PP.<> PP.text "?" PP.<> PP.colon PP.<+> pp fty-       fty -> text name PP.<> PP.colon PP.<+> pp fty)-  . H.toList+ppObject :: HashMap Text FlowType -> Poly [PP.Doc]+ppObject = mapM ppField . H.toList+  where+    ppField (name, fty) = do+      case fty of+        Fix (Omitable fty') ->+          (\fty'' -> text name PP.<> PP.text "?" PP.<> PP.colon PP.<+> fty'') <$> pp fty'+        fty' ->+          (\fty'' -> text name PP.<> PP.colon PP.<+> fty'') <$> pp fty' -pp :: FlowType -> PP.Doc+getVar :: TypeRep -> Poly Text+getVar rep = do+  s <- get+  case M.lookup rep s of+    Just i -> return i+    Nothing -> do+      let r = polyVarNames !! M.size s+      r <$ modify' (M.insert rep r)++polyVarNames :: [Text]+polyVarNames =+  map T.singleton ['A'..'Z'] +++  zipWith (\i t -> t `T.append` T.pack (show i)) [0 :: Int ..] polyVarNames++pp :: FlowType -> Poly PP.Doc pp (Fix ft) = case ft of-  ObjectMap keyName a -> braceList-    [ PP.brackets (text keyName PP.<> PP.text ": string") PP.<>-      PP.colon PP.<+>-      pp a-    ]-  Object hm -> braceList (ppObject hm)-  ExactObject hm -> braceBarList (ppObject hm)-  Array a -> mayWrap a (pp a) PP.<> PP.string "[]"-  Tuple t -> PP.list (map pp (V.toList t))+  ObjectMap keyName a ->+    (\r -> braceList+      [ PP.brackets (text keyName PP.<> PP.text ": string") PP.<>+        PP.colon PP.<+>+        r+      ]) <$> pp a+  Object hm -> braceList <$> ppObject hm+  ExactObject hm -> braceBarList <$> ppObject hm+  Array a -> (\r -> mayWrap a r PP.<> PP.string "[]") <$> pp a+  Tuple t -> PP.list <$> mapM pp (V.toList t)   Alt a b -> ppAlts [a] b-  Prim pt -> case pt of+  Prim pt -> return $ case pt of     Boolean -> PP.text "boolean"     Number  -> PP.text "number"     String  -> PP.text "string"     Void    -> PP.text "void"     Any     -> PP.text "any"     Mixed   -> PP.text "mixed"-  Nullable a -> PP.char '?' PP.<> mayWrap a (pp a)-  Omitable a -> PP.char '?' PP.<> mayWrap a (pp a) -- hopefully these are caught-  Literal a -> ppJson a-  Tag t -> PP.squotes (text t)-  Name (FlowName _ t) -> text t-  _ -> PP.string (show ft)+  Nullable a -> (\r -> PP.char '?' PP.<> mayWrap a r) <$> pp a+  Omitable a -> (\r -> PP.char '?' PP.<> mayWrap a r) <$> pp a -- hopefully these are caught+  Literal a -> return (ppJson a)+  Tag t -> return (PP.squotes (text t))+  Name (FlowName _ t) -> return (text t)+  PolyVar rep -> text <$> getVar rep+  PolyApply a vars -> do+    n  <- pp a+    vs <- mapM getVar vars+    return (n PP.<> PP.angles (PP.hsep (PP.punctuate PP.comma (map text vs))))+  _ -> return (PP.string (show ft))  -- | Pretty-print a flowtype in flowtype syntax showFlowType :: FlowType -> Text-showFlowType = T.pack . show . pp+showFlowType ft = T.pack (show (evalState (pp ft) M.empty))  -------------------------------------------------------------------------------- -- Module exporting@@ -259,9 +287,16 @@ exportFlowTypeAs name ft =   T.pack . render $   PP.string "export type " PP.<>-  PP.string (T.unpack name) PP.<+> PP.string "=" PP.<$>-  PP.indent 2 (pp ft) PP.<> PP.string ";"+  PP.string (T.unpack name) PP.<> withVars (runState (pp ft) M.empty)   where+    main r = PP.string "=" PP.<$> PP.indent 2 r PP.<> PP.string ";"+    withVars (r, vars)+      | M.null vars = PP.space PP.<> main r+      | otherwise = PP.angles (PP.hsep+                               (PP.punctuate PP.comma (map text (M.elems vars))))+                    PP.<+>+                    main r+     render = ($[]) . PP.displayS . PP.renderPretty 1.0 80  -- | Compute all the dependencies of a 'FlowTyped' thing, including itself.@@ -334,13 +369,20 @@  flowTypePreferName :: (Typeable a, FlowTyped a) => Proxy a -> FlowType flowTypePreferName p = case flowTypeName p of-  Just n  -> Fix (Name (FlowName p n))+  Just n | null vars -> name+         | otherwise -> Fix (PolyApply name vars)+    where+      vars = flowTypeVars p+      name = Fix (Name (FlowName p n))   Nothing -> flowType p  class Typeable a => FlowTyped a where   flowType :: Proxy a -> FlowType   flowTypeName :: Proxy a -> Maybe Text +  flowTypeVars :: Proxy a -> [TypeRep]+  flowTypeVars _ = []+   flowOptions :: Proxy a -> Options   flowOptions _ = A.defaultOptions @@ -484,12 +526,7 @@   gflowVal opt p = gflowVal opt (fmap unM1 p)  instance FlowTyped r => GFlowVal (Rec0 r) where-  gflowVal _opt p = case flowTypePreferName (fmap unK1 p) of-    ty-      | not (isPrim p'), Just name <- flowTypeName p' -> noInfo (Name (FlowName p' name))-      | otherwise -> cata noInfo ty-    where-      p' = fmap unK1 p+  gflowVal _opt p = cata noInfo (flowTypePreferName (fmap unK1 p))  instance (GFlowVal a, GFlowVal b) => GFlowVal (a :+: b) where   gflowVal opt _ = noInfo@@ -656,16 +693,25 @@   flowType _ = Fix (Array (flowTypePreferName (Proxy :: Proxy a)))   flowTypeName _ = Nothing +data Var :: Nat -> Type where Var :: Var a++instance Typeable a => FlowTyped (Var a) where+  isPrim _ = False+  flowType _ = Fix (PolyVar (typeRep (Proxy :: Proxy (Var a))))+  flowTypeName _ = Nothing+ -- | This instance is defined recursively. You'll probably need to use -- 'dependencies' to extract a usable definition-instance FlowTyped a => FlowTyped (Tree.Tree a) where+instance (Typeable a, KnownNat a, v ~ Var a) => FlowTyped (Tree.Tree v) where   isPrim _ = False-  flowType _ = Fix (Tuple-                    (V.fromList-                     [ flowType (Proxy :: Proxy a)-                     , Fix (Array (flowType (Proxy :: Proxy (Tree.Tree a))))-                     ]))+  flowType _ = Fix+    (Tuple+     (V.fromList+      [ flowType (Proxy :: Proxy v)+      , Fix (Array (flowTypePreferName (Proxy :: Proxy (Tree.Tree v))))+      ]))   flowTypeName _ = Just "Tree"+  flowTypeVars _ = [typeRep (Proxy :: Proxy v)]  instance FlowTyped () where   isPrim _ = False
test/Spec.hs view
@@ -1,12 +1,15 @@-{-# LANGUAGE DeriveGeneric     #-}-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DataKinds           #-}+{-# LANGUAGE DeriveGeneric       #-}+{-# LANGUAGE GADTs               #-}+{-# LANGUAGE OverloadedStrings   #-}+{-# LANGUAGE ScopedTypeVariables #-} import           Data.Aeson            (Value) import           Data.Aeson.Flow import           Data.Functor.Foldable (Fix (..)) import           Data.HashMap.Strict   (HashMap)-import qualified Data.HashMap.Strict   as H import           Data.Proxy            (Proxy (..)) import           Data.Text             (Text)+import           Data.Tree             (Tree) import           Data.Vector           (Vector) import           GHC.Generics import           Test.Tasty@@ -50,6 +53,15 @@  instance FlowTyped Hmap +data Poly2 a b = Poly2 a b | Poly2Go (Poly2 a b)+  deriving (Generic)++instance (a ~ Var 0, b ~ Var 1) => FlowTyped (Poly2 a b) where+  flowTypeVars _ =+    [ typeRep (Proxy :: Proxy a)+    , typeRep (Proxy :: Proxy b)+    ]+ main :: IO () main = defaultMain $ testGroup "aeson-flowtyped"   [ testCase "nullable" $@@ -132,4 +144,22 @@     [ Export (Proxy :: Proxy Codep)     ] +  , testCase "polymorphism (arity 1)" $+    "// @flow\n\+    \// This module has been generated by aeson-flowtyped.\n\n\+    \export type Tree<A> =\n\+    \  [A,Tree<A>[]];\n" @=?+    generateFlowModule defaultFlowModuleOptions+    [ Export (Proxy :: Proxy (Tree (Var 0)))+    ]++  , testCase "polymorphism (arity 2)" $+    "// @flow\n\+    \// This module has been generated by aeson-flowtyped.\n\n\+    \export type Poly2<A, B> =\n\+    \  {| tag: 'Poly2', contents: [A,B] |} |\n\+    \  {| tag: 'Poly2Go', contents: Poly2<A, B> |};\n" @=?+    generateFlowModule defaultFlowModuleOptions+    [ Export (Proxy :: Proxy (Poly2 (Var 0) (Var 1)))+    ]   ]