diff --git a/nix/tests.nix b/nix/tests.nix index 37c2f62..c199702 100644 --- a/nix/tests.nix +++ b/nix/tests.nix @@ -26,6 +26,7 @@ let (generateCode { fileName = "spot_api.yml"; extraFlags = [ "--opaque-schema=\"aggTrade\"" ]; }) (generateCode { fileName = "uber.json"; }) (generateCode { fileName = "z_complex_self_made_example.yml"; }) + (generateCode { fileName = "petstore.yaml"; extraFlags = [ "--module-name=\"Petstore.API\"" ]; }) ]; codeForSpecsLevelTwo = [ (generateCode { fileName = "official-petstore.yaml"; }) diff --git a/openapi3-code-generator/src/OpenAPI/Generate/IO.hs b/openapi3-code-generator/src/OpenAPI/Generate/IO.hs index 540503c..d25caed 100644 --- a/openapi3-code-generator/src/OpenAPI/Generate/IO.hs +++ b/openapi3-code-generator/src/OpenAPI/Generate/IO.hs @@ -152,16 +152,18 @@ permitProceed settings = do getHsBootFiles :: OAO.Settings -> [([String], String)] -> FilesWithContent getHsBootFiles settings modelModules = let outputDirectory = T.unpack $ OAO.settingOutputDir settings - moduleName = T.unpack $ OAO.settingModuleName settings + moduleName = OAO.settingModuleName settings + moduleNameStr = OAO.getModuleName moduleName + modulePathInfo = OAO.mkModulePathInfo moduleName in BF.bimap - ((outputDirectory ) . (srcDirectory ) . (moduleName ) . (<> ".hs-boot") . foldr1 ()) + ((\suffix -> outputDirectory srcDirectory OAO.getModuleInfoPath modulePathInfo (Just suffix) ".hs-boot") . foldr1 ()) ( T.unpack . T.unlines . ( \xs -> case xs of x : xs' -> x : "import qualified Data.Aeson" - : "import qualified " <> T.pack moduleName <> ".Common" + : "import qualified " <> T.pack moduleNameStr <> ".Common" : xs' _ -> xs ) @@ -202,19 +204,21 @@ data OutputFiles = OutputFiles generateFilesToCreate :: OAT.OpenApiSpecification -> OAO.Settings -> IO OutputFiles generateFilesToCreate spec settings = do let outputDirectory = T.unpack $ OAO.settingOutputDir settings - moduleName = T.unpack $ OAO.settingModuleName settings + moduleName = OAO.settingModuleName settings + modulePathInfo = OAO.mkModulePathInfo moduleName + moduleNameStr = OAO.getModuleName moduleName packageName = T.unpack $ OAO.settingPackageName settings env = OAM.createEnvironment settings $ Ref.buildReferenceMap spec logMessages = mapM_ (putStrLn . T.unpack) . OAL.filterAndTransformLogs (OAO.settingLogLevel settings) - showAndReplace = replaceOpenAPI moduleName . show - ((operationsQ, operationDependencies), logs) = OAM.runGenerator env $ defineOperations moduleName spec + showAndReplace = replaceOpenAPI moduleNameStr . show + ((operationsQ, operationDependencies), logs) = OAM.runGenerator env $ defineOperations moduleNameStr spec logMessages logs operationModules <- runQ operationsQ - configurationInfo <- runQ $ defineConfigurationInformation moduleName spec - let (modelsQ, logsModels) = OAM.runGenerator env $ defineModels moduleName spec operationDependencies + configurationInfo <- runQ $ defineConfigurationInformation moduleNameStr spec + let (modelsQ, logsModels) = OAM.runGenerator env $ defineModels moduleNameStr spec operationDependencies logMessages logsModels modelModules <- fmap (BF.second showAndReplace) <$> runQ modelsQ - let (securitySchemesQ, logs') = OAM.runGenerator env $ defineSecuritySchemes moduleName spec + let (securitySchemesQ, logs') = OAM.runGenerator env $ defineSecuritySchemes moduleNameStr spec logMessages logs' securitySchemes' <- runQ securitySchemesQ let modules = @@ -222,34 +226,35 @@ generateFilesToCreate spec settings = do <> modelModules <> [ (["Configuration"], showAndReplace configurationInfo), (["SecuritySchemes"], showAndReplace securitySchemes'), - (["Common"], replaceOpenAPI moduleName $ replaceVersionNumber $(embedFile "src/OpenAPI/Common.hs")) + (["Common"], replaceOpenAPI moduleNameStr $ replaceVersionNumber $(embedFile "src/OpenAPI/Common.hs")) ] modulesToExport = fmap - ( (moduleName <>) + ( (moduleNameStr <>) . ("." <>) . joinWithPoint . fst ) modules - mainFile = outputDirectory srcDirectory (moduleName ++ ".hs") - mainModuleContent = show $ Doc.createModuleHeaderWithReexports moduleName modulesToExport "The main module which exports all functionality." + mainFile = outputDirectory srcDirectory OAO.getModuleInfoPath modulePathInfo Nothing ".hs" + mainModuleContent = show $ Doc.createModuleHeaderWithReexports moduleNameStr modulesToExport "The main module which exports all functionality." hsBootFiles = getHsBootFiles settings modelModules pure $ OutputFiles ( BF.second (unlines . lines) <$> (mainFile, mainModuleContent) - : (BF.first ((outputDirectory ) . (srcDirectory ) . (moduleName ) . (<> ".hs") . foldr1 ()) <$> modules) + : (BF.first ((\suffix -> outputDirectory srcDirectory OAO.getModuleInfoPath modulePathInfo (Just suffix) ".hs") . foldr1 ()) <$> modules) <> hsBootFiles ) - (BF.first (outputDirectory ) <$> cabalProjectFiles packageName moduleName modulesToExport) + (BF.first (outputDirectory ) <$> cabalProjectFiles packageName moduleNameStr modulesToExport) (BF.first (outputDirectory ) <$> stackProjectFiles) (BF.first (outputDirectory ) <$> nixProjectFiles packageName) writeFiles :: OAO.Settings -> OutputFiles -> IO () writeFiles settings OutputFiles {..} = do let outputDirectory = T.unpack $ OAO.settingOutputDir settings - moduleName = T.unpack $ OAO.settingModuleName settings + modulePathInfo = OAO.mkModulePathInfo $ OAO.settingModuleName settings + moduleDir = OAO.getModuleInfoDir modulePathInfo incremental = OAO.settingIncremental settings write = mapM_ $ if incremental then writeFileIncremental else writeFileWithLog putStrLn "Remove old output directory" @@ -257,8 +262,8 @@ writeFiles settings OutputFiles {..} = do void $ tryIOError (removeDirectoryRecursive outputDirectory) putStrLn "Output directory removed, create missing directories" - createDirectoryIfMissing True (outputDirectory srcDirectory moduleName "Operations") - createDirectoryIfMissing True (outputDirectory srcDirectory moduleName "Types") + createDirectoryIfMissing True (outputDirectory srcDirectory moduleDir "Operations") + createDirectoryIfMissing True (outputDirectory srcDirectory moduleDir "Types") putStrLn "Directories created" write outputFilesModuleFiles write outputFilesCabalFiles diff --git a/openapi3-code-generator/src/OpenAPI/Generate/OptParse.hs b/openapi3-code-generator/src/OpenAPI/Generate/OptParse.hs index 7cac6c8..3d5a927 100644 --- a/openapi3-code-generator/src/OpenAPI/Generate/OptParse.hs +++ b/openapi3-code-generator/src/OpenAPI/Generate/OptParse.hs @@ -7,6 +7,7 @@ module OpenAPI.Generate.OptParse ( Settings (..), getSettings, + module OAT, ) where @@ -19,7 +20,7 @@ import qualified Data.Text as T import qualified OpenAPI.Generate.Log as OAL import OpenAPI.Generate.OptParse.Configuration import OpenAPI.Generate.OptParse.Flags -import OpenAPI.Generate.OptParse.Types +import OpenAPI.Generate.OptParse.Types as OAT import Options.Applicative import Options.Applicative.Help (string) import Path @@ -42,7 +43,7 @@ data Settings = Settings -- | Name of the stack project settingPackageName :: !Text, -- | Name of the module - settingModuleName :: !Text, + settingModuleName :: !ModuleName, -- | The minimum log level to output settingLogLevel :: !OAL.LogSeverity, -- | Overwrite output directory without question @@ -127,7 +128,7 @@ combineToSettings Flags {..} mConf configurationFilePath = do let settingOpenApiSpecification = fromMaybe "openapi-specification.yml" $ flagOpenApiSpecification <|> mConfigOpenApiSpecification settingOutputDir = fromMaybe "out" $ flagOutputDir <|> mConfigOutputDir settingPackageName = fromMaybe "openapi" $ flagPackageName <|> mc configPackageName - settingModuleName = fromMaybe "OpenAPI" $ flagModuleName <|> mc configModuleName + settingModuleName = mkModuleName . T.unpack $ fromMaybe "OpenAPI" (flagModuleName <|> mc configModuleName) settingLogLevel = fromMaybe OAL.InfoSeverity $ flagLogLevel <|> mc configLogLevel settingForce = fromMaybe False $ flagForce <|> mc configForce settingIncremental = fromMaybe False $ flagIncremental <|> mc configIncremental diff --git a/openapi3-code-generator/src/OpenAPI/Generate/OptParse/Types.hs b/openapi3-code-generator/src/OpenAPI/Generate/OptParse/Types.hs index bc64d52..65d6ac5 100644 --- a/openapi3-code-generator/src/OpenAPI/Generate/OptParse/Types.hs +++ b/openapi3-code-generator/src/OpenAPI/Generate/OptParse/Types.hs @@ -1,9 +1,60 @@ +{-# LANGUAGE OverloadedStrings #-} + module OpenAPI.Generate.OptParse.Types ( FixedValueStrategy (..), + ModuleName, + ModulePathInfo, + mkModuleName, + getModuleName, + mkModulePathInfo, + getModuleInfoPath, + getModuleInfoDir, ) where import Autodocodec +import qualified Data.Maybe as Maybe +import qualified Data.Text as T +import System.FilePath (()) + +newtype ModuleName = ModuleName String + deriving (Show, Eq) + +newtype ModulePathInfo = ModulePathInfo (Maybe FilePath, FilePath) + +mkModuleName :: String -> ModuleName +mkModuleName = ModuleName + +getModuleName :: ModuleName -> String +getModuleName (ModuleName moduleNameStr) = moduleNameStr + +mkModulePathInfo :: ModuleName -> ModulePathInfo +mkModulePathInfo (ModuleName moduleNameStr) = + let (dirMay, fileNoExtensionMay) = + foldl + ( \acc next -> + let dMay = case acc of + (Nothing, Just prev) -> Just prev + (Just dir, Just prev) -> Just $ dir prev + (dMay', Nothing) -> dMay' + in (dMay, Just $ T.unpack next) + ) + (Nothing, Nothing) + . T.splitOn "." + . T.pack + $ moduleNameStr + in ModulePathInfo (dirMay, Maybe.fromMaybe moduleNameStr fileNoExtensionMay) + +getModuleInfoPath :: ModulePathInfo -> Maybe String -> String -> FilePath +getModuleInfoPath (ModulePathInfo (dirMay, fileNoExtension)) suffixMay extension = + let file = case suffixMay of + Nothing -> fileNoExtension <> extension + Just suffix -> fileNoExtension suffix <> extension + in maybe file ( file) dirMay + +getModuleInfoDir :: ModulePathInfo -> FilePath +getModuleInfoDir (ModulePathInfo (dirMay, fileNoExtension)) = + maybe fileNoExtension ( fileNoExtension) dirMay data FixedValueStrategy = FixedValueStrategyExclude | FixedValueStrategyInclude deriving (Eq, Bounded, Enum)