git.iko.soy/rowtype-yoga/purslint
on main help sign in
9 files changed+217−34
since splitsnapshots
unifiedsplit
.github/ISSUE_TEMPLATE/bug_report.yml+53 README.md+4−2 bin/purslint-cli/spago.yaml+1 bin/purslint-cli/src/Main.purs+76−31 spago.lock+81 spago.yaml+1 vscode-extension/package.json+1−1 vscode-extension/purslint.jpg vscode-extension/purslint.png
.github/ISSUE_TEMPLATE/bug_report.ymlnew file+53
@@ -0,0 +1,53 @@
1+name: Bug report
2+description: Report incorrect lint results with input and output.
3+title: "[Bug]: "
4+labels:
5+ - bug
6+body:
7+ - type: markdown
8+ attributes:
9+ value: |
10+ Thanks for taking the time to report a bug.
11+ If possible, include a golden file with input, actual output, and expected output.
12+ - type: textarea
13+ id: input
14+ attributes:
15+ label: Input
16+ description: |
17+ Paste the input here (or attach a golden file and mention the filename).
18+ Include any relevant configuration.
19+ placeholder: |
20+ ```purs
21+ -- Your input code here
22+ ```
23+ validations:
24+ required: true
25+ - type: textarea
26+ id: actual
27+ attributes:
28+ label: Actual output
29+ description: Paste the current output from purslint.
30+ placeholder: |
31+ ```
32+ -- Warnings, fixes, or logs
33+ ```
34+ validations:
35+ required: true
36+ - type: textarea
37+ id: expected
38+ attributes:
39+ label: Expected output
40+ description: Describe the expected output or behaviour.
41+ placeholder: |
42+ ```
43+ -- Expected warnings, fixes, or logs
44+ ```
45+ validations:
46+ required: true
47+ - type: textarea
48+ id: extra
49+ attributes:
50+ label: Additional context
51+ description: Links, screenshots, or anything else helpful.
52+ validations:
53+ required: false
README.md+4−2
@@ -1,7 +1,7 @@
11# Purslint
22
33<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" />
55</p>
66
77<p align="center">
@@ -10,7 +10,9 @@
1010 </a>
1111</p>
1212
13−A PureScript linter inspired by [hlint](https://github.com/ndmitchell/hlint), providing suggestions for cleaner, more idiomatic PureScript code.
13+A PureScript linter.
14+
15+Purslint is very new and may have bugs, so please use an editor with undo functionality. :D
1416
1517## Install
1618
bin/purslint-cli/spago.yaml+1
@@ -8,6 +8,7 @@ package:
88 - foldable-traversable
99 - maybe
1010 - newtype
11+ - optparse
1112 - prelude
1213 - purslint
1314 - strings
bin/purslint-cli/src/Main.purs+76−31
@@ -4,14 +4,20 @@ import Prelude
44
55import Data.Array as Array
66import Data.Either (Either(..))
7+import Data.Enum (fromEnum)
78import Data.Foldable (for_)
89import Data.Maybe (Maybe(..))
910import Data.Newtype (unwrap)
1011import Data.String.CodeUnits as String
12+import Data.Tuple.Nested ((/\))
1113import Effect (Effect)
1214import Effect.Console (log)
1315import Node.FS.Simple as FS
1416import 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)
1521import Purslint.Config (defaultConfig, filterRules, parseConfig)
1622import Purslint.Fix (applyAllFixes)
1723import Purslint.Rule (Rule)
@@ -99,6 +105,13 @@ import Purslint.Rules.RedundantParens (redundantParensRule)
99105import Purslint.Runner (runRules)
100106import Purslint.Types (LintResult(..), LintWarning(..), Severity(..), SourceCode(..), Suggestion(..))
101107
108+type CliOptions =
109+ { fix :: Boolean
110+ , listRules :: Boolean
111+ , initConfig :: Boolean
112+ , paths :: Array String
113+ }
114+
102115-- | All available rules (81 total)
103116allRules :: Array Rule
104117allRules =
@@ -337,38 +350,70 @@ initConfig = do
337350 FS.writeTextFile ".purslintrc" sampleConfig
338351 log "Created .purslintrc"
339352
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+
340387main :: Effect Unit
341388main = do
342389 args <- Process.argv
343− -- args[0] is node, args[1] is the script, args[2..] are the actual arguments
344− let userArgs = Array.drop 1 args
345− case userArgs 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
390+ maybeCli <- parseFlags args
391+ case maybeCli of
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
366400 else do
367− -- Lint mode
368− totalWarnings <- Array.foldM (\acc path -> do
369− count <- lintPathWithConfig enabledRules path
370− pure (acc + count)) 0 paths
371− when (totalWarnings > 0) do
372− log ""
373− log $ "Total: " <> show totalWarnings <> " warning" <> if totalWarnings == 1 then "" else "s"
374− Process.exit 1
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
412+ -- Lint mode
413+ totalWarnings <- Array.foldM (\acc path -> do
414+ count <- lintPathWithConfig enabledRules path
415+ pure (acc + count)) 0 cli.paths
416+ when (totalWarnings > 0) do
417+ log ""
418+ log $ "Total: " <> show totalWarnings <> " warning" <> if totalWarnings == 1 then "" else "s"
419+ Process.exit 1
spago.lock+81
@@ -83,6 +83,7 @@
8383 "node-buffer",
8484 "node-fs",
8585 "node-process",
86+ "optparse",
8687 "prelude",
8788 "purslint",
8889 "strings"
@@ -104,6 +105,7 @@
104105 "enums",
105106 "exceptions",
106107 "exists",
108+ "exitcodes",
107109 "foldable-traversable",
108110 "foreign",
109111 "foreign-object",
@@ -130,6 +132,8 @@
130132 "now",
131133 "nullable",
132134 "numbers",
135+ "open-memoize",
136+ "optparse",
133137 "ordered-collections",
134138 "orders",
135139 "parallel",
@@ -233,10 +237,13 @@
233237 "either",
234238 "maybe",
235239 "newtype",
240+ "optparse",
236241 "prelude",
237242 "purslint"
238243 ],
239244 "build_plan": [
245+ "aff",
246+ "arraybuffer-types",
240247 "arrays",
241248 "bifunctors",
242249 "catenable-lists",
@@ -244,13 +251,17 @@
244251 "const",
245252 "contravariant",
246253 "control",
254+ "datetime",
247255 "distributive",
248256 "effect",
249257 "either",
250258 "enums",
251259 "exceptions",
252260 "exists",
261+ "exitcodes",
253262 "foldable-traversable",
263+ "foreign",
264+ "foreign-object",
254265 "free",
255266 "functions",
256267 "functors",
@@ -263,11 +274,20 @@
263274 "lists",
264275 "maybe",
265276 "newtype",
277+ "node-buffer",
278+ "node-event-emitter",
279+ "node-process",
280+ "node-streams",
266281 "nonempty",
282+ "nullable",
267283 "numbers",
284+ "open-memoize",
285+ "optparse",
268286 "ordered-collections",
269287 "orders",
288+ "parallel",
270289 "partial",
290+ "posix-types",
271291 "prelude",
272292 "profunctor",
273293 "purslint",
@@ -1075,6 +1095,14 @@
10751095 "unsafe-coerce"
10761096 ]
10771097 },
1098+ "exitcodes": {
1099+ "type": "registry",
1100+ "version": "4.0.0",
1101+ "integrity": "sha256-4wxViTbyOoyKJ/WaRGI6+hZmgMKI5Miv16lSwefiLSM=",
1102+ "dependencies": [
1103+ "enums"
1104+ ]
1105+ },
10781106 "foldable-traversable": {
10791107 "type": "registry",
10801108 "version": "6.0.0",
@@ -1458,6 +1486,59 @@
14581486 "maybe"
14591487 ]
14601488 },
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+ },
14611542 "ordered-collections": {
14621543 "type": "registry",
14631544 "version": "3.2.0",
spago.yaml+1
@@ -11,6 +11,7 @@ package:
1111 - either
1212 - maybe
1313 - newtype
14+ - optparse
1415 - prelude
1516 - purslint
1617 - arrays
vscode-extension/package.json+1−1
@@ -4,7 +4,7 @@
44 "description": "PureScript linter inspired by hlint",
55 "version": "0.1.1",
66 "publisher": "RowtypeYoga",
7− "icon": "purslint.jpg",
7+ "icon": "purslint.png",
88 "engines": {
99 "vscode": "^1.85.0"
1010 },
vscode-extension/purslint.jpgdeleted

Binary file not shown.

vscode-extension/purslint.pngnew file

Binary file not shown.