mirror of
https://github.com/jfmengels/elm-review.git
synced 2024-12-25 02:34:36 +03:00
Add project visitors to module visitors
This commit is contained in:
parent
1d5ca98a61
commit
7bd35b1941
@ -11,7 +11,9 @@ module Review.Rule3 exposing
|
||||
, withDeclarationExitVisitor
|
||||
, withDeclarationListVisitor
|
||||
, withDeclarationVisitor
|
||||
, withDependenciesModuleVisitor
|
||||
, withDependenciesProjectVisitor
|
||||
, withElmJsonModuleVisitor
|
||||
, withElmJsonProjectVisitor
|
||||
, withExpressionEnterVisitor
|
||||
, withExpressionExitVisitor
|
||||
@ -22,6 +24,7 @@ module Review.Rule3 exposing
|
||||
, withModuleContext
|
||||
, withModuleDefinitionVisitor
|
||||
, withModuleVisitor
|
||||
, withReadmeModuleVisitor
|
||||
, withReadmeProjectVisitor
|
||||
, withSimpleCommentsVisitor
|
||||
, withSimpleDeclarationVisitor
|
||||
@ -101,6 +104,11 @@ type ModuleRuleSchema schemaState moduleContext
|
||||
, expressionVisitorsOnEnter : List (Visitor Expression moduleContext)
|
||||
, expressionVisitorsOnExit : List (Visitor Expression moduleContext)
|
||||
, finalEvaluationFns : List (moduleContext -> List (Error {}))
|
||||
|
||||
-- Project visitors
|
||||
, elmJsonVisitors : List (Maybe Elm.Project.Project -> moduleContext -> moduleContext)
|
||||
, readmeVisitors : List (Maybe String -> moduleContext -> moduleContext)
|
||||
, dependenciesVisitors : List (Dict String Review.Project.Dependency.Dependency -> moduleContext -> moduleContext)
|
||||
}
|
||||
|
||||
|
||||
@ -113,7 +121,7 @@ withModuleVisitor visitor (ProjectRuleSchema schema) =
|
||||
ProjectRuleSchema { schema | moduleVisitors = visitor :: schema.moduleVisitors }
|
||||
|
||||
|
||||
newModuleRuleSchema : String -> moduleContext -> ModuleRuleSchema { moduleContext : Required } moduleContext
|
||||
newModuleRuleSchema : String -> moduleContext -> ModuleRuleSchema { canCollectProjectData : () } moduleContext
|
||||
newModuleRuleSchema name initialModuleContext =
|
||||
ModuleRuleSchema
|
||||
{ name = name
|
||||
@ -128,6 +136,9 @@ newModuleRuleSchema name initialModuleContext =
|
||||
, expressionVisitorsOnEnter = []
|
||||
, expressionVisitorsOnExit = []
|
||||
, finalEvaluationFns = []
|
||||
, elmJsonVisitors = []
|
||||
, readmeVisitors = []
|
||||
, dependenciesVisitors = []
|
||||
}
|
||||
|
||||
|
||||
@ -185,19 +196,16 @@ fromModuleRuleSchema ((ModuleRuleSchema schema) as moduleVisitor) =
|
||||
Nothing ->
|
||||
Debug.todo "Define initial module context"
|
||||
|
||||
--elmJsonVisitors : List (Maybe { elmJsonKey : ElmJsonKey, project : Elm.Project.Project } -> moduleContext -> ( List (Error {}), moduleContext ))
|
||||
--elmJsonVisitors =
|
||||
-- schema.elmJsonVisitors
|
||||
projectRule : ProjectRuleSchema { schemaState | hasAtLeastOneVisitor : () } moduleContext moduleContext
|
||||
projectRule =
|
||||
ProjectRuleSchema
|
||||
{ name = schema.name
|
||||
, initialProjectContext = initialContext
|
||||
, elmJsonVisitors = [] -- List (Maybe { elmJsonKey : ElmJsonKey, project : Elm.Project.Project } -> projectContext -> ( List (Error {}), projectContext ))
|
||||
, readmeVisitors = [] -- (Maybe { readmeKey : ReadmeKey, content : String } -> projectContext -> ( List (Error {}), projectContext ))
|
||||
, dependenciesVisitors = [] -- (Dict String Review.Project.Dependency.Dependency -> projectContext -> ( List (Error {}), projectContext ))
|
||||
, elmJsonVisitors = compactProjectDataVisitors (Maybe.map .project) schema.elmJsonVisitors
|
||||
, readmeVisitors = compactProjectDataVisitors (Maybe.map .content) schema.readmeVisitors
|
||||
, dependenciesVisitors = compactProjectDataVisitors identity schema.dependenciesVisitors
|
||||
, moduleVisitors = [ removeExtensibleRecordTypeVariable (always moduleVisitor) ]
|
||||
, moduleContextCreator = Just (Context.init (always initialContext))
|
||||
, moduleContextCreator = Just (Context.init identity)
|
||||
, folder = Nothing
|
||||
|
||||
-- TODO Jeroen Only allow to set it if there is a folder, but not several times
|
||||
@ -208,6 +216,27 @@ fromModuleRuleSchema ((ModuleRuleSchema schema) as moduleVisitor) =
|
||||
fromProjectRuleSchema projectRule
|
||||
|
||||
|
||||
compactProjectDataVisitors : (rawData -> data) -> List (data -> moduleContext -> moduleContext) -> List (rawData -> moduleContext -> ( List nothing, moduleContext ))
|
||||
compactProjectDataVisitors getData visitors =
|
||||
if List.isEmpty visitors then
|
||||
[]
|
||||
|
||||
else
|
||||
[ \rawData moduleContext ->
|
||||
let
|
||||
data : data
|
||||
data =
|
||||
getData rawData
|
||||
in
|
||||
( []
|
||||
, List.foldl
|
||||
(\visitor moduleContext_ -> visitor data moduleContext_)
|
||||
moduleContext
|
||||
(List.reverse visitors)
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
{-| This function that is supplied by the user will be stored in the `ProjectRuleSchema`,
|
||||
but it contains an extensible record. This means that `ProjectRuleSchema` will
|
||||
need an additional type variable for no useful value. Because we have full control
|
||||
@ -222,30 +251,99 @@ removeExtensibleRecordTypeVariable function =
|
||||
function >> (\(ModuleRuleSchema param) -> ModuleRuleSchema param)
|
||||
|
||||
|
||||
{-| Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will visit the project's
|
||||
[`elm.json`](https://package.elm-lang.org/packages/elm/project-metadata-utils/latest/Elm-Project) file.
|
||||
|
||||
--runModuleRule_New
|
||||
-- (reverseVisitors_New moduleVisitor)
|
||||
-- Nothing
|
||||
-- |> Rule schema.name Exceptions.init
|
||||
--fromProjectRuleSchema : ProjectRuleSchema { schemaState | hasAtLeastOneVisitor : () } projectContext moduleContext -> Rule
|
||||
--fromProjectRuleSchema ((ProjectRuleSchema schema) as projectRuleSchema) =
|
||||
-- Rule schema.name
|
||||
-- Exceptions.init
|
||||
-- (Review.Visitor.run (fromProjectRuleSchemaToRunnableProjectVisitor projectRuleSchema) Nothing)
|
||||
--fromProjectRuleSchemaToRunnableProjectVisitor : ProjectRuleSchema schemaState projectContext moduleContext -> Review.Visitor.RunnableProjectVisitor projectContext moduleContext
|
||||
--fromProjectRuleSchemaToRunnableProjectVisitor (ProjectRuleSchema schema) =
|
||||
-- { name = schema.name
|
||||
-- , initialProjectContext = schema.initialProjectContext
|
||||
-- , elmJsonVisitors = List.reverse schema.elmJsonVisitors
|
||||
-- , readmeVisitors = List.reverse schema.readmeVisitors
|
||||
-- , dependenciesVisitors = List.reverse schema.dependenciesVisitors
|
||||
-- , moduleVisitor = mergeModuleVisitors schema.name schema.moduleContextCreator schema.moduleVisitors
|
||||
-- , folder = schema.folder
|
||||
--
|
||||
-- -- TODO Jeroen Only allow to set it if there is a folder, but not several times
|
||||
-- , traversalType = schema.traversalType
|
||||
-- , finalEvaluationFns = List.reverse schema.finalEvaluationFns
|
||||
-- }
|
||||
The following example forbids exposing a module in an "Internal" directory in your `elm.json` file.
|
||||
|
||||
import Elm.Module
|
||||
import Elm.Project
|
||||
import Elm.Syntax.Module as Module exposing (Module)
|
||||
import Elm.Syntax.Node as Node exposing (Node)
|
||||
import Review.Rule as Rule exposing (Error, Rule)
|
||||
|
||||
type alias Context =
|
||||
Maybe Elm.Project.Project
|
||||
|
||||
rule : Rule
|
||||
rule =
|
||||
Rule.newModuleRuleSchema "DoNoExposeInternalModules" Nothing
|
||||
|> Rule.withElmJsonModuleVisitor elmJsonVisitor
|
||||
|> Rule.withModuleDefinitionVisitor moduleDefinitionVisitor
|
||||
|> Rule.fromModuleRuleSchema
|
||||
|
||||
elmJsonVisitor : Maybe Elm.Project.Project -> Context -> Context
|
||||
elmJsonVisitor elmJson context =
|
||||
elmJson
|
||||
|
||||
moduleDefinitionVisitor : Node Module -> Context -> ( List (Error {}), Context )
|
||||
moduleDefinitionVisitor node context =
|
||||
let
|
||||
moduleName : List String
|
||||
moduleName =
|
||||
Node.value node |> Module.moduleName
|
||||
in
|
||||
if List.member "Internal" moduleName then
|
||||
case context of
|
||||
Just (Elm.Project.Package { exposed }) ->
|
||||
let
|
||||
exposedModules : List String
|
||||
exposedModules =
|
||||
case exposed of
|
||||
Elm.Project.ExposedList names ->
|
||||
names
|
||||
|> List.map Elm.Module.toString
|
||||
|
||||
Elm.Project.ExposedDict fakeDict ->
|
||||
fakeDict
|
||||
|> List.concatMap Tuple.second
|
||||
|> List.map Elm.Module.toString
|
||||
in
|
||||
if List.member (String.join "." moduleName) exposedModules then
|
||||
( [ Rule.error "Do not expose modules in `Internal` as part of the public API" (Node.range node) ], context )
|
||||
|
||||
else
|
||||
( [], context )
|
||||
|
||||
_ ->
|
||||
( [], context )
|
||||
|
||||
else
|
||||
( [], context )
|
||||
|
||||
-}
|
||||
withElmJsonModuleVisitor :
|
||||
(Maybe Elm.Project.Project -> moduleContext -> moduleContext)
|
||||
-> ModuleRuleSchema { schemaState | canCollectProjectData : () } moduleContext
|
||||
-> ModuleRuleSchema { schemaState | canCollectProjectData : () } moduleContext
|
||||
withElmJsonModuleVisitor visitor (ModuleRuleSchema schema) =
|
||||
ModuleRuleSchema { schema | elmJsonVisitors = visitor :: schema.elmJsonVisitors }
|
||||
|
||||
|
||||
{-| Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will visit
|
||||
the project's `README.md` file.
|
||||
-}
|
||||
withReadmeModuleVisitor :
|
||||
(Maybe String -> moduleContext -> moduleContext)
|
||||
-> ModuleRuleSchema { schemaState | canCollectProjectData : () } moduleContext
|
||||
-> ModuleRuleSchema { schemaState | canCollectProjectData : () } moduleContext
|
||||
withReadmeModuleVisitor visitor (ModuleRuleSchema schema) =
|
||||
ModuleRuleSchema { schema | readmeVisitors = visitor :: schema.readmeVisitors }
|
||||
|
||||
|
||||
{-| Add a visitor to the [`ProjectRuleSchema`](#ProjectRuleSchema) which will visit the project's
|
||||
[dependencies](./Review-Project-Dependency).
|
||||
|
||||
You can use this look at the modules contained in dependencies, which can make the rule very precise when it targets
|
||||
specific functions.
|
||||
|
||||
-}
|
||||
withDependenciesModuleVisitor :
|
||||
(Dict String Review.Project.Dependency.Dependency -> moduleContext -> moduleContext)
|
||||
-> ModuleRuleSchema { schemaState | canCollectProjectData : () } moduleContext
|
||||
-> ModuleRuleSchema { schemaState | canCollectProjectData : () } moduleContext
|
||||
withDependenciesModuleVisitor visitor (ModuleRuleSchema schema) =
|
||||
ModuleRuleSchema { schema | dependenciesVisitors = visitor :: schema.dependenciesVisitors }
|
||||
|
||||
|
||||
withElmJsonProjectVisitor :
|
||||
@ -360,6 +458,9 @@ mergeModuleVisitors initialProjectContext maybeModuleContextCreator visitors =
|
||||
, expressionVisitorsOnEnter = []
|
||||
, expressionVisitorsOnExit = []
|
||||
, finalEvaluationFns = []
|
||||
, elmJsonVisitors = []
|
||||
, readmeVisitors = []
|
||||
, dependenciesVisitors = []
|
||||
}
|
||||
in
|
||||
Just
|
||||
|
@ -248,7 +248,7 @@ computeProjectContext projectVisitor project maybePreviousCache =
|
||||
computeReadme () =
|
||||
let
|
||||
( errorsForVisitor, contextForVisitor ) =
|
||||
( elmJsonCacheEntry.errors, elmJsonCacheEntry.context )
|
||||
( [], elmJsonCacheEntry.context )
|
||||
|> accumulateWithListOfVisitors projectVisitor.readmeVisitors readmeData
|
||||
in
|
||||
{ value = readmeData
|
||||
@ -274,6 +274,7 @@ computeProjectContext projectVisitor project maybePreviousCache =
|
||||
|
||||
dependenciesCacheEntry : CacheEntryFor (Dict String Review.Project.Dependency.Dependency) projectContext
|
||||
dependenciesCacheEntry =
|
||||
-- TODO Rewrite these steps to make it less likely to make an error at every step
|
||||
let
|
||||
dependencies : Dict String Review.Project.Dependency.Dependency
|
||||
dependencies =
|
||||
@ -283,7 +284,7 @@ computeProjectContext projectVisitor project maybePreviousCache =
|
||||
computeDependencies () =
|
||||
let
|
||||
( errorsForVisitor, contextForVisitor ) =
|
||||
( elmJsonCacheEntry.errors, elmJsonCacheEntry.context )
|
||||
( [], readmeCacheEntry.context )
|
||||
|> accumulateWithListOfVisitors projectVisitor.dependenciesVisitors dependencies
|
||||
in
|
||||
{ value = dependencies
|
||||
@ -296,7 +297,7 @@ computeProjectContext projectVisitor project maybePreviousCache =
|
||||
if
|
||||
-- If the previous context stayed the same
|
||||
(previousCache.readme.context /= readmeCacheEntry.context)
|
||||
-- and the readme stayed the same
|
||||
-- and the dependencies stayed the same
|
||||
|| (previousCache.dependencies.value == dependencies)
|
||||
then
|
||||
previousCache.dependencies
|
||||
|
@ -4,6 +4,7 @@ import Elm.Syntax.Declaration exposing (Declaration)
|
||||
import Elm.Syntax.Expression exposing (Expression)
|
||||
import Elm.Syntax.Node exposing (Node)
|
||||
import Review.Rule as Rule exposing (Error, Rule)
|
||||
import Review.Rule3 as Rule3
|
||||
import Review.Test
|
||||
import Test exposing (Test, test)
|
||||
|
||||
@ -20,29 +21,29 @@ all =
|
||||
let
|
||||
rule : Rule
|
||||
rule =
|
||||
Rule.newModuleRuleSchema "TestRule" "\n0 - initial context"
|
||||
|> Rule.withElmJsonModuleVisitor (\_ context -> context ++ "\n1.1 - withElmJsonModuleVisitor")
|
||||
|> Rule.withElmJsonModuleVisitor (\_ context -> context ++ "\n1.2 - withElmJsonModuleVisitor")
|
||||
|> Rule.withReadmeModuleVisitor (\_ context -> context ++ "\n2.1 - withReadmeModuleVisitor")
|
||||
|> Rule.withReadmeModuleVisitor (\_ context -> context ++ "\n2.2 - withReadmeModuleVisitor")
|
||||
|> Rule.withDependenciesModuleVisitor (\_ context -> context ++ "\n3.1 - withDependenciesModuleVisitor")
|
||||
|> Rule.withDependenciesModuleVisitor (\_ context -> context ++ "\n3.2 - withDependenciesModuleVisitor")
|
||||
|> Rule.withModuleDefinitionVisitor (\_ context -> ( [], context ++ "\n4.1 - withModuleDefinitionVisitor" ))
|
||||
|> Rule.withModuleDefinitionVisitor (\_ context -> ( [], context ++ "\n4.2 - withModuleDefinitionVisitor" ))
|
||||
|> Rule.withImportVisitor (\_ context -> ( [], context ++ "\n5.1 - withImportVisitor" ))
|
||||
|> Rule.withImportVisitor (\_ context -> ( [], context ++ "\n5.2 - withImportVisitor" ))
|
||||
|> Rule.withDeclarationListVisitor (\_ context -> ( [], context ++ "\n6.1 - withDeclarationListVisitor" ))
|
||||
|> Rule.withDeclarationListVisitor (\_ context -> ( [], context ++ "\n6.2 - withDeclarationListVisitor" ))
|
||||
|> Rule.withDeclarationEnterVisitor (\_ context -> ( [], context ++ "\n7.1 - withDeclarationEnterVisitor" ))
|
||||
|> Rule.withDeclarationEnterVisitor (\_ context -> ( [], context ++ "\n7.2 - withDeclarationEnterVisitor" ))
|
||||
|> Rule.withDeclarationExitVisitor (\_ context -> ( [], context ++ "\n10.2 - withDeclarationExitVisitor" ))
|
||||
|> Rule.withDeclarationExitVisitor (\_ context -> ( [], context ++ "\n10.1 - withDeclarationExitVisitor" ))
|
||||
|> Rule.withExpressionEnterVisitor (\_ context -> ( [], context ++ "\n8.1 - withExpressionEnterVisitor" ))
|
||||
|> Rule.withExpressionEnterVisitor (\_ context -> ( [], context ++ "\n8.2 - withExpressionEnterVisitor" ))
|
||||
|> Rule.withExpressionExitVisitor (\_ context -> ( [], context ++ "\n9.2 - withExpressionExitVisitor" ))
|
||||
|> Rule.withExpressionExitVisitor (\_ context -> ( [], context ++ "\n9.1 - withExpressionExitVisitor" ))
|
||||
|> Rule.withFinalModuleEvaluation finalEvaluation
|
||||
|> Rule.fromModuleRuleSchema
|
||||
Rule3.newModuleRuleSchema "Visitor order" "\n0 - initial context"
|
||||
|> Rule3.withElmJsonModuleVisitor (\_ context -> context ++ "\n1.1 - withElmJsonModuleVisitor")
|
||||
|> Rule3.withElmJsonModuleVisitor (\_ context -> context ++ "\n1.2 - withElmJsonModuleVisitor")
|
||||
|> Rule3.withReadmeModuleVisitor (\_ context -> context ++ "\n2.1 - withReadmeModuleVisitor")
|
||||
|> Rule3.withReadmeModuleVisitor (\_ context -> context ++ "\n2.2 - withReadmeModuleVisitor")
|
||||
|> Rule3.withDependenciesModuleVisitor (\_ context -> context ++ "\n3.1 - withDependenciesModuleVisitor")
|
||||
|> Rule3.withDependenciesModuleVisitor (\_ context -> context ++ "\n3.2 - withDependenciesModuleVisitor")
|
||||
|> Rule3.withModuleDefinitionVisitor (\_ context -> ( [], context ++ "\n4.1 - withModuleDefinitionVisitor" ))
|
||||
|> Rule3.withModuleDefinitionVisitor (\_ context -> ( [], context ++ "\n4.2 - withModuleDefinitionVisitor" ))
|
||||
|> Rule3.withImportVisitor (\_ context -> ( [], context ++ "\n5.1 - withImportVisitor" ))
|
||||
|> Rule3.withImportVisitor (\_ context -> ( [], context ++ "\n5.2 - withImportVisitor" ))
|
||||
|> Rule3.withDeclarationListVisitor (\_ context -> ( [], context ++ "\n6.1 - withDeclarationListVisitor" ))
|
||||
|> Rule3.withDeclarationListVisitor (\_ context -> ( [], context ++ "\n6.2 - withDeclarationListVisitor" ))
|
||||
|> Rule3.withDeclarationEnterVisitor (\_ context -> ( [], context ++ "\n7.1 - withDeclarationEnterVisitor" ))
|
||||
|> Rule3.withDeclarationEnterVisitor (\_ context -> ( [], context ++ "\n7.2 - withDeclarationEnterVisitor" ))
|
||||
|> Rule3.withDeclarationExitVisitor (\_ context -> ( [], context ++ "\n10.2 - withDeclarationExitVisitor" ))
|
||||
|> Rule3.withDeclarationExitVisitor (\_ context -> ( [], context ++ "\n10.1 - withDeclarationExitVisitor" ))
|
||||
|> Rule3.withExpressionEnterVisitor (\_ context -> ( [], context ++ "\n8.1 - withExpressionEnterVisitor" ))
|
||||
|> Rule3.withExpressionEnterVisitor (\_ context -> ( [], context ++ "\n8.2 - withExpressionEnterVisitor" ))
|
||||
|> Rule3.withExpressionExitVisitor (\_ context -> ( [], context ++ "\n9.2 - withExpressionExitVisitor" ))
|
||||
|> Rule3.withExpressionExitVisitor (\_ context -> ( [], context ++ "\n9.1 - withExpressionExitVisitor" ))
|
||||
|> Rule3.withFinalModuleEvaluation finalEvaluation
|
||||
|> Rule3.fromModuleRuleSchema
|
||||
|
||||
finalEvaluation : Context -> List (Error {})
|
||||
finalEvaluation context =
|
||||
|
Loading…
Reference in New Issue
Block a user