mirror of
https://github.com/jfmengels/elm-review.git
synced 2024-12-25 10:41:47 +03:00
Report a global error when an import cycle is found
This commit is contained in:
parent
c01be0f6fe
commit
23632062ca
@ -234,7 +234,7 @@ TODO Link to "creating a module rule" and project rule instead
|
|||||||
See [`newModuleRuleSchema`](#newModuleRuleSchema), and [`newProjectRuleSchema`](#newProjectRuleSchema) for how to create one.
|
See [`newModuleRuleSchema`](#newModuleRuleSchema), and [`newProjectRuleSchema`](#newProjectRuleSchema) for how to create one.
|
||||||
-}
|
-}
|
||||||
type Rule
|
type Rule
|
||||||
= Rule String (Project -> ( List Error, Rule ))
|
= Rule String (Project -> List (Graph.NodeContext ModuleName ()) -> ( List Error, Rule ))
|
||||||
|
|
||||||
|
|
||||||
{-| Represents a schema for a module [`Rule`](#Rule).
|
{-| Represents a schema for a module [`Rule`](#Rule).
|
||||||
@ -322,26 +322,51 @@ to compare them or compare the model that holds them.
|
|||||||
review : List Rule -> Project -> ( List Error, List Rule )
|
review : List Rule -> Project -> ( List Error, List Rule )
|
||||||
review rules project =
|
review rules project =
|
||||||
let
|
let
|
||||||
( ruleErrors, rulesWithCache ) =
|
sortedModules : Result (Graph.Edge ()) (List (Graph.NodeContext ModuleName ()))
|
||||||
runRules rules project
|
sortedModules =
|
||||||
|
project
|
||||||
|
|> Review.Project.moduleGraph
|
||||||
|
|> Graph.checkAcyclic
|
||||||
|
|> Result.map Graph.topologicalSort
|
||||||
in
|
in
|
||||||
( List.concat
|
case sortedModules of
|
||||||
[ ruleErrors
|
Ok nodeContexts ->
|
||||||
, project
|
let
|
||||||
|> Review.Project.filesThatFailedToParse
|
( ruleErrors, rulesWithCache ) =
|
||||||
|> List.map parsingError
|
runRules rules project nodeContexts
|
||||||
]
|
in
|
||||||
, rulesWithCache
|
( List.concat
|
||||||
)
|
[ ruleErrors
|
||||||
|
, project
|
||||||
|
|> Review.Project.filesThatFailedToParse
|
||||||
|
|> List.map parsingError
|
||||||
|
]
|
||||||
|
, rulesWithCache
|
||||||
|
)
|
||||||
|
|
||||||
|
Err _ ->
|
||||||
|
( [ Error
|
||||||
|
{ filePath = "GLOBAL ERROR"
|
||||||
|
, ruleName = "Incorrect project"
|
||||||
|
, message = "Import cycle discovered"
|
||||||
|
, 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."
|
||||||
|
]
|
||||||
|
, range = { start = { row = 0, column = 0 }, end = { row = 0, column = 0 } }
|
||||||
|
, fixes = Nothing
|
||||||
|
}
|
||||||
|
]
|
||||||
|
, rules
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
runRules : List Rule -> Project -> ( List Error, List Rule )
|
runRules : List Rule -> Project -> List (Graph.NodeContext ModuleName ()) -> ( List Error, List Rule )
|
||||||
runRules rules project =
|
runRules rules project nodeContexts =
|
||||||
List.foldl
|
List.foldl
|
||||||
(\(Rule _ fn) ( errors, previousRules ) ->
|
(\(Rule _ fn) ( errors, previousRules ) ->
|
||||||
let
|
let
|
||||||
( ruleErrors, ruleWithCache ) =
|
( ruleErrors, ruleWithCache ) =
|
||||||
fn project
|
fn project nodeContexts
|
||||||
in
|
in
|
||||||
( List.concat [ ruleErrors, errors ], ruleWithCache :: previousRules )
|
( List.concat [ ruleErrors, errors ], ruleWithCache :: previousRules )
|
||||||
)
|
)
|
||||||
@ -472,8 +497,8 @@ newModuleRuleCache =
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
runModuleRule : ModuleRuleSchema { anything | hasAtLeastOneVisitor : () } moduleContext -> ModuleRuleCache moduleContext -> Project -> ( List Error, Rule )
|
runModuleRule : ModuleRuleSchema { anything | hasAtLeastOneVisitor : () } moduleContext -> ModuleRuleCache moduleContext -> Project -> List (Graph.NodeContext ModuleName ()) -> ( List Error, Rule )
|
||||||
runModuleRule ((ModuleRuleSchema schema) as moduleRuleSchema) previousCache project =
|
runModuleRule ((ModuleRuleSchema schema) as moduleRuleSchema) previousCache project _ =
|
||||||
let
|
let
|
||||||
initialContext : moduleContext
|
initialContext : moduleContext
|
||||||
initialContext =
|
initialContext =
|
||||||
@ -721,125 +746,119 @@ type alias ProjectRuleCache projectContext =
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
runProjectRule : ProjectRuleSchema projectContext moduleContext -> ProjectRuleCache projectContext -> Project -> ( List Error, Rule )
|
runProjectRule : ProjectRuleSchema projectContext moduleContext -> ProjectRuleCache projectContext -> Project -> List (Graph.NodeContext ModuleName ()) -> ( List Error, Rule )
|
||||||
runProjectRule ((ProjectRuleSchema schema) as wrappedSchema) startCache project =
|
runProjectRule ((ProjectRuleSchema schema) as wrappedSchema) startCache project nodeContexts =
|
||||||
let
|
let
|
||||||
graph : Graph ModuleName ()
|
graph : Graph ModuleName ()
|
||||||
graph =
|
graph =
|
||||||
project
|
project
|
||||||
|> Review.Project.moduleGraph
|
|> Review.Project.moduleGraph
|
||||||
in
|
in
|
||||||
case Graph.checkAcyclic graph |> Result.map Graph.topologicalSort of
|
let
|
||||||
Ok nodeContexts ->
|
initialContext : projectContext
|
||||||
|
initialContext =
|
||||||
|
schema.context.initProjectContext
|
||||||
|
|> accumulateContext schema.elmJsonVisitors (Review.Project.elmJson project)
|
||||||
|
|> accumulateContext schema.dependenciesVisitors (Review.Project.dependencyModules project)
|
||||||
|
|
||||||
|
modules : Dict ModuleName ProjectModule
|
||||||
|
modules =
|
||||||
|
project
|
||||||
|
|> Review.Project.modules
|
||||||
|
|> List.foldl
|
||||||
|
(\module_ dict ->
|
||||||
|
Dict.insert
|
||||||
|
(getModuleName module_)
|
||||||
|
module_
|
||||||
|
dict
|
||||||
|
)
|
||||||
|
Dict.empty
|
||||||
|
|
||||||
|
projectModulePaths : Set String
|
||||||
|
projectModulePaths =
|
||||||
|
project
|
||||||
|
|> Review.Project.modules
|
||||||
|
|> List.map .path
|
||||||
|
|> Set.fromList
|
||||||
|
|
||||||
|
computeModule : ProjectRuleCache projectContext -> List ProjectModule -> ProjectModule -> { source : String, errors : List Error, context : projectContext }
|
||||||
|
computeModule cache importedModules module_ =
|
||||||
let
|
let
|
||||||
initialContext : projectContext
|
fileKey : FileKey
|
||||||
initialContext =
|
fileKey =
|
||||||
schema.context.initProjectContext
|
FileKey module_.path
|
||||||
|> accumulateContext schema.elmJsonVisitors (Review.Project.elmJson project)
|
|
||||||
|> accumulateContext schema.dependenciesVisitors (Review.Project.dependencyModules project)
|
|
||||||
|
|
||||||
modules : Dict ModuleName ProjectModule
|
moduleNameNode_ : Node ModuleName
|
||||||
modules =
|
moduleNameNode_ =
|
||||||
project
|
moduleNameNode module_.ast.moduleDefinition
|
||||||
|> Review.Project.modules
|
|
||||||
|> List.foldl
|
|
||||||
(\module_ dict ->
|
|
||||||
Dict.insert
|
|
||||||
(getModuleName module_)
|
|
||||||
module_
|
|
||||||
dict
|
|
||||||
)
|
|
||||||
Dict.empty
|
|
||||||
|
|
||||||
projectModulePaths : Set String
|
initialModuleContext : moduleContext
|
||||||
projectModulePaths =
|
initialModuleContext =
|
||||||
project
|
case schema.traversalType of
|
||||||
|> Review.Project.modules
|
AllModulesInParallel ->
|
||||||
|> List.map .path
|
schema.context.fromProjectToModule
|
||||||
|> Set.fromList
|
fileKey
|
||||||
|
moduleNameNode_
|
||||||
|
initialContext
|
||||||
|
|
||||||
computeModule : ProjectRuleCache projectContext -> List ProjectModule -> ProjectModule -> { source : String, errors : List Error, context : projectContext }
|
ImportedModulesFirst ->
|
||||||
computeModule cache importedModules module_ =
|
importedModules
|
||||||
let
|
|> List.filterMap
|
||||||
fileKey : FileKey
|
(\importedModule ->
|
||||||
fileKey =
|
Dict.get importedModule.path cache
|
||||||
FileKey module_.path
|
|> Maybe.map .context
|
||||||
|
)
|
||||||
|
|> List.foldl schema.context.foldProjectContexts initialContext
|
||||||
|
|> schema.context.fromProjectToModule fileKey moduleNameNode_
|
||||||
|
|
||||||
moduleNameNode_ : Node ModuleName
|
moduleVisitor : ModuleRuleSchema { hasAtLeastOneVisitor : () } moduleContext
|
||||||
moduleNameNode_ =
|
moduleVisitor =
|
||||||
moduleNameNode module_.ast.moduleDefinition
|
emptySchema "" initialModuleContext
|
||||||
|
|> schema.moduleVisitorSchema
|
||||||
|
|> reverseVisitors
|
||||||
|
|
||||||
initialModuleContext : moduleContext
|
( fileErrors, context ) =
|
||||||
initialModuleContext =
|
visitModuleForProjectRule
|
||||||
case schema.traversalType of
|
moduleVisitor
|
||||||
AllModulesInParallel ->
|
initialModuleContext
|
||||||
schema.context.fromProjectToModule
|
module_
|
||||||
fileKey
|
|
||||||
moduleNameNode_
|
|
||||||
initialContext
|
|
||||||
|
|
||||||
ImportedModulesFirst ->
|
|
||||||
importedModules
|
|
||||||
|> List.filterMap
|
|
||||||
(\importedModule ->
|
|
||||||
Dict.get importedModule.path cache
|
|
||||||
|> Maybe.map .context
|
|
||||||
)
|
|
||||||
|> List.foldl schema.context.foldProjectContexts initialContext
|
|
||||||
|> schema.context.fromProjectToModule fileKey moduleNameNode_
|
|
||||||
|
|
||||||
moduleVisitor : ModuleRuleSchema { hasAtLeastOneVisitor : () } moduleContext
|
|
||||||
moduleVisitor =
|
|
||||||
emptySchema "" initialModuleContext
|
|
||||||
|> schema.moduleVisitorSchema
|
|
||||||
|> reverseVisitors
|
|
||||||
|
|
||||||
( fileErrors, context ) =
|
|
||||||
visitModuleForProjectRule
|
|
||||||
moduleVisitor
|
|
||||||
initialModuleContext
|
|
||||||
module_
|
|
||||||
in
|
|
||||||
{ source = module_.source
|
|
||||||
, errors = List.map (setFilePathIfUnset module_) fileErrors
|
|
||||||
, context =
|
|
||||||
schema.context.fromModuleToProject
|
|
||||||
fileKey
|
|
||||||
moduleNameNode_
|
|
||||||
context
|
|
||||||
}
|
|
||||||
|
|
||||||
newStartCache : ProjectRuleCache projectContext
|
|
||||||
newStartCache =
|
|
||||||
startCache
|
|
||||||
|> Dict.filter (\path _ -> Set.member path projectModulePaths)
|
|
||||||
|
|
||||||
newCache : ProjectRuleCache projectContext
|
|
||||||
newCache =
|
|
||||||
List.foldl
|
|
||||||
(computeModuleAndCacheResult schema.traversalType modules graph computeModule)
|
|
||||||
( newStartCache, Set.empty )
|
|
||||||
nodeContexts
|
|
||||||
|> Tuple.first
|
|
||||||
|
|
||||||
contextsAndErrorsPerFile : List ( List Error, projectContext )
|
|
||||||
contextsAndErrorsPerFile =
|
|
||||||
newCache
|
|
||||||
|> Dict.values
|
|
||||||
|> List.map (\cacheEntry -> ( cacheEntry.errors, cacheEntry.context ))
|
|
||||||
|
|
||||||
errors : List Error
|
|
||||||
errors =
|
|
||||||
List.concat
|
|
||||||
[ List.concatMap Tuple.first contextsAndErrorsPerFile
|
|
||||||
, errorsFromFinalEvaluationForProject wrappedSchema initialContext contextsAndErrorsPerFile
|
|
||||||
]
|
|
||||||
in
|
in
|
||||||
( errors, Rule schema.name (runProjectRule wrappedSchema newCache) )
|
{ source = module_.source
|
||||||
|
, errors = List.map (setFilePathIfUnset module_) fileErrors
|
||||||
|
, context =
|
||||||
|
schema.context.fromModuleToProject
|
||||||
|
fileKey
|
||||||
|
moduleNameNode_
|
||||||
|
context
|
||||||
|
}
|
||||||
|
|
||||||
Err _ ->
|
newStartCache : ProjectRuleCache projectContext
|
||||||
-- TODO return some kind of global error?
|
newStartCache =
|
||||||
( [], Rule schema.name (runProjectRule wrappedSchema startCache) )
|
startCache
|
||||||
|
|> Dict.filter (\path _ -> Set.member path projectModulePaths)
|
||||||
|
|
||||||
|
newCache : ProjectRuleCache projectContext
|
||||||
|
newCache =
|
||||||
|
List.foldl
|
||||||
|
(computeModuleAndCacheResult schema.traversalType modules graph computeModule)
|
||||||
|
( newStartCache, Set.empty )
|
||||||
|
nodeContexts
|
||||||
|
|> Tuple.first
|
||||||
|
|
||||||
|
contextsAndErrorsPerFile : List ( List Error, projectContext )
|
||||||
|
contextsAndErrorsPerFile =
|
||||||
|
newCache
|
||||||
|
|> Dict.values
|
||||||
|
|> List.map (\cacheEntry -> ( cacheEntry.errors, cacheEntry.context ))
|
||||||
|
|
||||||
|
errors : List Error
|
||||||
|
errors =
|
||||||
|
List.concat
|
||||||
|
[ List.concatMap Tuple.first contextsAndErrorsPerFile
|
||||||
|
, errorsFromFinalEvaluationForProject wrappedSchema initialContext contextsAndErrorsPerFile
|
||||||
|
]
|
||||||
|
in
|
||||||
|
( errors, Rule schema.name (runProjectRule wrappedSchema newCache) )
|
||||||
|
|
||||||
|
|
||||||
setRuleName : String -> Error -> Error
|
setRuleName : String -> Error -> Error
|
||||||
|
Loading…
Reference in New Issue
Block a user