elm-review/tests/NoSimpleLetBody.elm
2021-02-10 17:15:09 +01:00

128 lines
3.9 KiB
Elm

module NoSimpleLetBody exposing (rule)
{-|
@docs rule
-}
import Elm.Syntax.Expression as Expression exposing (Expression)
import Elm.Syntax.Node as Node exposing (Node)
import Review.Rule as Rule exposing (Rule)
{-| Reports when a let expression's body is a simple reference to a value declared in the let expression.
config =
[ NoSimpleLetBody.rule
]
The reasoning behind this rule is that it is not necessary to assign a name (and type annotation) to the result of a let expression,
since they are redundant with the value or function containing the expression.
If it feels necessary to give a name anyway because it helps clarify the context, then it might be a sign that the computation of that value should be extracted to a function.
## Fail
a =
let
b =
1
c =
b + 1
in
c
## Success
Anything that is not simply a reference to a value declared in the let expression is okay.
a =
let
b =
1
in
b + 1
The rule will not report when the referenced value was destructured in the let expression.
first tuple =
let
( value, _ ) =
tuple
in
value
## When (not) to enable this rule
This rule resolves a minor style issue, and may not be worth enforcing depending on how strongly you feel about this issue.
I recommend having your full team's buy-in before enabling this rule to reduce the amount of frustration it will trigger when
it causes the tests or even the CI pipeline to fail. This rule does not (currently) provide an automatic fix which may increase
your team's frustration if they disagree with or don't care about this rule.
## Try it out
You can try this rule out by running the following command:
```bash
elm-review --template jfmengels/elm-review-code-style/example --rules NoSimpleLetBody
```
-}
rule : Rule
rule =
Rule.newModuleRuleSchema "NoSimpleLetBody" ()
|> Rule.withSimpleExpressionVisitor expressionVisitor
|> Rule.fromModuleRuleSchema
expressionVisitor : Node Expression -> List (Rule.Error {})
expressionVisitor node =
case Node.value node of
Expression.LetExpression { declarations, expression } ->
case Node.value expression of
Expression.FunctionOrValue [] name ->
let
declared : List String
declared =
List.filterMap
(\declaration ->
case Node.value declaration of
Expression.LetFunction function ->
function.declaration
|> Node.value
|> .name
|> Node.value
|> Just
Expression.LetDestructuring _ _ ->
Nothing
)
declarations
in
if List.member name declared then
[ Rule.error
{ message = "The referenced value should be inlined."
, details =
[ "The name of the value is redundant with the surrounding expression."
, "If you believe that the expression needs a name because it is too complex, consider splitting the expression up more or extracting it to a new function."
]
}
(Node.range expression)
]
else
[]
_ ->
[]
_ ->
[]