packages feed

autoexporter 1.1.20 → 2.0.0.1

raw patch · 6 files changed

+207/−178 lines, 6 filesdep ~Cabaldep ~basePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: Cabal, base

API changes (from Hackage documentation)

Files

LICENSE.markdown view
@@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021 Taylor Fausak+Copyright (c) 2022 Taylor Fausak  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal
autoexporter.cabal view
@@ -1,7 +1,7 @@-cabal-version: >= 1.10+cabal-version: 2.2  name: autoexporter-version: 1.1.20+version: 2.0.0.1  synopsis: Automatically re-export modules. description: Autoexporter automatically re-exports modules.@@ -17,10 +17,15 @@   location: https://github.com/tfausak/autoexporter   type: git -library+flag pedantic+  default: False+  description: Enables @-Werror@, which turns warnings into errors.+  manual: True++common library   build-depends:-    base >= 4.13.0 && < 4.16-    , Cabal >= 3.0.1 && < 3.5+    , base >= 4.13.0 && < 4.17+    , Cabal >= 3.0.1 && < 3.7     , directory >= 1.3.6 && < 1.4     , filepath >= 1.4.2 && < 1.5   default-language: Haskell2010@@ -28,18 +33,40 @@     -Weverything     -Wno-implicit-prelude     -Wno-missing-deriving-strategies+    -Wno-missing-exported-signatures     -Wno-unsafe-  exposed-modules: Autoexporter-  hs-source-dirs: src/lib+    -Wno-all-missed-specialisations+    -Wno-missed-specialisations +  if flag(pedantic)+    ghc-options: -Werror+   if impl(ghc >= 8.10)     ghc-options:       -Wno-missing-safe-haskell-mode       -Wno-prepositive-qualified-module +  if impl(ghc >= 9.2)+    ghc-options:+      -Wno-missing-kind-signatures++common executable+  import: library++  build-depends: autoexporter+  ghc-options:+    -rtsopts+    -threaded+    -Wno-unused-packages++library+  import: library++  exposed-modules: Autoexporter+  hs-source-dirs: source/library+ executable autoexporter-  build-depends: base, autoexporter-  default-language: Haskell2010-  ghc-options: -rtsopts -threaded-  hs-source-dirs: src/exe+  import: executable++  hs-source-dirs: source/executable   main-is: Main.hs
+ source/executable/Main.hs view
@@ -0,0 +1,8 @@+module Main+  ( main+  ) where++import qualified Autoexporter++main :: IO ()+main = Autoexporter.autoexporter
+ source/library/Autoexporter.hs view
@@ -0,0 +1,160 @@+-- | This package isn't really meant to be used as a library. It's typically+-- used as a GHC preprocessor, like so:+--+-- > {-# OPTIONS_GHC -F -pgmF autoexporter #-}+--+-- For more information, please see the README on GitHub:+-- <https://github.com/tfausak/autoexporter#readme>.+module Autoexporter+  ( autoexporter+  ) where++import qualified Control.Exception as Exception+import qualified Data.List as List+import qualified Data.Maybe as Maybe+import qualified Distribution.ModuleName as Cabal+import qualified Distribution.Text as Cabal+import qualified System.Directory as Directory+import qualified System.Environment as Environment+import qualified System.FilePath as FilePath+++autoexporter :: IO ()+autoexporter = do+  -- Start by getting the command line arguments. We expect three positional+  -- arguments from GHC: the path to the original source file, the path to the+  -- actual input file, and the path to the output file. The source and input+  -- files could be different if another preprocessor is involved. Since we+  -- don't consider the file's contents, we can ignore the input file.+  --+  -- After GHC's arguments, we have to check for anything passed in by the user+  -- with @-optF@.+  arguments <- Environment.getArgs+  (input, output, depth) <- case arguments of+    [input, _, output] -> pure (input, output, DepthShallow)+    [input, _, output, "--deep"] -> pure (input, output, DepthDeep)+    _ -> Exception.throwIO (InvalidArguments arguments)++  -- Next we convert the original source file path into a module name. If we+  -- aren't able to do this then something weird is going on and we should+  -- crash.+  moduleName <- case toModuleName input of+    Just moduleName -> pure moduleName+    Nothing -> Exception.throwIO (InvalidModuleName input)++  -- Then we want to find all of the relevant modules to re-export. Note that+  -- we simply ignore non-Haskell files and files that don't form valid module+  -- names. Also we sort the module names so that the output is deterministic.+  entries <- listDirectory depth (FilePath.dropExtension input)+  let moduleNames = getModuleNames entries++  -- Finally we render the module and write it to the output file.+  let content = renderModule moduleName moduleNames+  writeFile output content+++-- | This type describes how to search for modules to export. A shallow search+-- only considers files in one directory. A deep search considers all files in+-- the directory tree.+data Depth+  = DepthShallow+  | DepthDeep+  deriving (Eq, Show)+++-- | This exception type is thrown when we don't know how to interpret the+-- arguments passed to the program.+newtype InvalidArguments+  = InvalidArguments [String]+  deriving (Eq, Show)++instance Exception.Exception InvalidArguments+++-- | This function attempts to convert an arbitrary file path into a valid+-- Haskell module name. Any extensions are ignored.+--+-- >>> toModuleName "invalid/module.name"+-- Nothing+-- >>> toModuleName "valid/Module.name"+-- Just (ModuleName ["Module"])+-- >>> toModuleName "Qualified/Module.name"+-- Just (ModuleName ["Qualified","Module"])+toModuleName :: FilePath -> Maybe Cabal.ModuleName+toModuleName =+  Maybe.listToMaybe+    . Maybe.mapMaybe (Cabal.simpleParse . List.intercalate ".")+    . List.tails+    . FilePath.splitDirectories+    . FilePath.dropExtensions+++-- | This exception type is thrown when we can't create a valid module name+-- from the source file path.+newtype InvalidModuleName+  = InvalidModuleName FilePath+  deriving (Eq, Show)++instance Exception.Exception InvalidModuleName+++-- | Lists all of the entries in the given directory. Note that unlike+-- 'Directory.listDirectory' the results of calling this function will include+-- the original directory name.+listDirectory :: Depth -> FilePath -> IO [FilePath]+listDirectory depth = case depth of+  DepthShallow -> listDirectoryShallow+  DepthDeep -> listDirectoryDeep+++listDirectoryShallow :: FilePath -> IO [FilePath]+listDirectoryShallow directory = do+  entries <- Directory.listDirectory directory+  pure (fmap (FilePath.combine directory) entries)+++listDirectoryDeep :: FilePath -> IO [FilePath]+listDirectoryDeep directory = do+  entries <- listDirectoryShallow directory+  let+    listEntry entry = do+      isDirectory <- Directory.doesDirectoryExist entry+      if isDirectory then listDirectoryDeep entry else pure [entry]+  fmap concat (mapM listEntry entries)+++-- | Given a list of file paths, returns a sorted list of module names from the+-- entries that were Haskell files.+getModuleNames :: [FilePath] -> [Cabal.ModuleName]+getModuleNames =+  List.sort . Maybe.mapMaybe toModuleName . filter isHaskellFile+++-- | This predicate tells you if the given file path is a Haskell source file.+isHaskellFile :: FilePath -> Bool+isHaskellFile = flip elem haskellExtensions . FilePath.takeExtensions+++-- | These are the extensions that we consider to be Haskell source files.+haskellExtensions :: [String]+haskellExtensions = [".hs", ".lhs"]+++-- | Given a module name and a list of module names to re-export, renders a+-- module with all the appropriate imports and exports.+renderModule :: Cabal.ModuleName -> [Cabal.ModuleName] -> String+renderModule moduleName moduleNames = unlines+  [ "{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}"+  , "module " <> Cabal.display moduleName <> " ("+  , List.intercalate "\n" (fmap renderExport moduleNames)+  , ") where"+  , List.intercalate "\n" (fmap renderImport moduleNames)+  ]+++renderExport :: Cabal.ModuleName -> String+renderExport moduleName = "module " <> Cabal.display moduleName <> ","+++renderImport :: Cabal.ModuleName -> String+renderImport moduleName = "import " <> Cabal.display moduleName
− src/exe/Main.hs
@@ -1,6 +0,0 @@-module Main ( main ) where--import qualified Autoexporter--main :: IO ()-main = Autoexporter.autoexporter
− src/lib/Autoexporter.hs
@@ -1,160 +0,0 @@--- | This package isn't really meant to be used as a library. It's typically--- used as a GHC preprocessor, like so:------ > {-# OPTIONS_GHC -F -pgmF autoexporter #-}------ For more information, please see the README on GitHub:--- <https://github.com/tfausak/autoexporter#readme>.-module Autoexporter ( autoexporter ) where--import qualified Control.Exception as Exception-import qualified Data.List as List-import qualified Data.Maybe as Maybe-import qualified Distribution.ModuleName as Cabal-import qualified Distribution.Text as Cabal-import qualified System.Directory as Directory-import qualified System.Environment as Environment-import qualified System.FilePath as FilePath---autoexporter :: IO ()-autoexporter = do-  -- Start by getting the command line arguments. We expect three positional-  -- arguments from GHC: the path to the original source file, the path to the-  -- actual input file, and the path to the output file. The source and input-  -- files could be different if another preprocessor is involved. Since we-  -- don't consider the file's contents, we can ignore the input file.-  ---  -- After GHC's arguments, we have to check for anything passed in by the user-  -- with @-optF@.-  arguments <- Environment.getArgs-  (input, output, depth) <- case arguments of-    [input, _, output] -> pure (input, output, DepthShallow)-    [input, _, output, "--deep"] -> pure (input, output, DepthDeep)-    _ -> Exception.throwIO (InvalidArguments arguments)--  -- Next we convert the original source file path into a module name. If we-  -- aren't able to do this then something weird is going on and we should-  -- crash.-  moduleName <- case toModuleName input of-    Just moduleName -> pure moduleName-    Nothing -> Exception.throwIO (InvalidModuleName input)--  -- Then we want to find all of the relevant modules to re-export. Note that-  -- we simply ignore non-Haskell files and files that don't form valid module-  -- names. Also we sort the module names so that the output is deterministic.-  entries <- listDirectory depth (FilePath.dropExtension input)-  let moduleNames = getModuleNames entries--  -- Finally we render the module and write it to the output file.-  let content = renderModule moduleName moduleNames-  writeFile output content----- | This type describes how to search for modules to export. A shallow search--- only considers files in one directory. A deep search considers all files in--- the directory tree.-data Depth-  = DepthShallow-  | DepthDeep-  deriving (Eq, Show)----- | This exception type is thrown when we don't know how to interpret the--- arguments passed to the program.-newtype InvalidArguments-  = InvalidArguments [String]-  deriving (Eq, Show)--instance Exception.Exception InvalidArguments----- | This function attempts to convert an arbitrary file path into a valid--- Haskell module name. Any extensions are ignored.------ >>> toModuleName "invalid/module.name"--- Nothing--- >>> toModuleName "valid/Module.name"--- Just (ModuleName ["Module"])--- >>> toModuleName "Qualified/Module.name"--- Just (ModuleName ["Qualified","Module"])-toModuleName :: FilePath -> Maybe Cabal.ModuleName-toModuleName-  = Maybe.listToMaybe-  . Maybe.mapMaybe Cabal.simpleParse-  . fmap (List.intercalate ".")-  . List.tails-  . FilePath.splitDirectories-  . FilePath.dropExtensions----- | This exception type is thrown when we can't create a valid module name--- from the source file path.-newtype InvalidModuleName-  = InvalidModuleName FilePath-  deriving (Eq, Show)--instance Exception.Exception InvalidModuleName----- | Lists all of the entries in the given directory. Note that unlike--- 'Directory.listDirectory' the results of calling this function will include--- the original directory name.-listDirectory :: Depth -> FilePath -> IO [FilePath]-listDirectory depth = case depth of-  DepthShallow -> listDirectoryShallow-  DepthDeep -> listDirectoryDeep---listDirectoryShallow :: FilePath -> IO [FilePath]-listDirectoryShallow directory = do-  entries <- Directory.listDirectory directory-  pure (fmap (FilePath.combine directory) entries)---listDirectoryDeep :: FilePath -> IO [FilePath]-listDirectoryDeep directory = do-  entries <- listDirectoryShallow directory-  let-    listEntry entry = do-      isDirectory <- Directory.doesDirectoryExist entry-      if isDirectory-        then listDirectoryDeep entry-        else pure [entry]-  fmap concat (mapM listEntry entries)----- | Given a list of file paths, returns a sorted list of module names from the--- entries that were Haskell files.-getModuleNames :: [FilePath] -> [Cabal.ModuleName]-getModuleNames = List.sort . Maybe.mapMaybe toModuleName . filter isHaskellFile----- | This predicate tells you if the given file path is a Haskell source file.-isHaskellFile :: FilePath -> Bool-isHaskellFile = flip elem haskellExtensions . FilePath.takeExtensions----- | These are the extensions that we consider to be Haskell source files.-haskellExtensions :: [String]-haskellExtensions = [".hs", ".lhs"]----- | Given a module name and a list of module names to re-export, renders a--- module with all the appropriate imports and exports.-renderModule :: Cabal.ModuleName -> [Cabal.ModuleName] -> String-renderModule moduleName moduleNames = unlines-  [ "{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}"-  , "module " <> Cabal.display moduleName <> " ("-  , List.intercalate "\n" (fmap renderExport moduleNames)-  , ") where"-  , List.intercalate "\n" (fmap renderImport moduleNames)-  ]---renderExport :: Cabal.ModuleName -> String-renderExport moduleName = "module " <> Cabal.display moduleName <> ","---renderImport :: Cabal.ModuleName -> String-renderImport moduleName = "import " <> Cabal.display moduleName