5Make lint rules safer by verifying that identifiers like `map`, `identity`, `<$>` actually refer to the standard Prelude functions, not user-defined functions with the same name.
9- `Purslint.Imports` module exists with:
10 - `getImportInfo :: Module Void -> ImportInfo` - extracts import info from a module
11 - `hasValue :: ImportInfo -> String -> Boolean` - check if a value is imported
12 - `hasOp :: ImportInfo -> String -> Boolean` - check if an operator is imported
13 - Lists of "Prelude-like" modules (Prelude, Data.Functor, Data.Traversable, etc.)
14 - Lists of standard values/operators we care about
18### Step 1: Update Rule type to receive ImportInfo
21-- In Purslint/Rule.purs
23 { imports :: ImportInfo
28 , run :: RuleContext -> Module Void -> Array LintWarning
31mkRule :: RuleId -> (RuleContext -> Module Void -> Array LintWarning) -> Rule
34### Step 2: Update Runner to pass context
37-- In Purslint/Runner.purs
38runRules :: Array Rule -> SourceCode -> Either String LintResult
39runRules rules (SourceCode source) = do
40 mod <- parseModule source
41 let imports = getImportInfo mod
43 let warnings = rules >>= \rule -> rule.run ctx mod
44 pure $ LintResult { warnings, moduleName: getModuleName mod }
47### Step 3: Update each rule to check imports
52checkExpr ctx expr = case expr of
53 ExprApp fnExpr args ->
55 ExprIdent qn | isMapLike qn && hasValue ctx.imports "map" ->
62 ExprOp lhs ops | isIdentity lhs && hasOp ctx.imports "<$>" ->
66### Step 4: Handle qualified imports (future)
68Track qualified imports like `import Data.Functor as F` and check for `F.map`.
72 { preludeValues :: Set String
73 , preludeOps :: Set String
74 , hasPrelude :: Boolean
75 , qualifiedModules :: Map String String -- alias -> module name
79Then in rules, also check `QualifiedName { module: Just alias }` against the map.
83All rules that check for specific identifiers:
85| Rule | Values to check | Operators to check |
86|------|-----------------|-------------------|
87| FmapId | `map`, `fmap`, `identity`, `id` | `<$>`, `<#>` |
88| MapFusion | `map`, `fmap` | `<$>`, `<#>` |
89| UseTraverse | `map`, `fmap`, `sequenceA` | `<$>` |
90| ConcatMap | `concat`, `join`, `map`, `fmap` | |
91| NotEqual | `not` | `==`, `/=` |
92| UseGuard | `pure`, `when`, `unless` | |
93| EtaReduce | (any function) | |
94| EtaReduceDecl | (any function) | |
95| RedundantBind | `pure` | `>>=` |
991. `lib/purslint/src/Purslint/Rule.purs` - Add RuleContext
1002. `lib/purslint/src/Purslint/Runner.purs` - Pass context to rules
1013. `lib/purslint/src/Purslint/Rules/*.purs` - All 9 rule files
1024. `bin/purslint-cli/src/Main.purs` - No changes needed (uses Runner)
1035. `bin/purslint-lsp/src/LSP.purs` - No changes needed (uses Runner)
107After implementation, test with:
112-- Should NOT trigger (no Prelude import)
113x = map identity [1,2,3]
116map :: forall a b. (a -> b) -> Array a -> Array b
127-- SHOULD trigger (Prelude imported)
128x = map identity [1,2,3]
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list