packages feed

servant-csharp 0.0.7.1 → 0.0.8.0

raw patch · 6 files changed

+368/−337 lines, 6 filesdep +aesondep +mtldep +servant-swaggerPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: aeson, mtl, servant-swagger, swagger2, unordered-containers

API changes (from Hackage documentation)

- CS: [apitemplate] :: GenerateCsConfig -> forall api. (HasForeign CSharp Text api, GenerateList Text (Foreign Text api)) => GenerateCsConfig -> Proxy api -> IO String
- CS: [assemblyinfotemplate] :: GenerateCsConfig -> GenerateCsConfig -> IO String
- CS: [classtemplate] :: GenerateCsConfig -> GenerateCsConfig -> IO String
- CS: [convertertemplate] :: GenerateCsConfig -> GenerateCsConfig -> IO String
- CS: [csprojtemplate] :: GenerateCsConfig -> GenerateCsConfig -> IO String
- CS: [enumtemplate] :: GenerateCsConfig -> GenerateCsConfig -> IO String
- CS: [outdir] :: GenerateCsConfig -> String
- CS: [sources] :: GenerateCsConfig -> [FilePath]
- CS: apiCsForAPI :: (HasForeign CSharp Text api, GenerateList Text (Foreign Text api)) => Proxy api -> IO String
- CS: apiCsForAPIWith :: (HasForeign CSharp Text api, GenerateList Text (Foreign Text api)) => GenerateCsConfig -> Proxy api -> IO String
- CS: assemblyInfoCsForAPI :: IO String
- CS: assemblyInfoCsForAPIWith :: GenerateCsConfig -> IO String
- CS: classCsForAPI :: IO String
- CS: classCsForAPIWith :: GenerateCsConfig -> IO String
- CS: converterCsForAPI :: IO String
- CS: converterCsForAPIWith :: GenerateCsConfig -> IO String
- CS: csprojForAPI :: IO String
- CS: csprojForAPIWith :: GenerateCsConfig -> IO String
- CS: enumCsForAPI :: IO String
- CS: enumCsForAPIWith :: GenerateCsConfig -> IO String
- CS: genCsForAPI :: (HasForeign CSharp Text api, GenerateList Text (Foreign Text api)) => GenerateCsConfig -> Proxy api -> IO ()
- CS.JsonDotNet: [apitemplate] :: GenerateCsConfig -> forall api. (HasForeign CSharp Text api, GenerateList Text (Foreign Text api)) => GenerateCsConfig -> Proxy api -> IO String
- CS.JsonDotNet: [assemblyinfotemplate] :: GenerateCsConfig -> GenerateCsConfig -> IO String
- CS.JsonDotNet: [classtemplate] :: GenerateCsConfig -> GenerateCsConfig -> IO String
- CS.JsonDotNet: [convertertemplate] :: GenerateCsConfig -> GenerateCsConfig -> IO String
- CS.JsonDotNet: [csprojtemplate] :: GenerateCsConfig -> GenerateCsConfig -> IO String
- CS.JsonDotNet: [enumtemplate] :: GenerateCsConfig -> GenerateCsConfig -> IO String
- CS.JsonDotNet: [outdir] :: GenerateCsConfig -> String
- CS.JsonDotNet: [sources] :: GenerateCsConfig -> [FilePath]
- CS.JsonDotNet: apiCsForAPI :: (HasForeign CSharp Text api, GenerateList Text (Foreign Text api)) => Proxy api -> IO String
- CS.JsonDotNet: apiCsForAPIWith :: (HasForeign CSharp Text api, GenerateList Text (Foreign Text api)) => GenerateCsConfig -> Proxy api -> IO String
- CS.JsonDotNet: assemblyInfoCsForAPI :: IO String
- CS.JsonDotNet: assemblyInfoCsForAPIWith :: GenerateCsConfig -> IO String
- CS.JsonDotNet: classCsForAPI :: IO String
- CS.JsonDotNet: classCsForAPIWith :: GenerateCsConfig -> IO String
- CS.JsonDotNet: converterCsForAPI :: IO String
- CS.JsonDotNet: converterCsForAPIWith :: GenerateCsConfig -> IO String
- CS.JsonDotNet: csprojForAPI :: IO String
- CS.JsonDotNet: csprojForAPIWith :: GenerateCsConfig -> IO String
- CS.JsonDotNet: enumCsForAPI :: IO String
- CS.JsonDotNet: enumCsForAPIWith :: GenerateCsConfig -> IO String
- CS.JsonDotNet: genCsForAPI :: (HasForeign CSharp Text api, GenerateList Text (Foreign Text api)) => GenerateCsConfig -> Proxy api -> IO ()
- CS.JsonDotNet: instance GHC.Show.Show CS.JsonDotNet.FieldType
+ CS: generateCsForAPI :: (HasSwagger api, HasForeign CSharp Text api, GenerateList Text (Foreign Text api)) => GenerateCsConfig -> Proxy api -> IO ()
+ CS.JsonDotNet: apiCsFrom :: (Monad m, HasForeign CSharp Text api, GenerateList Text (Foreign Text api)) => GenerateCsConfig -> Proxy api -> SwagT m String
+ CS.JsonDotNet: assemblyInfoCs :: GenerateCsConfig -> IO String
+ CS.JsonDotNet: classCs :: Monad m => GenerateCsConfig -> SwagT m String
+ CS.JsonDotNet: converterCs :: Monad m => GenerateCsConfig -> SwagT m String
+ CS.JsonDotNet: enumCs :: Monad m => SwagT m String
+ CS.JsonDotNet: generateCsForAPI :: (HasSwagger api, HasForeign CSharp Text api, GenerateList Text (Foreign Text api)) => GenerateCsConfig -> Proxy api -> IO ()
+ CS.JsonDotNet: projectCsproj :: GenerateCsConfig -> IO String
+ CS.JsonDotNet.Base: SwagT :: (Swagger -> m a) -> SwagT m a
+ CS.JsonDotNet.Base: [runSwagT] :: SwagT m a -> Swagger -> m a
+ CS.JsonDotNet.Base: generateFrom :: HasSwagger api => Swag a -> Proxy api -> a
+ CS.JsonDotNet.Base: instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (CS.JsonDotNet.Base.SwagT m)
+ CS.JsonDotNet.Base: instance Control.Monad.Trans.Class.MonadTrans CS.JsonDotNet.Base.SwagT
+ CS.JsonDotNet.Base: instance GHC.Base.Monad m => GHC.Base.Applicative (CS.JsonDotNet.Base.SwagT m)
+ CS.JsonDotNet.Base: instance GHC.Base.Monad m => GHC.Base.Functor (CS.JsonDotNet.Base.SwagT m)
+ CS.JsonDotNet.Base: instance GHC.Base.Monad m => GHC.Base.Monad (CS.JsonDotNet.Base.SwagT m)
+ CS.JsonDotNet.Base: instance GHC.Base.Monad m => GHC.Base.Monoid (CS.JsonDotNet.Base.SwagT m [a])
+ CS.JsonDotNet.Base: mkSwag :: Monad m => (Swagger -> a) -> SwagT m a
+ CS.JsonDotNet.Base: newtype SwagT m a
+ CS.JsonDotNet.Base: runSwagger :: Swag a -> Swagger -> a
+ CS.JsonDotNet.Base: type Swag = SwagT Identity
+ CS.JsonDotNet.Internal.Types: CRef :: CCate
+ CS.JsonDotNet.Internal.Types: CSt :: CCate
+ CS.JsonDotNet.Internal.Types: CVal :: CCate
+ CS.JsonDotNet.Internal.Types: DayConv :: ConverterType
+ CS.JsonDotNet.Internal.Types: EnumConv :: ConverterType
+ CS.JsonDotNet.Internal.Types: FBool :: FieldType
+ CS.JsonDotNet.Internal.Types: FDay :: FieldType
+ CS.JsonDotNet.Internal.Types: FEnum :: Text -> [Value] -> FieldType
+ CS.JsonDotNet.Internal.Types: FInteger :: FieldType
+ CS.JsonDotNet.Internal.Types: FList :: FieldType -> FieldType
+ CS.JsonDotNet.Internal.Types: FNullable :: FieldType -> FieldType
+ CS.JsonDotNet.Internal.Types: FNumber :: FieldType
+ CS.JsonDotNet.Internal.Types: FObject :: Text -> [(Text, FieldType)] -> FieldType
+ CS.JsonDotNet.Internal.Types: FRefEnum :: Text -> FieldType
+ CS.JsonDotNet.Internal.Types: FRefObject :: Text -> FieldType
+ CS.JsonDotNet.Internal.Types: FRefPrim :: Text -> FieldType -> FieldType
+ CS.JsonDotNet.Internal.Types: FString :: FieldType
+ CS.JsonDotNet.Internal.Types: FUTCTime :: FieldType
+ CS.JsonDotNet.Internal.Types: ItemConv :: ConverterType -> ConverterType
+ CS.JsonDotNet.Internal.Types: NoConv :: ConverterType
+ CS.JsonDotNet.Internal.Types: data CCate
+ CS.JsonDotNet.Internal.Types: data ConverterType
+ CS.JsonDotNet.Internal.Types: data FieldType
+ CS.JsonDotNet.Internal.Types: instance GHC.Show.Show CS.JsonDotNet.Internal.Types.CCate
+ CS.JsonDotNet.Internal.Types: instance GHC.Show.Show CS.JsonDotNet.Internal.Types.ConverterType
+ CS.JsonDotNet.Internal.Types: instance GHC.Show.Show CS.JsonDotNet.Internal.Types.FieldType
+ CS.JsonDotNet.Internal.Types: isFEnum :: FieldType -> Bool
+ CS.JsonDotNet.Internal.Types: isFObj :: FieldType -> Bool
+ CS.JsonDotNet.Internal.Types: isFPrim :: FieldType -> Bool
+ CS.JsonDotNet.Internal.Types: nullable :: FieldType -> CCate
- CS: GenerateCsConfig :: String -> String -> String -> String -> String -> String -> (GenerateCsConfig -> IO String) -> (forall api. (HasForeign CSharp Text api, GenerateList Text (Foreign Text api)) => GenerateCsConfig -> Proxy api -> IO String) -> (GenerateCsConfig -> IO String) -> (GenerateCsConfig -> IO String) -> (GenerateCsConfig -> IO String) -> (GenerateCsConfig -> IO String) -> Maybe String -> [FilePath] -> GenerateCsConfig
+ CS: GenerateCsConfig :: String -> String -> String -> String -> String -> Maybe UUID -> GenerateCsConfig
- CS: [guid] :: GenerateCsConfig -> Maybe String
+ CS: [guid] :: GenerateCsConfig -> Maybe UUID
- CS.JsonDotNet: GenerateCsConfig :: String -> String -> String -> String -> String -> String -> (GenerateCsConfig -> IO String) -> (forall api. (HasForeign CSharp Text api, GenerateList Text (Foreign Text api)) => GenerateCsConfig -> Proxy api -> IO String) -> (GenerateCsConfig -> IO String) -> (GenerateCsConfig -> IO String) -> (GenerateCsConfig -> IO String) -> (GenerateCsConfig -> IO String) -> Maybe String -> [FilePath] -> GenerateCsConfig
+ CS.JsonDotNet: GenerateCsConfig :: String -> String -> String -> String -> String -> Maybe UUID -> GenerateCsConfig
- CS.JsonDotNet: [guid] :: GenerateCsConfig -> Maybe String
+ CS.JsonDotNet: [guid] :: GenerateCsConfig -> Maybe UUID

