mirror of
https://github.com/jfmengels/elm-review.git
synced 2024-11-22 22:33:13 +03:00
Add documentation
This commit is contained in:
parent
fc93fad157
commit
0710792368
@ -1,6 +1,6 @@
|
||||
# elm-lint
|
||||
|
||||
An [Elm](http://elm-lang.org/) linter written in Elm.
|
||||
An [Elm](http://elm-lang.org/) linter written in Elm. Get your code from correct to better.
|
||||
|
||||
## Try it
|
||||
|
||||
|
@ -1,12 +1,28 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"summary": "helpful summary of your project, less than 80 characters",
|
||||
"repository": "https://github.com/user/project.git",
|
||||
"summary": "A linter for Elm. Get your code from correct to better.",
|
||||
"repository": "https://github.com/jfmengels/elm-lint.git",
|
||||
"license": "BSD3",
|
||||
"source-directories": [
|
||||
"src"
|
||||
],
|
||||
"exposed-modules": [],
|
||||
"exposed-modules": [
|
||||
"Lint",
|
||||
"Lint.Types",
|
||||
"Lint.Rules.DefaultPatternPosition",
|
||||
"Lint.Rules.NoConstantCondition",
|
||||
"Lint.Rules.NoDebug",
|
||||
"Lint.Rules.NoDuplicateImports",
|
||||
"Lint.Rules.NoExposingEverything",
|
||||
"Lint.Rules.NoImportingEverything",
|
||||
"Lint.Rules.NoNestedLet",
|
||||
"Lint.Rules.NoUnannotatedFunction",
|
||||
"Lint.Rules.NoUnusedVariables",
|
||||
"Lint.Rules.NoUselessIf",
|
||||
"Lint.Rules.NoUselessPatternMatching",
|
||||
"Lint.Rules.NoWarningComments",
|
||||
"Lint.Rules.SimplifyPiping"
|
||||
],
|
||||
"dependencies": {
|
||||
"elm-community/list-extra": "5.0.1 <= v < 6.0.0",
|
||||
"elm-lang/core": "5.0.0 <= v < 6.0.0",
|
||||
|
@ -14,40 +14,40 @@ import Regex exposing (regex, escape)
|
||||
|
||||
-- Rules
|
||||
|
||||
import DefaultPatternPosition
|
||||
import NoConstantCondition
|
||||
import NoDebug
|
||||
import NoDuplicateImports
|
||||
import NoExposingEverything
|
||||
import NoImportingEverything
|
||||
import NoNestedLet
|
||||
import NoUnannotatedFunction
|
||||
import NoUnusedVariables
|
||||
import NoUselessIf
|
||||
import NoUselessPatternMatching
|
||||
import NoWarningComments
|
||||
import SimplifyPiping
|
||||
import Lint.Rules.DefaultPatternPosition
|
||||
import Lint.Rules.NoConstantCondition
|
||||
import Lint.Rules.NoDebug
|
||||
import Lint.Rules.NoDuplicateImports
|
||||
import Lint.Rules.NoExposingEverything
|
||||
import Lint.Rules.NoImportingEverything
|
||||
import Lint.Rules.NoNestedLet
|
||||
import Lint.Rules.NoUnannotatedFunction
|
||||
import Lint.Rules.NoUnusedVariables
|
||||
import Lint.Rules.NoUselessIf
|
||||
import Lint.Rules.NoUselessPatternMatching
|
||||
import Lint.Rules.NoWarningComments
|
||||
import Lint.Rules.SimplifyPiping
|
||||
|
||||
|
||||
type Msg
|
||||
= Replace String
|
||||
|
||||
|
||||
rules : List (String -> List Types.Error)
|
||||
rules : List (String -> List Lint.Types.Error)
|
||||
rules =
|
||||
[ DefaultPatternPosition.rule { position = DefaultPatternPosition.Last }
|
||||
, NoConstantCondition.rule
|
||||
, NoDebug.rule
|
||||
, NoDuplicateImports.rule
|
||||
, NoExposingEverything.rule
|
||||
, NoImportingEverything.rule
|
||||
, NoNestedLet.rule
|
||||
, NoUnannotatedFunction.rule
|
||||
, NoUnusedVariables.rule
|
||||
, NoUselessIf.rule
|
||||
, NoUselessPatternMatching.rule
|
||||
, NoWarningComments.rule
|
||||
, SimplifyPiping.rule
|
||||
[ Lint.Rules.DefaultPatternPosition.rule { position = Lint.Rules.DefaultPatternPosition.Last }
|
||||
, Lint.Rules.NoConstantCondition.rule
|
||||
, Lint.Rules.NoDebug.rule
|
||||
, Lint.Rules.NoDuplicateImports.rule
|
||||
, Lint.Rules.NoExposingEverything.rule
|
||||
, Lint.Rules.NoImportingEverything.rule
|
||||
, Lint.Rules.NoNestedLet.rule
|
||||
, Lint.Rules.NoUnannotatedFunction.rule
|
||||
, Lint.Rules.NoUnusedVariables.rule
|
||||
, Lint.Rules.NoUselessIf.rule
|
||||
, Lint.Rules.NoUselessPatternMatching.rule
|
||||
, Lint.Rules.NoWarningComments.rule
|
||||
, Lint.Rules.SimplifyPiping.rule
|
||||
]
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"summary": "helpful summary of your project, less than 80 characters",
|
||||
"repository": "https://github.com/user/project.git",
|
||||
"summary": "Online example for elm-lint",
|
||||
"repository": "https://github.com/jfmengels/elm-lint.git",
|
||||
"license": "BSD3",
|
||||
"source-directories": [
|
||||
".",
|
||||
|
86
src/Lint.elm
86
src/Lint.elm
@ -1,14 +1,67 @@
|
||||
module Lint exposing (lint, visitExpression, doNothing)
|
||||
|
||||
{-| A linter for Elm.
|
||||
|
||||
See Lint.Rules for the implemented rules.
|
||||
|
||||
@docs lint, doNothing, visitExpression
|
||||
-}
|
||||
|
||||
import Ast
|
||||
import Ast.Expression exposing (Expression)
|
||||
import Lint.Types exposing (Error, LintImplementation, LintRule, Direction, Visitor)
|
||||
import Lint.Visitor exposing (transformStatementsIntoVisitors, expressionToVisitors)
|
||||
|
||||
|
||||
doNothing : LintImplementation a context
|
||||
doNothing ctx _ =
|
||||
( [], ctx )
|
||||
{-| Lints source code using a given rule implementation, and gives back a list of errors that were found.
|
||||
|
||||
rule : String -> List Error
|
||||
rule input =
|
||||
lint input implementation
|
||||
|
||||
implementation : LintRule Context
|
||||
implementation =
|
||||
{ statementFn = doNothing
|
||||
, typeFn = doNothing
|
||||
, expressionFn = expressionFn
|
||||
, moduleEndFn = (\ctx -> ( [], ctx ))
|
||||
, initialContext = Context
|
||||
}
|
||||
-}
|
||||
lint : String -> LintRule context -> List Error
|
||||
lint source =
|
||||
source
|
||||
|> Ast.parse
|
||||
|> Result.map (\( _, _, statements ) -> statements)
|
||||
|> Result.withDefault []
|
||||
|> transformStatementsIntoVisitors
|
||||
|> lintWithVisitors
|
||||
|
||||
|
||||
{-| Visit an expression using a sub rule implementation. The use of this function is not encouraged, but it can make
|
||||
part of the implementation of complex rules much easier. It gives back a list of errors and a context.
|
||||
|
||||
expressionFn : Context -> Direction Expression -> ( List Error, Context )
|
||||
expressionFn ctx node =
|
||||
case node of
|
||||
Enter (Case expr patterns) ->
|
||||
visitExpression subimplementation expr
|
||||
_ ->
|
||||
( [], ctx )
|
||||
|
||||
subimplementation : LintRule Subcontext
|
||||
subimplementation =
|
||||
{ statementFn = doNothing
|
||||
, typeFn = doNothing
|
||||
, expressionFn = subexpressionFn
|
||||
, moduleEndFn = (\ctx -> ( [], ctx ))
|
||||
, initialContext = Subcontext
|
||||
}
|
||||
-}
|
||||
visitExpression : LintRule context -> Expression -> ( List Error, context )
|
||||
visitExpression rule expression =
|
||||
expressionToVisitors expression
|
||||
|> List.foldl (visitAndAccumulate rule) ( [], rule.initialContext )
|
||||
|
||||
|
||||
visitAndAccumulate : LintRule context -> Visitor context -> ( List Error, context ) -> ( List Error, context )
|
||||
@ -24,17 +77,18 @@ lintWithVisitors visitors rule =
|
||||
|> Tuple.first
|
||||
|
||||
|
||||
visitExpression : LintRule context -> Expression -> ( List Error, context )
|
||||
visitExpression rule expression =
|
||||
expressionToVisitors expression
|
||||
|> List.foldl (visitAndAccumulate rule) ( [], rule.initialContext )
|
||||
{-| Basic implementation of a visitor function that does nothing, i.e. return an empty list of errors and an untouched
|
||||
context. This is used to avoid a bit of boilerplate for visitor functions whose node types we are not interested in.
|
||||
|
||||
|
||||
lint : String -> LintRule context -> List Error
|
||||
lint source =
|
||||
source
|
||||
|> Ast.parse
|
||||
|> Result.map (\( _, _, statements ) -> statements)
|
||||
|> Result.withDefault []
|
||||
|> transformStatementsIntoVisitors
|
||||
|> lintWithVisitors
|
||||
implementation : LintRule Context
|
||||
implementation =
|
||||
{ statementFn = doNothing
|
||||
, typeFn = doNothing
|
||||
, expressionFn = expressionFn
|
||||
, moduleEndFn = (\ctx -> ( [], ctx ))
|
||||
, initialContext = Context
|
||||
}
|
||||
-}
|
||||
doNothing : LintImplementation a context
|
||||
doNothing ctx _ =
|
||||
( [], ctx )
|
||||
|
@ -1,24 +1,104 @@
|
||||
module Lint.Types exposing (..)
|
||||
module Lint.Types exposing (Error, LintImplementation, Direction(..), LintRule, Visitor)
|
||||
|
||||
{-| This module contains types that are used for writing rules.
|
||||
|
||||
# Elementary types
|
||||
@docs Error, Direction
|
||||
|
||||
# Writing rules
|
||||
@docs LintRule, LintImplementation
|
||||
|
||||
# Internal types
|
||||
@docs Visitor
|
||||
-}
|
||||
|
||||
import Ast.Expression exposing (..)
|
||||
import Ast.Statement exposing (..)
|
||||
|
||||
|
||||
{-| Value that describes an error found by a given rule, that contains the name of the rule that raised the error, and
|
||||
a description of the error.
|
||||
|
||||
error : Error
|
||||
error =
|
||||
Error "NoDebug" "Forbidden use of Debug"
|
||||
-}
|
||||
type alias Error =
|
||||
{ rule : String
|
||||
, message : String
|
||||
}
|
||||
|
||||
|
||||
{-| A LintImplementation is a function that takes a given Context object, as defined by each rule, a node (with a
|
||||
Direction) and returns a list of errors and an updated Context.
|
||||
Every rule should implement three LintImplementation functions, one for every Node type (Statement, Type and
|
||||
Expression).
|
||||
The Context is there to accumulate information about the source code as the AST is being visited and is shared by all
|
||||
the LintImplementation functions of your rule.
|
||||
It must return a list of errors which will be reported to the user, that are violations of the thing the rule wants to
|
||||
enforce.
|
||||
|
||||
rule : String -> List Error
|
||||
rule input =
|
||||
lint input implementation
|
||||
|
||||
implementation : LintRule Context
|
||||
implementation =
|
||||
{ statementFn = doNothing
|
||||
, typeFn = doNothing
|
||||
, expressionFn = expressionFn
|
||||
, moduleEndFn = (\ctx -> ( [], ctx ))
|
||||
, initialContext = Context
|
||||
}
|
||||
-}
|
||||
type alias LintImplementation nodeType context =
|
||||
context -> Direction nodeType -> ( List Error, context )
|
||||
|
||||
|
||||
{-| When visiting the AST, nodes are visited twice:
|
||||
- on Enter, before the children of the node will be visited
|
||||
- on Exit, after the children of the node have been visited
|
||||
|
||||
expressionFn : Context -> Direction Expression -> ( List Error, Context )
|
||||
expressionFn ctx node =
|
||||
case node of
|
||||
Enter (Variable names) ->
|
||||
( [], markVariableAsUsed ctx names )
|
||||
|
||||
-- Find variables declared in `let .. in ..` expression
|
||||
Enter (Let declarations body) ->
|
||||
( [], registerVariables ctx declarations )
|
||||
|
||||
-- When exiting the `let .. in ..` expression, report the variables that were not used.
|
||||
Exit (Let _ _) ->
|
||||
( unusedVariables ctx |> List.map createError, ctx )
|
||||
-}
|
||||
type Direction node
|
||||
= Enter node
|
||||
| Exit node
|
||||
|
||||
|
||||
type alias LintImplementation nodeType context =
|
||||
context -> Direction nodeType -> ( List Error, context )
|
||||
{-| A LintRule is the implementation of a rule. It is a record that contains:
|
||||
- initialContext: An initial context
|
||||
- statementFn: A LintImplementation for Statement nodes
|
||||
- typeFn: A LintImplementation for Type nodes
|
||||
- expressionFn: A LintImplementation for Expression nodes
|
||||
- moduleEndFn: A function that takes a context and returns a list of error. Similar to a LintImplementation, but will
|
||||
be called after visiting the whole AST.
|
||||
|
||||
rule : String -> List Error
|
||||
rule input =
|
||||
lint input implementation
|
||||
|
||||
implementation : LintRule Context
|
||||
implementation =
|
||||
{ statementFn = doNothing
|
||||
, typeFn = doNothing
|
||||
, expressionFn = expressionFn
|
||||
, moduleEndFn = (\ctx -> ( [], ctx ))
|
||||
, initialContext = Context
|
||||
}
|
||||
-}
|
||||
type alias LintRule context =
|
||||
{ statementFn : LintImplementation Statement context
|
||||
, typeFn : LintImplementation Type context
|
||||
@ -28,5 +108,10 @@ type alias LintRule context =
|
||||
}
|
||||
|
||||
|
||||
{-| Shorthand for a function that takes a rule's implementation, a context and returns ( List Error, context ).
|
||||
A Visitor represents a node and calls the appropriate function for the given node type.
|
||||
|
||||
Note: this is internal API, and will be removed in a future version.
|
||||
-}
|
||||
type alias Visitor context =
|
||||
LintRule context -> context -> ( List Error, context )
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"summary": "helpful summary of your project, less than 80 characters",
|
||||
"repository": "https://github.com/user/project.git",
|
||||
"summary": "Tests for elm-lint",
|
||||
"repository": "https://github.com/jfmengels/elm-lint.git",
|
||||
"license": "BSD3",
|
||||
"source-directories": [
|
||||
".",
|
||||
|
Loading…
Reference in New Issue
Block a user