Add DefaultPatternPosition rule

This commit is contained in:
Jeroen Engels 2017-01-22 23:50:00 +01:00
parent fb59dfc294
commit 2b3a3e5a88
8 changed files with 195 additions and 2 deletions

View File

@ -18,6 +18,7 @@ You can read the slides for my [presentation](http://slides.com/jeroenengels/elm
## Rules
- [DefaultPatternPosition](rules/DefaultPatternPosition.md) - Enforce the default pattern to always appear first or last.
- [NoConstantCondition](rules/NoConstantCondition.md) - Forbid the use of expressions in an If condition whose value are always the same.
- [NoDebug](rules/NoDebug.md) - Forbid the use of `Debug` before it goes into production.
- [NoDuplicateImports](rules/NoDuplicateImports.md) - Forbid importing the same module several times in a file.

View File

@ -9,6 +9,7 @@
],
"exposed-modules": [],
"dependencies": {
"elm-community/list-extra": "5.0.1 <= v < 6.0.0",
"elm-lang/core": "5.0.0 <= v < 6.0.0",
"elm-lang/html": "2.0.0 <= v < 3.0.0",
"jfmengels/elm-ast": "1.0.1 <= v < 2.0.0"

View File

@ -14,6 +14,7 @@ import Regex exposing (regex, escape)
-- Rules
import DefaultPatternPosition
import NoConstantCondition
import NoDebug
import NoDuplicateImports
@ -32,7 +33,8 @@ type Msg
rules : List (String -> List Types.Error)
rules =
[ NoConstantCondition.rule
[ DefaultPatternPosition.rule { position = DefaultPatternPosition.Last }
, NoConstantCondition.rule
, NoDebug.rule
, NoDuplicateImports.rule
, NoExposingEverything.rule

View File

@ -10,6 +10,7 @@
],
"exposed-modules": [],
"dependencies": {
"elm-community/list-extra": "5.0.1 <= v < 6.0.0",
"elm-lang/core": "5.0.0 <= v < 6.0.0",
"elm-lang/html": "2.0.0 <= v < 3.0.0",
"jfmengels/elm-ast": "1.0.0 <= v < 2.0.0"

View File

@ -0,0 +1,94 @@
module DefaultPatternPosition exposing (rule, PatternPosition(..))
import Ast.Expression exposing (..)
import Html.Attributes exposing (pattern)
import Lint exposing (doNothing, lint)
import List.Extra exposing (findIndex)
import Regex
import Set exposing (Set)
import Types exposing (Direction(..), Error, LintRule)
type alias Context =
{}
type PatternPosition
= First
| Last
type alias Configuration =
{ position : PatternPosition
}
rule : Configuration -> String -> List Error
rule config input =
lint input (implementation config)
implementation : Configuration -> LintRule Context
implementation configuration =
{ statementFn = doNothing
, typeFn = doNothing
, expressionFn = expressionFn configuration
, moduleEndFn = (\ctx -> ( [], ctx ))
, initialContext = Context
}
error : String -> Error
error =
Error "DefaultPatternPosition"
{-| TODO Share this in a util file, already defined in NoUselessPatternMatching
-}
isVariable : String -> Bool
isVariable =
Regex.contains (Regex.regex "^[_a-z][\\w\\d]*$")
isDefaultPattern : ( Expression, Expression ) -> Bool
isDefaultPattern pattern =
case Tuple.first pattern of
Variable names ->
if isVariable (String.join "." names) then
True
else
False
_ ->
False
findDefaultPattern : List ( Expression, Expression ) -> Maybe Int
findDefaultPattern =
findIndex isDefaultPattern
expressionFn : Configuration -> Context -> Direction Expression -> ( List Error, Context )
expressionFn config ctx node =
case node of
Enter (Case expr patterns) ->
case findDefaultPattern patterns of
Nothing ->
( [], ctx )
Just index ->
case config.position of
First ->
if index /= 0 then
( [ error "Expected default pattern to appear first in the list of patterns" ], ctx )
else
( [], ctx )
Last ->
if index /= (List.length patterns) - 1 then
( [ error "Expected default pattern to appear last in the list of patterns" ], ctx )
else
( [], ctx )
_ ->
( [], ctx )

View File

@ -0,0 +1,91 @@
port module DefaultPatternPositionTest exposing (all)
import Expect
import Test exposing (describe, test, Test)
import DefaultPatternPosition exposing (rule, PatternPosition(First, Last))
import Types exposing (Error)
error : String -> Error
error position =
Error "DefaultPatternPosition" ("Expected default pattern to appear " ++ position ++ " in the list of patterns")
tests : List Test
tests =
[ test "should not report when default pattern is at the expected position (first)" <|
\() ->
"""a = case b of
_ -> 1
Bar -> 1
Foo -> 1
"""
|> rule { position = First }
|> Expect.equal []
, test "should not report when default pattern is at the expected position (last)" <|
\() ->
"""a = case b of
Foo -> 1
Bar -> 1
_ -> 1
"""
|> rule { position = Last }
|> Expect.equal []
, test "should not report when there is no default pattern (first)" <|
\() ->
"""a = case b of
Foo -> 1
Bar -> 1
"""
|> rule { position = First }
|> Expect.equal []
, test "should not report when there is no default pattern (last)" <|
\() ->
"""a = case b of
Foo -> 1
Bar -> 1
"""
|> rule { position = Last }
|> Expect.equal []
, test "should report an error when the default pattern is not at the expected position (first) (opposite expected position)" <|
\() ->
"""a = case b of
Foo -> 1
Bar -> 1
_ -> 1
"""
|> rule { position = First }
|> Expect.equal [ error "first" ]
, test "should report an error when the default pattern is not at the expected position (first) (somewhere in the middle)" <|
\() ->
"""a = case b of
Foo -> 1
_ -> 1
Bar -> 1
"""
|> rule { position = First }
|> Expect.equal [ error "first" ]
, test "should report an error when the default pattern is not at the expected position (last) (opposite expected position)" <|
\() ->
"""a = case b of
_ -> 1
Foo -> 1
Bar -> 1
"""
|> rule { position = Last }
|> Expect.equal [ error "last" ]
, test "should report an error when the default pattern is not at the expected position (last) (somewhere in the middle)" <|
\() ->
"""a = case b of
Foo -> 1
_ -> 1
Bar -> 1
"""
|> rule { position = Last }
|> Expect.equal [ error "last" ]
]
all : Test
all =
describe "DefaultPatternPosition" tests

View File

@ -3,6 +3,7 @@ port module Tests exposing (..)
import Test exposing (describe, Test)
import Test.Runner.Node exposing (run)
import Json.Encode exposing (Value)
import DefaultPatternPositionTest
import NoConstantConditionTest
import NoDebugTest
import NoDuplicateImportsTest
@ -25,7 +26,8 @@ port emit : ( String, Value ) -> Cmd msg
all : Test
all =
describe "Visitors"
[ NoConstantConditionTest.all
[ DefaultPatternPositionTest.all
, NoConstantConditionTest.all
, NoDebugTest.all
, NoDuplicateImportsTest.all
, NoImportingEverythingTest.all

View File

@ -11,6 +11,7 @@
"exposed-modules": [],
"dependencies": {
"elm-community/elm-test": "3.1.0 <= v < 4.0.0",
"elm-community/list-extra": "5.0.1 <= v < 6.0.0",
"elm-lang/core": "5.0.0 <= v < 6.0.0",
"elm-lang/html": "2.0.0 <= v < 3.0.0",
"jfmengels/elm-ast": "1.0.1 <= v < 2.0.0",