Display the import cycle when one occurs

This commit is contained in:
Jeroen Engels 2021-02-23 22:05:34 +01:00
parent e2a3c23585
commit 6b409c8547

View File

@ -252,6 +252,7 @@ reason or seemingly inappropriately.
-} -}
import Ansi
import Dict exposing (Dict) import Dict exposing (Dict)
import Elm.Docs import Elm.Docs
import Elm.Project import Elm.Project
@ -531,21 +532,32 @@ checkForDuplicateModules project =
getModulesSortedByImport : Project -> Result (List Review.Error.ReviewError) (List (Graph.NodeContext ModuleName ())) getModulesSortedByImport : Project -> Result (List Review.Error.ReviewError) (List (Graph.NodeContext ModuleName ()))
getModulesSortedByImport project = getModulesSortedByImport project =
let let
sortedModules : Result (Graph.Edge ()) (List (Graph.NodeContext ModuleName ())) moduleGraph : Graph (List String) ()
sortedModules = moduleGraph =
project project
|> Review.Project.Internal.moduleGraph |> Review.Project.Internal.moduleGraph
sortedModules : Result (Graph.Edge ()) (List (Graph.NodeContext ModuleName ()))
sortedModules =
moduleGraph
|> Graph.checkAcyclic |> Graph.checkAcyclic
|> Result.map Graph.topologicalSort |> Result.map Graph.topologicalSort
in in
Result.mapError Result.mapError
(\_ -> (\edge ->
let
cycle : List ModuleName
cycle =
findCycle moduleGraph edge
|> List.reverse
in
[ Review.Error.ReviewError [ Review.Error.ReviewError
{ filePath = "GLOBAL ERROR" { filePath = "GLOBAL ERROR"
, ruleName = "Incorrect project" , ruleName = "Incorrect project"
, message = "Import cycle discovered" , message = "Import cycle discovered"
, details = , details =
[ "I detected an import cycle in your project. This prevents me from working correctly, and results in a error for the Elm compiler anyway. Please resolve it using the compiler's suggestions, then try running `elm-review` again." [ "I detected an import cycle in your project. This prevents me from working correctly, and results in a error for the Elm compiler anyway. Please resolve it using the compiler's suggestions, then try running `elm-review` again."
, printCycle cycle
] ]
, range = { start = { row = 0, column = 0 }, end = { row = 0, column = 0 } } , range = { start = { row = 0, column = 0 }, end = { row = 0, column = 0 } }
, fixes = Nothing , fixes = Nothing
@ -556,6 +568,52 @@ getModulesSortedByImport project =
sortedModules sortedModules
findCycle : Graph n e -> Graph.Edge e -> List n
findCycle graph edge =
let
startingNode : Graph.NodeId
startingNode =
edge.from
targetNode : Graph.NodeId
targetNode =
edge.to
reachedTarget : List { a | node : { b | id : Graph.NodeId } } -> Bool
reachedTarget path =
Maybe.map (.node >> .id) (List.head path) == Just targetNode
visitorDiscoverCycle : List { a | node : { id : Graph.NodeId, label : n } } -> b -> List n -> List n
visitorDiscoverCycle path _ acc =
if List.isEmpty acc then
-- we haven't found the cycle yet
if reachedTarget path then
List.map (.node >> .label) path
else
[]
else
-- we already found the cycle
acc
in
Graph.guidedBfs Graph.alongIncomingEdges visitorDiscoverCycle [ startingNode ] [] graph
|> Tuple.first
printCycle : List ModuleName -> String
printCycle moduleNames =
moduleNames
|> List.map (String.join "." >> Ansi.yellow)
|> String.join "\n \n "
|> wrapInCycle
wrapInCycle : String -> String
wrapInCycle string =
" \n " ++ string ++ "\n "
extractResultValue : Result a a -> a extractResultValue : Result a a -> a
extractResultValue result = extractResultValue result =
case result of case result of