JsonGrammar 1.0 → 1.0.1
raw patch · 8 files changed
+48/−47 lines, 8 filesdep ~aesondep ~semigroupsdep ~stack-prismsetup-changedPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: aeson, semigroups, stack-prism
API changes (from Hackage documentation)
- Language.JsonGrammar: (:-) :: h -> t -> :- h t
+ Language.JsonGrammar: (:-) :: h -> t -> (:-) h t
Files
- JsonGrammar.cabal +6/−6
- Setup.hs +1/−0
- src/Language/JsonGrammar.hs +3/−3
- src/Language/JsonGrammar/Grammar.hs +21/−21
- src/Language/JsonGrammar/Parser.hs +3/−3
- src/Language/JsonGrammar/Serializer.hs +3/−3
- src/Language/JsonGrammar/TypeScript.hs +9/−9
- tests/Tests.hs +2/−2
JsonGrammar.cabal view
@@ -1,5 +1,5 @@ Name: JsonGrammar-Version: 1.0+Version: 1.0.1 Synopsis: Combinators for bidirectional JSON parsing Description: Combinators for bidirectional JSON parsing @@ -32,11 +32,11 @@ Language.JsonGrammar.Serializer, Language.JsonGrammar.Util Build-Depends: base >= 3.0 && < 5,- aeson >= 0.6 && < 0.8,- semigroups >= 0.5 && < 0.16,+ aeson >= 0.6 && < 0.9,+ semigroups >= 0.5 && < 0.17, language-typescript >= 0.0.4 && < 0.1, mtl >= 2.1 && < 2.3,- stack-prism < 0.2,+ stack-prism >= 0.1 && < 0.2, -- constraints copied from aeson-0.6.1.0: attoparsec >= 0.8.6.1, bytestring,@@ -54,9 +54,9 @@ Main-Is: Tests.hs Other-Modules: Types Build-Depends: JsonGrammar,- stack-prism < 0.2,+ stack-prism >= 0.1 && < 0.2, base >= 3.0 && < 5,- aeson >= 0.6 && < 0.8,+ aeson >= 0.6 && < 0.9, language-typescript >= 0.0.4 && < 0.1, text >= 0.11.0.2, test-framework >= 0.8 && < 0.9,
Setup.hs view
@@ -1,2 +1,3 @@ import Distribution.Simple+ main = defaultMain
src/Language/JsonGrammar.hs view
@@ -27,7 +27,7 @@ ) where -import Prelude hiding ((.))+import Prelude (Monad(..), Maybe(..)) import Control.Category ((.)) import Data.Aeson.Types (Parser) @@ -83,11 +83,11 @@ -- > interface Person {age : number ;name : string ;} -- | Parse a JSON value according to the specified grammar.-parse :: Grammar Val (a :- ()) (b :- ()) -> a -> Parser b+parse :: Grammar 'Val (a :- ()) (b :- ()) -> a -> Parser b parse = parseValue . unstack -- | Serialize a Haskell value to a JSON value according to the specified grammar.-serialize :: Grammar Val (a :- ()) (b :- ()) -> b -> Maybe a+serialize :: Grammar 'Val (a :- ()) (b :- ()) -> b -> Maybe a serialize = serializeValue . unstack unstack :: Grammar c (a :- ()) (b :- ()) -> Grammar c a b
src/Language/JsonGrammar/Grammar.hs view
@@ -14,7 +14,7 @@ Json(..), el, prop ) where -import Prelude hiding (id, (.))+import Prelude (Maybe(..), Monad(..), Int, Float, Eq(..)) import Control.Applicative ((<$>)) import Control.Category (Category(..)) import Data.Aeson (Value, FromJSON(..), ToJSON(..))@@ -47,17 +47,17 @@ Pure :: (t1 -> Parser t2) -> (t2 -> Maybe t1) -> Grammar c t1 t2 Many :: Grammar c t t -> Grammar c t t - Literal :: Value -> Grammar Val (Value :- t) t+ Literal :: Value -> Grammar 'Val (Value :- t) t - Label :: Text -> Grammar Val t1 t2 -> Grammar Val t1 t2+ Label :: Text -> Grammar 'Val t1 t2 -> Grammar 'Val t1 t2 - Object :: Grammar Obj t1 t2 -> Grammar Val (Value :- t1) t2- Property :: Text -> Grammar Val (Value :- t1) t2 -> Grammar Obj t1 t2+ Object :: Grammar 'Obj t1 t2 -> Grammar 'Val (Value :- t1) t2+ Property :: Text -> Grammar 'Val (Value :- t1) t2 -> Grammar 'Obj t1 t2 - Array :: Grammar Arr t1 t2 -> Grammar Val (Value :- t1) t2- Element :: Grammar Val (Value :- t1) t2 -> Grammar Arr t1 t2+ Array :: Grammar 'Arr t1 t2 -> Grammar 'Val (Value :- t1) t2+ Element :: Grammar 'Val (Value :- t1) t2 -> Grammar 'Arr t1 t2 - Coerce :: Type -> Grammar Val t1 t2 -> Grammar Val t1 t2+ Coerce :: Type -> Grammar 'Val t1 t2 -> Grammar 'Val t1 t2 -- | The '.' operator is the main way to compose two grammars. instance Category (Grammar c) where@@ -70,7 +70,7 @@ mappend = (:<>) -- | String literals convert to grammars that expect or produce a specific JSON string 'literal' value.-instance IsString (Grammar Val (Value :- t) t) where+instance IsString (Grammar 'Val (Value :- t) t) where fromString = literal . fromString @@ -87,15 +87,15 @@ many = Many -- | Expect or produce a literal JSON 'Value'. You can only use this constructor in the value context 'Val'.-literal :: Value -> Grammar Val (Value :- t) t+literal :: Value -> Grammar 'Val (Value :- t) t literal = Literal -- | Label a value grammar with a name. This doesn't affect the JSON conversion itself, but it generates an interface definition when converting to TypeScript 'interfaces'.-label :: Text -> Grammar Val t1 t2 -> Grammar Val t1 t2+label :: Text -> Grammar 'Val t1 t2 -> Grammar 'Val t1 t2 label = Label -- | Expect or produce a JSON object whose properties match the specified 'Obj' grammar. You can create 'Obj' grammars using 'property'. Alternatively, if you want to match an empty object, use @object 'id'@.-object :: Grammar Obj t1 t2 -> Grammar Val (Value :- t1) t2+object :: Grammar 'Obj t1 t2 -> Grammar 'Val (Value :- t1) t2 object = Object -- | Expect or produce an object property with the specified name, and a value that can be parsed/produced by the specified grammar. This function creates a grammar in the 'Obj' context. You can combine multiple @property@ grammars using the '.' operator from 'Category'.@@ -104,23 +104,23 @@ -- -- > grammar = object (propertiesA <> propertiesB) -- > where--- > propertiesA = property "type" "A" . fromPiso constructorA . prop "foo"--- > propertiesB = property "type" "B" . fromPiso constructorB . prop "bar" . prop "baz"-property :: Text -> Grammar Val (Value :- t1) t2 -> Grammar Obj t1 t2+-- > propertiesA = property "type" "A" . fromPrism constructorA . prop "foo"+-- > propertiesB = property "type" "B" . fromPrism constructorB . prop "bar" . prop "baz"+property :: Text -> Grammar 'Val (Value :- t1) t2 -> Grammar 'Obj t1 t2 property = Property -- | Expect or produce a JSON array value whose contents match the specified 'Arr' grammar. You can create 'Arr' grammars using 'element'. Alternatively, if you want to match an empty array, use @array 'id'@.-array :: Grammar Arr t1 t2 -> Grammar Val (Value :- t1) t2+array :: Grammar 'Arr t1 t2 -> Grammar 'Val (Value :- t1) t2 array = Array -- | Expect or produce a JSON array element whose value matches the specified 'Val' grammar.-element :: Grammar Val (Value :- t1) t2 -> Grammar Arr t1 t2+element :: Grammar 'Val (Value :- t1) t2 -> Grammar 'Arr t1 t2 element = Element -- | Mark a grammar to be of a specific TypeScript type. This doesn't affect the JSON conversion, but when generating TypeScript 'interfaces' a coercion causes the interface generator to stop looking at the underlying grammar and just use the specified TypeScript 'Type' as inferred type instead. -- -- This is useful if you write a grammar that, for example, wraps a primitive type like string (in which case you would specify @'Predefined' 'StringType'@ as type). Another use is when you find the generated interface can't be described by a 'Grammar', for example because it uses a generic type parameter.-coerce :: Type -> Grammar Val t1 t2 -> Grammar Val t1 t2+coerce :: Type -> Grammar 'Val t1 t2 -> Grammar 'Val t1 t2 coerce = Coerce @@ -158,7 +158,7 @@ -- | A type class for types that can be converted from and to JSON using a 'Grammar'. The grammar is expected to be in the value context 'Val' and consumes (or produces) a JSON 'Value'. class Json a where- grammar :: Grammar Val (Value :- t) (a :- t)+ grammar :: Grammar 'Val (Value :- t) (a :- t) instance Json Text where grammar = Coerce (Predefined StringType) liftAeson instance Json Int where grammar = Coerce (Predefined NumberType) liftAeson@@ -183,11 +183,11 @@ g (x :- t) = Just (toJSON x :- t) -- | Expect or produce an object 'property' whose value grammar is specified by 'grammar'.-prop :: Json a => Text -> Grammar Obj t (a :- t)+prop :: Json a => Text -> Grammar 'Obj t (a :- t) prop n = Property n grammar -- | Expect or produce an array 'element' whose value grammar is specified by 'grammar'.-el :: Json a => Grammar Arr t (a :- t)+el :: Json a => Grammar 'Arr t (a :- t) el = Element grammar -- | Create a 'pure' grammar that expects or produces a specific Haskell value.
src/Language/JsonGrammar/Parser.hs view
@@ -17,7 +17,7 @@ -- | Convert a 'Grammar' to a JSON 'Parser'.-parseValue :: Grammar Val t1 t2 -> t1 -> Parser t2+parseValue :: Grammar 'Val t1 t2 -> t1 -> Parser t2 parseValue = \case Id -> return g1 :. g2 -> parseValue g2 >=> parseValue g1@@ -45,7 +45,7 @@ -parseProperties :: Object -> Grammar Obj t1 t2 -> t1 -> Parser t2+parseProperties :: Object -> Grammar 'Obj t1 t2 -> t1 -> Parser t2 parseProperties obj = \case Id -> return g1 :. g2 -> parseProperties obj g2 >=> parseProperties obj g1@@ -61,7 +61,7 @@ parseValue g (val :- x) -parseElements :: Grammar Arr t1 t2 -> (Array, t1) -> Parser (Array, t2)+parseElements :: Grammar 'Arr t1 t2 -> (Array, t1) -> Parser (Array, t2) parseElements = \case Id -> return g1 :. g2 -> parseElements g2 >=> parseElements g1
src/Language/JsonGrammar/Serializer.hs view
@@ -16,7 +16,7 @@ -- | Convert a 'Grammar' to a JSON serializer.-serializeValue :: Grammar Val t1 t2 -> t2 -> Maybe t1+serializeValue :: Grammar 'Val t1 t2 -> t2 -> Maybe t1 serializeValue = \case Id -> return g1 :. g2 -> serializeValue g1 >=> serializeValue g2@@ -43,7 +43,7 @@ serializeProperties ::- Grammar Obj t1 t2 -> (Ae.Object, t2) -> Maybe (Ae.Object, t1)+ Grammar 'Obj t1 t2 -> (Ae.Object, t2) -> Maybe (Ae.Object, t1) serializeProperties = \case Id -> return g1 :. g2 -> serializeProperties g1 >=> serializeProperties g2@@ -60,7 +60,7 @@ return (H.insert n val obj, y) -serializeElements :: Grammar Arr t1 t2 -> (Ae.Array, t2) -> Maybe (Ae.Array, t1)+serializeElements :: Grammar 'Arr t1 t2 -> (Ae.Array, t2) -> Maybe (Ae.Array, t1) serializeElements = \case Id -> return g1 :. g2 -> serializeElements g1 >=> serializeElements g2
src/Language/JsonGrammar/TypeScript.hs view
@@ -19,10 +19,10 @@ import Language.TypeScript -toType :: GrammarMap -> Grammar Val t1 t2 -> Maybe Type+toType :: GrammarMap -> Grammar 'Val t1 t2 -> Maybe Type toType gm = go where- go :: Grammar Val t1 t2 -> Maybe Type+ go :: Grammar 'Val t1 t2 -> Maybe Type go = \case Id -> Nothing g1 :. g2 ->@@ -53,10 +53,10 @@ emptyComment :: CommentPlaceholder emptyComment = Left (0, 0) -toProperties :: GrammarMap -> Grammar Obj t1 t2 -> HashMap Text (Maybe Optional, Type)+toProperties :: GrammarMap -> Grammar 'Obj t1 t2 -> HashMap Text (Maybe Optional, Type) toProperties gm = go where- go :: Grammar Obj t1 t2 -> HashMap Text (Maybe Optional, Type)+ go :: Grammar 'Obj t1 t2 -> HashMap Text (Maybe Optional, Type) go = \case Id -> H.empty g1 :. g2 ->@@ -78,10 +78,10 @@ Property n g -> maybe H.empty (\ty -> H.singleton n (Nothing, ty)) (toType gm g) -toElementType :: GrammarMap -> Grammar Arr t1 t2 -> Maybe Type+toElementType :: GrammarMap -> Grammar 'Arr t1 t2 -> Maybe Type toElementType gm = go where- go :: Grammar Arr t1 t2 -> Maybe Type+ go :: Grammar 'Arr t1 t2 -> Maybe Type go = \case Id -> Nothing g1 :. g2 -> unify <$> go g1 <*> go g2@@ -129,9 +129,9 @@ Ae.Bool _ -> Predefined BooleanType Ae.Null -> Predefined VoidType -- TODO -type GrammarMap = HashMap Text (SomeGrammar Val)+type GrammarMap = HashMap Text (SomeGrammar 'Val) -grammarMap :: [SomeGrammar Val] -> GrammarMap+grammarMap :: [SomeGrammar 'Val] -> GrammarMap grammarMap gs = execState (mapM_ (\(SomeGrammar g) -> buildGrammarMap g) gs) H.empty where@@ -167,7 +167,7 @@ SomeGrammar :: Grammar c t1 t2 -> SomeGrammar c -- | Generate a list of TypeScript interface declarations from the specified grammars.-interfaces :: [SomeGrammar Val] -> [DeclarationElement]+interfaces :: [SomeGrammar 'Val] -> [DeclarationElement] interfaces gs = tys where gm = grammarMap gs
tests/Tests.hs view
@@ -73,8 +73,8 @@ printInterfaces [SomeGrammar personGrammar] defaultMain [test1, test2] -personGrammar :: Grammar Val (Value :- t) (Person :- t)+personGrammar :: Grammar 'Val (Value :- t) (Person :- t) personGrammar = grammar -printInterfaces :: [SomeGrammar Val] -> IO ()+printInterfaces :: [SomeGrammar 'Val] -> IO () printInterfaces gs = putStrLn (renderDeclarationSourceFile (interfaces gs))