on master help sign in
Initial commit
commit20a4ea9b8e55e3f69086f94ed7a9c4a2f6980d85 authoriko <ilyakooo0@gmail.com> dateWed 7 Aug 2019, 23:06 (7 years ago) parent4de7972
15 files changed+438
.gitignore+4 .hext.yaml+12 .hlint.yaml+60 ChangeLog.md+3 README.md+24 Setup.hs+9 UNLICENSE+24 app/Main.hs+23 package.yaml+53 src/Control/Hext/Arguments.hs+38 src/Control/Hext/Config.hs+23 src/Control/Hext/Processor.hs+46 src/Data/Haskell/Parser.hs+44 stack.yaml+66 test/Spec.hs+9
.gitignorenew file+4
@@ -0,0 +1,4 @@
1+.stack-work/
2+hext.cabal
3+*~
4+stack.yaml.lock
.hext.yamlnew file+12
@@ -0,0 +1,12 @@
1+- src:
2+ - src
3+ - tests
4+ - app
5+
6+ extensions:
7+ - OverloadedStrings
8+ - NoImplicitPrelude
9+ - TypeApplications
10+ - DeriveGeneric
11+ - DeriveAnyClass
12+ - RecordWildCards
.hlint.yamlnew file+60
@@ -0,0 +1,60 @@
1+# HLint configuration file
2+# https://github.com/ndmitchell/hlint
3+##########################
4+
5+# This file contains a template configuration file, which is typically
6+# placed as .hlint.yaml in the root of your project
7+
8+
9+# Specify additional command line arguments
10+#
11+# - arguments: [--color, --cpp-simple, -XQuasiQuotes]
12+
13+
14+# Control which extensions/flags/modules/functions can be used
15+#
16+# - extensions:
17+# - default: false # all extension are banned by default
18+# - name: [PatternGuards, ViewPatterns] # only these listed extensions can be used
19+# - {name: CPP, within: CrossPlatform} # CPP can only be used in a given module
20+#
21+# - flags:
22+# - {name: -w, within: []} # -w is allowed nowhere
23+#
24+# - modules:
25+# - {name: [Data.Set, Data.HashSet], as: Set} # if you import Data.Set qualified, it must be as 'Set'
26+# - {name: Control.Arrow, within: []} # Certain modules are banned entirely
27+#
28+# - functions:
29+# - {name: unsafePerformIO, within: []} # unsafePerformIO can only appear in no modules
30+
31+
32+# Add custom hints for this project
33+#
34+# Will suggest replacing "wibbleMany [myvar]" with "wibbleOne myvar"
35+# - error: {lhs: "wibbleMany [x]", rhs: wibbleOne x}
36+
37+
38+# Turn on hints that are off by default
39+#
40+# Ban "module X(module X) where", to require a real export list
41+# - warn: {name: Use explicit module export list}
42+#
43+# Replace a $ b $ c with a . b $ c
44+# - group: {name: dollar, enabled: true}
45+#
46+# Generalise map to fmap, ++ to <>
47+# - group: {name: generalise, enabled: true}
48+
49+
50+# Ignore some builtin hints
51+- ignore: {name: Unused LANGUAGE pragma}
52+# - ignore: {name: Use let}
53+# - ignore: {name: Use const, within: SpecialModule} # Only within certain modules
54+
55+# Define some custom infix operators
56+# - fixity: infixr 3 ~^#^~
57+
58+
59+# To generate a suitable file for HLint do:
60+# $ hlint --default > .hlint.yaml
ChangeLog.mdnew file+3
@@ -0,0 +1,3 @@
1+# Changelog for hext
2+
3+## Unreleased changes
README.mdnew file+24
@@ -0,0 +1,24 @@
1+# hext
2+
3+It can be tempting to keep all GHC extensions in your stack.yaml or cabal file but many haskell tools don't have integrations with build tools like stack and cabal, and thus would break if they don't see an explicit language pragma at the start of the file.
4+
5+Hext alows you to mainain a single list of GHC extensions and automatically apply them to every file.
6+
7+Create a `.hext.yaml` file and put it into your project directory:
8+
9+```yaml
10+- src:
11+ - src
12+ - tests
13+ - app
14+
15+ extensions:
16+ - OverloadedStrings
17+ - NoImplicitPrelude
18+ - TypeApplications
19+ - DeriveGeneric
20+ - DeriveAnyClass
21+ - RecordWildCards
22+```
23+
24+You can create multiple groups with different GHC extensions.
Setup.hsnew file+9
@@ -0,0 +1,9 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
3+{-# LANGUAGE TypeApplications #-}
4+{-# LANGUAGE DeriveGeneric #-}
5+{-# LANGUAGE DeriveAnyClass #-}
6+{-# LANGUAGE RecordWildCards #-}
7+
8+import Distribution.Simple
9+main = defaultMain
UNLICENSEnew file+24
@@ -0,0 +1,24 @@
1+This is free and unencumbered software released into the public domain.
2+
3+Anyone is free to copy, modify, publish, use, compile, sell, or
4+distribute this software, either in source code form or as a compiled
5+binary, for any purpose, commercial or non-commercial, and by any
6+means.
7+
8+In jurisdictions that recognize copyright laws, the author or authors
9+of this software dedicate any and all copyright interest in the
10+software to the public domain. We make this dedication for the benefit
11+of the public at large and to the detriment of our heirs and
12+successors. We intend this dedication to be an overt act of
13+relinquishment in perpetuity of all present and future rights to this
14+software under copyright law.
15+
16+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22+OTHER DEALINGS IN THE SOFTWARE.
23+
24+For more information, please refer to <http://unlicense.org>
app/Main.hsnew file+23
@@ -0,0 +1,23 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
3+{-# LANGUAGE TypeApplications #-}
4+{-# LANGUAGE DeriveGeneric #-}
5+{-# LANGUAGE DeriveAnyClass #-}
6+{-# LANGUAGE RecordWildCards #-}
7+
8+module Main where
9+
10+import Relude
11+
12+import Data.Haskell.Parser
13+import Control.Hext.Arguments
14+import Control.Hext.Config
15+import Control.Hext.Processor
16+import Text.Megaparsec
17+
18+main :: IO ()
19+main = do
20+ Options{..} <- parseOptions
21+ configs <- getConfigs extensionsPath
22+ forM_ configs $ \Config{..} ->
23+ mapM_ (processFiles extensions) $ maybe src pure activeDirectory
package.yamlnew file+53
@@ -0,0 +1,53 @@
1+name: hext
2+version: 0.1.0.0
3+github: "ilyakooo0/hext"
4+license: Unlicense
5+author: "iko"
6+maintainer: "ilyakooo0@gmail.com"
7+copyright: "2019 Ilya Kostyuchenko"
8+
9+extra-source-files:
10+- README.md
11+- ChangeLog.md
12+
13+# Metadata used when publishing your package
14+# synopsis: Short description of your package
15+# category: Web
16+
17+# To avoid duplicated efforts in documentation and dealing with the
18+# complications of embedding Haddock markup inside cabal files, it is
19+# common to point users to the README.md file.
20+description: Please see the README on GitHub at <https://github.com/ilyakooo0/hext#readme>
21+
22+dependencies:
23+- base >= 4.7 && < 5
24+- megaparsec
25+- relude
26+- yaml
27+- optparse-applicative
28+- directory-tree
29+
30+library:
31+ source-dirs: src
32+
33+executables:
34+ hext:
35+ main: Main.hs
36+ source-dirs: app
37+ ghc-options:
38+ - -threaded
39+ - -rtsopts
40+ - -with-rtsopts=-N
41+ dependencies:
42+ - hext
43+
44+tests:
45+ hext-test:
46+ main: Spec.hs
47+ source-dirs: test
48+ ghc-options:
49+ - -threaded
50+ - -rtsopts
51+ - -with-rtsopts=-N
52+ dependencies:
53+ - hext
src/Control/Hext/Arguments.hsnew file+38
@@ -0,0 +1,38 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
3+{-# LANGUAGE TypeApplications #-}
4+{-# LANGUAGE DeriveGeneric #-}
5+{-# LANGUAGE DeriveAnyClass #-}
6+{-# LANGUAGE RecordWildCards #-}
7+
8+module Control.Hext.Arguments
9+ ( parseOptions
10+ , Options(..)
11+ ) where
12+
13+import Relude
14+
15+import Options.Applicative
16+
17+parseOptions :: IO Options
18+parseOptions = execParser $ info
19+ (Options <$> activeDirectoryArgument <*> extensionsFilePath)
20+ (fullDesc
21+ <> progDesc "Add GHC extensions to source files automatically.")
22+
23+data Options = Options
24+ { activeDirectory :: Maybe FilePath
25+ , extensionsPath :: FilePath
26+ }
27+
28+activeDirectoryArgument :: Parser (Maybe FilePath)
29+activeDirectoryArgument = argument (maybeReader $ (Just . Just))
30+ ( help "The directiry to scan for .hs files."
31+ <> value Nothing )
32+
33+extensionsFilePath :: Parser FilePath
34+extensionsFilePath = option auto
35+ ( short 'i'
36+ <> long "input"
37+ <> help "The input yaml filw with extensions."
38+ <> value ".hext.yaml" )
src/Control/Hext/Config.hsnew file+23
@@ -0,0 +1,23 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
3+{-# LANGUAGE TypeApplications #-}
4+{-# LANGUAGE DeriveGeneric #-}
5+{-# LANGUAGE DeriveAnyClass #-}
6+{-# LANGUAGE RecordWildCards #-}
7+
8+module Control.Hext.Config
9+ ( getConfigs
10+ , Config(..)
11+ ) where
12+
13+import Relude
14+
15+import Data.Yaml
16+
17+data Config = Config
18+ { extensions :: [Text]
19+ , src :: [FilePath]
20+ } deriving (Show, Eq, Ord, Generic, FromJSON)
21+
22+getConfigs :: FilePath -> IO [Config]
23+getConfigs = decodeFileThrow
src/Control/Hext/Processor.hsnew file+46
@@ -0,0 +1,46 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
3+{-# LANGUAGE TypeApplications #-}
4+{-# LANGUAGE DeriveGeneric #-}
5+{-# LANGUAGE DeriveAnyClass #-}
6+{-# LANGUAGE RecordWildCards #-}
7+
8+module Control.Hext.Processor
9+ ( processFiles
10+ ) where
11+
12+import Relude
13+
14+import Data.List hiding (unlines)
15+import System.Directory.Tree
16+import Data.Haskell.Parser
17+
18+getFiles :: FilePath -> IO [FilePath]
19+getFiles dir = do
20+ (_ :/ tree) <- readDirectoryWith return dir
21+ return . (>>= getHs) . unwrapDir $ tree
22+ where
23+ unwrapDir :: DirTree a -> [DirTree a]
24+ unwrapDir (Dir _ paths) = paths
25+ unwrapDir _ = []
26+
27+ getHs :: DirTree FilePath -> [FilePath]
28+ getHs (File _ path) | ".hs" `isSuffixOf` path = pure path
29+ getHs (Dir name paths) | not $ "." `isPrefixOf` name = paths >>= getHs
30+ getHs _ = []
31+
32+processFile :: [Text] -> Text -> Text
33+processFile extensions file =
34+ (unlines . fmap wrapExtension) extensions
35+ <> "\n"
36+ <> withoutExtensions file
37+ where
38+ wrapExtension :: Text -> Text
39+ wrapExtension e = "{-# LANGUAGE " <> e <> " #-}"
40+
41+processFiles :: [Text] -> FilePath -> IO ()
42+processFiles extensions dir = do
43+ files <- getFiles dir
44+ forM_ files $ \file -> do
45+ contents <- readFileText file
46+ writeFileText file . processFile extensions $ contents
src/Data/Haskell/Parser.hsnew file+44
@@ -0,0 +1,44 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
3+{-# LANGUAGE TypeApplications #-}
4+{-# LANGUAGE DeriveGeneric #-}
5+{-# LANGUAGE DeriveAnyClass #-}
6+{-# LANGUAGE RecordWildCards #-}
7+
8+module Data.Haskell.Parser
9+ ( withoutExtensions
10+ , withoutExtensionsParser
11+ ) where
12+
13+import Relude hiding (some, many)
14+
15+import Text.Megaparsec
16+import Text.Megaparsec.Char
17+
18+withoutExtensions :: Text -> Text
19+withoutExtensions t = fromMaybe t $ flip (parseMaybe @()) t withoutExtensionsParser
20+
21+withoutExtensionsParser :: (Ord e) => ParsecT e Text m Text
22+withoutExtensionsParser = do
23+ _ <- many extensionExpr
24+ takeRest
25+ where
26+ extensionExpr = do
27+ space
28+ chunk "{-#"
29+ space
30+ chunk "LANGUAGE"
31+ space
32+ some extensions
33+ space
34+ chunk "#-}"
35+ space
36+
37+ extensions = do
38+ some letterChar
39+ space
40+ optional $ do
41+ single ','
42+ space
43+ extensions
44+ return ()
stack.yamlnew file+66
@@ -0,0 +1,66 @@
1+# This file was automatically generated by 'stack init'
2+#
3+# Some commonly used options have been documented as comments in this file.
4+# For advanced use and comprehensive documentation of the format, please see:
5+# https://docs.haskellstack.org/en/stable/yaml_configuration/
6+
7+# Resolver to choose a 'specific' stackage snapshot or a compiler version.
8+# A snapshot resolver dictates the compiler version and the set of packages
9+# to be used for project dependencies. For example:
10+#
11+# resolver: lts-3.5
12+# resolver: nightly-2015-09-21
13+# resolver: ghc-7.10.2
14+#
15+# The location of a snapshot can be provided as a file or url. Stack assumes
16+# a snapshot provided as a file might change, whereas a url resource does not.
17+#
18+# resolver: ./custom-snapshot.yaml
19+# resolver: https://example.com/snapshots/2018-01-01.yaml
20+resolver: lts-14.0
21+
22+# User packages to be built.
23+# Various formats can be used as shown in the example below.
24+#
25+# packages:
26+# - some-directory
27+# - https://example.com/foo/bar/baz-0.0.2.tar.gz
28+# subdirs:
29+# - auto-update
30+# - wai
31+packages:
32+- .
33+# Dependency packages to be pulled from upstream that are not in the resolver.
34+# These entries can reference officially published versions as well as
35+# forks / in-progress versions pinned to a git hash. For example:
36+#
37+# extra-deps:
38+# - acme-missiles-0.3
39+# - git: https://github.com/commercialhaskell/stack.git
40+# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
41+#
42+# extra-deps: []
43+
44+# Override default flag values for local packages and extra-deps
45+# flags: {}
46+
47+# Extra package databases containing global packages
48+# extra-package-dbs: []
49+
50+# Control whether we use the GHC we find on the path
51+# system-ghc: true
52+#
53+# Require a specific version of stack, using version ranges
54+# require-stack-version: -any # Default
55+# require-stack-version: ">=2.1"
56+#
57+# Override the architecture used by stack, especially useful on Windows
58+# arch: i386
59+# arch: x86_64
60+#
61+# Extra directories used by stack for building
62+# extra-include-dirs: [/path/to/dir]
63+# extra-lib-dirs: [/path/to/dir]
64+#
65+# Allow a newer minor version of GHC than the snapshot specifies
66+# compiler-check: newer-minor
test/Spec.hsnew file+9
@@ -0,0 +1,9 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
3+{-# LANGUAGE TypeApplications #-}
4+{-# LANGUAGE DeriveGeneric #-}
5+{-# LANGUAGE DeriveAnyClass #-}
6+{-# LANGUAGE RecordWildCards #-}
7+
8+main :: IO ()
9+main = putStrLn "Test suite not yet implemented"