json-autotype 1.0.15 → 1.0.16
raw patch · 8 files changed
+176/−119 lines, 8 filesdep +optparse-applicativedep ~aesondep ~basedep ~directory
Dependencies added: optparse-applicative
Dependency ranges changed: aeson, base, directory, lens, process, vector
Files
- Data/Aeson/AutoType/CodeGen.hs +1/−1
- Data/Aeson/AutoType/Format.hs +1/−1
- Data/Aeson/AutoType/Pretty.hs +7/−0
- GenerateJSONParser.hs +76/−47
- GenerateTestJSON.hs +57/−32
- TestQC.hs +2/−15
- changelog.md +8/−0
- json-autotype.cabal +24/−23
Data/Aeson/AutoType/CodeGen.hs view
@@ -52,7 +52,7 @@ ," (.:), (.:?), (.=), object)" ,"import Data.Monoid" ,"import Data.Text (Text)"- ,"import GHC.Generics" + ,"import qualified GHC.Generics" ,"" ,"-- | Workaround for https://github.com/bos/aeson/issues/287." ,"o .:?? val = fmap join (o .:? val)"
Data/Aeson/AutoType/Format.hs view
@@ -64,7 +64,7 @@ -- | Wrap a data type declaration wrapDecl :: Text -> Text -> Text-wrapDecl identifier contents = Text.unlines [header, contents, " } deriving (Show,Eq,Generic)"]+wrapDecl identifier contents = Text.unlines [header, contents, " } deriving (Show,Eq,GHC.Generics.Generic)"] --,"\nderiveJSON defaultOptions ''" `Text.append` identifier] where header = Text.concat ["data ", identifier, " = ", identifier, " { "]
Data/Aeson/AutoType/Pretty.hs view
@@ -3,7 +3,11 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE CPP #-}+#if MIN_VERSION_aeson(1,2,1)+#else {-# OPTIONS_GHC -fno-warn-orphans #-}+#endif -- | Instances of @Text.PrettyPrint.Out@ class to visualize -- Aeson @Value@ data structure. @@ -33,7 +37,10 @@ doc (V.toList -> v) = "<" <+> doc v <+> ">" docPrec _ = doc +#if MIN_VERSION_aeson(1,2,1)+#else deriving instance Generic Value+#endif instance Out Value
GenerateJSONParser.hs view
@@ -1,27 +1,28 @@-{-# LANGUAGE TemplateHaskell #-}+-- {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE StandaloneDeriving #-}+-- {-# LANGUAGE DeriveGeneric #-}+-- {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE ViewPatterns #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Main where import Control.Applicative-import Control.Monad (forM_, when, unless)+import Control.Monad (forM_, when, unless) import Data.Maybe-import Data.List (partition)+import Data.Monoid+import Data.List (partition) import System.Exit-import System.IO (stdin, stderr, stdout, IOMode(..))---import System.IO.Posix.MMap (mmapFileByteString)-import System.FilePath (splitExtension)-import System.Process (system)+import System.IO (stdin, stderr, stdout, IOMode(..))+--import System.IO.Posix.MMap (mmapFileByteString)+import System.FilePath (splitExtension)+import System.Process (system) import qualified Data.ByteString.Lazy.Char8 as BSL import qualified Data.HashMap.Strict as Map import Data.Aeson import qualified Data.Text as Text import qualified Data.Text.IO as Text-import Data.Text (Text)+import Data.Text (Text) import Text.PrettyPrint.GenericPretty (pretty) import Data.Aeson.AutoType.Pretty@@ -31,23 +32,39 @@ import Data.Aeson.AutoType.CodeGen import Data.Aeson.AutoType.Util import qualified Data.Yaml as Yaml-import HFlags +import Options.Applicative+import CommonCLI+ -- * Command line flags-defineFlag "o:outputFilename" defaultOutputFilename "Write output to the given file"-defineFlag "suggest" True "Suggest candidates for unification"-defineFlag "autounify" True "Automatically unify suggested candidates"-defineFlag "t:test" False "Try to run generated parser after"-defineFlag "d:debug" False "Set this flag to see more debugging info"-defineFlag "y:typecheck" True "Set this flag to typecheck after unification"-defineFlag "yaml" False "Parse inputs as YAML instead of JSON"-defineFlag "p:preprocessor" False "Work as GHC preprocessor (skip preprocessor pragma)"-defineFlag "fakeFlag" True "Ignore this flag - it doesn't exist!!! It is workaround to library problem."+--defineFlag "o:outputFilename" defaultOutputFilename "Write output to the given file"+--defineFlag "suggest" True "Suggest candidates for unification"+--defineFlag "autounify" True "Automatically unify suggested candidates"+--defineFlag "t:test" False "Try to run generated parser after"+--defineFlag "d:debug" False "Set this flag to see more debugging info"+--defineFlag "y:typecheck" True "Set this flag to typecheck after unification"+--defineFlag "yaml" False "Parse inputs as YAML instead of JSON"+--defineFlag "p:preprocessor" False "Work as GHC preprocessor (skip preprocessor pragma)"+--defineFlag "fakeFlag" True "Ignore this flag - it doesn't exist!!! It is workaround to library problem." --- | Works like @Debug.trace@ when the --debug flag is enabled, and does nothing otherwise.-myTrace :: String -> IO ()-myTrace msg = flags_debug `when` putStrLn msg+data Options = Options {+ tyOpts :: TypeOpts+ , outputFilename :: FilePath+ , typecheck :: Bool+ , yaml :: Bool+ , preprocessor :: Bool+ , filenames :: [FilePath]+ } +optParser :: Parser Options+optParser =+ Options <$> tyOptParser+ <*> strOption (short 'o' <> long "output" <> value defaultOutputFilename)+ <*> unflag (short 'n' <> long "no-typecheck" <> help "Do not typecheck after unification")+ <*> switch (long "yaml" <> help "Parse inputs as YAML instead of JSON" )+ <*> switch (short 'p' <> long "preprocessor" <> help "Work as GHC preprocessor (and skip preprocessor pragma)" )+ <*> some (argument str (metavar "FILES..."))+ -- | Report an error to error output. report :: Text -> IO () report = Text.hPutStrLn stderr@@ -60,8 +77,8 @@ -- | Extracts type from JSON file, along with the original @Value@. -- In order to facilitate dealing with failures, it returns a triple of -- @FilePath@, extracted @Type@, and a JSON @Value@.-extractTypeFromJSONFile :: FilePath -> IO (Maybe (FilePath, Type, Value))-extractTypeFromJSONFile inputFilename =+extractTypeFromJSONFile :: Options -> FilePath -> IO (Maybe (FilePath, Type, Value))+extractTypeFromJSONFile opts inputFilename = withFileOrHandle inputFilename ReadMode stdin $ \hInput -> -- First we decode JSON input into Aeson's Value type do Text.hPutStrLn stderr $ "Processing " `Text.append` Text.pack (show inputFilename)@@ -79,19 +96,17 @@ `Text.append` Text.pack inputFilename) return $ Just (inputFilename, t, v) where- decoder | flags_yaml = Yaml.decode . BSL.toStrict- | otherwise = decode+ decoder | yaml opts = Yaml.decode . BSL.toStrict+ | otherwise = decode+ -- | Works like @Debug.trace@ when the --debug flag is enabled, and does nothing otherwise.+ myTrace :: String -> IO ()+ myTrace msg = debug (tyOpts opts) `when` putStrLn msg+ -- | Perform preprocessing of JSON input to drop initial pragma.+ preprocess :: BSL.ByteString -> BSL.ByteString+ preprocess | preprocessor opts = dropPragma+ | otherwise = id --- | Perform preprocessing of JSON input to drop initial pragma.-preprocess :: BSL.ByteString -> BSL.ByteString-preprocess | flags_preprocessor = dropPragma- | otherwise = id --- | Drop initial pragma.-dropPragma :: BSL.ByteString -> BSL.ByteString-dropPragma input | "{-#" `BSL.isPrefixOf` input = BSL.dropWhile (/='\n') input- | otherwise = input- -- | Type checking all input files with given type, -- and return a list of filenames for files that passed the check. typeChecking :: Type -> [FilePath] -> [Value] -> IO [FilePath]@@ -106,18 +121,18 @@ map fst -> failures) = partition snd checkedFiles -- | Take a set of JSON input filenames, Haskell output filename, and generate module parsing these JSON files.-generateHaskellFromJSONs :: [FilePath] -> FilePath -> IO ()-generateHaskellFromJSONs inputFilenames outputFilename = do+generateHaskellFromJSONs :: Options -> [FilePath] -> FilePath -> IO ()+generateHaskellFromJSONs opts inputFilenames outputFilename = do -- Read type from each file (filenames, typeForEachFile,- valueForEachFile) <- (unzip3 . catMaybes) <$> mapM extractTypeFromJSONFile inputFilenames+ valueForEachFile) <- (unzip3 . catMaybes) <$> mapM (extractTypeFromJSONFile opts) inputFilenames -- Unify all input types when (null typeForEachFile) $ do report "No valid JSON input file..." exitFailure let finalType = foldr1 unifyTypes typeForEachFile- passedTypeCheck <- if flags_typecheck+ passedTypeCheck <- if typecheck opts then typeChecking finalType filenames valueForEachFile else return filenames -- We split different dictionary labels to become different type trees (and thus different declarations.)@@ -127,21 +142,35 @@ -- We compute which type labels are candidates for unification let uCands = unificationCandidates splitted myTrace $ "CANDIDATES:\n" ++ pretty uCands- when flags_suggest $ forM_ uCands $ \cs -> do+ when (suggest $ tyOpts opts) $ forM_ uCands $ \cs -> do putStr "-- " Text.putStrLn $ "=" `Text.intercalate` cs -- We unify the all candidates or only those that have been given as command-line flags.- let unified = if flags_autounify+ let unified = if autounify $ tyOpts opts then unifyCandidates uCands splitted else splitted myTrace $ "UNIFIED:\n" ++ pretty unified -- We start by writing module header writeHaskellModule outputFilename unified- when flags_test $- exitWith =<< system (unwords $ ["runghc", "-package=aeson-0.9.0.1", outputFilename] ++ passedTypeCheck)+ when (test $ tyOpts opts) $+ exitWith =<< system (unwords $ ["runghc", "-package=aeson", outputFilename] ++ passedTypeCheck)+ where+ -- | Works like @Debug.trace@ when the --debug flag is enabled, and does nothing otherwise.+ myTrace :: String -> IO ()+ myTrace msg = debug (tyOpts opts) `when` putStrLn msg +-- | Drop initial pragma.+dropPragma :: BSL.ByteString -> BSL.ByteString+dropPragma input | "{-#" `BSL.isPrefixOf` input = BSL.dropWhile (/='\n') input+ | otherwise = input++ -- | Initialize flags, and run @generateHaskellFromJSONs@. main :: IO ()-main = do filenames <- $initHFlags "json-autotype -- automatic type and parser generation from JSON"- -- TODO: should integrate all inputs into single type set!!!- generateHaskellFromJSONs filenames flags_outputFilename+main = do opts <- execParser optInfo+ generateHaskellFromJSONs opts (filenames opts) (outputFilename opts)+ where+ optInfo = info (optParser <**> helper)+ ( fullDesc+ <> progDesc "Parser JSON or YAML, get its type, and generate appropriate parser."+ <> header "json-autotype -- automatic type and parser generation from JSON")
GenerateTestJSON.hs view
@@ -3,6 +3,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ViewPatterns #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleContexts #-}@@ -21,6 +22,7 @@ import qualified Data.ByteString.Lazy.Char8 as BSL import qualified Data.HashMap.Strict as Map import qualified Data.Set as Set+import Data.Semigroup ((<>)) import Data.Aeson import Data.Function (on) import Data.List@@ -39,25 +41,42 @@ import Data.Aeson.AutoType.CodeGen import Data.Aeson.AutoType.Util import Data.Aeson.AutoType.Test-import HFlags+import Options.Applicative +import CommonCLI+ -- * Command line flags-defineFlag "z:size" (10 :: Int) "Size of generated elements"-defineFlag "s:stem" ("Test" :: FilePath) "Test filename stem"-defineFlag "c:count" (100 :: Int) "Number of test cases to generate."+--defineFlag "z:size" (10 :: Int) "Size of generated elements"+--defineFlag "s:stem" ("Test" :: FilePath) "Test filename stem"+--defineFlag "c:count" (100 :: Int) "Number of test cases to generate." --defineFlag "o:outputFilename" defaultOutputFilename "Write output to the given file"-flags_suggest = True+--flags_suggest = True --defineFlag "suggest" True "Suggest candidates for unification"-defineFlag "autounify" True "Automatically unify suggested candidates"-defineFlag "t:test" True "Try to run generated parser after"-defineFlag "d:debug" False "Set this flag to see more debugging info"-defineFlag "keep" False "Keep also the successful tests"-defineFlag "fakeFlag" True "Ignore this flag - it doesn't exist!!! It is workaround for a library problem."+--defineFlag "autounify" True "Automatically unify suggested candidates"+--defineFlag "t:test" True "Try to run generated parser after"+--defineFlag "d:debug" False "Set this flag to see more debugging info"+--defineFlag "keep" False "Keep also the successful tests"+--defineFlag "fakeFlag" True "Ignore this flag - it doesn't exist!!! It is workaround for a library problem." --- Tracing is switched off:-myTrace :: String -> IO ()-myTrace msg = flags_debug `when` putStrLn msg+data Options = Options {+ tyOpts :: TypeOpts+ , keep :: Bool+ , stem :: FilePath+ , count :: Int+ , size :: Int+ } +optParser :: Parser Options+optParser =+ Options <$> tyOptParser+ <*> switch (long "keep" <> help "Also keep successful tests" )+ <*> strOption (long "stem" <> value "Test" <> help "Output filename stem" )+ <*> intOpt (long "count" <> value 100 <> help "Number of tests to perform" )+ <*> intOpt (long "size" <> value 10 <> help "size of generated test cases")+ -- <*> some (argument str (metavar "FILES..."))+ where+ intOpt = option auto+ -- | Report an error to error output. report :: Text -> IO () report = Text.hPutStrLn stderr@@ -68,8 +87,8 @@ exitFailure -- | Read JSON and extract @Type@ information from it.-extractTypeFromJSONFile :: FilePath -> IO (Maybe Type)-extractTypeFromJSONFile inputFilename =+extractTypeFromJSONFile :: (String -> IO ()) -> FilePath -> IO (Maybe Type)+extractTypeFromJSONFile myTrace inputFilename = withFileOrHandle inputFilename ReadMode stdin $ \hIn -> -- First we decode JSON input into Aeson's Value type do bs <- BSL.hGetContents hIn@@ -84,6 +103,7 @@ myTrace $ "Type: " ++ pretty t return $ Just t + vectorWithoutDuplicates :: Ord b => Int -> Gen b -> Gen [b] vectorWithoutDuplicates i gen = take i . removeDuplicates@@ -120,16 +140,16 @@ (Object a) `compare` (Object b) = Map.toList a `compare` Map.toList b -- | Take a set of JSON input filenames, Haskell output filename, and generate module parsing these JSON files.-generateTestJSONs :: IO ()-generateTestJSONs = do+generateTestJSONs :: Options -> IO ()+generateTestJSONs Options {tyOpts=TyOptions {..}, ..}= do testValues :: [Value] <- generate $- resize flags_size $+ resize size $ vectorWithoutDuplicates 100 arbitraryTopValue results <- forM (zip3 inputFilenames outputFilenames testValues) $ \(inputFilename, outputFilename, jsonValue) -> do BSL.writeFile inputFilename $ encode jsonValue -- Read type from each file- typeForEachFile <- catMaybes <$> mapM extractTypeFromJSONFile [inputFilename]+ typeForEachFile <- catMaybes <$> mapM (extractTypeFromJSONFile myTrace) [inputFilename] -- Unify all input types when (null typeForEachFile) $ do report "No valid JSON input file..."@@ -142,33 +162,38 @@ -- We compute which type labels are candidates for unification let uCands = unificationCandidates splitted myTrace $ "CANDIDATES:\n" ++ pretty uCands- when flags_suggest $ forM_ uCands $ \cs -> do+ when suggest $ forM_ uCands $ \cs -> do putStr "-- " Text.putStrLn $ "=" `Text.intercalate` cs -- We unify the all candidates or only those that have been given as command-line flags.- let unified = if flags_autounify+ let unified = if autounify then unifyCandidates uCands splitted else splitted myTrace $ "UNIFIED:\n" ++ pretty unified -- We start by writing module header writeHaskellModule outputFilename unified- if flags_test+ if test then do- r <- (==ExitSuccess) <$> system (unwords ["runghc", "-package=aeson-0.9.0.1", outputFilename, inputFilename])+ r <- (==ExitSuccess) <$> system (unwords ["runghc", "-package=aeson", outputFilename, inputFilename]) when r $ mapM_ removeFile [inputFilename, outputFilename] return r else return True putStrLn $ "Successfully generated " ++ show (length results) ++- " JSON files, out of planned " ++ show flags_count ++ " cases."+ " JSON files, out of planned " ++ show count ++ " cases." where- makeInputFilename = (<.>".json") . (flags_stem ++) . show- makeOutputFilename = (<.>".hs") . (flags_stem ++) . show- inputFilenames = map makeInputFilename [1..flags_count]- outputFilenames = map makeOutputFilename [1..flags_count]+ makeInputFilename = (<.>".json") . (stem ++) . show+ makeOutputFilename = (<.>".hs") . (stem ++) . show+ inputFilenames = map makeInputFilename [1..count]+ outputFilenames = map makeOutputFilename [1..count]+ myTrace :: String -> IO ()+ myTrace msg = debug `when` putStrLn msg main :: IO ()-main = do filenames <- $initHFlags "testJSON -- automatic test JSON generation"- -- TODO: should integrate all inputs into single type set!!!- generateTestJSONs-+main = do opts <- execParser optInfo+ generateTestJSONs opts+ where+ optInfo = info (optParser <**> helper)+ ( fullDesc+ <> progDesc "Generate a number of JSON test files, and generate type and parser for each."+ <> header "Self-test for json-autotype" )
TestQC.hs view
@@ -16,25 +16,12 @@ prop_typeCheck :: Value -> Bool prop_typeCheck v = v `typeCheck` extractType v -{--prop_typeSize :: Value -> Bool-prop_typeSize v = valueSize v >= typeSize (extractType v)--prop_valueAndValueTypeSize :: Value -> Bool-prop_valueAndValueTypeSize v = valueSize v >= valueTypeSize v--prop_valueTypeSizeAndTypeSize :: Value -> Bool-prop_valueTypeSizeAndTypeSize v = valueTypeSize v >= typeSize (extractType v) -}---- | Maximum reasonable depth for quick testing+-- | Maximum reasonable depth for quick exhaustive testing depth = 5 main :: IO ()-main = do smallCheck depth prop_typeCheck+main = do smallCheck depth prop_typeCheck quickCheckWith myArgs prop_typeCheck- {- prop_typeSize,- prop_valueAndValueTypeSize,- prop_valueTypeSizeAndTypeSize]-} where -- 17 - reasonable size for runghc --myArgs i = stdArgs { maxSize=i }
changelog.md view
@@ -1,5 +1,13 @@ Changelog =========+ 1.0.16 Nov 2017+ * Dependencies updated to resolve #12, #15.+ * Fixed orphan Generic for Aeson >= 1.2.1 (#14).+ * Cleaned option parsing code.+ * Qualify GHC.Generics import.+ * Switch to optparse-applicative+ * Option to explicitly unify selected entries+ 1.0.15 Dec 2016 * Support YAML input.
json-autotype.cabal view
@@ -1,6 +1,6 @@ -- Build information for the package. name: json-autotype-version: 1.0.15+version: 1.0.16 synopsis: Automatic type declaration for JSON input data description: Generates datatype declarations with Aeson's "FromJSON" instances from a set of example ".json" files.@@ -34,7 +34,7 @@ extra-source-files: README.md changelog.md cabal-version: >=1.10 bug-reports: https://github.com/mgajda/json-autotype/issues-tested-with: GHC==7.8.4,GHC==7.10.3,GHC==7.6.3+tested-with: GHC==7.8.4,GHC==7.10.3,GHC==7.6.3,GHC==8.0.1,GHC==8.2.2 source-repository head type: git@@ -60,25 +60,25 @@ other-modules: -- internal module Data.Aeson.AutoType.Util- build-depends: base >=4.3 && <4.10,+ build-depends: base >=4.3 && <4.11, GenericPretty >=1.2 && <1.3,- aeson >=0.7 && <0.13,+ aeson >=0.7 && <1.3, bytestring >=0.9 && <0.11, containers >=0.3 && <0.6, filepath >=1.3 && <1.5, hashable >=1.2 && <1.3, ---hint >=0.4 && <0.6,- hflags >=0.3 && <0.5,+ optparse-applicative >=0.14 && <1.0, lens >=4.1 && <4.16, mmap >=0.5 && <0.6, mtl >=2.1 && <2.3, pretty >=1.1 && <1.3,- process >=1.1 && <1.5,+ process >=1.1 && <1.7, scientific >=0.3 && <0.5, text >=1.1 && <1.4, uniplate >=1.6 && <1.7, unordered-containers >=0.2 && <0.3,- vector >=0.9 && <0.12+ vector >=0.9 && <0.13 default-language: Haskell2010 executable json-autotype@@ -102,22 +102,23 @@ RecordWildCards build-depends: base >=4.3 && <4.10, GenericPretty >=1.2 && <1.3,- aeson >=0.7 && <0.12,+ aeson >=0.7 && <1.3, bytestring >=0.9 && <0.11, containers >=0.3 && <0.6, filepath >=1.3 && <1.5, hashable >=1.2 && <1.3, --hint >=0.4 && <0.6, hflags >=0.3 && <0.5,- lens >=4.1 && <4.15,+ lens >=4.1 && <4.16, mtl >=2.1 && <2.3,+ optparse-applicative >=0.14 && <1.0, pretty >=1.1 && <1.3,- process >=1.1 && <1.5,+ process >=1.1 && <1.7, scientific >=0.3 && <0.5, text >=1.1 && <1.4, uniplate >=1.6 && <1.7, unordered-containers >=0.2 && <0.3,- vector >=0.9 && <0.12,+ vector >=0.9 && <0.13, yaml >=0.8 && <0.9 -- hs-source-dirs: default-language: Haskell2010@@ -143,28 +144,28 @@ RecordWildCards build-depends: base >=4.3 && <4.10, GenericPretty >=1.2 && <1.3,- aeson >=0.7 && <0.12,+ aeson >=0.7 && <1.3, bytestring >=0.9 && <0.11, containers >=0.3 && <0.6,- directory >=1.1 && <1.3,+ directory >=1.1 && <1.4, filepath >=1.3 && <1.5, hashable >=1.2 && <1.3,- lens >=4.1 && <4.15,+ lens >=4.1 && <4.16, mtl >=2.1 && <2.3, pretty >=1.1 && <1.3,- process >=1.1 && <1.5,+ process >=1.1 && <1.7, scientific >=0.3 && <0.5, smallcheck >=1.0 && <1.2, text >=1.1 && <1.4, uniplate >=1.6 && <1.7, unordered-containers >=0.2 && <0.3,- vector >=0.9 && <0.12,+ vector >=0.9 && <0.13, QuickCheck >=2.4 && <3.0 -- hs-source-dirs: default-language: Haskell2010 -- Test suite with Haskell code generation and compilation-test-suite json-autotype-random-test+test-suite json-autotype-gen-test type: exitcode-stdio-1.0 main-is: GenerateTestJSON.hs other-modules: Data.Aeson.AutoType.Util@@ -184,23 +185,23 @@ RecordWildCards build-depends: base >=4.3 && <4.10, GenericPretty >=1.2 && <1.3,- aeson >=0.7 && <0.12,+ aeson >=0.7 && <1.3, bytestring >=0.9 && <0.11, containers >=0.3 && <0.6,- directory >=1.1 && <1.3,+ directory >=1.1 && <1.4, filepath >=1.3 && <1.5, hashable >=1.2 && <1.3,- hflags >=0.3 && <0.5,- lens >=4.1 && <4.15,+ optparse-applicative >=0.14 && <1.0,+ lens >=4.1 && <4.16, mtl >=2.1 && <2.3, pretty >=1.1 && <1.3,- process >=1.1 && <1.5,+ process >=1.1 && <1.7, scientific >=0.3 && <0.5, smallcheck >=1.0 && <1.2, text >=1.1 && <1.4, uniplate >=1.6 && <1.7, unordered-containers >=0.2 && <0.3,- vector >=0.9 && <0.12,+ vector >=0.9 && <0.13, QuickCheck >=2.4 && <3.0 -- hs-source-dirs: default-language: Haskell2010