git.iko.soy/rowtype-yoga/purslint
on main help sign in
README.md+3−1
since splitsnapshots
unifiedsplit
@@ -1,7 +1,7 @@
1# Purslint
1# Purslint
2
2
3<p align="center">
3<p align="center">
4− <img src="vscode-extension/purslint.jpg" alt="Purslint logo" width="180" />
4+ <img src="vscode-extension/purslint.png" alt="Purslint logo" width="180" />
5</p>
5</p>
6
6
7<p align="center">
7<p align="center">
@@ -12,6 +12,8 @@
12
12
13A PureScript linter.
13A PureScript linter.
14
14
15+Purslint is very new and may have bugs, so please use an editor with undo functionality. :D
16+
15## Install
17## Install
16
18
17### VS Code (Marketplace)
19### VS Code (Marketplace)
bin/purslint-cli/spago.yaml+1
@@ -8,6 +8,7 @@ package:
8 - foldable-traversable
8 - foldable-traversable
9 - maybe
9 - maybe
10 - newtype
10 - newtype
11+ - optparse
11 - prelude
12 - prelude
12 - purslint
13 - purslint
13 - strings
14 - strings
bin/purslint-cli/src/Main.purs+76−31
@@ -4,14 +4,20 @@ import Prelude
4
4
5import Data.Array as Array
5import Data.Array as Array
6import Data.Either (Either(..))
6import Data.Either (Either(..))
7+import Data.Enum (fromEnum)
7import Data.Foldable (for_)
8import Data.Foldable (for_)
8import Data.Maybe (Maybe(..))
9import Data.Maybe (Maybe(..))
9import Data.Newtype (unwrap)
10import Data.Newtype (unwrap)
10import Data.String.CodeUnits as String
11import Data.String.CodeUnits as String
12+import Data.Tuple.Nested ((/\))
11import Effect (Effect)
13import Effect (Effect)
12import Effect.Console (log)
14import Effect.Console (log)
13import Node.FS.Simple as FS
15import Node.FS.Simple as FS
14import Node.CLI as Process
16import Node.CLI as Process
17+import Options.Applicative (Parser, argument, execParserPure, fullDesc, header, help, helper, info, long, many, metavar, progDesc, str, switch, (<**>))
18+import Options.Applicative.Builder (defaultPrefs)
19+import Options.Applicative.Types (CompletionResult(..), ParserFailure(ParserFailure), ParserResult(..))
20+import Options.Applicative.Help.Types (ParserHelp(ParserHelp), renderHelp)
15import Purslint.Config (defaultConfig, filterRules, parseConfig)
21import Purslint.Config (defaultConfig, filterRules, parseConfig)
16import Purslint.Fix (applyAllFixes)
22import Purslint.Fix (applyAllFixes)
17import Purslint.Rule (Rule)
23import Purslint.Rule (Rule)
@@ -99,6 +105,13 @@ import Purslint.Rules.RedundantParens (redundantParensRule)
99import Purslint.Runner (runRules)
105import Purslint.Runner (runRules)
100import Purslint.Types (LintResult(..), LintWarning(..), Severity(..), SourceCode(..), Suggestion(..))
106import Purslint.Types (LintResult(..), LintWarning(..), Severity(..), SourceCode(..), Suggestion(..))
101
107
108+type CliOptions =
109+ { fix :: Boolean
110+ , listRules :: Boolean
111+ , initConfig :: Boolean
112+ , paths :: Array String
113+ }
114+
102-- | All available rules (81 total)
115-- | All available rules (81 total)
103allRules :: Array Rule
116allRules :: Array Rule
104allRules =
117allRules =
@@ -337,38 +350,70 @@ initConfig = do
337 FS.writeTextFile ".purslintrc" sampleConfig
350 FS.writeTextFile ".purslintrc" sampleConfig
338 log "Created .purslintrc"
351 log "Created .purslintrc"
339
352
353+parseFlags :: Array String -> Effect (Maybe CliOptions)
354+parseFlags args = case parseFlags' (Array.drop 2 args) of
355+ Success cli -> pure (Just cli)
356+ Failure (ParserFailure pf) -> case pf programName of
357+ ph@(ParserHelp _) /\ exitCode /\ i /\ _unit -> do
358+ log $ renderHelp i ph
359+ Process.exit (fromEnum exitCode)
360+ pure Nothing
361+ CompletionInvoked (CompletionResult { execCompletion }) -> do
362+ executedCompletion <- execCompletion programName
363+ log executedCompletion
364+ Process.exit 0
365+ pure Nothing
366+ where
367+ programName = "purslint"
368+
369+parseFlags' :: Array String -> ParserResult CliOptions
370+parseFlags' = execParserPure defaultPrefs opts
371+ where
372+ opts =
373+ info (flagsParser <**> helper) $
374+ fullDesc
375+ <> progDesc "Lint PureScript source files"
376+ <> header "purslint - a linter for PureScript"
377+
378+flagsParser :: Parser CliOptions
379+flagsParser = ado
380+ fix <- switch $ long "fix" <> help "Auto-fix issues (where possible)"
381+ listRules <- switch $ long "list" <> help "List all available rules"
382+ initConfig <- switch $ long "init" <> help "Create a sample .purslintrc"
383+ pathsList <- many $ argument str $ metavar "PATH..."
384+ let paths = Array.fromFoldable pathsList
385+ in { fix, listRules, initConfig, paths }
386+
340main :: Effect Unit
387main :: Effect Unit
341main = do
388main = do
342 args <- Process.argv
389 args <- Process.argv
343− -- args[0] is node, args[1] is the script, args[2..] are the actual arguments
390+ maybeCli <- parseFlags args
344− let userArgs = Array.drop 1 args
345− case userArgs of
391+ case maybeCli of
346− [] -> showUsage
347− ["--help"] -> showUsage
348− ["-h"] -> showUsage
349− ["--list"] -> listRules
350− ["--init"] -> initConfig
351− _ -> do
352− -- Check for --fix flag
353− let hasFix = Array.elem "--fix" userArgs
354− let paths = Array.filter (\a -> a /= "--fix") userArgs
355−
356− -- Load config and filter rules
357− config <- loadConfig
358− let enabledRules = filterRules allRules config
359−
360− if hasFix then do
361− -- Fix mode
362− _ <- Array.foldM (\acc path -> do
363− count <- fixPath enabledRules path
364− pure (acc + count)) 0 paths
365− pure unit
392+ Nothing -> pure unit
393+ Just cli ->
394+ if cli.listRules then
395+ listRules
396+ else if cli.initConfig then
397+ initConfig
398+ else if Array.null cli.paths then
399+ showUsage
366 else do
400 else do
401+ -- Load config and filter rules
402+ config <- loadConfig
403+ let enabledRules = filterRules allRules config
404+
405+ if cli.fix then do
406+ -- Fix mode
407+ _ <- Array.foldM (\acc path -> do
408+ count <- fixPath enabledRules path
409+ pure (acc + count)) 0 cli.paths
410+ pure unit
411+ else do
367− -- Lint mode
412+ -- Lint mode
368− totalWarnings <- Array.foldM (\acc path -> do
413+ totalWarnings <- Array.foldM (\acc path -> do
369− count <- lintPathWithConfig enabledRules path
414+ count <- lintPathWithConfig enabledRules path
370− pure (acc + count)) 0 paths
415+ pure (acc + count)) 0 cli.paths
371− when (totalWarnings > 0) do
416+ when (totalWarnings > 0) do
372− log ""
417+ log ""
373− log $ "Total: " <> show totalWarnings <> " warning" <> if totalWarnings == 1 then "" else "s"
418+ log $ "Total: " <> show totalWarnings <> " warning" <> if totalWarnings == 1 then "" else "s"
374− Process.exit 1
419+ Process.exit 1
spago.lock+81
@@ -83,6 +83,7 @@
83 "node-buffer",
83 "node-buffer",
84 "node-fs",
84 "node-fs",
85 "node-process",
85 "node-process",
86+ "optparse",
86 "prelude",
87 "prelude",
87 "purslint",
88 "purslint",
88 "strings"
89 "strings"
@@ -104,6 +105,7 @@
104 "enums",
105 "enums",
105 "exceptions",
106 "exceptions",
106 "exists",
107 "exists",
108+ "exitcodes",
107 "foldable-traversable",
109 "foldable-traversable",
108 "foreign",
110 "foreign",
109 "foreign-object",
111 "foreign-object",
@@ -130,6 +132,8 @@
130 "now",
132 "now",
131 "nullable",
133 "nullable",
132 "numbers",
134 "numbers",
135+ "open-memoize",
136+ "optparse",
133 "ordered-collections",
137 "ordered-collections",
134 "orders",
138 "orders",
135 "parallel",
139 "parallel",
@@ -233,10 +237,13 @@
233 "either",
237 "either",
234 "maybe",
238 "maybe",
235 "newtype",
239 "newtype",
240+ "optparse",
236 "prelude",
241 "prelude",
237 "purslint"
242 "purslint"
238 ],
243 ],
239 "build_plan": [
244 "build_plan": [
245+ "aff",
246+ "arraybuffer-types",
240 "arrays",
247 "arrays",
241 "bifunctors",
248 "bifunctors",
242 "catenable-lists",
249 "catenable-lists",
@@ -244,13 +251,17 @@
244 "const",
251 "const",
245 "contravariant",
252 "contravariant",
246 "control",
253 "control",
254+ "datetime",
247 "distributive",
255 "distributive",
248 "effect",
256 "effect",
249 "either",
257 "either",
250 "enums",
258 "enums",
251 "exceptions",
259 "exceptions",
252 "exists",
260 "exists",
261+ "exitcodes",
253 "foldable-traversable",
262 "foldable-traversable",
263+ "foreign",
264+ "foreign-object",
254 "free",
265 "free",
255 "functions",
266 "functions",
256 "functors",
267 "functors",
@@ -263,11 +274,20 @@
263 "lists",
274 "lists",
264 "maybe",
275 "maybe",
265 "newtype",
276 "newtype",
277+ "node-buffer",
278+ "node-event-emitter",
279+ "node-process",
280+ "node-streams",
266 "nonempty",
281 "nonempty",
282+ "nullable",
267 "numbers",
283 "numbers",
284+ "open-memoize",
285+ "optparse",
268 "ordered-collections",
286 "ordered-collections",
269 "orders",
287 "orders",
288+ "parallel",
270 "partial",
289 "partial",
290+ "posix-types",
271 "prelude",
291 "prelude",
272 "profunctor",
292 "profunctor",
273 "purslint",
293 "purslint",
@@ -1075,6 +1095,14 @@
1075 "unsafe-coerce"
1095 "unsafe-coerce"
1076 ]
1096 ]
1077 },
1097 },
1098+ "exitcodes": {
1099+ "type": "registry",
1100+ "version": "4.0.0",
1101+ "integrity": "sha256-4wxViTbyOoyKJ/WaRGI6+hZmgMKI5Miv16lSwefiLSM=",
1102+ "dependencies": [
1103+ "enums"
1104+ ]
1105+ },
1078 "foldable-traversable": {
1106 "foldable-traversable": {
1079 "type": "registry",
1107 "type": "registry",
1080 "version": "6.0.0",
1108 "version": "6.0.0",
@@ -1458,6 +1486,59 @@
1458 "maybe"
1486 "maybe"
1459 ]
1487 ]
1460 },
1488 },
1489+ "open-memoize": {
1490+ "type": "registry",
1491+ "version": "6.2.0",
1492+ "integrity": "sha256-p1m7wF3aHQ80yUvqMs20OTMl496WS6YpKlmI2Nkg9j0=",
1493+ "dependencies": [
1494+ "either",
1495+ "integers",
1496+ "lazy",
1497+ "lists",
1498+ "maybe",
1499+ "partial",
1500+ "prelude",
1501+ "strings",
1502+ "tuples"
1503+ ]
1504+ },
1505+ "optparse": {
1506+ "type": "registry",
1507+ "version": "5.0.1",
1508+ "integrity": "sha256-cEzEkNW4q0gZlXl4z0zn+H2vs6l2UAp7NPHCsois73k=",
1509+ "dependencies": [
1510+ "aff",
1511+ "arrays",
1512+ "bifunctors",
1513+ "console",
1514+ "control",
1515+ "effect",
1516+ "either",
1517+ "enums",
1518+ "exists",
1519+ "exitcodes",
1520+ "foldable-traversable",
1521+ "free",
1522+ "gen",
1523+ "integers",
1524+ "lazy",
1525+ "lists",
1526+ "maybe",
1527+ "newtype",
1528+ "node-buffer",
1529+ "node-process",
1530+ "node-streams",
1531+ "nonempty",
1532+ "numbers",
1533+ "open-memoize",
1534+ "partial",
1535+ "prelude",
1536+ "strings",
1537+ "tailrec",
1538+ "transformers",
1539+ "tuples"
1540+ ]
1541+ },
1461 "ordered-collections": {
1542 "ordered-collections": {
1462 "type": "registry",
1543 "type": "registry",
1463 "version": "3.2.0",
1544 "version": "3.2.0",
spago.yaml+1
@@ -11,6 +11,7 @@ package:
11 - either
11 - either
12 - maybe
12 - maybe
13 - newtype
13 - newtype
14+ - optparse
14 - prelude
15 - prelude
15 - purslint
16 - purslint
16 - arrays
17 - arrays
vscode-extension/package.json+1−1
@@ -4,7 +4,7 @@
4 "description": "PureScript linter inspired by hlint",
4 "description": "PureScript linter inspired by hlint",
5 "version": "0.1.1",
5 "version": "0.1.1",
6 "publisher": "RowtypeYoga",
6 "publisher": "RowtypeYoga",
7− "icon": "purslint.jpg",
7+ "icon": "purslint.png",
8 "engines": {
8 "engines": {
9 "vscode": "^1.85.0"
9 "vscode": "^1.85.0"
10 },
10 },
vscode-extension/purslint.jpgdeleted

Binary file not shown.

vscode-extension/purslint.pngnew file

Binary file not shown.