elm-review/tests/NoDebug/Log.elm
2020-04-05 09:47:59 +02:00

129 lines
3.3 KiB
Elm

module NoDebug.Log exposing (rule)
{-|
@docs rule
-}
import Elm.Syntax.Exposing as Exposing
import Elm.Syntax.Expression as Expression exposing (Expression)
import Elm.Syntax.Import exposing (Import)
import Elm.Syntax.Node as Node exposing (Node)
import Review.Rule as Rule exposing (Error, Rule)
{-| Forbid the use of [`Debug.log`](https://package.elm-lang.org/packages/elm/core/latest/Debug) before it goes into production or fails in the CI.
`Debug.log` is useful to debug your code, but should not be pushed to production.
config =
[ NoDebug.Log.rule
]
## Fail
if Debug.log "condition" condition then
a
else
b
## Success
if condition then
a
else
b
# When (not) to use this rule
You should use this rule if you're developing a package meant to be published,
or an application that is put into production, and wish to know about the use of
[`Debug.log`](https://package.elm-lang.org/packages/elm/core/latest/Debug#log)
module before committing your changes.
You should not use this rule if you are developing an application that is not
put into production, and you do not care about having stray debug logs, and you
do not ship to production.
-}
rule : Rule
rule =
Rule.newModuleRuleSchema "NoDebugLog" { hasLogBeenImported = False }
|> Rule.withImportVisitor importVisitor
|> Rule.withExpressionVisitor expressionVisitor
|> Rule.fromModuleRuleSchema
type alias Context =
{ hasLogBeenImported : Bool
}
error : Node a -> Error {}
error node =
Rule.error
{ message = "Remove the use of `Debug.log` before shipping to production"
, details =
[ "`Debug.log` is useful when developing, but is not meant to be shipped to production or published in a package. I suggest removing its use before committing and attempting to push to production."
]
}
(Node.range node)
importVisitor : Node Import -> Context -> ( List nothing, Context )
importVisitor node context =
let
moduleName : List String
moduleName =
node
|> Node.value
|> .moduleName
|> Node.value
in
if moduleName == [ "Debug" ] then
case node |> Node.value |> .exposingList |> Maybe.map Node.value of
Just (Exposing.All _) ->
( [], { hasLogBeenImported = True } )
Just (Exposing.Explicit importedNames) ->
( [], { hasLogBeenImported = List.any isLog importedNames } )
Nothing ->
( [], context )
else
( [], context )
isLog : Node Exposing.TopLevelExpose -> Bool
isLog node =
case Node.value node of
Exposing.FunctionExpose "log" ->
True
_ ->
False
expressionVisitor : Node Expression -> Rule.Direction -> Context -> ( List (Error {}), Context )
expressionVisitor node direction context =
case ( direction, Node.value node ) of
( Rule.OnEnter, Expression.FunctionOrValue [ "Debug" ] "log" ) ->
( [ error node ], context )
( Rule.OnEnter, Expression.FunctionOrValue [] "log" ) ->
if context.hasLogBeenImported then
( [ error node ], context )
else
( [], context )
_ ->
( [], context )