Backport elm-review-debug

This commit is contained in:
Jeroen Engels 2021-01-24 16:43:58 +01:00
parent fa8bc02068
commit 63819d3fb7
4 changed files with 365 additions and 238 deletions

View File

@ -6,10 +6,11 @@ module NoDebug.Log exposing (rule)
-} -}
import Elm.Syntax.Exposing as Exposing
import Elm.Syntax.Expression as Expression exposing (Expression) import Elm.Syntax.Expression as Expression exposing (Expression)
import Elm.Syntax.Import exposing (Import) import Elm.Syntax.Node as Node exposing (Node(..))
import Elm.Syntax.Node as Node exposing (Node) import Elm.Syntax.Range exposing (Range)
import Review.Fix
import Review.ModuleNameLookupTable as ModuleNameLookupTable exposing (ModuleNameLookupTable)
import Review.Rule as Rule exposing (Error, Rule) import Review.Rule as Rule exposing (Error, Rule)
@ -63,75 +64,223 @@ elm-review --template jfmengels/elm-review-debug/example --rules NoDebug.Log
-} -}
rule : Rule rule : Rule
rule = rule =
Rule.newModuleRuleSchema "NoDebug.Log" { hasLogBeenImported = False } Rule.newModuleRuleSchemaUsingContextCreator "NoDebug.Log" initContext
|> Rule.withImportVisitor importVisitor |> Rule.withExpressionEnterVisitor expressionVisitor
|> Rule.withExpressionVisitor expressionVisitor
|> Rule.fromModuleRuleSchema |> Rule.fromModuleRuleSchema
type alias Context = type alias Context =
{ hasLogBeenImported : Bool { lookupTable : ModuleNameLookupTable
, rangesToIgnore : List Range
} }
error : Node a -> Error {} initContext : Rule.ContextCreator () Context
error node = initContext =
Rule.error Rule.initContextCreator
(\lookupTable () ->
{ lookupTable = lookupTable
, rangesToIgnore = []
}
)
|> Rule.withModuleNameLookupTable
error : Node a -> Maybe Range -> Error {}
error node rangeToRemove =
Rule.errorWithFix
{ message = "Remove the use of `Debug.log` before shipping to production" { message = "Remove the use of `Debug.log` before shipping to production"
, details = , 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." [ "`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) (Node.range node)
(case rangeToRemove of
Just range ->
importVisitor : Node Import -> Context -> ( List nothing, Context ) [ Review.Fix.removeRange range ]
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 -> Nothing ->
( [], context ) []
)
else
( [], context )
isLog : Node Exposing.TopLevelExpose -> Bool handleWhenSingleArg : Range -> Context -> Node Expression -> ( List (Error {}), Context )
isLog node = handleWhenSingleArg rangeToPotentiallyRemove context node =
case Node.value node of case Node.value node of
Exposing.FunctionExpose "log" -> Expression.Application (((Node logFunctionRange (Expression.FunctionOrValue _ "log")) as logFunctionNode) :: logArguments) ->
True case ModuleNameLookupTable.moduleNameAt context.lookupTable logFunctionRange of
Just [ "Debug" ] ->
let
rangeToRemove : Maybe Range
rangeToRemove =
case logArguments of
[ _ ] ->
Just rangeToPotentiallyRemove
_ -> _ ->
False Nothing
in
( [ error logFunctionNode rangeToRemove ]
, { context | rangesToIgnore = Node.range node :: logFunctionRange :: context.rangesToIgnore }
)
_ ->
( [], context )
_ ->
( [], context )
expressionVisitor : Node Expression -> Rule.Direction -> Context -> ( List (Error {}), Context ) collectPipeline : Node Expression -> ( List Range, List (Node Expression) )
expressionVisitor node direction context = collectPipeline node =
case ( direction, Node.value node ) of collectPipelineHelp node
( Rule.OnEnter, Expression.FunctionOrValue [ "Debug" ] "log" ) ->
( [ error node ], context )
( Rule.OnEnter, Expression.FunctionOrValue [] "log" ) ->
if context.hasLogBeenImported then collectPipelineHelp : Node Expression -> ( List Range, List (Node Expression) )
( [ error node ], context ) collectPipelineHelp node =
case Node.value node of
Expression.OperatorApplication "|>" _ left right ->
let
( x1, y1 ) =
collectPipelineHelp left
( x2, y2 ) =
collectPipelineHelp right
in
( Node.range node :: (x1 ++ x2), y1 ++ y2 )
_ ->
( [], [ node ] )
expressionVisitor : Node Expression -> Context -> ( List (Error {}), Context )
expressionVisitor node context =
if List.member (Node.range node) context.rangesToIgnore then
( [], context )
else else
( [], context ) expressionVisitorHelp node context
expressionVisitorHelp : Node Expression -> Context -> ( List (Error {}), Context )
expressionVisitorHelp node context =
case Node.value node of
Expression.OperatorApplication "|>" _ left right ->
let
( pipelineOperators, pipelineOperations ) =
collectPipeline node
contextWithIgnoredElements : Context
contextWithIgnoredElements =
{ context | rangesToIgnore = List.concat [ pipelineOperators, List.map Node.range pipelineOperations, context.rangesToIgnore ] }
( errorsAfterLeft, contextAfterLeft ) =
handleWhenSingleArg
{ start = (Node.range left).start
, end = (Node.range right).start
}
contextWithIgnoredElements
left
in
List.foldl
(\pipelineItem ( prev, ( errors, ctx ) ) ->
let
( newErrors, newContext ) =
handleWhenSingleArg
{ start = (Node.range prev).end
, end = (Node.range pipelineItem).end
}
ctx
pipelineItem
in
( pipelineItem, ( newErrors ++ errors, newContext ) )
)
( left, ( errorsAfterLeft, contextAfterLeft ) )
pipelineOperations
|> Tuple.second
Expression.OperatorApplication "<|" _ left right ->
handleWhenSingleArg
{ start = (Node.range left).start
, end = (Node.range right).start
}
context
left
Expression.OperatorApplication "<<" _ left right ->
let
( errorsLeft, contextAfterLeft ) =
handleWhenSingleArg
{ start = (Node.range left).start
, end = (Node.range right).start
}
context
left
( errorsRight, contextAfterRight ) =
handleWhenSingleArg
{ start = (Node.range left).end
, end = (Node.range right).end
}
contextAfterLeft
right
in
( errorsLeft ++ errorsRight, contextAfterRight )
Expression.OperatorApplication ">>" _ left right ->
let
( errorsLeft, contextAfterLeft ) =
handleWhenSingleArg
{ start = (Node.range left).start
, end = (Node.range right).start
}
context
left
( errorsRight, contextAfterRight ) =
handleWhenSingleArg
{ start = (Node.range left).end
, end = (Node.range right).end
}
contextAfterLeft
right
in
( errorsLeft ++ errorsRight, contextAfterRight )
Expression.Application (((Node logFunctionRange (Expression.FunctionOrValue _ "log")) as logFunctionNode) :: logArguments) ->
let
rangeToRemove : Maybe Range
rangeToRemove =
case logArguments of
[ _, valueToLog ] ->
Just
{ start = logFunctionRange.start
, end = (Node.range valueToLog).start
}
_ ->
Nothing
in
reportIfDebugLog logFunctionNode context rangeToRemove
Expression.FunctionOrValue _ "log" ->
reportIfDebugLog node context Nothing
_ ->
( [], context )
reportIfDebugLog : Node Expression -> Context -> Maybe Range -> ( List (Error {}), Context )
reportIfDebugLog node context rangeToRemove =
if List.member (Node.range node) context.rangesToIgnore then
( [], context )
else
case ModuleNameLookupTable.moduleNameFor context.lookupTable node of
Just [ "Debug" ] ->
( [ error node rangeToRemove ]
, { context | rangesToIgnore = Node.range node :: context.rangesToIgnore }
)
_ -> _ ->
( [], context ) ( [], context )

View File

@ -1,6 +1,8 @@
module NoDebug.LogTest exposing (all) module NoDebug.LogTest exposing (all)
import Dependencies.ElmCore
import NoDebug.Log exposing (rule) import NoDebug.Log exposing (rule)
import Review.Project as Project exposing (Project)
import Review.Test exposing (ReviewResult) import Review.Test exposing (ReviewResult)
import Test exposing (Test, describe, test) import Test exposing (Test, describe, test)
@ -9,7 +11,25 @@ testRule : String -> ReviewResult
testRule string = testRule string =
"module A exposing (..)\n\n" "module A exposing (..)\n\n"
++ string ++ string
|> Review.Test.run rule |> Review.Test.runWithProjectData project rule
errorDetails : { message : String, details : List String, under : String }
errorDetails =
{ message = message
, details = details
, under = "Debug.log"
}
project : Project
project =
Project.addDependency Dependencies.ElmCore.dependency Project.new
whenFixed : String -> Review.Test.ExpectedError -> Review.Test.ExpectedError
whenFixed string =
Review.Test.whenFixed ("module A exposing (..)\n\n" ++ string)
message : String message : String
@ -47,21 +67,13 @@ b = Debug.todo ""
\() -> \() ->
testRule "a = Debug.log" testRule "a = Debug.log"
|> Review.Test.expectErrors |> Review.Test.expectErrors
[ Review.Test.error [ Review.Test.error errorDetails
{ message = message
, details = details
, under = "Debug.log"
}
] ]
, test "should report Debug.log calls" <| , test "should report Debug.log calls" <|
\() -> \() ->
testRule "a = Debug.log z" testRule "a = Debug.log z"
|> Review.Test.expectErrors |> Review.Test.expectErrors
[ Review.Test.error [ Review.Test.error errorDetails
{ message = message
, details = details
, under = "Debug.log"
}
] ]
, test "should report multiple Debug.log calls" <| , test "should report multiple Debug.log calls" <|
\() -> \() ->
@ -70,170 +82,176 @@ a = Debug.log z
b = Debug.log z b = Debug.log z
""" """
|> Review.Test.expectErrors |> Review.Test.expectErrors
[ Review.Test.error [ Review.Test.error errorDetails
{ message = message
, details = details
, under = "Debug.log"
}
|> Review.Test.atExactly { start = { row = 4, column = 5 }, end = { row = 4, column = 14 } } |> Review.Test.atExactly { start = { row = 4, column = 5 }, end = { row = 4, column = 14 } }
, Review.Test.error , Review.Test.error errorDetails
{ message = message
, details = details
, under = "Debug.log"
}
|> Review.Test.atExactly { start = { row = 5, column = 5 }, end = { row = 5, column = 14 } } |> Review.Test.atExactly { start = { row = 5, column = 5 }, end = { row = 5, column = 14 } }
] ]
, test "should report Debug.log in a binary expression" <| , test "should report Debug.log in a binary expression" <|
\() -> \() ->
testRule "a = ( Debug.log z ) + 2" testRule "a = ( Debug.log z ) + 2"
|> Review.Test.expectErrors |> Review.Test.expectErrors
[ Review.Test.error [ Review.Test.error errorDetails
{ message = message
, details = details
, under = "Debug.log"
}
] ]
, test "should report Debug.log in a << binary expression" <| , test "should report Debug.log in a << binary expression (on the right)" <|
\() -> \() ->
testRule "a = fn << Debug.log" testRule "a = fn << Debug.log b"
|> Review.Test.expectErrors |> Review.Test.expectErrors
[ Review.Test.error [ Review.Test.error errorDetails
{ message = message |> whenFixed "a = fn"
, details = details
, under = "Debug.log"
}
] ]
, test "should report Debug.log in a pipe expression" <| , test "should report Debug.log in a << binary expression (on the left)" <|
\() ->
testRule "a = Debug.log b << fn"
|> Review.Test.expectErrors
[ Review.Test.error errorDetails
|> whenFixed "a = fn"
]
, test "should report Debug.log in a >> binary expression (on the right)" <|
\() ->
testRule "a = fn >> Debug.log b"
|> Review.Test.expectErrors
[ Review.Test.error errorDetails
|> whenFixed "a = fn"
]
, test "should report Debug.log in a >> binary expression (on the left)" <|
\() ->
testRule "a = Debug.log b >> fn"
|> Review.Test.expectErrors
[ Review.Test.error errorDetails
|> whenFixed "a = fn"
]
, test "should report Debug.log in a |> pipe expression" <|
\() -> \() ->
testRule "a = fn |> Debug.log z" testRule "a = fn |> Debug.log z"
|> Review.Test.expectErrors |> Review.Test.expectErrors
[ Review.Test.error [ Review.Test.error errorDetails
{ message = message |> whenFixed "a = fn"
, details = details ]
, under = "Debug.log" , test "should report Debug.log in a large |> pipe expression (pipes on each side)" <|
} \() ->
testRule "a = fn |> Debug.log z |> fn2"
|> Review.Test.expectErrors
[ Review.Test.error errorDetails
|> whenFixed "a = fn |> fn2"
]
, test "should report Debug.log multiple times in a pipeline expression with multiple Debug.log calls" <|
\() ->
testRule "a = fn |> Debug.log z |> fn2 |> Debug.log y"
|> Review.Test.expectErrors
[ Review.Test.error errorDetails
|> Review.Test.atExactly { start = { row = 3, column = 11 }, end = { row = 3, column = 20 } }
|> whenFixed "a = fn |> fn2 |> Debug.log y"
, Review.Test.error errorDetails
|> Review.Test.atExactly { start = { row = 3, column = 33 }, end = { row = 3, column = 42 } }
|> whenFixed "a = fn |> Debug.log z |> fn2"
]
, test "should report Debug.log in a <| pipe expression" <|
\() ->
testRule "a = Debug.log z <| fn"
|> Review.Test.expectErrors
[ Review.Test.error errorDetails
|> whenFixed "a = fn"
]
, test "should report Debug.log in a large <| pipe expression" <|
\() ->
testRule "a = foo <| Debug.log z <| fn"
|> Review.Test.expectErrors
[ Review.Test.error errorDetails
|> whenFixed "a = foo <| fn"
] ]
, test "should report Debug.log in an list expression" <| , test "should report Debug.log in an list expression" <|
\() -> \() ->
testRule "a = [ Debug.log z y ]" testRule "a = [ Debug.log z y ]"
|> Review.Test.expectErrors |> Review.Test.expectErrors
[ Review.Test.error [ Review.Test.error errorDetails
{ message = message |> whenFixed "a = [ y ]"
, details = details
, under = "Debug.log"
}
] ]
, test "should report Debug.log in an record expression" <| , test "should report Debug.log in a record expression" <|
\() -> \() ->
testRule "a = { foo = Debug.log z y }" testRule "a = { foo = Debug.log z y }"
|> Review.Test.expectErrors |> Review.Test.expectErrors
[ Review.Test.error [ Review.Test.error errorDetails
{ message = message |> whenFixed "a = { foo = y }"
, details = details
, under = "Debug.log"
}
] ]
, test "should report Debug.log in an record update expression" <| , test "should report Debug.log in a record update expression" <|
\() -> \() ->
testRule "a = { model | foo = Debug.log z y }" testRule "a = { model | foo = Debug.log z y }"
|> Review.Test.expectErrors |> Review.Test.expectErrors
[ Review.Test.error [ Review.Test.error errorDetails
{ message = message |> whenFixed "a = { model | foo = y }"
, details = details
, under = "Debug.log"
}
] ]
, test "should report Debug.log in an lambda expression" <| , test "should report Debug.log in an lambda expression" <|
\() -> \() ->
testRule "a = (\\foo -> Debug.log z foo)" testRule "a = (\\foo -> Debug.log z foo)"
|> Review.Test.expectErrors |> Review.Test.expectErrors
[ Review.Test.error [ Review.Test.error errorDetails
{ message = message |> whenFixed "a = (\\foo -> foo)"
, details = details
, under = "Debug.log"
}
] ]
, test "should report Debug.log in an if expression condition" <| , test "should report Debug.log in an if expression condition" <|
\() -> \() ->
testRule "a = if Debug.log a b then True else False" testRule "a = if Debug.log a b then True else False"
|> Review.Test.expectErrors |> Review.Test.expectErrors
[ Review.Test.error [ Review.Test.error errorDetails
{ message = message |> whenFixed "a = if b then True else False"
, details = details
, under = "Debug.log"
}
] ]
, test "should report Debug.log in an if expression then branch" <| , test "should report Debug.log in an if expression then branch" <|
\() -> \() ->
testRule "a = if True then Debug.log a b else False" testRule "a = if True then Debug.log a b else False"
|> Review.Test.expectErrors |> Review.Test.expectErrors
[ Review.Test.error [ Review.Test.error errorDetails
{ message = message |> whenFixed "a = if True then b else False"
, details = details
, under = "Debug.log"
}
] ]
, test "should report Debug.log in an if expression else branch" <| , test "should report Debug.log in an if expression else branch" <|
\() -> \() ->
testRule "a = if True then True else Debug.log a b" testRule "a = if True then True else Debug.log a b"
|> Review.Test.expectErrors |> Review.Test.expectErrors
[ Review.Test.error [ Review.Test.error errorDetails
{ message = message |> whenFixed "a = if True then True else b"
, details = details
, under = "Debug.log"
}
] ]
, test "should report Debug.log in a case value" <| , test "should report Debug.log in a case value" <|
\() -> \() ->
testRule """ testRule """
a = case Debug.log a b of a = case Debug.log a b of
_ -> [] _ -> []"""
"""
|> Review.Test.expectErrors |> Review.Test.expectErrors
[ Review.Test.error [ Review.Test.error errorDetails
{ message = message |> whenFixed """
, details = details a = case b of
, under = "Debug.log" _ -> []"""
}
] ]
, test "should report Debug.log in a case body" <| , test "should report Debug.log in a case body" <|
\() -> \() ->
testRule """ testRule """
a = case a of a = case a of
_ -> Debug.log a b _ -> Debug.log a b"""
"""
|> Review.Test.expectErrors |> Review.Test.expectErrors
[ Review.Test.error [ Review.Test.error errorDetails
{ message = message |> whenFixed """
, details = details a = case a of
, under = "Debug.log" _ -> b"""
}
] ]
, test "should report Debug.log in let declaration section" <| , test "should report Debug.log in let declaration section" <|
\() -> \() ->
testRule """ testRule """
a = let b = Debug.log a b a = let b = Debug.log a c
in b in b"""
"""
|> Review.Test.expectErrors |> Review.Test.expectErrors
[ Review.Test.error [ Review.Test.error errorDetails
{ message = message |> whenFixed """
, details = details a = let b = c
, under = "Debug.log" in b"""
}
] ]
, test "should report Debug.log in let body" <| , test "should report Debug.log in let body" <|
\() -> \() ->
testRule """ testRule """
a = let b = c a = let b = c
in Debug.log a b in Debug.log a b"""
"""
|> Review.Test.expectErrors |> Review.Test.expectErrors
[ Review.Test.error [ Review.Test.error errorDetails
{ message = message |> whenFixed """
, details = details a = let b = c
, under = "Debug.log" in b"""
}
] ]
, test "should not report calls from a module containing Debug but that is not Debug" <| , test "should not report calls from a module containing Debug but that is not Debug" <|
\() -> \() ->
@ -259,6 +277,10 @@ a = log "" 1
, under = "log" , under = "log"
} }
|> Review.Test.atExactly { start = { row = 5, column = 5 }, end = { row = 5, column = 8 } } |> Review.Test.atExactly { start = { row = 5, column = 5 }, end = { row = 5, column = 8 } }
|> whenFixed """
import Debug exposing (log)
a = 1
"""
] ]
, test "should report the use of `log` when it has been implicitly imported" <| , test "should report the use of `log` when it has been implicitly imported" <|
\() -> \() ->
@ -272,6 +294,10 @@ a = log "" 1
, details = details , details = details
, under = "log" , under = "log"
} }
|> whenFixed """
import Debug exposing (..)
a = 1
"""
] ]
, test "should not report the use of `log` when it has not been imported" <| , test "should not report the use of `log` when it has not been imported" <|
\() -> \() ->

View File

@ -6,10 +6,9 @@ module NoDebug.TodoOrToString exposing (rule)
-} -}
import Elm.Syntax.Exposing as Exposing
import Elm.Syntax.Expression as Expression exposing (Expression) import Elm.Syntax.Expression as Expression exposing (Expression)
import Elm.Syntax.Import exposing (Import)
import Elm.Syntax.Node as Node exposing (Node) import Elm.Syntax.Node as Node exposing (Node)
import Review.ModuleNameLookupTable as ModuleNameLookupTable exposing (ModuleNameLookupTable)
import Review.Rule as Rule exposing (Error, Rule) import Review.Rule as Rule exposing (Error, Rule)
@ -84,96 +83,42 @@ elm-review --template jfmengels/elm-review-debug/example --rules NoDebug.TodoOrT
-} -}
rule : Rule rule : Rule
rule = rule =
Rule.newModuleRuleSchema "NoDebug.TodoOrToString" init Rule.newModuleRuleSchemaUsingContextCreator "NoDebug.TodoOrToString" init
|> Rule.withImportVisitor importVisitor |> Rule.withExpressionEnterVisitor expressionVisitor
|> Rule.withExpressionVisitor expressionVisitor
|> Rule.fromModuleRuleSchema |> Rule.fromModuleRuleSchema
type alias Context = type alias Context =
{ hasTodoBeenImported : Bool ModuleNameLookupTable
, hasToStringBeenImported : Bool
}
init : Context init : Rule.ContextCreator () Context
init = init =
{ hasTodoBeenImported = False Rule.initContextCreator (\lookupTable () -> lookupTable)
, hasToStringBeenImported = False |> Rule.withModuleNameLookupTable
}
error : Node a -> String -> Error {} expressionVisitor : Node Expression -> Context -> ( List (Error {}), Context )
error node name = expressionVisitor node context =
Rule.error case Node.value node of
Expression.FunctionOrValue _ name ->
if name == "todo" || name == "toString" then
case ModuleNameLookupTable.moduleNameFor context node of
Just [ "Debug" ] ->
( [ Rule.error
{ message = "Remove the use of `Debug." ++ name ++ "` before shipping to production" { message = "Remove the use of `Debug." ++ name ++ "` before shipping to production"
, details = , details =
[ "`Debug." ++ name ++ "` can be 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." [ "`Debug." ++ name ++ "` can be 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) (Node.range node)
]
, context
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 _) ->
( [], { hasTodoBeenImported = True, hasToStringBeenImported = True } )
Just (Exposing.Explicit importedNames) ->
( []
, { context
| hasTodoBeenImported = List.any (is "todo") importedNames
, hasToStringBeenImported = List.any (is "toString") importedNames
}
) )
Nothing ->
( [], context )
else
( [], context )
is : String -> Node Exposing.TopLevelExpose -> Bool
is name node =
case Node.value node of
Exposing.FunctionExpose functionName ->
name == functionName
_ -> _ ->
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" ] name ) ->
if name == "todo" then
( [ error node name ], context )
else if name == "toString" then
( [ error node name ], context )
else
( [], context ) ( [], context )
( Rule.OnEnter, Expression.FunctionOrValue [] name ) ->
if name == "todo" && context.hasTodoBeenImported then
( [ error node name ], context )
else if name == "toString" && context.hasToStringBeenImported then
( [ error node name ], context )
else else
( [], context ) ( [], context )

View File

@ -1,6 +1,8 @@
module NoDebug.TodoOrToStringTest exposing (all) module NoDebug.TodoOrToStringTest exposing (all)
import Dependencies.ElmCore
import NoDebug.TodoOrToString exposing (rule) import NoDebug.TodoOrToString exposing (rule)
import Review.Project as Project exposing (Project)
import Review.Test exposing (ReviewResult) import Review.Test exposing (ReviewResult)
import Test exposing (Test, describe, test) import Test exposing (Test, describe, test)
@ -9,7 +11,12 @@ testRule : String -> ReviewResult
testRule string = testRule string =
"module A exposing (..)\n\n" "module A exposing (..)\n\n"
++ string ++ string
|> Review.Test.run rule |> Review.Test.runWithProjectData project rule
project : Project
project =
Project.addDependency Dependencies.ElmCore.dependency Project.new
todoMessage : String todoMessage : String