dotenv 0.8.0.7 → 0.9.0.0
raw patch · 17 files changed
+41/−687 lines, 17 filesdep −voiddep −yamldep ~basePVP ok
version bump matches the API change (PVP)
Dependencies removed: void, yaml
Dependency ranges changed: base
API changes (from Hackage documentation)
- Configuration.Dotenv: defaultValidatorMap :: ValidatorMap
- Configuration.Dotenv: loadSafeFile :: MonadIO m => ValidatorMap -> FilePath -> Config -> m [(String, String)]
- Configuration.Dotenv: type ValidatorMap = Map Text (Text -> Bool)
Files
- CHANGELOG.md +10/−0
- README.md +1/−64
- app/Main.hs +9/−25
- dotenv.cabal +8/−27
- spec/Configuration/Dotenv/Scheme/ParseSpec.hs +0/−35
- spec/Configuration/Dotenv/SchemeSpec.hs +0/−84
- spec/Configuration/DotenvSpec.hs +10/−67
- spec/fixtures/.dotenv.safe +0/−5
- spec/fixtures/.scheme.yml +0/−16
- src/Configuration/Dotenv.hs +1/−23
- src/Configuration/Dotenv/Environment.hs +2/−12
- src/Configuration/Dotenv/Parse.hs +0/−12
- src/Configuration/Dotenv/ParsedVariable.hs +0/−5
- src/Configuration/Dotenv/Scheme.hs +0/−70
- src/Configuration/Dotenv/Scheme/Helpers.hs +0/−87
- src/Configuration/Dotenv/Scheme/Parser.hs +0/−65
- src/Configuration/Dotenv/Scheme/Types.hs +0/−90
CHANGELOG.md view
@@ -1,4 +1,14 @@ ## MASTER++## Dotenv 0.9.0.0+* Remove `loadSafeFile`. Users must create their own parsers to convert the+read values from `System.Environment` to another data type. Therefore,+`loadSafeFile` won't be needed. We'll remove this functionality to reduce+dependencies.++## Dotenv 0.8.1.0+* Correct bounds for base. GHC support for versions older than 8.0 was dropped.+ ## Dotenv 0.8.0.7 * Allow megaparsec-0.9.0.0
README.md view
@@ -1,4 +1,4 @@-[](https://travis-ci.org/stackbuilders/dotenv-hs) [](http://hackage.haskell.org/package/dotenv)+[](https://github.com/stackbuilders/dotenv-hs/actions/workflows/build-and-test.yml) [](http://hackage.haskell.org/package/dotenv) # Dotenv files for Haskell @@ -80,46 +80,6 @@ postgres://myusername@localhost/database ``` -### Type checking envs-Env variables are simple strings. However, they can represent other types like-integers, booleans, IP addresses, emails, URIs, and so on. We provide an interface-that performs type checking after loading the envs and before running your application.-If the type-check succeeded the application is executed, otherwise you will get an-error with the types that mismatch.--In order to use this functionality you can use the `loadSafeFile` which takes the same-configuration value as the `loadFile` function. Also, you need to have a `.schema.yml`-in your current directory. This file must have the following structure:--```yaml-- name: DOTENV- type: bool- required: true-- name: OTHERENV- type: bool-- name: PORT- type: integer- required: true-- name: TOKEN- type: text- required: false-```--It is a list of type and envs. So, in this example, `DOTENV` must have a value-of `true` or `false` otherwise it won't be parsed as a boolean value. And envs-like `PORT` must be any integer. Currently, we are supporting the following types:--- `bool` - Accepts values `false` or `true`-- `integer` - Accepts values of possitive integers-- `text` - Any text--**require** specifies if the env var is obligatory or not. In case you set it to true-but do not provide it, you wil get an exception. When **required** is omited, the default-value is `false`.--**NOTE:** All the variables which are **required** in the `schema.yml` must be defined-in the dotenvs.- ## Configuration The first argument to `loadFile` specifies the configuration. You cans use@@ -211,29 +171,6 @@ current environment settings. By invoking the program `env` in place of `myprogram` above you can see what the environment will look like after evaluating multiple Dotenv files.--The `--schema FILE` will get the envs configuration from the `FILE`. For instance:--```shell-$ cat .env-PORT=123a-$ cat .schema.yml-- name: PORT- required: true- type: integer-```--running `dotenv` will throw:--```shell-$ dotenv -s .schema.yml "echo $PORT"-dotenv: 1:4:-unexpected 'a'-expecting digit or end of input-```--**NOTE:** The flag can be omited when the `.schema.yml` is in the current working-directory. To disable type checking add the flag `--no-schema`. ## Author
app/Main.hs view
@@ -3,25 +3,20 @@ module Main where -import Data.Version (showVersion)-#if MIN_VERSION_optparse_applicative(0,13,0)-import Data.Monoid ((<>))+import Data.Version (showVersion)+#if !MIN_VERSION_base(4,13,0)+import Data.Monoid ((<>)) #endif -import Options.Applicative-import Paths_dotenv (version)+import Options.Applicative+import Paths_dotenv (version) -import Control.Monad (void, unless)+import Control.Monad (void) -import Configuration.Dotenv- (Config(..)- , loadFile- , loadSafeFile- , defaultConfig- , defaultValidatorMap)+import Configuration.Dotenv (Config (..), defaultConfig, loadFile) -import System.Process (system)-import System.Exit (exitWith)+import System.Exit (exitWith)+import System.Process (system) data Options = Options { dotenvFiles :: [String]@@ -29,8 +24,6 @@ , override :: Bool , program :: String , args :: [String]- , schemaFile :: FilePath- , disableSchema :: Bool } deriving (Show) main :: IO ()@@ -47,8 +40,6 @@ } in do void $ loadFile configDotenv- unless disableSchema- (void $ loadSafeFile defaultValidatorMap schemaFile configDotenv) system (program ++ concatMap (" " ++) args) >>= exitWith where opts = info (helper <*> versionOption <*> config)@@ -80,10 +71,3 @@ <*> argument str (metavar "PROGRAM") <*> many (argument str (metavar "ARG"))-- <*> strOption ( long "schema"- <> short 's'- <> help "Set the file path for the schema.yml file"- <> value ".schema.yml" )-- <*> switch ( long "no-schema" <> help "Omit type checking" )
dotenv.cabal view
@@ -1,5 +1,5 @@ name: dotenv-version: 0.8.0.7+version: 0.9.0.0 synopsis: Loads environment variables from dotenv files homepage: https://github.com/stackbuilders/dotenv-hs description:@@ -49,8 +49,6 @@ data-files: .dotenv .dotenv.example- .scheme.yml- .dotenv.safe flag static description: Creates static binary.@@ -64,15 +62,14 @@ executable dotenv main-is: Main.hs- build-depends: base >=4.7 && <5.0+ build-depends: base >= 4.9 && < 5.0 , base-compat >= 0.4 , dotenv- , optparse-applicative >=0.11 && < 0.17+ , optparse-applicative >= 0.11 && < 0.17 , megaparsec , process , text- , transformers >=0.4 && < 0.6- , yaml >= 0.8+ , transformers >= 0.4 && < 0.6 other-modules: Paths_dotenv hs-source-dirs: app@@ -92,12 +89,8 @@ , Configuration.Dotenv.ParsedVariable , Configuration.Dotenv.Text , Configuration.Dotenv.Types- , Configuration.Dotenv.Scheme- , Configuration.Dotenv.Scheme.Helpers- , Configuration.Dotenv.Scheme.Parser- , Configuration.Dotenv.Scheme.Types - build-depends: base >=4.7 && <5.0+ build-depends: base >= 4.9 && < 5.0 , base-compat >= 0.4 , directory , megaparsec >= 7.0.1 && < 10.0@@ -106,11 +99,7 @@ , text , transformers >=0.4 && < 0.6 , exceptions >= 0.8 && < 0.11- , yaml >= 0.8 - if !impl(ghc >= 7.10)- build-depends: void == 0.7.*- hs-source-dirs: src ghc-options: -Wall if flag(dev)@@ -132,14 +121,8 @@ , Configuration.Dotenv.Types , Configuration.Dotenv.Parse , Configuration.Dotenv.ParsedVariable- , Configuration.Dotenv.SchemeSpec- , Configuration.Dotenv.Scheme.ParseSpec- , Configuration.Dotenv.Scheme- , Configuration.Dotenv.Scheme.Helpers- , Configuration.Dotenv.Scheme.Parser- , Configuration.Dotenv.Scheme.Types - build-depends: base >=4.7 && <5.0+ build-depends: base >= 4.9 && < 5.0 , base-compat >= 0.4 , containers , dotenv@@ -148,13 +131,11 @@ , hspec , process , text- , transformers >=0.4 && < 0.6+ , transformers >= 0.4 && < 0.6 , exceptions >= 0.8 && < 0.11 , hspec-megaparsec >= 2.0 && < 3.0- , yaml >= 0.8 - if !impl(ghc >= 7.10)- build-depends: void == 0.7.*+ build-tools: hspec-discover >= 2.0 && < 3.0 if flag(dev) ghc-options: -Wall -Werror
− spec/Configuration/Dotenv/Scheme/ParseSpec.hs
@@ -1,35 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--{-# OPTIONS_GHC -fno-warn-orphans #-}--module Configuration.Dotenv.Scheme.ParseSpec (spec) where--import Data.Yaml (decodeFileEither)-import Test.Hspec--import Configuration.Dotenv.Scheme.Types---- | Extract Right from Either----fromRight :: (Show a, Show b) => Either a b -> b-fromRight (Right v) = v-fromRight (Left v) = error ("Left " ++ show v ++ " constructor instead" )---- |----spec :: Spec-spec =- describe "parse a config env file" $- it "parses the env config values from a file" $- let expected :: [Env]- expected =- [ Env "DOTENV" (EnvType "bool") True- , Env "OTHERENV" (EnvType "bool") False- , Env "PORT" (EnvType "integer") True- , Env "TOKEN" (EnvType "integer") False- , Env "URL" (EnvType "text") True- , Env "TWO" (EnvType "twoLetters") False- ]- in do- actual <- decodeFileEither "spec/fixtures/.scheme.yml"- fromRight actual `shouldBe` expected
− spec/Configuration/Dotenv/SchemeSpec.hs
@@ -1,84 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Configuration.Dotenv.SchemeSpec (spec) where--import Configuration.Dotenv.Scheme-import Configuration.Dotenv.Scheme.Types-import Control.Exception (evaluate)--import Test.Hspec---- |----spec :: Spec-spec = do- describe "checkScheme" $ do- context "when the env configs are unique" $- it "should succeed the check" $- let schemeEnvs =- [ Env "FOO" (EnvType "bool") True- , Env "BAR" (EnvType "integer") True- ]- in checkScheme schemeEnvs `shouldBe` schemeEnvs-- context "when there are duplicated env configs" $- it "should fail the check" $- let schemeEnvs =- [ Env "FOO" (EnvType "bool") True- , Env "BAR" (EnvType "integer") True- , Env "FOO" (EnvType "integer") True- ]- msg = "Duplicated env variable configuration in schema: FOO"- in evaluate (checkScheme schemeEnvs) `shouldThrow` errorCall msg-- describe "checkConfig" $- context "when the envs have the correct type" $ do- context "when the envs in the dotenvs are defined in the scheme" $ do- context "when the required envs are defined" $- it "should succeed the type check" $- let schemeEnvs =- [ Env "FOO" (EnvType "bool") True- , Env "BAR" (EnvType "integer") False- ]- dotenvs = [("FOO","True"), ("BAR","123")]- in checkConfig defaultValidatorMap dotenvs schemeEnvs `shouldReturn` ()-- context "when the not required envs are missing" $- it "should succeed the type check" $- let schemeEnvs =- [ Env "FOO" (EnvType "bool") True- , Env "BAR" (EnvType "integer") False- ]- dotenvs = [("FOO","True")]- in checkConfig defaultValidatorMap dotenvs schemeEnvs `shouldReturn` ()-- context "when the required envs are missing" $- it "should fail before the type check" $- let schemeEnvs =- [ Env "FOO" (EnvType "bool") True- , Env "BAR" (EnvType "integer") False- ]- dotenvs = [("BAR","123")]- msg = "The following envs: FOO must be in the dotenvs"- in checkConfig defaultValidatorMap dotenvs schemeEnvs `shouldThrow` errorCall msg-- context "when there are missing dotenvs in the scheme" $- it "should fail before type checking" $- let schemeEnvs =- [ Env "FOO" (EnvType "bool") True- , Env "BAR" (EnvType "integer") False- ]- dotenvs = [("FOO","True"), ("BAR","123"), ("BAZ","text")]- msg = "The following envs: BAZ must be in your scheme.yml"- in checkConfig defaultValidatorMap dotenvs schemeEnvs `shouldThrow` errorCall msg-- context "when there are missing scheme envs in the dotenv vars" $- it "should fail before type checking" $- let schemeEnvs =- [ Env "FOO" (EnvType "bool") True- , Env "BAZ" (EnvType "text") True- , Env "BAR" (EnvType "integer") False- ]- dotenvs = [("FOO","True"), ("BAR","123")]- msg = "The following envs: BAZ must be in the dotenvs"- in checkConfig defaultValidatorMap dotenvs schemeEnvs `shouldThrow` errorCall msg
spec/Configuration/DotenvSpec.hs view
@@ -1,38 +1,20 @@-{-# LANGUAGE CPP #-}+{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} module Configuration.DotenvSpec (main, spec) where -import Configuration.Dotenv.Types (Config(..))-import Configuration.Dotenv.Environment- ( getEnvironment- , lookupEnv- , setEnv- , unsetEnv- )-import Configuration.Dotenv- ( load- , loadFile- , loadSafeFile- , parseFile- , onMissingFile- )+import Configuration.Dotenv (load, loadFile,+ onMissingFile, parseFile)+import Configuration.Dotenv.Environment (getEnvironment, lookupEnv,+ setEnv, unsetEnv)+import Configuration.Dotenv.Types (Config (..)) -import Test.Hspec--import System.Process (readCreateProcess, shell)-import Control.Monad (liftM, void)-import Data.Maybe (fromMaybe)-import qualified Data.Text as T-import qualified Data.Map.Lazy as M-#if !MIN_VERSION_base(4,8,0)-import Data.Functor ((<$>))-#endif+import Test.Hspec -#if !MIN_VERSION_base(4,8,0)-import Control.Applicative ((<$))-#endif+import Control.Monad (liftM, void)+import Data.Maybe (fromMaybe)+import System.Process (readCreateProcess, shell) main :: IO () main = hspec spec@@ -106,45 +88,6 @@ lookupEnv "DOTENV" `shouldReturn` Just "true" lookupEnv "UNICODE_TEST" `shouldReturn` Just "Manabí" lookupEnv "ANOTHER_ENV" `shouldReturn` Just "hello"-- describe "loadSafeFile" $ after_ clearEnvs $- context "given a custom map" $ do- context "when the envs are written accordingly to the rules in the map" $- it "should validate accordingly to the rules in the custom map" $- let hasTwoLetters text = T.length text == 2- customMap = M.fromList- [ ("twoLetters", hasTwoLetters)- , ("bool", const True)- , ("text", const True)- , ("integer", const True)- ]- schemaFile = "spec/fixtures/.scheme.yml"- config = Config ["spec/fixtures/.dotenv.safe"] [] False- expectedEnvs =- [ ("DOTENV","true")- , ("OTHERENV","false")- , ("PORT","8000")- , ("URL","http://example.com")- , ("TWO","xD")- ]- in do- envs <- loadSafeFile customMap schemaFile config- envs `shouldMatchList` expectedEnvs-- context "when the envs are written in an unexpected way" $- it "should throw an errorCall" $- let unexpectedFormat text = T.length text == 3- customMap = M.fromList- [ ("twoLetters", unexpectedFormat)- , ("bool", const True)- , ("text", const True)- , ("integer", const True)- ]- schemaFile = "spec/fixtures/.scheme.yml"- config = Config ["spec/fixtures/.dotenv.safe"] [] False- in void $ loadSafeFile customMap schemaFile config- `shouldThrow` anyErrorCall- describe "parseFile" $ after_ clearEnvs $ do it "returns variables from a file without changing the environment" $ do
− spec/fixtures/.dotenv.safe
@@ -1,5 +0,0 @@-DOTENV=true-OTHERENV=false-PORT=8000-URL=http://example.com-TWO=xD
− spec/fixtures/.scheme.yml
@@ -1,16 +0,0 @@-- name: DOTENV- type: bool- required: true-- name: OTHERENV- type: bool- required: false-- name: PORT- type: integer- required: true-- name: TOKEN- type: integer-- name: URL- type: text- required: true-- name: TWO- type: twoLetters
src/Configuration/Dotenv.hs view
@@ -16,13 +16,10 @@ -- * Dotenv Load Functions load , loadFile- , loadSafeFile , parseFile , onMissingFile -- * Dotenv Types , module Configuration.Dotenv.Types- , ValidatorMap- , defaultValidatorMap ) where @@ -30,17 +27,13 @@ setEnv) import Configuration.Dotenv.Parse (configParser) import Configuration.Dotenv.ParsedVariable (interpolateParsedVariables)-import Configuration.Dotenv.Scheme-import Configuration.Dotenv.Scheme.Types (ValidatorMap,- defaultValidatorMap) import Configuration.Dotenv.Types (Config (..), defaultConfig)-import Control.Monad (liftM, when)+import Control.Monad (liftM) import Control.Monad.Catch import Control.Monad.IO.Class (MonadIO (..)) import Data.List (intersectBy, union, unionBy)-import System.Directory (doesFileExist) import System.IO.Error (isDoesNotExistError) import Text.Megaparsec (errorBundlePretty, parse) @@ -112,18 +105,3 @@ -> m a -- ^ Action to perform if file is indeed missing -> m a onMissingFile f h = catchIf isDoesNotExistError f (const h)---- | @loadSafeFile@ parses the /.scheme.yml/ file and will perform the type checking--- of the environment variables in the /.env/ file.-loadSafeFile- :: MonadIO m- => ValidatorMap -- ^ Map with custom validations- -> FilePath -- ^ Filepath for schema file- -> Config -- ^ Dotenv configuration- -> m [(String, String)] -- ^ Environment variables loaded-loadSafeFile mapFormat schemaFile config = do- envs <- loadFile config- exists <- liftIO $ doesFileExist schemaFile- when exists $- liftIO (readScheme schemaFile >>= checkConfig mapFormat envs . checkScheme)- return envs
src/Configuration/Dotenv/Environment.hs view
@@ -8,20 +8,10 @@ ) where #if MIN_VERSION_base(4,11,0)-import System.Environment.Blank (getEnvironment, unsetEnv)+import System.Environment.Blank (getEnvironment, getEnv, unsetEnv) import qualified System.Environment.Blank as Blank #else-#if MIN_VERSION_base(4,7,0)-import System.Environment (getEnvironment, setEnv, unsetEnv)-#else-import System.Environment.Compat (getEnvironment, setEnv, unsetEnv)-#endif-#endif--#if MIN_VERSION_base(4,11,0)-import System.Environment.Blank (getEnv)-#else-import System.Environment (lookupEnv)+import System.Environment (getEnvironment, lookupEnv, setEnv, unsetEnv) #endif #if MIN_VERSION_base(4,11,0)
src/Configuration/Dotenv/Parse.hs view
@@ -12,18 +12,12 @@ -- information on the dotenv format can be found in the project README and the -- test suite. -{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} module Configuration.Dotenv.Parse (configParser) where import Configuration.Dotenv.ParsedVariable-#if MIN_VERSION_base(4,8,0) import Control.Applicative (empty, many, some, (<|>))-#else-import Control.Applicative (empty, many, some, (*>),- (<$>), (<*), (<*>), (<|>))-#endif import Control.Monad (void) import Data.Void (Void) import Text.Megaparsec (Parsec, anySingle,@@ -121,11 +115,5 @@ -- | Skip line comment and stop before newline character without consuming -- it. skipLineComment :: Parser ()-#if MIN_VERSION_megaparsec(5,1,0) skipLineComment = L.skipLineComment "#"-#else-skipLineComment = p >> void (manyTill anyChar n)- where p = string "#"- n = lookAhead (void newline) <|> eof-#endif {-# INLINE skipLineComment #-}
src/Configuration/Dotenv/ParsedVariable.hs view
@@ -9,8 +9,6 @@ -- -- Helpers to interpolate environment variables -{-# LANGUAGE CPP #-}- module Configuration.Dotenv.ParsedVariable (ParsedVariable(..), VarName, VarValue(..),@@ -20,9 +18,6 @@ import Configuration.Dotenv.Environment (lookupEnv) import Control.Monad (foldM)-#if !MIN_VERSION_base(4,8,0)-import Data.Functor ((<$>))-#endif import Control.Applicative ((<|>)) import System.Process (readCreateProcess, shell)
− src/Configuration/Dotenv/Scheme.hs
@@ -1,70 +0,0 @@--- |--- Module : Configuration.Dotenv.Types--- Copyright : © 2015–2020 Stack Builders Inc.--- License : MIT------ Maintainer : Stack Builders <hackage@stackbuilders.com>--- Stability : experimental--- Portability : portable------ Helpers for loadSafeFile--module Configuration.Dotenv.Scheme- ( checkConfig- , checkScheme- , readScheme- )- where--import Control.Monad--import Data.List-import Data.Yaml (decodeFileEither,- prettyPrintParseException)--import Configuration.Dotenv.Scheme.Helpers-import Configuration.Dotenv.Scheme.Parser-import Configuration.Dotenv.Scheme.Types--readScheme :: FilePath -> IO [Env]-readScheme schemeFile = do- eitherEnvConf <- decodeFileEither schemeFile- case eitherEnvConf of- Right envConfs -> return envConfs- Left errorYaml -> error (prettyPrintParseException errorYaml)--checkScheme :: [Env] -> [Env]-checkScheme envConfs =- case duplicatedConfs of- [] -> envConfs- dups -> error (duplicatedConfErrorMsg $ uniqueConfs dups)- where- duplicatedConfs = deleteFirstsBy confEquals envConfs (uniqueConfs envConfs)- uniqueConfs = nubBy confEquals- a `confEquals` b = envName a == envName b--duplicatedConfErrorMsg :: [Env] -> String-duplicatedConfErrorMsg = ("Duplicated env variable configuration in schema: " ++) . showMissingDotenvs--checkConfig- :: ValidatorMap- -> [(String, String)]- -> [Env]- -> IO ()-checkConfig mapFormat envvars envsWithType =- let envsTypeAndValue = joinEnvs envsWithType envvars- valuesAndTypes = matchValueAndType envsTypeAndValue- dotenvsMissing = filter required (missingDotenvs envsWithType envsTypeAndValue)- schemeEnvsMissing = missingSchemeEnvs envvars envsTypeAndValue- in do- unless (null dotenvsMissing)- (error $ "The following envs: "- ++ showMissingDotenvs dotenvsMissing- ++ " must be in the dotenvs")- unless (null schemeEnvsMissing)- (error $ "The following envs: "- ++ showMissingSchemeEnvs schemeEnvsMissing- ++ " must be in your scheme.yml")- case parseEnvsWithScheme mapFormat valuesAndTypes of- Left errors -> error (unlines errors)- _ -> return ()
− src/Configuration/Dotenv/Scheme/Helpers.hs
@@ -1,87 +0,0 @@--- |--- Module : Configuration.Dotenv.Types--- Copyright : © 2015–2020 Stack Builders Inc.--- License : MIT------ Maintainer : Stack Builders <hackage@stackbuilders.com>--- Stability : experimental--- Portability : portable------ Helpers for loadSafeFile--{-# LANGUAGE CPP #-}-{-# LANGUAGE RecordWildCards #-}--module Configuration.Dotenv.Scheme.Helpers- ( joinEnvs- , matchValueAndType- , missingDotenvs- , missingSchemeEnvs- , sepWithCommas- , showMissingDotenvs- , showMissingSchemeEnvs- )- where--#if !MIN_VERSION_base(4,8,0)-import Control.Applicative ((<*>))-import Data.Functor ((<$>))-#endif-import Data.List--import Configuration.Dotenv.Scheme.Types--matchValueAndType- :: [(Env, (String, String))]- -> [(String, EnvType)]-matchValueAndType =- let getValueAndType (Env{..}, (_, value)) = (value, envType)- in map getValueAndType--joinEnvs- :: [Env]- -> [(String, String)]- -> [(Env, (String, String))]-joinEnvs =- let sameName (Env{..}, (name,_)) = envName == name- in joinBy sameName--joinBy :: ((a,b) -> Bool) -> [a] -> [b] -> [(a,b)]-joinBy p xs ys =- let cartesianProduct = (,) <$> xs <*> ys- in filter p cartesianProduct--missingDotenvs- :: [Env]- -> [(Env, (String, String))]- -> [Env]-missingDotenvs =- let sameName envOne envTwo = envName envOne == envName envTwo- in missingLeft sameName--missingLeft :: (a -> a -> Bool) -> [a] -> [(a,b)] -> [a]-missingLeft p xs xys =- let getAllLeft = map fst xys- in deleteFirstsBy p xs getAllLeft--missingSchemeEnvs- :: [(String, String)]- -> [(Env, (String, String))]- -> [(String, String)]-missingSchemeEnvs =- let sameName (nameOne,_) (nameTwo,_) = nameOne == nameTwo- in missingRight sameName--missingRight :: (b -> b -> Bool) -> [b] -> [(a,b)] -> [b]-missingRight p ys xys =- let getAllRight = map snd xys- in deleteFirstsBy p ys getAllRight--sepWithCommas :: [String] -> String-sepWithCommas = intercalate ", "--showMissingDotenvs :: [Env] -> String-showMissingDotenvs = sepWithCommas . map envName--showMissingSchemeEnvs :: [(String, String)] -> String-showMissingSchemeEnvs = sepWithCommas . map fst
− src/Configuration/Dotenv/Scheme/Parser.hs
@@ -1,65 +0,0 @@--- |--- Module : Configuration.Dotenv.Types--- Copyright : © 2015–2020 Stack Builders Inc.--- License : MIT------ Maintainer : Stack Builders <hackage@stackbuilders.com>--- Stability : experimental--- Portability : portable------ Helpers for loadSafeFile--{-# LANGUAGE CPP #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ScopedTypeVariables #-}--module Configuration.Dotenv.Scheme.Parser- ( defaultValidatorMap- , parseEnvsWithScheme- , typeValidator- )- where--#if !MIN_VERSION_base(4,8,0)-import Control.Applicative (pure, (*>))-import Data.Functor ((<$>))-#endif--import Data.Either--import qualified Data.Map.Lazy as ML--import qualified Data.Text as T--import Configuration.Dotenv.Scheme.Types----- |----parseEnvsWithScheme- :: ValidatorMap -- ^ MapFormat validations- -> [(String, EnvType)] -- ^ Value and Type- -> Either [String] ()-parseEnvsWithScheme validatorMap valuesAndTypes =- let parsedEithers = parseEnvs <$> valuesAndTypes- parseEnvWith = typeValidator validatorMap- parseEnvs (val, type') = val `parseEnvWith` type'- in if all isRight parsedEithers- then Right ()- else Left (lefts parsedEithers)---- |----typeValidator- :: ValidatorMap -- ^ MapFormat validations- -> String -- ^ Value of the env variable- -> EnvType -- ^ Type that the env variable should have- -> Either String ()-typeValidator validatorMap envVal (EnvType type_) =- let errorMsg = "Couldn't parse " ++ envVal ++ " as " ++ T.unpack type_- in case ML.lookup type_ validatorMap of- Nothing -> Left errorMsg- Just validator ->- if validator (T.pack envVal)- then Right ()- else Left errorMsg
− src/Configuration/Dotenv/Scheme/Types.hs
@@ -1,90 +0,0 @@--- |--- Module : Configuration.Dotenv.Types--- Copyright : © 2015–2020 Stack Builders Inc.--- License : MIT------ Maintainer : Stack Builders <hackage@stackbuilders.com>--- Stability : experimental--- Portability : portable------ Types for 'loadSafeFile' (e. g., 'ValidatorMap')--{-# LANGUAGE CPP #-}-{-# LANGUAGE OverloadedStrings #-}--module Configuration.Dotenv.Scheme.Types where--#if !MIN_VERSION_base(4,8,0)-import Control.Applicative (pure, (<*>))-import Data.Functor ((<$>))-#endif--import Data.Maybe (isJust)--import Data.Map.Lazy (Map)--import Data.Yaml--import qualified Data.Map.Lazy as ML--import Data.Text (Text)-import qualified Data.Text as T--import Text.Read (readMaybe)----- |----newtype EnvType = EnvType Text- deriving (Show, Eq, Ord)---- |----instance FromJSON EnvType where- parseJSON (String value) = pure (EnvType value)- parseJSON anyOther = fail ("Not an object: " ++ show anyOther)---- |----data Env =- Env- { envName :: String- , envType :: EnvType- , required :: Bool- } deriving (Show, Eq, Ord)---- |----instance FromJSON Env where- parseJSON (Object m) =- Env- <$> m .: "name"- <*> m .: "type"- <*> m .:? "required" .!= False- parseJSON x = fail ("Not an object: " ++ show x)---- | Parameters:------ - __Key:__ Name of the /format/ to check.------ - __Value:__ Function to check if some text meets the condition.----type ValidatorMap = Map Text (Text -> Bool)----- | Default configuration for 'loadSafeFile'. It currently checks:--- @bool@, @integer@, and @text@.----defaultValidatorMap :: ValidatorMap-defaultValidatorMap =- let booleanValidator :: Text -> Bool- booleanValidator text = isJust (readMaybe (T.unpack text) :: Maybe Bool)- integerValidator :: Text -> Bool- integerValidator text = isJust (readMaybe (T.unpack text) :: Maybe Integer)- textValidator :: Text -> Bool- textValidator = const True- in ML.fromList- [ ("bool", booleanValidator)- , ("integer", integerValidator)- , ("text", textValidator)- ]