Replace withprojectVisitor by withElmJsonVisitor

This way, we'll be able to
- Optimize for rules that don't need some of the project details, by not 
loading them in the first place
- Read at first glance which project's data the rule will look at
This commit is contained in:
Jeroen Engels 2019-08-22 13:09:04 +02:00
parent b730fec914
commit 8c9a7c5f85
2 changed files with 25 additions and 30 deletions

View File

@ -23,8 +23,6 @@ module Lint.Project exposing
-} -}
-- TODO rename this module to avoid collisions and ambiguity
import Elm.Project import Elm.Project

View File

@ -2,7 +2,8 @@ module Lint.Rule exposing
( Rule, Schema ( Rule, Schema
, newSchema, fromSchema , newSchema, fromSchema
, withSimpleModuleDefinitionVisitor, withSimpleImportVisitor, withSimpleDeclarationVisitor, withSimpleExpressionVisitor , withSimpleModuleDefinitionVisitor, withSimpleImportVisitor, withSimpleDeclarationVisitor, withSimpleExpressionVisitor
, withInitialContext, withProjectVisitor, withModuleDefinitionVisitor, withImportVisitor, Direction(..), withDeclarationVisitor, withExpressionVisitor, withFinalEvaluation , withInitialContext, withModuleDefinitionVisitor, withImportVisitor, Direction(..), withDeclarationVisitor, withExpressionVisitor, withFinalEvaluation
, withElmJsonVisitor
, withFixes , withFixes
, Error, error, errorMessage, errorDetails, errorRange, errorFixes , Error, error, errorMessage, errorDetails, errorRange, errorFixes
, name, analyzer , name, analyzer
@ -19,6 +20,7 @@ An AST is a tree-like structure which represents your source code.
Then, `elm-lint` will traverse the nodes in the AST in the following order, and Then, `elm-lint` will traverse the nodes in the AST in the following order, and
call the visitor function associated to the type of node: call the visitor function associated to the type of node:
- The `elm.json` file, visited by [`withElmJsonVisitor`](#withElmJsonVisitor) (can only collect data)
- The module definition, visited by [`withSimpleModuleDefinitionVisitor`](#withSimpleModuleDefinitionVisitor) and [`withModuleDefinitionVisitor`](#withModuleDefinitionVisitor) - The module definition, visited by [`withSimpleModuleDefinitionVisitor`](#withSimpleModuleDefinitionVisitor) and [`withModuleDefinitionVisitor`](#withModuleDefinitionVisitor)
- Each import statement, visited by [`withSimpleImportVisitor`](#withSimpleImportVisitor) and [`withImportVisitor`](#withImportVisitor) - Each import statement, visited by [`withSimpleImportVisitor`](#withSimpleImportVisitor) and [`withImportVisitor`](#withImportVisitor)
- Each declaration statement, visited by [`withSimpleDeclarationVisitor`](#withSimpleDeclarationVisitor) and [`withDeclarationVisitor`](#withDeclarationVisitor). - Each declaration statement, visited by [`withSimpleDeclarationVisitor`](#withSimpleDeclarationVisitor) and [`withDeclarationVisitor`](#withDeclarationVisitor).
@ -156,7 +158,12 @@ patterns you would want to forbid, but that are not handled by the example.
## Builder functions with context ## Builder functions with context
@docs withInitialContext, withProjectVisitor, withModuleDefinitionVisitor, withImportVisitor, Direction, withDeclarationVisitor, withExpressionVisitor, withFinalEvaluation @docs withInitialContext, withModuleDefinitionVisitor, withImportVisitor, Direction, withDeclarationVisitor, withExpressionVisitor, withFinalEvaluation
## Builder functions to analyze the project's data
@docs withElmJsonVisitor
## Automatic fixing ## Automatic fixing
@ -175,6 +182,7 @@ patterns you would want to forbid, but that are not handled by the example.
-} -}
import Elm.Project
import Elm.Syntax.Declaration exposing (Declaration(..)) import Elm.Syntax.Declaration exposing (Declaration(..))
import Elm.Syntax.Expression exposing (Expression(..), Function, LetDeclaration(..)) import Elm.Syntax.Expression exposing (Expression(..), Function, LetDeclaration(..))
import Elm.Syntax.File exposing (File) import Elm.Syntax.File exposing (File)
@ -235,7 +243,7 @@ type
= Schema = Schema
{ name : String { name : String
, initialContext : context , initialContext : context
, projectVisitor : Project -> context -> context , elmJsonVisitor : Maybe Elm.Project.Project -> context -> context
, moduleDefinitionVisitor : Node Module -> context -> ( List Error, context ) , moduleDefinitionVisitor : Node Module -> context -> ( List Error, context )
, importVisitor : Node Import -> context -> ( List Error, context ) , importVisitor : Node Import -> context -> ( List Error, context )
, expressionVisitor : Node Expression -> Direction -> context -> ( List Error, context ) , expressionVisitor : Node Expression -> Direction -> context -> ( List Error, context )
@ -311,7 +319,7 @@ newSchema name_ =
Schema Schema
{ name = name_ { name = name_
, initialContext = () , initialContext = ()
, projectVisitor = \project context -> context , elmJsonVisitor = \elmJson context -> context
, moduleDefinitionVisitor = \node context -> ( [], context ) , moduleDefinitionVisitor = \node context -> ( [], context )
, importVisitor = \node context -> ( [], context ) , importVisitor = \node context -> ( [], context )
, expressionVisitor = \direction node context -> ( [], context ) , expressionVisitor = \direction node context -> ( [], context )
@ -329,7 +337,7 @@ fromSchema (Schema schema) =
, analyzer = , analyzer =
\project file -> \project file ->
schema.initialContext schema.initialContext
|> schema.projectVisitor project |> schema.elmJsonVisitor (Lint.Project.elmJson project)
|> schema.moduleDefinitionVisitor file.moduleDefinition |> schema.moduleDefinitionVisitor file.moduleDefinition
|> accumulateList schema.importVisitor file.imports |> accumulateList schema.importVisitor file.imports
|> accumulateList (visitDeclaration schema.declarationVisitor schema.expressionVisitor) file.declarations |> accumulateList (visitDeclaration schema.declarationVisitor schema.expressionVisitor) file.declarations
@ -658,7 +666,7 @@ withInitialContext initialContext_ (Schema schema) =
Schema Schema
{ name = schema.name { name = schema.name
, initialContext = initialContext_ , initialContext = initialContext_
, projectVisitor = \project context -> context , elmJsonVisitor = \elmJson context -> context
, moduleDefinitionVisitor = \node context -> ( [], context ) , moduleDefinitionVisitor = \node context -> ( [], context )
, importVisitor = \node context -> ( [], context ) , importVisitor = \node context -> ( [], context )
, expressionVisitor = \node direction context -> ( [], context ) , expressionVisitor = \node direction context -> ( [], context )
@ -667,16 +675,9 @@ withInitialContext initialContext_ (Schema schema) =
} }
{-| Add a visitor to the [`Schema`](#Schema) which will visit the project's
-- TODO Is having both withInitialContext and withProjectVisitor redundant? [`elm.json`](https://package.elm-lang.org/packages/elm/project-metadata-utils/latest/Elm-Project) file.
-- Since withProjectVisitor doesn't really need an initial context and can set information, such as the contents of the `elm.json` file, to collect data (`module SomeModuleName exposing (a, b)`), collect data in the `context` and/or report patterns.
-- one up itself.
-- Maybe have one or the other, using phantom types?
{-| Add a visitor to the [`Schema`](#Schema) which will visit the project's known
information, such as the contents of the `elm.json` file.
[module definition](https://package.elm-lang.org/packages/stil4m/elm-syntax/latest/Elm-Syntax-Module) (`module SomeModuleName exposing (a, b)`), collect data in the `context` and/or report patterns.
The following example forbids the use of `Html.button` except in the "Button" file. The following example forbids the use of `Html.button` except in the "Button" file.
THe example is simplified to only forbid the use of the `Html.button` expression. THe example is simplified to only forbid the use of the `Html.button` expression.
@ -685,7 +686,6 @@ THe example is simplified to only forbid the use of the `Html.button` expression
import Elm.Project import Elm.Project
import Elm.Syntax.Module as Module exposing (Module) import Elm.Syntax.Module as Module exposing (Module)
import Elm.Syntax.Node as Node exposing (Node) import Elm.Syntax.Node as Node exposing (Node)
import Lint.Project as Project exposing (Project)
import Lint.Rule as Rule exposing (Error, Rule) import Lint.Rule as Rule exposing (Error, Rule)
type alias Context = type alias Context =
@ -695,13 +695,13 @@ THe example is simplified to only forbid the use of the `Html.button` expression
rule = rule =
Rule.newSchema "DoNoExposeInternalModules" Rule.newSchema "DoNoExposeInternalModules"
|> Rule.withInitialContext Nothing |> Rule.withInitialContext Nothing
|> Rule.withProjectVisitor projectVisitor |> Rule.withElmJsonVisitor elmJsonVisitor
|> Rule.withModuleDefinitionVisitor moduleDefinitionVisitor |> Rule.withModuleDefinitionVisitor moduleDefinitionVisitor
|> Rule.fromSchema |> Rule.fromSchema
projectVisitor : Project -> Context -> Context elmJsonVisitor : Maybe Elm.Project.Project -> Context -> Context
projectVisitor project context = elmJsonVisitor elmJson context =
Project.elmJson project elmJson
moduleDefinitionVisitor : Node Module -> Context -> ( List Error, Context ) moduleDefinitionVisitor : Node Module -> Context -> ( List Error, Context )
moduleDefinitionVisitor node context = moduleDefinitionVisitor node context =
@ -732,19 +732,16 @@ THe example is simplified to only forbid the use of the `Html.button` expression
else else
( [], context ) ( [], context )
Just (Elm.Project.Application _) -> _ ->
( [], context )
Nothing ->
( [], context ) ( [], context )
else else
( [], context ) ( [], context )
-} -}
withProjectVisitor : (Project -> context -> context) -> Schema configurationState context -> Schema configurationState context withElmJsonVisitor : (Maybe Elm.Project.Project -> context -> context) -> Schema configurationState context -> Schema configurationState context
withProjectVisitor visitor (Schema schema) = withElmJsonVisitor visitor (Schema schema) =
Schema { schema | projectVisitor = visitor } Schema { schema | elmJsonVisitor = visitor }
{-| Add a visitor to the [`Schema`](#Schema) which will visit the `File`'s {-| Add a visitor to the [`Schema`](#Schema) which will visit the `File`'s