aeson-typescript 0.1.0.3 → 0.1.0.4
raw patch · 5 files changed
+99/−7 lines, 5 filesPVP: minor bump suggested
API additions: PVP suggests at least a minor version bump
API changes (from Hackage documentation)
+ Data.Aeson.TypeScript.TH: data TSDeclaration
+ Data.Aeson.TypeScript.TH: deriveJSONAndTypeScript :: Options -> Name -> Q [Dec]
+ Data.Aeson.TypeScript.TH: formatTSDeclarations' :: FormattingOptions -> [TSDeclaration] -> String
Files
- README.md +15/−0
- aeson-typescript.cabal +2/−2
- src/Data/Aeson/TypeScript/Instances.hs +1/−1
- src/Data/Aeson/TypeScript/TH.hs +49/−3
- src/Data/Aeson/TypeScript/Types.hs +32/−1
README.md view
@@ -55,6 +55,21 @@ $(deriveTypeScript (getJSONOptions (Proxy :: Proxy MyType)) ''MyType) ``` +Or, if you want to be even more concise and don't mind defining the instances in the same file,++```haskell+myOptions = defaultOptions {fieldLabelModifier = drop 4}++$(deriveJSONAndTypeScript myOptions ''MyType)+```++Remembering that the Template Haskell `Q` monad is an ordinary monad, you can derive instances for several types at once like this:++```haskell+$(mconcat <$> traverse (deriveJSONAndTypeScript myOptions) [''MyType1, ''MyType2, ''MyType3])+```++ # Suggestions for use This library was written to make it easier to typecheck your TypeScript frontend against your Haskell backend. Here's how I like to integrate it into my workflow:
aeson-typescript.cabal view
@@ -2,10 +2,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 642ba0d728cb3be28a4296b85b360f01995570c1a66ec3a36bfb1432d2095f58+-- hash: d5296dac0383543d81935518f35792eb914876a69e7b96def8b6dcfdbd6a53f5 name: aeson-typescript-version: 0.1.0.3+version: 0.1.0.4 synopsis: Generate TypeScript definition files from your ADTs description: Please see the README on Github at <https://github.com/codedownio/aeson-typescript#readme> category: Text, Web, JSON
src/Data/Aeson/TypeScript/Instances.hs view
@@ -87,4 +87,4 @@ getTypeScriptType _ = [i|{[k: #{getTypeScriptType (Proxy :: Proxy a)}]: #{getTypeScriptType (Proxy :: Proxy b)}}|] instance (TypeScript a) => TypeScript (Set a) where- getTypeScriptType _ = (((getTypeScriptType (Proxy :: Proxy a))) <> "[]");+ getTypeScriptType _ = getTypeScriptType (Proxy :: Proxy a) <> "[]";
src/Data/Aeson/TypeScript/TH.hs view
@@ -11,7 +11,7 @@ If you already use Aeson's Template Haskell support to derive your instances, then deriving TypeScript is as simple as @-$(deriveTypeScript myAesonOptions ''MyType)+$('deriveTypeScript' myAesonOptions ''MyType) @ For example,@@ -35,7 +35,7 @@ Now we can use the newly created instances. @->>> putStrLn $ formatTSDeclarations $ getTypeScriptDeclarations (Proxy :: Proxy D)+>>> putStrLn $ 'formatTSDeclarations' $ 'getTypeScriptDeclarations' (Proxy :: Proxy D) type D\<T\> = "nullary" | IUnary\<T\> | IProduct\<T\> | IRecord\<T\>; @@ -61,6 +61,30 @@ $(deriveTypeScript (getJSONOptions (Proxy :: Proxy MyType)) ''MyType) @ +Or, if you want to be even more concise and don't mind defining the instances in the same file,++@+myOptions = 'defaultOptions' {'fieldLabelModifier' = 'drop' 4}++$(deriveJSONAndTypeScript myOptions ''MyType)+@++Remembering that the Template Haskell 'Q' monad is an ordinary monad, you can derive instances for several types at once like this:++@+$('mconcat' \<$\> 'traverse' ('deriveJSONAndTypeScript' myOptions) [''MyType1, ''MyType2, ''MyType3])+@++Once you've defined all necessary instances, you can write a main function to dump them out into a @.d.ts@ file. For example:++@+main = putStrLn $ 'formatTSDeclarations' (+ ('getTypeScriptDeclaration' (Proxy :: Proxy MyType1)) <>+ ('getTypeScriptDeclaration' (Proxy :: Proxy MyType2)) <>+ ...+)+@+ -} module Data.Aeson.TypeScript.TH (@@ -69,19 +93,24 @@ -- * The main typeclass TypeScript(..), + TSDeclaration,+ -- * Formatting declarations formatTSDeclarations,+ formatTSDeclarations', formatTSDeclaration, FormattingOptions(..), -- * Convenience tools HasJSONOptions(..),+ deriveJSONAndTypeScript, module Data.Aeson.TypeScript.Instances ) where import Control.Monad import Data.Aeson as A+import Data.Aeson.TH as A import Data.Aeson.TypeScript.Formatting import Data.Aeson.TypeScript.Instances () import Data.Aeson.TypeScript.Types@@ -142,7 +171,7 @@ getTypeScriptType _ = "T10" --- | Generates a 'TypeScript' instance declaration for the given data type or data family instance constructor.+-- | Generates a 'TypeScript' instance declaration for the given data type. deriveTypeScript :: Options -- ^ Encoding options. -> Name@@ -265,6 +294,23 @@ let brackets = AppE (VarE 'mconcat) (ListE [stringE "<", headType, tailsWithCommas, stringE ">"]) return $ (AppE (AppE (VarE 'mappend) baseName) brackets)++-- * Convenience functions++-- | Convenience function to generate 'A.ToJSON', 'A.FromJSON', and 'TypeScript' instances simultaneously, so the instances are guaranteed to be in sync.+--+-- This function is given mainly as an illustration. If you want some other permutation of instances, such as 'A.ToJSON' and 'A.TypeScript' only, just take a look at the source and write your own version.+--+-- @since 0.1.0.4+deriveJSONAndTypeScript :: Options+ -- ^ Encoding options.+ -> Name+ -- ^ Name of the type for which to generate 'A.ToJSON', 'A.FromJSON', and 'TypeScript' instance declarations.+ -> Q [Dec]+deriveJSONAndTypeScript options name = do+ ts <- deriveTypeScript options name+ json <- A.deriveJSON options name+ return $ ts <> json -- * Util stuff
src/Data/Aeson/TypeScript/Types.hs view
@@ -10,6 +10,7 @@ import Data.Data import Data.Monoid import Data.Proxy+import Data.Set import Data.String import Data.String.Interpolate.IsString import qualified Data.Text as T@@ -18,6 +19,36 @@ import Language.Haskell.TH.Datatype -- | The typeclass that defines how a type is turned into TypeScript.+--+-- The 'getTypeScriptDeclarations' method describes the top-level declarations that are needed for a type,+-- while 'getTypeScriptType' describes how references to the type should be translated. The 'getTypeScriptOptional'+-- method exists purely so that 'Maybe' types can be encoded with a question mark.+--+-- Instances for common types are built-in and are usually very simple; for example,+--+-- @+-- instance TypeScript Bool where+-- getTypeScriptType _ = "boolean"+-- @+--+-- Most of the time you should not need to write instances by hand; in fact, the 'TSDeclaration'+-- constructors are deliberately opaque. However, you may occasionally need to specify the type of something.+-- For example, since 'UTCTime' is encoded to a JSON string and is not built-in to this library:+--+-- @+-- import Data.Time.Clock (UTCTime)+--+-- instance TypeScript UTCTime where+-- getTypeScriptType _ = "string"+-- @+--+-- If you need to write a definition for a higher-order type, it may depend on a type parameter. For example,+-- a 'Set' is encoded to a JSON list of the underlying type:+--+-- @+-- instance (TypeScript a) => TypeScript (Set a) where+-- getTypeScriptType _ = getTypeScriptType (Proxy :: Proxy a) <> "[]";+-- @ class TypeScript a where getTypeScriptDeclarations :: Proxy a -> [TSDeclaration] -- ^ Get the declaration(s) needed for this type.@@ -45,7 +76,7 @@ newtype TSString a = TSString { unpackTSString :: String } deriving Show instance IsString (TSString a) where- fromString x = TSString x+ fromString = TSString -- * Formatting options