elm-review/tests/NoDebug/Log.elm

245 lines
7.6 KiB
Elm
Raw Normal View History

module NoDebug.Log exposing (rule)
2020-03-07 01:03:37 +03:00
2020-04-05 10:47:59 +03:00
{-|
2020-03-07 01:03:37 +03:00
@docs rule
-}
import Elm.Syntax.Expression as Expression exposing (Expression)
2021-01-24 18:43:58 +03:00
import Elm.Syntax.Node as Node exposing (Node(..))
import Elm.Syntax.Range exposing (Range)
import Review.Fix
import Review.ModuleNameLookupTable as ModuleNameLookupTable exposing (ModuleNameLookupTable)
2020-03-07 01:03:37 +03:00
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.
2021-08-19 21:57:29 +03:00
🔧 Running with `--fix` will automatically remove all the reported errors.
`Debug.log` is useful to debug your code, but should not be pushed to production.
2020-03-07 01:03:37 +03:00
config =
[ NoDebug.Log.rule
2020-03-07 01:03:37 +03:00
]
## 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.
2020-08-09 19:55:15 +03:00
## Try it out
You can try this rule out by running the following command:
```bash
2020-09-22 20:40:30 +03:00
elm-review --template jfmengels/elm-review-debug/example --rules NoDebug.Log
2020-08-09 19:55:15 +03:00
```
2020-03-07 01:03:37 +03:00
-}
rule : Rule
rule =
2021-01-24 18:43:58 +03:00
Rule.newModuleRuleSchemaUsingContextCreator "NoDebug.Log" initContext
|> Rule.withExpressionEnterVisitor expressionVisitor
|> Rule.providesFixesForModuleRule
2020-06-28 08:49:27 +03:00
|> Rule.fromModuleRuleSchema
2020-03-07 01:03:37 +03:00
type alias Context =
2021-01-24 18:43:58 +03:00
{ lookupTable : ModuleNameLookupTable
, rangesToIgnore : List Range
2020-03-07 01:03:37 +03:00
}
2021-01-24 18:43:58 +03:00
initContext : Rule.ContextCreator () Context
initContext =
Rule.initContextCreator
(\lookupTable () ->
{ lookupTable = lookupTable
, rangesToIgnore = []
}
)
|> Rule.withModuleNameLookupTable
error : Node a -> Maybe Range -> Error {}
error node rangeToRemove =
Rule.errorWithFix
2020-03-07 01:03:37 +03:00
{ 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)
2021-01-24 18:43:58 +03:00
(case rangeToRemove of
Just range ->
[ Review.Fix.removeRange range ]
2020-03-07 01:03:37 +03:00
2021-01-24 18:43:58 +03:00
Nothing ->
[]
)
2020-03-07 01:03:37 +03:00
2022-10-15 12:38:32 +03:00
handleWhenSingleArg : (() -> Range) -> Context -> Node Expression -> ( List (Error {}), Context )
2021-01-24 18:43:58 +03:00
handleWhenSingleArg rangeToPotentiallyRemove context node =
case Node.value node of
Expression.Application (((Node logFunctionRange (Expression.FunctionOrValue _ "log")) as logFunctionNode) :: logArguments) ->
case ModuleNameLookupTable.moduleNameAt context.lookupTable logFunctionRange of
Just [ "Debug" ] ->
let
rangeToRemove : Maybe Range
rangeToRemove =
case logArguments of
[ _ ] ->
2022-10-15 12:38:32 +03:00
Just (rangeToPotentiallyRemove ())
2021-01-24 18:43:58 +03:00
_ ->
Nothing
in
( [ error logFunctionNode rangeToRemove ]
, { context | rangesToIgnore = Node.range node :: logFunctionRange :: context.rangesToIgnore }
)
_ ->
( [], context )
2020-03-07 01:03:37 +03:00
2021-01-24 18:43:58 +03:00
_ ->
( [], context )
2020-03-07 01:03:37 +03:00
2021-01-24 18:43:58 +03:00
expressionVisitor : Node Expression -> Context -> ( List (Error {}), Context )
expressionVisitor node context =
case Node.value node of
Expression.OperatorApplication "|>" _ left right ->
2021-04-06 18:33:00 +03:00
handleWhenSingleArg
2022-10-15 12:38:32 +03:00
(\() ->
{ start = (Node.range left).end
, end = (Node.range right).end
}
)
2021-04-06 18:33:00 +03:00
context
right
2021-01-24 18:43:58 +03:00
Expression.OperatorApplication "<|" _ left right ->
handleWhenSingleArg
2022-10-15 12:38:32 +03:00
(\() ->
{ start = (Node.range left).start
, end = (Node.range right).start
}
)
2021-01-24 18:43:58 +03:00
context
left
Expression.OperatorApplication "<<" _ left right ->
let
( errorsLeft, contextAfterLeft ) =
handleWhenSingleArg
2022-10-15 12:38:32 +03:00
(\() ->
{ start = (Node.range left).start
, end = (Node.range right).start
}
)
2021-01-24 18:43:58 +03:00
context
left
( errorsRight, contextAfterRight ) =
handleWhenSingleArg
2022-10-15 12:38:32 +03:00
(\() ->
{ start = (Node.range left).end
, end = (Node.range right).end
}
)
2021-01-24 18:43:58 +03:00
contextAfterLeft
right
in
( errorsLeft ++ errorsRight, contextAfterRight )
Expression.OperatorApplication ">>" _ left right ->
let
( errorsLeft, contextAfterLeft ) =
handleWhenSingleArg
2022-10-15 12:38:32 +03:00
(\() ->
{ start = (Node.range left).start
, end = (Node.range right).start
}
)
2021-01-24 18:43:58 +03:00
context
left
( errorsRight, contextAfterRight ) =
handleWhenSingleArg
2022-10-15 12:38:32 +03:00
(\() ->
{ start = (Node.range left).end
, end = (Node.range right).end
}
)
2021-01-24 18:43:58 +03:00
contextAfterLeft
right
in
( errorsLeft ++ errorsRight, contextAfterRight )
Expression.Application (((Node logFunctionRange (Expression.FunctionOrValue _ "log")) as logFunctionNode) :: logArguments) ->
let
2022-10-15 12:38:32 +03:00
rangeToRemove : () -> Maybe Range
rangeToRemove () =
2021-01-24 18:43:58 +03:00
case logArguments of
[ _, valueToLog ] ->
Just
{ start = logFunctionRange.start
, end = (Node.range valueToLog).start
}
_ ->
Nothing
in
reportIfDebugLog logFunctionNode context rangeToRemove
Expression.FunctionOrValue _ "log" ->
2022-10-15 12:38:32 +03:00
reportIfDebugLog node context (always Nothing)
2020-03-07 01:03:37 +03:00
_ ->
( [], context )
2021-01-24 18:43:58 +03:00
2022-10-15 12:38:32 +03:00
reportIfDebugLog : Node Expression -> Context -> (() -> Maybe Range) -> ( List (Error {}), Context )
2021-01-24 18:43:58 +03:00
reportIfDebugLog node context rangeToRemove =
if List.member (Node.range node) context.rangesToIgnore then
( [], context )
else
case ModuleNameLookupTable.moduleNameFor context.lookupTable node of
Just [ "Debug" ] ->
2022-10-15 12:38:32 +03:00
( [ error node (rangeToRemove ()) ]
2021-01-24 18:43:58 +03:00
, { context | rangesToIgnore = Node.range node :: context.rangesToIgnore }
)
_ ->
( [], context )