mirror of
https://github.com/jfmengels/elm-review.git
synced 2024-11-27 12:08:51 +03:00
Re-add DefaultPatternPosition
This commit is contained in:
parent
21411aaf8c
commit
ede98bc179
8
elm.json
8
elm.json
@ -8,15 +8,19 @@
|
||||
"Lint",
|
||||
"Lint.Rule",
|
||||
"Lint.Rule.NoDebug",
|
||||
"Lint.Rule.NoUnusedVariables"
|
||||
"Lint.Rule.NoUnusedVariables",
|
||||
"Lint.Rule.NoImportingEverything",
|
||||
"Lint.Rule.DefaultPatternPosition"
|
||||
],
|
||||
"elm-version": "0.19.0 <= v < 0.20.0",
|
||||
"dependencies": {
|
||||
"elm/core": "1.0.0 <= v < 2.0.0",
|
||||
"elm/regex": "1.0.0 <= v < 2.0.0",
|
||||
"elm-community/list-extra": "8.2.0 <= v < 9.0.0",
|
||||
"mgold/elm-nonempty-list": "4.0.1 <= v < 5.0.0",
|
||||
"stil4m/elm-syntax": "7.1.0 <= v < 8.0.0"
|
||||
},
|
||||
"test-dependencies": {
|
||||
"elm-explorations/test": "1.2.1 <= v < 2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import Html.Attributes exposing (class, id, style)
|
||||
import Html.Events exposing (onInput)
|
||||
import Lint exposing (Rule, Severity(..), lintSource)
|
||||
import Lint.Error exposing (Error)
|
||||
import Lint.Rule.DefaultPatternPosition
|
||||
import Lint.Rule.NoDebug
|
||||
import Lint.Rule.NoImportingEverything
|
||||
import Lint.Rule.NoUnusedVariables
|
||||
@ -23,8 +24,8 @@ config =
|
||||
[ ( Critical, Lint.Rule.NoDebug.rule )
|
||||
, ( Critical, Lint.Rule.NoUnusedVariables.rule )
|
||||
, ( Critical, Lint.Rule.NoImportingEverything.rule { exceptions = [ "Html" ] } )
|
||||
, ( Critical, Lint.Rule.DefaultPatternPosition.rule { position = Lint.Rule.DefaultPatternPosition.Last } )
|
||||
|
||||
-- , ( Critical, Lint.Rule.DefaultPatternPosition.rule { position = Lint.Rule.DefaultPatternPosition.Last } )
|
||||
-- , ( Critical, Lint.Rule.NoConstantCondition.rule )
|
||||
-- , ( Critical, Lint.Rule.NoDuplicateImports.rule )
|
||||
-- , ( Critical, Lint.Rule.NoExposingEverything.rule )
|
||||
|
@ -10,6 +10,8 @@
|
||||
"elm/browser": "1.0.1",
|
||||
"elm/core": "1.0.0",
|
||||
"elm/html": "1.0.0",
|
||||
"elm/regex": "1.0.0",
|
||||
"elm-community/list-extra": "8.2.0",
|
||||
"mgold/elm-nonempty-list": "4.0.0",
|
||||
"stil4m/elm-syntax": "7.0.2"
|
||||
},
|
||||
@ -21,7 +23,6 @@
|
||||
"elm/url": "1.0.0",
|
||||
"elm/virtual-dom": "1.0.2",
|
||||
"elm-community/json-extra": "4.0.0",
|
||||
"elm-community/list-extra": "8.1.0",
|
||||
"rtfeldman/elm-hex": "1.0.0",
|
||||
"rtfeldman/elm-iso8601-date-strings": "1.1.2",
|
||||
"stil4m/structured-writer": "1.0.2"
|
||||
|
161
src/Lint/Rule/DefaultPatternPosition.elm
Normal file
161
src/Lint/Rule/DefaultPatternPosition.elm
Normal file
@ -0,0 +1,161 @@
|
||||
module Lint.Rule.DefaultPatternPosition exposing (rule, Configuration, PatternPosition(..))
|
||||
|
||||
{-|
|
||||
|
||||
@docs rule, Configuration, PatternPosition
|
||||
|
||||
|
||||
# Fail
|
||||
|
||||
rules =
|
||||
[ DefaultPatternPosition.rule { position = Lint.Rules.DefaultPatternPosition.Last }
|
||||
]
|
||||
|
||||
case value of
|
||||
-- LintError, this pattern should appear last
|
||||
_ -> result
|
||||
Foo -> bar
|
||||
|
||||
-- --------------------
|
||||
|
||||
rules =
|
||||
[ DefaultPatternPosition.rule { position = Lint.Rules.DefaultPatternPosition.First }
|
||||
]
|
||||
|
||||
case value of
|
||||
Foo -> bar
|
||||
-- LintError, this pattern should appear first
|
||||
_ -> result
|
||||
|
||||
|
||||
# Success
|
||||
|
||||
rules =
|
||||
[ DefaultPatternPosition.rule { position = Lint.Rules.DefaultPatternPosition.Last }
|
||||
]
|
||||
|
||||
case value of
|
||||
Foo -> bar
|
||||
_ -> result
|
||||
|
||||
case value of
|
||||
-- No default pattern
|
||||
Foo -> bar
|
||||
Bar -> foo
|
||||
|
||||
-- --------------------
|
||||
|
||||
rules =
|
||||
[ DefaultPatternPosition.rule { position = Lint.Rules.DefaultPatternPosition.First }
|
||||
]
|
||||
|
||||
case value of
|
||||
_ -> result
|
||||
Foo -> bar
|
||||
|
||||
-}
|
||||
|
||||
import Elm.Syntax.Expression exposing (Expression(..))
|
||||
import Elm.Syntax.Node as Node exposing (Node)
|
||||
import Elm.Syntax.Pattern exposing (Pattern(..))
|
||||
import Lint exposing (Rule, lint)
|
||||
import Lint.Error exposing (Error)
|
||||
import Lint.Rule exposing (Direction(..), Implementation, createRule)
|
||||
import List.Extra exposing (findIndex)
|
||||
import Regex
|
||||
|
||||
|
||||
type alias Context =
|
||||
{}
|
||||
|
||||
|
||||
{-| Configures whether the default pattern should appear first or last.
|
||||
-}
|
||||
type PatternPosition
|
||||
= First
|
||||
| Last
|
||||
|
||||
|
||||
{-| Configuration for the rule.
|
||||
-}
|
||||
type alias Configuration =
|
||||
{ position : PatternPosition
|
||||
}
|
||||
|
||||
|
||||
{-| Enforce the default pattern to always appear first or last.
|
||||
-}
|
||||
rule : Configuration -> Rule
|
||||
rule config input =
|
||||
lint input (implementation config)
|
||||
|
||||
|
||||
implementation : Configuration -> Implementation Context
|
||||
implementation configuration =
|
||||
createRule
|
||||
{}
|
||||
(\v -> { v | visitExpression = visitExpression configuration })
|
||||
|
||||
|
||||
error : Node a -> String -> Error
|
||||
error node message =
|
||||
Error
|
||||
"DefaultPatternPosition"
|
||||
message
|
||||
(Node.range node)
|
||||
|
||||
|
||||
|
||||
{- TODO Share isVariable this in a util file, already defined in NoUselessPatternMatching -}
|
||||
|
||||
|
||||
isVariable : String -> Bool
|
||||
isVariable =
|
||||
Regex.fromString "^[_a-z][\\w\\d]*$"
|
||||
|> Maybe.withDefault Regex.never
|
||||
|> Regex.contains
|
||||
|
||||
|
||||
isDefaultPattern : Pattern -> Bool
|
||||
isDefaultPattern pattern =
|
||||
case pattern of
|
||||
AllPattern ->
|
||||
True
|
||||
|
||||
_ ->
|
||||
False
|
||||
|
||||
|
||||
findDefaultPattern : List ( Node Pattern, Node Expression ) -> Maybe Int
|
||||
findDefaultPattern patterns =
|
||||
patterns
|
||||
|> List.map (Tuple.first >> Node.value)
|
||||
|> findIndex isDefaultPattern
|
||||
|
||||
|
||||
visitExpression : Configuration -> Context -> Direction -> Node Expression -> ( List Error, Context )
|
||||
visitExpression config ctx direction node =
|
||||
case ( direction, Node.value node ) of
|
||||
( Enter, CaseExpression { cases } ) ->
|
||||
case findDefaultPattern cases of
|
||||
Nothing ->
|
||||
( [], ctx )
|
||||
|
||||
Just index ->
|
||||
case config.position of
|
||||
First ->
|
||||
if index /= 0 then
|
||||
( [ error node "Expected default pattern to appear first in the list of patterns" ], ctx )
|
||||
|
||||
else
|
||||
( [], ctx )
|
||||
|
||||
Last ->
|
||||
if index /= List.length cases - 1 then
|
||||
( [ error node "Expected default pattern to appear last in the list of patterns" ], ctx )
|
||||
|
||||
else
|
||||
( [], ctx )
|
||||
|
||||
_ ->
|
||||
( [], ctx )
|
110
tests/DefaultPatternPositionTest.elm
Normal file
110
tests/DefaultPatternPositionTest.elm
Normal file
@ -0,0 +1,110 @@
|
||||
module DefaultPatternPositionTest exposing (all)
|
||||
|
||||
import Elm.Syntax.Range exposing (Location, Range)
|
||||
import Lint exposing (Rule)
|
||||
import Lint.Error exposing (Error)
|
||||
import Lint.Rule exposing (LintResult)
|
||||
import Lint.Rule.DefaultPatternPosition exposing (Configuration, PatternPosition(..), rule)
|
||||
import Test exposing (Test, describe, test)
|
||||
import TestUtil exposing (expectErrorsWithoutRange, location, ruleTester)
|
||||
|
||||
|
||||
testRule : Configuration -> String -> LintResult
|
||||
testRule options =
|
||||
ruleTester (rule options)
|
||||
|
||||
|
||||
error : String -> Error
|
||||
error position =
|
||||
Error
|
||||
"DefaultPatternPosition"
|
||||
("Expected default pattern to appear " ++ position ++ " in the list of patterns")
|
||||
(location ( 0, 0 ) ( 0, 0 ))
|
||||
|
||||
|
||||
tests : List Test
|
||||
tests =
|
||||
[ test "should not report when default pattern is at the expected position (first)" <|
|
||||
\() ->
|
||||
"""module A exposing(..)
|
||||
a = case b of
|
||||
_ -> 1
|
||||
Bar -> 1
|
||||
Foo -> 1
|
||||
"""
|
||||
|> testRule { position = First }
|
||||
|> expectErrorsWithoutRange []
|
||||
, test "should not report when default pattern is at the expected position (last)" <|
|
||||
\() ->
|
||||
"""module A exposing(..)
|
||||
a = case b of
|
||||
Foo -> 1
|
||||
Bar -> 1
|
||||
_ -> 1
|
||||
"""
|
||||
|> testRule { position = Last }
|
||||
|> expectErrorsWithoutRange []
|
||||
, test "should not report when there is no default pattern (first)" <|
|
||||
\() ->
|
||||
"""module A exposing(..)
|
||||
a = case b of
|
||||
Foo -> 1
|
||||
Bar -> 1
|
||||
"""
|
||||
|> testRule { position = First }
|
||||
|> expectErrorsWithoutRange []
|
||||
, test "should not report when there is no default pattern (last)" <|
|
||||
\() ->
|
||||
"""module A exposing(..)
|
||||
a = case b of
|
||||
Foo -> 1
|
||||
Bar -> 1
|
||||
"""
|
||||
|> testRule { position = Last }
|
||||
|> expectErrorsWithoutRange []
|
||||
, test "should report an error when the default pattern is not at the expected position (first) (opposite expected position)" <|
|
||||
\() ->
|
||||
"""module A exposing(..)
|
||||
a = case b of
|
||||
Foo -> 1
|
||||
Bar -> 1
|
||||
_ -> 1
|
||||
"""
|
||||
|> testRule { position = First }
|
||||
|> expectErrorsWithoutRange [ error "first" ]
|
||||
, test "should report an error when the default pattern is not at the expected position (first) (somewhere in the middle)" <|
|
||||
\() ->
|
||||
"""module A exposing(..)
|
||||
a = case b of
|
||||
Foo -> 1
|
||||
_ -> 1
|
||||
Bar -> 1
|
||||
"""
|
||||
|> testRule { position = First }
|
||||
|> expectErrorsWithoutRange [ error "first" ]
|
||||
, test "should report an error when the default pattern is not at the expected position (last) (opposite expected position)" <|
|
||||
\() ->
|
||||
"""module A exposing(..)
|
||||
a = case b of
|
||||
_ -> 1
|
||||
Foo -> 1
|
||||
Bar -> 1
|
||||
"""
|
||||
|> testRule { position = Last }
|
||||
|> expectErrorsWithoutRange [ error "last" ]
|
||||
, test "should report an error when the default pattern is not at the expected position (last) (somewhere in the middle)" <|
|
||||
\() ->
|
||||
"""module A exposing(..)
|
||||
a = case b of
|
||||
Foo -> 1
|
||||
_ -> 1
|
||||
Bar -> 1
|
||||
"""
|
||||
|> testRule { position = Last }
|
||||
|> expectErrorsWithoutRange [ error "last" ]
|
||||
]
|
||||
|
||||
|
||||
all : Test
|
||||
all =
|
||||
describe "DefaultPatternPosition" tests
|
Loading…
Reference in New Issue
Block a user