Files

servant-csharp.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/  name:                servant-csharp-version:             0.0.7.1+version:             0.0.8.0 synopsis:            Generate servant client library for C# description:         Generate servant client library for C# homepage:            https://github.com/cutsea110/servant-csharp.git@@ -20,15 +20,20 @@   exposed-modules:     CS                      , CS.Common                      , CS.JsonDotNet+                     , CS.JsonDotNet.Base+                     , CS.JsonDotNet.Internal+                     , CS.JsonDotNet.Internal.Types   -- other-modules:          other-extensions:    OverloadedStrings                      , ScopedTypeVariables                      , MultiParamTypeClasses                      , FlexibleContexts                      , FlexibleInstances+                     , TupleSections                      , TypeSynonymInstances                      , QuasiQuotes-  build-depends:       base >=4.8 && <4.9+  build-depends:       aeson >= 0.11.1.4+                     , base >=4.8 && <4.9                      , bytestring >=0.10 && <0.11                      , directory >=1.2 && <1.3                      , filepath >=1.4 && <1.5@@ -36,10 +41,14 @@                      , heredocs >=0.1 && <0.2                      , http-types >=0.9 && <0.10                      , lens >=4.13 && <4.14+                     , mtl >= 2.2.1                      , servant >= 0.6.1                      , servant-foreign >=0.7 && <0.8+                     , servant-swagger >= 1.0.3+                     , swagger2 >= 2.0.2                      , text >=1.2 && <1.3                      , time >=1.5 && <1.6+                     , unordered-containers >= 0.2.7.0                      , uuid >=1.3 && <1.4                      , uuid-types >=1.0 && <1.1   hs-source-dirs:      src
src/CS.hs view
@@ -1,17 +1,4 @@-module CS ( genCsForAPI--          , classCsForAPI-          , classCsForAPIWith-          , apiCsForAPI-          , apiCsForAPIWith-          , enumCsForAPI-          , enumCsForAPIWith-          , converterCsForAPI-          , converterCsForAPIWith-          , assemblyInfoCsForAPI-          , assemblyInfoCsForAPIWith-          , csprojForAPI-          , csprojForAPIWith+module CS ( generateCsForAPI            , GenerateCsConfig(..)           , def
src/CS/JsonDotNet.hs view
@@ -1,255 +1,91 @@ {-# LANGUAGE ExplicitForAll #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GADTs #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-}-module CS.JsonDotNet ( genCsForAPI+{-# LANGUAGE TupleSections #-}+module CS.JsonDotNet ( GenerateCsConfig(..)+                     , def -                     , classCsForAPI-                     , classCsForAPIWith-                     , apiCsForAPI-                     , apiCsForAPIWith-                     , enumCsForAPI-                     , enumCsForAPIWith-                     , converterCsForAPI-                     , converterCsForAPIWith-                     , assemblyInfoCsForAPI-                     , assemblyInfoCsForAPIWith-                     , csprojForAPI-                     , csprojForAPIWith+                     , generateCsForAPI -                     , GenerateCsConfig(..)-                     , def+                     , apiCsFrom+                     , enumCs+                     , classCs+                     , converterCs+                     , assemblyInfoCs+                     , projectCsproj                      ) where -import Prelude hiding (concat, lines, unlines)-import Control.Arrow++import Control.Arrow ((***), (&&&)) import Control.Lens hiding ((<.>))+import Control.Monad.Trans+import Control.Monad.Identity+import Data.Aeson import Data.ByteString (ByteString) import Data.ByteString.Char8 as BC (unpack) import Data.Char (toUpper, toLower)-import Data.List (intercalate, concat)+import qualified Data.HashMap.Lazy as M+import Data.List (intercalate) import Data.Maybe (fromJust) import Data.Monoid ((<>)) import Data.Proxy-import Data.Text as T (Text, unpack, pack)+import Data.Swagger hiding (namespace)+import Data.Text as T (Text, unpack) import Data.Time.Clock (UTCTime(..), getCurrentTime) import Data.Time.Calendar (toGregorian)-import Data.UUID.Types (toString)+import System.Directory (createDirectoryIfMissing)+import System.FilePath ((</>),(<.>))+import Data.UUID.Types (toString, UUID) import Data.UUID.V4 as UUID (nextRandom)-import Language.Haskell.Exts import Servant.Foreign-import System.Directory (createDirectoryIfMissing)-import System.FilePath ((</>), (<.>))+import Servant.Swagger import Text.Heredoc  import CS.Common (CSharp, getEndpoints)+import CS.JsonDotNet.Internal+import CS.JsonDotNet.Base  data GenerateCsConfig     = GenerateCsConfig { namespace :: String-                       , outdir :: String                        , classCsName :: String                        , apiCsName :: String                        , enumCsName :: String                        , converterCsName :: String-                       , classtemplate :: GenerateCsConfig -> IO String-                       , apitemplate ::  forall api.-                                         (HasForeign CSharp Text api,-                                          GenerateList Text (Foreign Text api))-                                         => GenerateCsConfig-                                     -> Proxy api-                                     -> IO String-                       , enumtemplate :: GenerateCsConfig -> IO String-                       , convertertemplate :: GenerateCsConfig -> IO String-                       , assemblyinfotemplate :: GenerateCsConfig -> IO String-                       , csprojtemplate :: GenerateCsConfig -> IO String-                       , guid :: Maybe String-                       , sources :: [FilePath]+                       , guid :: Maybe UUID                        }  def :: GenerateCsConfig def = GenerateCsConfig { namespace = "ServantClientAPI"-                       , outdir = "gen"                        , classCsName = "Classes.cs"                        , apiCsName = "API.cs"                        , enumCsName = "Enum.cs"                        , converterCsName = "JsonConverter.cs"-                       , classtemplate = defClassTemplate-                       , apitemplate = defAPITemplate-                       , enumtemplate = defEnumTemplate-                       , convertertemplate = defConvTemplate-                       , assemblyinfotemplate = defAssemblyInfoTemplate-                       , csprojtemplate = defCsprojTemplate                        , guid = Nothing-                       , sources = []                        } -genCsForAPI :: (HasForeign CSharp Text api,-             GenerateList Text (Foreign Text api)) =>-            GenerateCsConfig -> Proxy api -> IO ()-genCsForAPI conf api = do-  guid' <- maybe (toString <$> UUID.nextRandom) return $ guid conf-  let conf' = conf { guid = Just guid' }-  createDirectoryIfMissing True $ outdir conf' </> namespace conf' </> "Properties"-  classCsForAPIWith conf' >>= writeFile (outdir conf' </> namespace conf' </> classCsName conf')-  apiCsForAPIWith conf' api >>= writeFile (outdir conf' </> namespace conf' </> apiCsName conf')-  enumCsForAPIWith conf' >>= writeFile (outdir conf' </> namespace conf' </> enumCsName conf')-  converterCsForAPIWith conf' >>= writeFile (outdir conf' </> namespace conf' </> converterCsName conf')-  assemblyInfoCsForAPIWith conf' >>= writeFile (outdir conf' </> namespace conf' </> "Properties" </> "AssemblyInfo.cs")-  csprojForAPIWith conf' >>= writeFile (outdir conf' </> namespace conf' </> namespace conf' <.> "csproj")- ---------------------------------------------------------------------------isDatatypeDecl :: Decl -> Bool-isDatatypeDecl (DataDecl _ DataType _ _ _ [qcon] _) = True-isDatatypeDecl _ = False -data FieldType = TInt-               | TString-               | TDay-               | TUTCTime-               | TEnum String-               | TGeneral String-               | TNewtype String FieldType-               | TList FieldType-               | TNullable FieldType--instance Show FieldType where-    show TInt = "int"-    show TString = "string"-    show TDay = "DateTime"-    show TUTCTime = "DateTime"-    show (TEnum s) = s-    show (TGeneral s) = s-    show (TNewtype s _) = s-    show (TList t) = "List<"<>show t<>">"-    show (TNullable TInt) = "int?"-    show (TNullable TString) = "string"-    show (TNullable TDay) = "DateTime?"-    show (TNullable TUTCTime) = "DateTime?"-    show (TNullable (TEnum t)) = show (TEnum t)<>"?"-    show (TNullable (TNewtype s TString)) = s-    show (TNullable (TNewtype s _)) = "Nullable<"<>s<>">"-    show (TNullable t) = "Nullable<"<>show t<>">"--showCSharpOriginalType :: FieldType -> String-showCSharpOriginalType TInt = "System.Int64"-showCSharpOriginalType TString = "System.String"-showCSharpOriginalType _ = error "don't support this type."--classTypes :: GenerateCsConfig -> IO [(String, [(String, FieldType)])]-classTypes conf = do-  enums <- fmap (map fst) $ enumTypes conf-  aliases <- usingAliases conf-  classTypesFromFiles enums aliases (sources conf)-    where-      classTypesFromFiles :: [String] -> [(String, FieldType)] -> [FilePath]-                          -> IO [(String, [(String, FieldType)])]-      classTypesFromFiles enums aliases hss-          = return . concat =<< mapM (classTypesFromFile enums aliases) hss--      classTypesFromFile :: [String] -> [(String, FieldType)] -> FilePath-                         -> IO [(String, [(String, FieldType)])]-      classTypesFromFile enums aliases hs = do-        ParseOk (Module _ _ _ _ _ _ decls) <- parseFile hs-        let xs = filter isDatatypeDecl decls-        return $ map toClass xs-            where-              toClass (DataDecl _ _ _ _ _ [qcon] _)-                  = toClass' qcon-              toClass' (QualConDecl _ _ _ (RecDecl (Ident name) fs))-                  = (name, map field fs)-              field ((Ident fname):[], ts)-                  = (fname, toType ts)-              toType :: Type -> FieldType-              toType (TyCon (UnQual (Ident t)))-                  = case t of-                      "String" -> TString-                      "Text" -> TString-                      "Int" -> TInt-                      "Integer" -> TInt-                      "Day" -> TDay-                      "UTCTime" -> TUTCTime-                      _ -> if t `elem` enums-                           then TEnum t-                           else maybe (TGeneral t) (TNewtype t)-                                    $ lookup t aliases-              toType (TyApp (TyCon (UnQual (Ident "Maybe"))) t)-                  = case toType t of-                      TList t -> TList t-                      t -> TNullable t-              toType (TyList t) = TList (toType t)-              toType _ = error "don't support this Type"-----------------------------------------------------------------------------isEnumLikeDataDecl :: Decl -> Bool-isEnumLikeDataDecl (DataDecl _ DataType _ _ _ xs _)-    = all isEnumLikeConDecl xs-isEnumLikeDataDecl _ = False--isEnumLikeConDecl :: QualConDecl -> Bool-isEnumLikeConDecl (QualConDecl _ _ _ (ConDecl _ [])) = True-isEnumLikeConDecl _ = False--enumTypes :: GenerateCsConfig -> IO [(String, [String])]-enumTypes = enumTypesFromFiles . sources-    where-      enumTypesFromFiles :: [FilePath] -> IO [(String, [String])]-      enumTypesFromFiles hss-          = return . concat =<< mapM enumTypesFromFile hss--      enumTypesFromFile :: FilePath -> IO [(String, [String])]-      enumTypesFromFile hs = do-        ParseOk (Module _ _ _ _ _ _ decls) <- parseFile hs-        let xs = filter isEnumLikeDataDecl decls-        return $ map toTuple xs-            where-              conName :: QualConDecl -> String-              conName (QualConDecl _ _ _ (ConDecl (Ident name) [])) = name-              conName _ = error "invalid enum type"-              toTuple (DataDecl _ _ _ (Ident name) _ xs _)-                  = (name, map conName xs)------------------------------------------------------------------------------- | TODO : more typeable-isNewtypeDecl :: Decl -> Bool-isNewtypeDecl (DataDecl _ NewType _ _ _ _ _) = True-isNewtypeDecl _ = False--isTypeDecl :: Decl -> Bool-isTypeDecl (TypeDecl _ _ _ _) = True-isTypeDecl _ = False--origType :: QualConDecl -> FieldType-origType (QualConDecl _ _ _ (RecDecl _ [(_, tycon)]))-    = origType' tycon--origType' :: Type -> FieldType-origType' (TyCon (UnQual (Ident t)))-    = case t of-        "String"  -> TString-        "Text"    -> TString-        "Int"     -> TInt-        "Integer" -> TInt-        t         -> error ("don't supported type. "<>t)--usingAliases :: GenerateCsConfig -> IO [(String, FieldType)]-usingAliases = usingAliasesFromFiles . sources-    where-      usingAliasesFromFiles :: [FilePath] -> IO [(String, FieldType)]-      usingAliasesFromFiles hss-          = return . concat =<< mapM usingAliasesFromFile hss--      usingAliasesFromFile :: FilePath -> IO [(String, FieldType)]-      usingAliasesFromFile hs = do-        ParseOk (Module _ _ _ _ _ _ decls) <- parseFile hs-        let xs = filter (\d -> isNewtypeDecl d || isTypeDecl d) decls-        return $ map toTuple xs-            where-              toTuple (DataDecl _ NewType _ (Ident name) _ [qcon] _)-                  = (name, origType qcon)-              toTuple (TypeDecl _ (Ident name) _ tycon)-                  = (name, origType' tycon)+-- | generate C# project+generateCsForAPI :: (HasSwagger api, HasForeign CSharp Text api,+                     GenerateList Text (Foreign Text api)) =>+                    GenerateCsConfig -> Proxy api -> IO ()+generateCsForAPI conf api = do+  let outDir = "gen" </> namespace conf+      swagger = toSwagger api+  writeFile (outDir </> "AssemblyInfo.cs") =<< assemblyInfoCs conf+  writeFile (outDir </> namespace conf <.> "csproj") =<< projectCsproj conf+  writeFile (outDir </> classCsName conf)+                $ runSwagger (classCs conf) swagger+  writeFile (outDir </> enumCsName conf)+                $ runSwagger enumCs swagger+  writeFile (outDir </> converterCsName conf)+                $ runSwagger (converterCs conf) swagger+  writeFile (outDir </> apiCsName conf)+                $ runSwagger (apiCsFrom conf api) swagger  -------------------------------------------------------------------------- retType :: Req Text -> String@@ -329,85 +165,11 @@ requestBodyExists :: Req Text -> Bool requestBodyExists = not . null . rqBody -classCsForAPI :: IO String-classCsForAPI = classCsForAPIWith def--classCsForAPIWith :: GenerateCsConfig -> IO String-classCsForAPIWith conf = (classtemplate conf) conf--apiCsForAPI :: (HasForeign CSharp Text api,-             GenerateList Text (Foreign Text api)) =>-            Proxy api -> IO String-apiCsForAPI = apiCsForAPIWith def--apiCsForAPIWith :: (HasForeign CSharp Text api,-                 GenerateList Text (Foreign Text api)) =>-                GenerateCsConfig -> Proxy api -> IO String-apiCsForAPIWith conf api = (apitemplate conf) conf api--enumCsForAPI :: IO String-enumCsForAPI = enumCsForAPIWith def--enumCsForAPIWith :: GenerateCsConfig -> IO String-enumCsForAPIWith conf = (enumtemplate conf) conf--converterCsForAPI :: IO String-converterCsForAPI = converterCsForAPIWith def--converterCsForAPIWith :: GenerateCsConfig -> IO String-converterCsForAPIWith conf = (convertertemplate conf) conf--defClassTemplate :: GenerateCsConfig -> IO String-defClassTemplate conf = do-  uas <- usingAliases conf-  classes <- classTypes conf-  return [heredoc|/* generated by servant-csharp */-using Newtonsoft.Json;-using Newtonsoft.Json.Converters;-using System;-using System.Collections.Generic;--#region type alias-$forall (n, t) <- uas-  using ${n} = ${showCSharpOriginalType t};-#endregion--namespace ${namespace conf}-{-    $forall (name, fields) <- classes-      #region ${name}-      [JsonObject("${name}")]-      public class ${name}-      {-          $forall (fname, ftype) <- fields-            $case ftype-              $of TDay-                [JsonProperty(PropertyName = "${fname}")]-                [JsonConverter(typeof(DayConverter))]-              $of TNullable TDay-                [JsonProperty(PropertyName = "${fname}")]-                [JsonConverter(typeof(DayConverter))]-              $of TEnum _-                [JsonProperty(PropertyName = "${fname}")]-                [JsonConverter(typeof(StringEnumConverter))]-              $of TNullable (TEnum _)-                [JsonProperty(PropertyName = "${fname}")]-                [JsonConverter(typeof(StringEnumConverter))]-              $of TList (TEnum _)-                [JsonProperty(PropertyName = "${fname}", ItemConverterType = typeof(StringEnumConverter))]-              $of _-                [JsonProperty(PropertyName = "${fname}")]-            public ${show ftype} ${fname} { get; set; }-      }-      #endregion-}-|]--defAPITemplate :: (HasForeign CSharp Text api,-                GenerateList Text (Foreign Text api)) =>-               GenerateCsConfig -> Proxy api -> IO String-defAPITemplate conf api = do-  uas <- usingAliases conf+apiCsFrom :: (Monad m, HasForeign CSharp Text api,+              GenerateList Text (Foreign Text api)) =>+             GenerateCsConfig -> Proxy api -> SwagT m String+apiCsFrom conf api = do+  uas <- prims   return [heredoc|/* generated by servant-csharp */ using Newtonsoft.Json; using System.Collections.Generic;@@ -420,7 +182,7 @@  #region type alias $forall (n, t) <- uas-  using ${n} = ${showCSharpOriginalType t};+  using ${T.unpack n} = ${showCSharpOriginalType t}; #endregion  namespace ${namespace conf}@@ -499,29 +261,206 @@ } |] -defEnumTemplate conf = do-  es <- enumTypes conf+--------------------------------------------------------------------------++defs :: Monad m => SwagT m [(Text, Schema)]+defs = mkSwag (M.toList . _swaggerDefinitions)++pathitems :: Monad m => SwagT m [(FilePath, PathItem)]+pathitems = mkSwag (M.toList . _swaggerPaths)++convProperty :: Monad m => ParamName -> Referenced Schema -> Bool+             -> SwagT m (ParamName, FieldType)+convProperty pname rs req+    = if req+      then convProp pname rs+      else do+        (n, f) <- convProp pname rs+        return (n, FNullable f)+    where+      convProp :: Monad m+                  => ParamName+                      -> Referenced Schema+                      -> SwagT m (ParamName, FieldType)+      convProp n (Ref (Reference s)) = convRef n s+      convProp n (Inline s) = convert (n, s)++convRef :: Monad m+           => ParamName -> Text -> SwagT m (ParamName, FieldType)+convRef pname tname = do+  fs <- enums <> prims <> models+  case lookup tname fs of+    Just ftype -> return $ (pname, conv ftype)+    Nothing -> error $ T.unpack $ "not found " <> pname+  where+    conv :: FieldType -> FieldType+    conv f | isFEnum f = FRefEnum tname+           | isFPrim f = FRefPrim tname f+           | isFObj  f = FRefObject tname+  +convObject :: Monad m => (Text, Schema) -> SwagT m (Text, FieldType)+convObject (name, s) = do+  return . (name,) . FObject name =<< fields+    where+      fields :: Monad m => SwagT m [(ParamName, FieldType)]+      fields = mapM (\(p, s) -> (convProperty p s (isReq p))) props+      props :: [(ParamName, Referenced Schema)]+      props = M.toList (_schemaProperties s)+      isReq :: ParamName -> Bool+      isReq pname = pname `elem` reqs+      reqs :: [ParamName]+      reqs = _schemaRequired s++convert :: Monad m => (Text, Schema) -> SwagT m (Text, FieldType)+convert (name, s) = do+  if not $ null enums'+  then return $ (name, FEnum name enums')+  else case type' of+         SwaggerString -> maybe (return (name, FString))+                                convByFormat+                                format'+         SwaggerInteger -> return (name, FInteger)+         SwaggerNumber -> return (name, FNumber)+         SwaggerBoolean -> return (name, FBool)+         SwaggerArray -> maybe (error "fail to convert SwaggerArray")+                               convByItemType+                               items'+         SwaggerNull -> error "convert don't support SwaggerNull yet"+         SwaggerObject -> convObject (name, s)+    where+      param' = _schemaParamSchema s+      items' = _paramSchemaItems param'+      type' = _paramSchemaType param'+      enums' = maybe [] id $ _paramSchemaEnum param'+      format' = _paramSchemaFormat param'+      convByFormat :: Monad m => Text -> SwagT m (Text, FieldType)+      convByFormat "date" = return (name, FDay)+      convByFormat "yyyy-mm-ddThh:MM:ssZ" = return (name, FUTCTime)+      convByItemType :: Monad m+                        => SwaggerItems Schema -> SwagT m (Text, FieldType)+      convByItemType (SwaggerItemsObject (Ref (Reference s))) = do+                      (n, t) <- convRef name s+                      return (n, FList t)+      convByItemType (SwaggerItemsPrimitive _ _)+          = error "don't support SwaggerItemsPrimitive yet"+      convByItemType (SwaggerItemsArray _)+          = error "don't support SwaggerItemsArray yet"++enums :: Monad m => SwagT m [(Text, FieldType)]+enums = filterM (return.isFEnum.snd) =<< mapM convert =<< defs++prims :: Monad m => SwagT m [(Text, FieldType)]+prims = filterM (return.isFPrim.snd) =<< mapM convert =<< defs++models :: Monad m => SwagT m [(Text, FieldType)]+models = filterM (return.isFObj.snd) =<< mapM convert =<< defs+enumCs :: Monad m => SwagT m String+enumCs = do+  es <- mapM (return.snd) =<< enums   return [heredoc|/* generated by servant-csharp */-namespace ${namespace conf}+namespace ServantClientBook {-    $forall (name, cs) <- es-      #region ${name}-      public enum ${name}+    $forall FEnum name cs <- es+      #region ${T.unpack name}+      public enum ${T.unpack name}       {-          $forall c <- cs-            ${c},+          $forall String c <- cs+            ${T.unpack c},       }       #endregion } |] -defConvTemplate conf = do+showCSharpOriginalType :: FieldType -> String+showCSharpOriginalType FInteger = "System.Int64"+showCSharpOriginalType FNumber = "System.Double"+showCSharpOriginalType FString = "System.String"+showCSharpOriginalType FDay = "System.DateTime"+showCSharpOriginalType FUTCTime = "System.DateTime"+showCSharpOriginalType _ = error "don't support this type."++show' :: FieldType -> String+show' FInteger = "int"+show' FNumber = "double"+show' FString = "string"+show' FBool = "bool"+show' FDay = "DateTime"+show' FUTCTime = "DateTime"+show' (FEnum name _) = T.unpack name+show' (FObject name _) = T.unpack name+show' (FList t) = "List<" <> show' t <> ">"+show' (FNullable t) = case nullable t of+                        CVal -> show' t <> "?"+                        CRef -> show' t+                        CSt  -> "Nullable<" <> show' t <> ">"+show' (FRefObject name) = T.unpack name+show' (FRefEnum name) = T.unpack name+show' (FRefPrim name _) = T.unpack name++converterType :: FieldType -> ConverterType+converterType FDay = DayConv+converterType (FRefPrim _ FDay) = DayConv+converterType (FEnum _ _) = EnumConv+converterType (FRefEnum _) = EnumConv+converterType (FNullable t) = converterType t+converterType (FList t) = case converterType t of+                            DayConv -> ItemConv DayConv+                            EnumConv -> ItemConv EnumConv+                            t' -> t'+converterType _ = NoConv+++classCs :: Monad m => GenerateCsConfig -> SwagT m String+classCs conf = do+  ps <- prims+  ms <- models   return [heredoc|/* generated by servant-csharp */ using Newtonsoft.Json;+using Newtonsoft.Json.Converters; using System;+using System.Collections.Generic; +#region type alias+$forall (n, t) <- ps+  using ${T.unpack n} = ${showCSharpOriginalType t};+#endregion+ namespace ${namespace conf} {+    $forall (_, FObject name' fields) <- ms+      $let name = T.unpack name'+        #region ${name}+        [JsonObject("${name}")]+        public class ${name}+        {+            $forall (fname', ftype) <- fields+              $let fname = T.unpack fname'+                $case converterType ftype+                  $of DayConv+                    [JsonProperty(PropertyName = "${fname}")]+                    [JsonConverter(typeof(DayConverter))]+                  $of ItemConv DayConv+                    [JsonProperty(PropertyName = "${fname}", ItemConverterType = typeof(DayConverter))]+                  $of EnumConv+                    [JsonProperty(PropertyName = "${fname}")]+                    [JsonConverter(typeof(StringEnumConverter))]+                  $of ItemConv EnumConv+                    [JsonProperty(PropertyName = "${fname}", ItemConverterType = typeof(StringEnumConverter))]+                  $of _+                    [JsonProperty(PropertyName = "${fname}")]+                public ${show' ftype} ${fname} { get; set; }+        }+        #endregion+}+|]++converterCs :: Monad m => GenerateCsConfig -> SwagT m String+converterCs conf = return [heredoc|/* generated by servant-csharp */+using Newtonsoft.Json;+using System;++namespace ${namespace conf}+{     public class DayConverter : JsonConverter     {         public override bool CanConvert(Type objectType)@@ -543,18 +482,10 @@ } |] -----------------------------------------------------------------------------assemblyInfoCsForAPI :: IO String-assemblyInfoCsForAPI = assemblyInfoCsForAPIWith def--assemblyInfoCsForAPIWith :: GenerateCsConfig -> IO String-assemblyInfoCsForAPIWith conf = (assemblyinfotemplate conf) conf--defAssemblyInfoTemplate :: GenerateCsConfig -> IO String-defAssemblyInfoTemplate conf = do+assemblyInfoCs :: GenerateCsConfig -> IO String+assemblyInfoCs conf = do   (year, _, _) <- fmap (toGregorian . utctDay) getCurrentTime-  guid <- maybe (toString <$> UUID.nextRandom) return $ guid conf+  guid' <- maybe UUID.nextRandom return $ guid conf   return [heredoc| using System.Reflection; using System.Runtime.CompilerServices;@@ -571,31 +502,25 @@  [assembly: ComVisible(false)] -[assembly: Guid("${guid}")]+[assembly: Guid("${toString guid'}")]  // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] |] -----------------------------------------------------------------------------csprojForAPI :: IO String-csprojForAPI = csprojForAPIWith def--csprojForAPIWith :: GenerateCsConfig -> IO String-csprojForAPIWith conf = (csprojtemplate conf) conf--defCsprojTemplate :: GenerateCsConfig -> IO String-defCsprojTemplate conf = do-  guid <- maybe ((map toUpper . toString) <$> UUID.nextRandom) return $ guid conf+projectCsproj :: GenerateCsConfig -> IO String+projectCsproj conf = do+  guid' <- maybe ((map toUpper . toString) <$> UUID.nextRandom)+                 (return . toString)+                 $ guid conf   return [heredoc|<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">   <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />   <PropertyGroup>     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>-    <ProjectGuid>{${guid}}</ProjectGuid>+    <ProjectGuid>{${guid'}}</ProjectGuid>     <OutputType>Library</OutputType>     <AppDesignerFolder>Properties</AppDesignerFolder>     <RootNamespace>${namespace conf}</RootNamespace>
+ src/CS/JsonDotNet/Base.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE FlexibleInstances #-}+module CS.JsonDotNet.Base where++import Control.Monad.Trans+import Control.Monad.Identity+import Data.Proxy+import Data.Swagger hiding (namespace)+import Servant.Swagger++type Swag = SwagT Identity++runSwagger :: Swag a -> Swagger -> a+runSwagger f = runIdentity . runSwagT f++mkSwag :: Monad m => (Swagger -> a) -> SwagT m a+mkSwag f = SwagT (return . f)++generateFrom :: HasSwagger api => Swag a -> Proxy api -> a+f `generateFrom` api = runSwagger f (toSwagger api)++newtype SwagT m a = SwagT { runSwagT :: Swagger -> m a }+instance Monad m => Functor (SwagT m) where+    fmap f x = SwagT $ \sw -> return . f =<< runSwagT x sw+instance Monad m => Applicative (SwagT m) where+    pure x = SwagT $ \sw -> return x+    f <*> g = SwagT $ \sw -> do+                f' <- runSwagT f sw+                g' <- runSwagT g sw+                return (f' g')+instance Monad m => Monad (SwagT m) where+    f >>= k = SwagT $ \sw ->+              runSwagT f sw >>= \f' ->+              runSwagT (k f') sw++instance Monad m => Monoid (SwagT m [a]) where+    mempty = SwagT $ \sw -> return mempty+    x `mappend` y = SwagT $ \sw -> do+                      x' <- runSwagT x sw+                      y' <- runSwagT y sw+                      return $ x' `mappend` y'++instance MonadTrans SwagT where+    lift m = SwagT $ \sw -> m++instance MonadIO m => MonadIO (SwagT m) where+    liftIO x = SwagT $ \sw -> liftIO x
+ src/CS/JsonDotNet/Internal.hs view
@@ -0,0 +1,4 @@+module CS.JsonDotNet.Internal ( module CS.JsonDotNet.Internal.Types+                              ) where++import CS.JsonDotNet.Internal.Types
+ src/CS/JsonDotNet/Internal/Types.hs view
@@ -0,0 +1,60 @@+module CS.JsonDotNet.Internal.Types where++import Data.Aeson+import Data.Text++data FieldType = FInteger+               | FNumber+               | FString+               | FBool+               | FDay+               | FUTCTime+               | FEnum Text [Value]+               | FObject Text [(Text, FieldType)]+               | FList FieldType+               | FNullable FieldType++               | FRefObject Text+               | FRefEnum Text+               | FRefPrim Text FieldType+                 deriving Show++isFEnum :: FieldType -> Bool+isFEnum (FEnum _ _) = True+isFEnum _ = False++isFPrim :: FieldType -> Bool+isFPrim FString = True+isFPrim FInteger = True+isFPrim FNumber = True+isFPrim FBool = True+isFPrim FDay = True+isFPrim FUTCTime = True+isFPrim _ = False++isFObj :: FieldType -> Bool+isFObj (FObject _ _) = True+isFObj _ = False++data CCate = CVal | CRef | CSt deriving Show++nullable :: FieldType -> CCate+nullable FInteger = CVal+nullable FNumber = CVal+nullable FString = CRef+nullable FBool = CVal+nullable FDay = CVal+nullable FUTCTime = CVal+nullable (FEnum _ _) = CSt+nullable (FObject _ _) = CSt+nullable (FList _) = CRef+nullable (FNullable _) = CRef+nullable (FRefObject _) = CVal+nullable (FRefEnum _) = CVal+nullable (FRefPrim _ t) = nullable t++data ConverterType = NoConv+                   | DayConv+                   | EnumConv+                   | ItemConv ConverterType+                     deriving Show