mirror of
https://github.com/jfmengels/elm-review.git
synced 2024-08-17 12:00:29 +03:00
1 line
234 KiB
JSON
1 line
234 KiB
JSON
[{"name":"Review.FilePattern","comment":" A module for selecting multiple files from the file system\nusing [`glob`] patterns and negated patterns.\n\n import Review.FilePattern as FilePattern\n\n filePatterns =\n [ FilePattern.include \"**/*.css\"\n , FilePattern.exclude \"**/*-test.css\"\n , FilePattern.excludeDirectory \"ignore-folder/\"\n ]\n\nSome `elm-review` APIs require a `List FilePattern` as an argument to figure out a list of files to match or not match.\n\nThis list works similar like [`.gitignore`] files: any matching file excluded by a previous pattern will become included again.\nFiles that are in [excluded directories](#excludeDirectory) are ignored entirely.\n\nA file pattern is always relative to the project's `elm.json` file, is case-sensitive,\nand should be written in the Unix style (`src/Some/File.elm`, not `src\\Some\\File.elm`).\n\n@docs FilePattern\n@docs include, exclude, excludeDirectory\n\n\n## Supported patterns\n\nThe supported patterns are the following:\n\n - `?` matches an unknown single character (except `/`). \"a?c\" would match \"abc\" or \"a5c\", but not \"ac\".\n - `*` matches any number of unknown characters (except `/`). \"some-\\*.txt\" would match \"some-file.txt\" and \"some-other-file.txt\", but not \"other-file.txt\" or \"some-folder/file.txt\".\n - `**` matches any number of sub-directories. \"projects/**/README.md\" would match \"projects/README.md\", \"projects/a/README.md\" and \"projects/a/b/README.md\". If you desire to include all files in a folder, then you need to end the pattern with `/**/*` (eg \"projects/**/\\*\" or \"projects/\\*\\*/\\*.md\").\n - `[characters]` matches one of the specified characters. `a[bc]d` would match \"abc\" and \"acd\", but not \"axd\".\n - `[^characters]` matches anything that is not one of the specified characters. `a[^bc]d` would match \"axc\", but not \"abd\" or \"acd\".\n - `[character1-character2]` matches a range of characters. `a[a-z]d` would match \"aac\" and \"azd\", but not \"a5d\".\n - `{string1|string2}` matches one of the provided strings. \"file.{js|ts}\" would match \"file.js\" and \"file.ts\" but not \"file.md\".\n\n\n## Using FilePattern\n\n@docs Summary, compact, match\n@docs toStrings\n\n[`glob`]: https://en.wikipedia.org/wiki/Glob_%28programming%29\n[`.gitignore`]: https://git-scm.com/docs/gitignore#_pattern_format\n\n","unions":[{"name":"FilePattern","comment":" A pattern to included or exclude files from a selection.\n","args":[],"cases":[]},{"name":"Summary","comment":" REPLACEME\n","args":[],"cases":[]}],"aliases":[],"values":[{"name":"compact","comment":" REPLACEME\n","type":"List.List Review.FilePattern.FilePattern -> Result.Result (List.List String.String) Review.FilePattern.Summary"},{"name":"exclude","comment":" REPLACEME\n","type":"String.String -> Review.FilePattern.FilePattern"},{"name":"excludeDirectory","comment":" REPLACEME\n","type":"String.String -> Review.FilePattern.FilePattern"},{"name":"include","comment":" REPLACEME\n","type":"String.String -> Review.FilePattern.FilePattern"},{"name":"match","comment":" REPLACEME\n","type":"{ includeByDefault : Basics.Bool } -> Review.FilePattern.Summary -> String.String -> Basics.Bool"},{"name":"toStrings","comment":" REPLACEME\n","type":"Review.FilePattern.Summary -> { files : List.List { pattern : String.String, included : Basics.Bool }, excludedDirectories : List.List String.String }"}],"binops":[]},{"name":"Review.Fix","comment":" Tools to write automatic error fixes.\n\nWhen creating a [`Review.Rule.Error`](./Review-Rule#Error), you can provide an automatic\nfix for the error using [`Review.Rule.errorWithFix`](./Review-Rule#errorWithFix)\nor other functions that end with \"withFix\" so that the user doesn't need to fix\nthe problem themselves.\n\nIn the [CLI](https://github.com/jfmengels/node-elm-review), the user can ask to fix the errors automatically, and in doing so,\nthey will be presented by a fix which they can accept or refuse. If the fix gets\nrefused, then the next fixable error will be presented. Otherwise, if the fix\ngets accepted, the file will be applied and the fixed file content get analyzed\nagain by the different rules in the user's configuration, and then another fix\nwill be presented. When there are no more fixable errors, the remaining errors\nwill be reported, just like when the user doesn't request errors to be automatically\nfixed.\n\nIn summary, errors will be presented one by one and the user will validate them.\nThe [CLI] also proposes an option to fix all the errors, which applies each fix\none by one and then asks the user to confirm the cumulated fix.\n\n\n# Guidelines\n\nAn automatic fix, when applied, should resolve the reported error completely.\nThis means that when the automatic fix is applied, the user should not have to\nthink about the error anymore or have to do additional work.\n\nImagine if the user applies a lot of automatic fixes all at once. We don't want them to have to\nremember having to do something, otherwise we may have just offloaded a lot of\nwork that they may forget to do. In that case, it is better not to provide a fix\nat all, so that they keep a reminder and the details of how to fix the problem.\n\nAn automatic fix should resolve only the reported error, not try to fix other\npotential errors. By only fixing one error at a time, the fix will be easier for\nthe user to digest and understand. The file will be re-reviewed when the fix is\napplied, and then another error can fix that one.\n\n\n# When (not) to provide an automatic fix?\n\nFor users, having an automatic fix always feels like a nice-to-have and they may\nrequest you to provide some, but they are not mandatory, and in some cases, it\nis better not to have any.\n\n\n## Reasons not to provide an automatic fix\n\n\n### A complete automatic fix is not possible\n\nSometimes, just by going through the whole file, you are missing some of the\ninformation needed to generate the right fix. Instead of providing a partial or\npotentially incorrect fix, it would be better to provide more details, hints or\nsuggestions.\n\n\n### The fix would result in a compiler error\n\nAn automatic fix should not cause changes that would break the file or the\nproject. In some cases, we can detect that the [fix will break things](#Problem),\nlike if the result of the fix is invalid Elm code (as in resulting in a parsing\nerror), but ultimately we can't detect that the project will still compile after\nthe fix is applied.\n\nUsers are notified that an automatic fix is available. For performance reasons,\nwe only check that a fix is valid before presenting it to the user and ignore it\nif it turns out to be invalid. This means that the user will be disappointed or\nconfused when the error ends up not being enforced. The only way we have to\nprevent this is to write tests, as fixes are applied in tests.\n\n\n### The user should learn about the problem and how to solve it\n\nSometimes problems are learning opportunities, and it is worth having the user\nspend some time reading through the details of the error and trying several\nalternatives in order to understand the problem and the tradeoffs of the\nsolutions. You can guide them by using great error details!\n\n\n## Reasons to provide an automatic fix\n\nThe reasons to provide an automatic fix are basically the opposite of the\nreasons not to provide an automatic fix:\n\n - We know how to fix the problem completely and accurately\n - The task is menial and the user will not learn much by fixing the error\n themselves\n\n\n# Strategies for writing automatic fixes effectively\n\n\n### Write a lot of tests\n\nAutomatic fixes are more error-prone than rules, especially since we may work\nwith re-writing ports of the code, for which the AST does not provide the\ncurrent formatting of a file (there is no information about spacing,\nline-breaks, ...). I suggest writing a lot of tests, and especially write tests\nwhere the formatting of the original file is a bit odd, as you may for instance\nunknowingly attempt to delete characters next to the thing you wanted to remove.\n\n\n### Store ranges in the context if necessary\n\nFixes work with ranges or position. If the context of a different element is not\navailable in the scope of where you create the error, then you should store it\nin the context of your rule.\n\n\n# Creating a fix\n\n@docs Fix, removeRange, replaceRangeBy, insertAt\n\n\n# Applying fixes\n\n@docs FixResult, Problem, fix\n\n[CLI]: https://github.com/jfmengels/node-elm-review\n\n\n# Tooling\n\n@docs toRecord\n\n","unions":[{"name":"FixResult","comment":" Represents the result of having applied a list of fixes to a source code.\n","args":[],"cases":[["Successful",["String.String"]],["Errored",["Review.Fix.Problem"]]]},{"name":"Problem","comment":" Represents a problem that may have occurred when attempting to apply a list\nof fixes.\n","args":[],"cases":[["Unchanged",[]],["SourceCodeIsNotValid",["String.String"]],["HasCollisionsInFixRanges",[]]]}],"aliases":[{"name":"Fix","comment":" Represents (part of a) fix that will be applied to a file's source code in order to\nautomatically fix a review error.\n","args":[],"type":"Review.Fix.Internal.Fix"}],"values":[{"name":"fix","comment":" Apply the changes on the source code.\n","type":"Review.Error.Target -> List.List Review.Fix.Fix -> String.String -> Review.Fix.FixResult"},{"name":"insertAt","comment":" Insert some code at the given position.\n","type":"{ row : Basics.Int, column : Basics.Int } -> String.String -> Review.Fix.Fix"},{"name":"removeRange","comment":" Remove the code in between a range.\n","type":"Elm.Syntax.Range.Range -> Review.Fix.Fix"},{"name":"replaceRangeBy","comment":" Replace the code in between a range by some other code.\n","type":"Elm.Syntax.Range.Range -> String.String -> Review.Fix.Fix"},{"name":"toRecord","comment":" Describe a fix as a range to replace by something else.\n\nThis is meant for external tooling. You shouldn't have to care about this\n\n","type":"Review.Fix.Fix -> { range : Elm.Syntax.Range.Range, replacement : String.String }"}],"binops":[]},{"name":"Review.ModuleNameLookupTable","comment":" Looks up the name of the module a function or type comes from based on the position of the element in the module's AST.\n\nWhen encountering a `Expression.FunctionOrValue ModuleName String` (among other nodes where we refer to a function or value),\nthe module name available represents the module name that is in the source code. But that module name can be an alias to\na different import, or it can be empty, meaning that it refers to a local value or one that has been imported explicitly\nor implicitly. Resolving which module the type or function comes from can be a bit tricky sometimes, and I recommend against\ndoing it yourself.\n\n`elm-review` computes this for you already. Store this value inside your module context, then use\n[`ModuleNameLookupTable.moduleNameFor`](./Review-ModuleNameLookupTable#moduleNameFor) or\n[`ModuleNameLookupTable.moduleNameAt`](./Review-ModuleNameLookupTable#moduleNameAt) to get the name of the module the\ntype or value comes from.\n\n@docs ModuleNameLookupTable, moduleNameFor, moduleNameAt\n@docs fullModuleNameFor, fullModuleNameAt\n\nNote: If you have been using [`elm-review-scope`](https://github.com/jfmengels/elm-review-scope) before, you should use this instead.\n\n\n## Testing\n\n@docs createForTests\n\n","unions":[],"aliases":[{"name":"ModuleNameLookupTable","comment":" Associates positions in the AST of a module to the name of the module that the contained variable or type originates\nfrom.\n","args":[],"type":"Review.ModuleNameLookupTable.Internal.ModuleNameLookupTable"}],"values":[{"name":"createForTests","comment":" Creates a module name lookup table from a list of ranges and module names. The first argument is the name of the\nmodule in which this lookup table would be used.\n\n**NOTE**: This is only meant to be used for testing purposes, not for direct use in rules.\n\nThis can be useful if you want to test individual functions that take a `ModuleNameLookupTable` as an argument.\n\n ModuleNameLookupTable.createForTests [ \"My\", \"Module\" ] []\n\n","type":"Elm.Syntax.ModuleName.ModuleName -> List.List ( Elm.Syntax.Range.Range, Elm.Syntax.ModuleName.ModuleName ) -> Review.ModuleNameLookupTable.ModuleNameLookupTable"},{"name":"fullModuleNameAt","comment":" This is the same as [`moduleNameAt`](#moduleNameAt), except that the function will return the current module name\nif the type or value was defined in this module, instead of `Just []`.\n","type":"Review.ModuleNameLookupTable.ModuleNameLookupTable -> Elm.Syntax.Range.Range -> Maybe.Maybe Elm.Syntax.ModuleName.ModuleName"},{"name":"fullModuleNameFor","comment":" This is the same as [`moduleNameFor`](#moduleNameFor), except that the function will return the current module name\nif the type or value was defined in this module, instead of `Just []`.\n","type":"Review.ModuleNameLookupTable.ModuleNameLookupTable -> Elm.Syntax.Node.Node a -> Maybe.Maybe Elm.Syntax.ModuleName.ModuleName"},{"name":"moduleNameAt","comment":" Returns the name of the module the type, value, or operator referred to by this [`Range`](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Range#Range).\n\nThe function returns `Just []` if the type or value was defined in this module. It returns `Just moduleName` if the Node is among these kinds of AST nodes (and `Nothing` for all the others):\n\n - `Expression.FunctionOrValue`\n - `nodeForTheName` in `Expression.RecordUpdateExpression nodeForTheName modifiers`\n - `nodeForTheName` in `TypeAnnotation.Typed nodeForTheName args`\n - `Pattern.NamedPattern`\n - `Expression.PrefixOperator`\n - `Expression.OperatorApplication`\n\n```elm\nexpressionVisitor : Node Expression -> Context -> ( List (Error {}), Context )\nexpressionVisitor node context =\n case Node.value node of\n Expression.RecordUpdateExpr (Node range name) _ ->\n case ModuleNameLookupTable.moduleNameAt context.lookupTable range of\n Just moduleName ->\n ( [], markVariableAsUsed ( moduleName, name ) context )\n\n Nothing ->\n ( [], context )\n\n _ ->\n ( [], context )\n```\n\nNote: If using a `Node` is easier in your situation than using a `Range`, use [`moduleNameFor`](#moduleNameFor) instead.\n\n","type":"Review.ModuleNameLookupTable.ModuleNameLookupTable -> Elm.Syntax.Range.Range -> Maybe.Maybe Elm.Syntax.ModuleName.ModuleName"},{"name":"moduleNameFor","comment":" Returns the name of the module the type, value, or operator referred to by this [`Node`](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Node#Node) was defined in.\n\nThe function returns `Just []` if the type or value was defined in this module. It returns `Just moduleName` if the Node is among these kinds of AST nodes (and `Nothing` for all the others):\n\n - `Expression.FunctionOrValue`\n - `nodeForTheName` in `Expression.RecordUpdateExpression nodeForTheName modifiers`\n - `nodeForTheName` in `TypeAnnotation.Typed nodeForTheName args`\n - `Pattern.NamedPattern`\n - `Expression.PrefixOperator`\n - `Expression.OperatorApplication`\n\n```elm\nexpressionVisitor : Node Expression -> Context -> ( List (Error {}), Context )\nexpressionVisitor node context =\n case Node.value node of\n Expression.FunctionOrValue _ \"color\" ->\n if ModuleNameLookupTable.moduleNameFor context.lookupTable node == Just [ \"Css\" ] then\n ( [ Rule.error\n { message = \"Do not use `Css.color` directly, use the Colors module instead\"\n , details = [ \"We made a module which contains all the available colors of our design system. Use the functions in there instead.\" ]\n }\n (Node.range node)\n ]\n , context\n )\n\n else\n ( [], context )\n\n _ ->\n ( [], context )\n```\n\nNote: If using a `Range` is easier in your situation than using a `Node`, use [`moduleNameAt`](#moduleNameAt) instead.\n\n","type":"Review.ModuleNameLookupTable.ModuleNameLookupTable -> Elm.Syntax.Node.Node a -> Maybe.Maybe Elm.Syntax.ModuleName.ModuleName"}],"binops":[]},{"name":"Review.Options","comment":" Configure how `elm-review` runs.\n\nYou should not have to use this when writing a rule. This is only necessary if you wish to run `elm-review` in a new\nprocess like the CLI.\n\n@docs ReviewOptions\n@docs defaults\n@docs withDataExtraction, withLogger, withSuppressedErrors\n\n@docs withFixes\n@docs FixMode, fixedDisabled, fixesEnabledWithLimit, fixesEnabledWithoutLimits\n@docs withIgnoredFixes\n\n","unions":[],"aliases":[{"name":"FixMode","comment":" Represents whether `elm-review` should apply fixes found in the reported errors.\n","args":[],"type":"Review.Options.Internal.FixMode"},{"name":"ReviewOptions","comment":" Represents the different options you can use to run the review process.\n","args":[],"type":"Review.Options.Internal.ReviewOptionsInternal"}],"values":[{"name":"defaults","comment":" Somewhat arbitrary default options.\n\n - Does not enable data extraction\n\n","type":"Review.Options.ReviewOptions"},{"name":"fixedDisabled","comment":" Don't apply fixes.\n","type":"Review.Options.FixMode"},{"name":"fixesEnabledWithLimit","comment":" Apply the fixes for every error whenever possible, but abort the whole review process once a number of errors have been fixed.\n","type":"Basics.Int -> Review.Options.FixMode"},{"name":"fixesEnabledWithoutLimits","comment":" Apply the fixes for every error whenever possible.\n","type":"Review.Options.FixMode"},{"name":"withDataExtraction","comment":" Enable or disable data extraction.\n","type":"Basics.Bool -> Review.Options.ReviewOptions -> Review.Options.ReviewOptions"},{"name":"withFixes","comment":" Set the fix mode.\n","type":"Review.Options.FixMode -> Review.Options.ReviewOptions -> Review.Options.ReviewOptions"},{"name":"withIgnoredFixes","comment":" Provide a predicate for ignoring fixes to apply. This is useful to ignore previously refused fixes in `elm-review --fix`.\n","type":"({ ruleName : String.String, filePath : String.String, message : String.String, details : List.List String.String, range : Elm.Syntax.Range.Range } -> Basics.Bool) -> Review.Options.ReviewOptions -> Review.Options.ReviewOptions"},{"name":"withLogger","comment":" Add a logger.\n","type":"Maybe.Maybe (List.List ( String.String, Json.Encode.Value ) -> List.List ( String.String, Json.Encode.Value )) -> Review.Options.ReviewOptions -> Review.Options.ReviewOptions"},{"name":"withSuppressedErrors","comment":" Add suppressions from the suppressed folder.\n","type":"Dict.Dict ( String.String, String.String ) Basics.Int -> Review.Options.ReviewOptions -> Review.Options.ReviewOptions"}],"binops":[]},{"name":"Review.Project","comment":" Represents the contents of the project to be analyzed. This information will\nthen be fed to the review rules.\n\nYou may need to use use this module if you want\n\n - to create test cases where the project is in a certain configuration\n - to make `elm-review` run in a new environment\n\nYou can safely ignore this module if you just want to write a review rule that\ndoes not look at project information (like the `elm.json`, dependencies, ...).\n\n@docs Project, new\n\n\n## Elm modules\n\n@docs ProjectModule, addModule, addParsedModule\n@docs removeModule\n@docs modules, modulesThatFailedToParse\n@docs precomputeModuleGraph\n\n\n# `elm.json`\n\n@docs addElmJson, elmJson\n\n\n# `README.md`\n\n@docs addReadme, readme\n\n\n# Extra files\n\n\"Extra files\" are files that `elm-review` doesn't load by default because they do not relate to Elm source files or Elm packages,\nthat rules can then visit.\n\n@docs addExtraFiles, addExtraFile, updateFile\n@docs removeExtraFile, removeFile\n@docs extraFiles\n\n\n# Project dependencies\n\n@docs addDependency\n@docs removeDependency, removeDependencies\n@docs directDependencies, dependencies\n\n\n# Diffing\n\n@docs diff\n\n","unions":[],"aliases":[{"name":"Project","comment":" Holds all the information related to the project such as the contents of\nthe `elm.json` file, the project modules and the project dependencies.\n","args":[],"type":"Review.Project.Internal.Project"},{"name":"ProjectModule","comment":" Represents a parsed file.\n","args":[],"type":"Review.Project.ProjectModule.ProjectModule"}],"values":[{"name":"addDependency","comment":" Add a dependency to the project. These will be available for rules to make\nbetter assumptions on what is happening in the code.\n\nKnowing the dependencies of the project will also help better parse the source\nfiles, since the dependencies will allow us to know the precedence and\nassociativity of operators, which has an impact on the resulting AST when\nparsing a file.\n\n**For tests**, `elm-review` comes with a few dependencies that you can find in\n[`Review.Test.Dependencies`](./Review-Test-Dependencies).\n\n","type":"Review.Project.Dependency.Dependency -> Review.Project.Project -> Review.Project.Project"},{"name":"addElmJson","comment":" Add the content of the `elm.json` file to the project, making it\navailable for rules to access using\n[`Review.Rule.withElmJsonModuleVisitor`](./Review-Rule#withElmJsonModuleVisitor) and\n[`Review.Rule.withElmJsonProjectVisitor`](./Review-Rule#withElmJsonProjectVisitor).\n\nThe `raw` value should be the raw JSON as a string, and `project` corresponds to\n[`elm/project-metadata-utils`'s `Elm.Project.Project` type](https://package.elm-lang.org/packages/elm/project-metadata-utils/latest/Elm-Project#Project).\n\n","type":"{ path : String.String, raw : String.String, project : Elm.Project.Project } -> Review.Project.Project -> Review.Project.Project"},{"name":"addExtraFile","comment":" Add (or update) a single extra file to the project.\n","type":"{ path : String.String, source : String.String } -> Review.Project.Project -> Review.Project.Project"},{"name":"addExtraFiles","comment":" Add (or update) extra files to the project.\n","type":"Dict.Dict String.String String.String -> Review.Project.Project -> Review.Project.Project"},{"name":"addModule","comment":" Add an Elm file to the project. If a file with the same path already exists,\nthen it will replace it.\n\nIf the file is syntactically valid Elm code, it will then be analyzed by the\nreview rules. Otherwise, the file will be added to the list of files that failed\nto parse, which you can get using [`modulesThatFailedToParse`](#modulesThatFailedToParse),\nand for which a parsing error will be reported when running [`the review function`](./Review-Rule#reviewV2).\n\n","type":"{ path : String.String, source : String.String } -> Review.Project.Project -> Review.Project.Project"},{"name":"addParsedModule","comment":" Add an already parsed module to the project. This module will then be analyzed by the rules.\n","type":"{ path : String.String, source : String.String, ast : Elm.Syntax.File.File } -> Review.Project.Project -> Review.Project.Project"},{"name":"addReadme","comment":" Add the content of the `README.md` file to the project, making it\navailable for rules to access using\n[`Review.Rule.withReadmeModuleVisitor`](./Review-Rule#withReadmeModuleVisitor) and\n[`Review.Rule.withReadmeProjectVisitor`](./Review-Rule#withReadmeProjectVisitor).\n","type":"{ path : String.String, content : String.String } -> Review.Project.Project -> Review.Project.Project"},{"name":"dependencies","comment":" Get the [dependencies](./Review-Project-Dependency#Dependency) of the project.\n","type":"Review.Project.Project -> Dict.Dict String.String Review.Project.Dependency.Dependency"},{"name":"diff","comment":" Get the files that have been modified between two versions of a Project.\n\nAdded or removed files are ignored.\n\n","type":"{ before : Review.Project.Project, after : Review.Project.Project } -> List.List { path : String.String, before : String.String, after : String.String }"},{"name":"directDependencies","comment":" Get the direct [dependencies](./Review-Project-Dependency#Dependency) of the project.\n","type":"Review.Project.Project -> Dict.Dict String.String Review.Project.Dependency.Dependency"},{"name":"elmJson","comment":" Get the contents of the `elm.json` file, if available.\n\nThis will give you a `Elm.Project.Project` type from the\n[`elm/project-metadata-utils`](https://package.elm-lang.org/packages/elm/project-metadata-utils/1.0.0/Elm-Project)\npackage, so you will need to install and use it to gain access to the\ninformation from the `elm.json` file.\n\n","type":"Review.Project.Project -> Maybe.Maybe { path : String.String, raw : String.String, project : Elm.Project.Project }"},{"name":"extraFiles","comment":" Get the extra files in the project.\n","type":"Review.Project.Project -> Dict.Dict String.String String.String"},{"name":"modules","comment":" Get the list of modules in the project.\n","type":"Review.Project.Project -> List.List Review.Project.ProjectModule"},{"name":"modulesThatFailedToParse","comment":" Get the list of file paths that failed to parse, because they were syntactically invalid Elm code.\n","type":"Review.Project.Project -> List.List { path : String.String, source : String.String }"},{"name":"new","comment":" Create a new empty Project.\n\n**For tests**, you can also start of with a project that contains the `elm/core` dependency using\n[`Review.Test.Dependencies.projectWithElmCore`](./Review-Test-Dependencies#projectWithElmCore). Some more prepared\ndependencies can be found in that same module.\n\n","type":"Review.Project.Project"},{"name":"precomputeModuleGraph","comment":" Precomputes the module graph.\n\n**@deprecated** This is not useful anymore.\n\n","type":"Review.Project.Project -> Review.Project.Project"},{"name":"readme","comment":" Get the contents of the `README.md` file, if available.\n","type":"Review.Project.Project -> Maybe.Maybe { path : String.String, content : String.String }"},{"name":"removeDependencies","comment":" Remove all dependencies of a project. Use this to flush the dependencies of\na project when they are changed, before re-adding them.\n","type":"Review.Project.Project -> Review.Project.Project"},{"name":"removeDependency","comment":" Remove a dependency from a project by name.\n","type":"String.String -> Review.Project.Project -> Review.Project.Project"},{"name":"removeExtraFile","comment":" Remove a single extra file from the project.\n","type":"String.String -> Review.Project.Project -> Review.Project.Project"},{"name":"removeFile","comment":" Remove an existing file from the project. The file can be an Elm file of the project\nand/or an extra file.\n","type":"String.String -> Review.Project.Project -> Review.Project.Project"},{"name":"removeModule","comment":" Remove a module from the project by its path.\n","type":"String.String -> Review.Project.Project -> Review.Project.Project"},{"name":"updateFile","comment":" Update an existing file in the project. The file can be an Elm file of the project\nand/or an extra file.\n","type":"{ path : String.String, source : String.String } -> Review.Project.Project -> Review.Project.Project"}],"binops":[]},{"name":"Review.Project.Dependency","comment":" Functions to create and read data about the project's dependencies.\n\nYou may need to use use this module if you want\n\n - to create test cases where the project has specific dependencies\n - to make `elm-review` run in a new environment\n\nYou can safely ignore this module if you just want to write a review rule that\ndoes not look at the project's dependencies.\n\n@docs Dependency\n\n\n# Access\n\n@docs name, elmJson, modules\n\n\n# Creation\n\n@docs create\n\n","unions":[{"name":"Dependency","comment":" Represents a dependency of the project.\n","args":[],"cases":[]}],"aliases":[],"values":[{"name":"create","comment":" Create a dependency.\n\nYou will need to use this if you try to make `elm-review` run in a new environment,\nbut you can safely ignore it if you just want to write a review rule or run it\nin existing environments like the CLI tool.\n\nYou could something like the following to create a test project in your tests.\n\n import Elm.Docs\n import Elm.Project\n import Elm.Type as Type\n import Json.Decode as Decode\n import Review.Project as Project exposing (Project)\n import Review.Project.Dependency as Dependency exposing (Dependency)\n\n testProject : Project\n testProject =\n Project.new\n |> Project.addDependency dependency\n\n dependency : Dependency\n dependency =\n Dependency.create\n \"author/dependency\"\n (createElmJson rawElmJson)\n modules\n\n modules : List Elm.Docs.Module\n modules =\n [ { name = \"Foo\"\n , comment = \"\"\n , unions = []\n , aliases = []\n , values =\n [ { name = \"someFunction\"\n , comment = \"\"\n , tipe = Type.Lambda (Type.Var \"a\") (Type.Var \"b\")\n }\n ]\n , binops = []\n }\n ]\n\n createElmJson : String -> Elm.Project.Project\n createElmJson rawElmJson =\n case Decode.decodeString Elm.Project.decoder rawElmJson of\n Ok elmJson ->\n elmJson\n\n Err _ ->\n Debug.todo \"Invalid elm.json contents in tests\"\n\n rawElmJson : String\n rawElmJson =\n \"\"\"\n {\n \"type\": \"package\",\n \"name\": \"author/dependency\",\n \"summary\": \"Summary\",\n \"license\": \"MIT\",\n \"version\": \"1.0.0\",\n \"exposed-modules\": [\n \"Foo\"\n ],\n \"elm-version\": \"0.19.0 <= v < 0.20.0\",\n \"dependencies\": {\n \"elm/core\": \"1.0.0 <= v < 2.0.0\"\n },\n \"test-dependencies\": {}\n }\n \"\"\"\n\n","type":"String.String -> Elm.Project.Project -> List.List Elm.Docs.Module -> Review.Project.Dependency.Dependency"},{"name":"elmJson","comment":" Get the [contents of the project's `elm.json`](https://package.elm-lang.org/packages/elm/project-metadata-utils/1.0.1/Elm-Project#Project)\nfile.\n","type":"Review.Project.Dependency.Dependency -> Elm.Project.Project"},{"name":"modules","comment":" Get the list of [modules](https://package.elm-lang.org/packages/elm/project-metadata-utils/1.0.1/Elm-Docs#Module)\ncontained in the dependency.\n","type":"Review.Project.Dependency.Dependency -> List.List Elm.Docs.Module"},{"name":"name","comment":" Get the name of the dependency.\n","type":"Review.Project.Dependency.Dependency -> String.String"}],"binops":[]},{"name":"Review.Rule","comment":" This module contains functions that are used for writing rules.\n\n**NOTE**: If you want to **create a package** containing `elm-review` rules, I highly recommend using the\n[CLI's](https://github.com/jfmengels/node-elm-review/) `elm-review new-package` subcommand. This will create a new package that will help you use the best practices and give you helpful tools like easy auto-publishing. More information is available in the maintenance file generated along with it.\n\nIf you want to **add/create a rule** for the package or for your local configuration, then I recommend using `elm-review new-rule`, which will create a source and test file which you can use as a starting point. For packages, it will add the rule everywhere it should be present (`exposed-modules`, README, ...).\n\n\n# How does it work?\n\n`elm-review` reads the modules, `elm.json`, dependencies and `README.md` from your project,\nand turns each module into an [Abstract Syntax Tree (AST)](https://en.wikipedia.org/wiki/Abstract_syntax_tree),\na tree-like structure which represents your source code, using the\n[`elm-syntax` package](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/).\n\n`elm-review` then feeds all this data into `review rules`, that traverse them to report problems.\nThe way that review rules go through the data depends on whether it is a [module rule](#creating-a-module-rule) or a [project rule](#creating-a-project-rule).\n\n`elm-review` relies on the [`elm-syntax` package](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/),\nand all the node types you'll see will be coming from there. You are likely to\nneed to have the documentation for that package open when writing a rule.\n\nThere are plenty of examples in this documentation, and you can also look at the\nsource code of existing rules to better grasp how they work.\n\n**NOTE**: These examples are only here to showcase how to write rules and how a function can\nbe used. They are not necessarily good rules to enforce. See the\n[section on whether to write a rule](./#when-to-write-or-enable-a-rule) for more on that.\nEven if you think they are good ideas to enforce, they are often not complete, as there are other\npatterns you would want to forbid, but that are not handled by the example.\n\n\n# What makes a good rule\n\nApart from the rationale on [whether a rule should be written](./#when-to-write-or-enable-a-rule),\nhere are a few tips on what makes a rule helpful.\n\nA review rule is an automated communication tool which sends messages to\ndevelopers who have written patterns your rule wishes to prevent. As all\ncommunication, the message is important.\n\n\n## A good rule name\n\nThe name of the rule (`NoUnusedVariables`, `NoDebug`, ...) should try to convey\nreally quickly what kind of pattern we're dealing with. Ideally, a user who\nencounters this pattern for the first time could guess the problem just from the\nname. And a user who encountered it several times should know how to fix the\nproblem just from the name too.\n\nI recommend having the name of the module containing the rule be the same as the\nrule name. This will make it easier to find the module in the project or on\nthe packages website when trying to get more information.\n\n\n## A helpful error message and details\n\nThe error message should give more information about the problem. It is split\ninto two parts:\n\n - The `message`: A short sentence that describes the forbidden pattern. A user\n that has encountered this error multiple times should know exactly what to do.\n Example: \"Function `foo` is never used\". With this information, a user who\n knows the rule probably knows that a function needs to be removed from the\n source code, and also knows which one.\n - The `details`: All the additional information that can be useful to the\n user, such as the rationale behind forbidding the pattern, and suggestions\n for a solution or alternative.\n\nWhen writing the error message that the user will see, try to make them be as\nhelpful as the messages the compiler gives you when it encounters a problem.\n\n\n## The smallest section of code that makes sense\n\nWhen creating an error, you need to specify under which section of the code this\nmessage appears. This is where you would see squiggly lines in your editor when\nyou have review or compiler errors.\n\nTo make the error easier to spot, it is best to make this section as small as\npossible, as long as that makes sense. For instance, in a rule that would forbid\n`Debug.log`, you would the error to appear under `Debug.log`, not on the whole\nfunction which contains this piece of code.\n\n\n## Good rule documentation\n\nThe rule documentation should give the same information as what you would see in\nthe error message.\n\nIf published in a package, the rule documentation should explain when not to\nenable the rule in the user's review configuration. For instance, for a rule that\nmakes sure that a package is publishable by ensuring that all docs are valid,\nthe rule might say something along the lines of \"If you are writing an\napplication, then you should not use this rule\".\n\nAdditionally, it could give a few examples of patterns that will be reported and\nof patterns that will not be reported, so that users can have a better grasp of\nwhat to expect.\n\n\n# Strategies for writing rules effectively\n\n\n## Use Test-Driven Development\n\nThis package comes with [`Review.Test`](./Review-Test), which works with [`elm-test`](https://github.com/elm-explorations/test).\nI recommend reading through [`the strategies for effective testing`](./Review-Test#strategies-for-effective-testing) before\nstarting writing a rule.\n\n\n## Look at the documentation for [`elm-syntax`](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/)\n\n`elm-review` is heavily dependent on the types that [`elm-syntax`](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/)\nprovides. If you don't understand the AST it provides, you will have a hard time\nimplementing the rule you wish to create.\n\n\n# Writing a Rule\n\n@docs Rule\n\n\n## Creating a module rule\n\nA \"module rule\" looks at modules (i.e. files) one by one. When it finishes looking at a module and reporting errors,\nit forgets everything about the module it just analyzed before starting to look at a different module. You should create one of these if you\ndo not need to know the contents of a different module in the project, such as what functions are exposed.\nIf you do need that information, you should create a [project rule](#creating-a-project-rule).\n\nIf you are new to writing rules, I would recommend learning how to build a module rule first, as they are in practice a\nsimpler version of project rules.\n\nThe traversal of a module rule is the following:\n\n - Read project-related info (only collect data in the context in these steps)\n - The `elm.json` file, visited by [`withElmJsonModuleVisitor`](#withElmJsonModuleVisitor)\n - The `README.md` file, visited by [`withReadmeModuleVisitor`](#withReadmeModuleVisitor)\n - Extra files that are not analyzed by default, visited by [`withExtraFilesModuleVisitor`](#withExtraFilesModuleVisitor)\n - The definition for dependencies, visited by [`withDirectDependenciesModuleVisitor`](#withDirectDependenciesModuleVisitor) and [`withDependenciesModuleVisitor`](#withDependenciesModuleVisitor)\n - Visit the Elm module (in the following order)\n - The module definition, visited by [`withSimpleModuleDefinitionVisitor`](#withSimpleModuleDefinitionVisitor) and [`withModuleDefinitionVisitor`](#withModuleDefinitionVisitor)\n - The module documentation, visited by [`withModuleDocumentationVisitor`](#withModuleDocumentationVisitor)\n - The module's list of comments, visited by [`withSimpleCommentsVisitor`](#withSimpleCommentsVisitor) and [`withCommentsVisitor`](#withCommentsVisitor)\n - Each import, visited by [`withSimpleImportVisitor`](#withSimpleImportVisitor) and [`withImportVisitor`](#withImportVisitor)\n - The list of declarations, visited by [`withDeclarationListVisitor`](#withDeclarationListVisitor)\n - Each declaration, visited in the following order:\n - [`withSimpleDeclarationVisitor`](#withSimpleDeclarationVisitor) and [`withDeclarationEnterVisitor`](#withDeclarationEnterVisitor)\n - The expression contained in the declaration will be visited recursively by [`withSimpleExpressionVisitor`](#withSimpleExpressionVisitor), [`withExpressionEnterVisitor`](#withExpressionEnterVisitor) and [`withExpressionExitVisitor`](#withExpressionExitVisitor).\n - [`withDeclarationExitVisitor`](#withDeclarationExitVisitor)\n - A final evaluation is made when the module has fully been visited, using [`withFinalModuleEvaluation`](#withFinalModuleEvaluation)\n\nEvaluating/visiting a node means two things:\n\n - Detecting patterns and reporting errors\n - Collecting data in a \"context\" (called `moduleContext` for module rules) to have more information available in a later\n node evaluation. You can only use the context and update it with \"non-simple with\\*\" visitor functions.\n I recommend using the \"simple with\\*\" visitor functions if you don't need to do either, as they are simpler to use\n\n@docs ModuleRuleSchema, newModuleRuleSchema, fromModuleRuleSchema\n\n\n## Builder functions without context\n\n@docs withSimpleModuleDefinitionVisitor, withSimpleCommentsVisitor, withSimpleImportVisitor, withSimpleDeclarationVisitor, withSimpleExpressionVisitor\n\n\n## Builder functions with context\n\n@docs newModuleRuleSchemaUsingContextCreator\n@docs withModuleDefinitionVisitor\n@docs withModuleDocumentationVisitor\n@docs withCommentsVisitor\n@docs withImportVisitor\n@docs Direction, withDeclarationEnterVisitor, withDeclarationExitVisitor, withDeclarationVisitor, withDeclarationListVisitor\n@docs withExpressionEnterVisitor, withExpressionExitVisitor, withExpressionVisitor\n@docs withCaseBranchEnterVisitor, withCaseBranchExitVisitor\n@docs withLetDeclarationEnterVisitor, withLetDeclarationExitVisitor\n@docs providesFixesForModuleRule\n@docs withFinalModuleEvaluation\n\n\n## Builder functions to analyze the project's data\n\n@docs withElmJsonModuleVisitor, withReadmeModuleVisitor, withDirectDependenciesModuleVisitor, withDependenciesModuleVisitor\n@docs withExtraFilesModuleVisitor\n\n\n## Creating a project rule\n\nProject rules can look at the global picture of an Elm project. Contrary to module\nrules, which forget everything about the module they were looking at when going from\none module to another, project rules can retain information about previously\nanalyzed modules, and use it to report errors when analyzing a different module or\nafter all modules have been visited.\n\nProject rules can also report errors in the `elm.json` or the `README.md` files.\n\nIf you are new to writing rules, I would recommend learning [how to build a module rule](#creating-a-module-rule)\nfirst, as they are in practice a simpler version of project rules.\n\n@docs ProjectRuleSchema, newProjectRuleSchema, fromProjectRuleSchema, withModuleVisitor, withModuleContext, withModuleContextUsingContextCreator, withElmJsonProjectVisitor, withReadmeProjectVisitor, withDirectDependenciesProjectVisitor, withDependenciesProjectVisitor, withFinalProjectEvaluation, withExtraFilesProjectVisitor, withContextFromImportedModules\n@docs providesFixesForProjectRule\n\n\n## Requesting more information\n\n@docs ContextCreator, initContextCreator, withModuleName, withModuleNameNode, withIsInSourceDirectories, withFilePath, withIsFileIgnored, withModuleNameLookupTable, withModuleKey, withSourceCodeExtractor, withFullAst, withModuleDocumentation\n\n\n### Requesting more information (DEPRECATED)\n\n@docs Metadata, withMetadata, moduleNameFromMetadata, moduleNameNodeFromMetadata, isInSourceDirectories\n\n\n## Errors\n\n@docs Error, error, errorWithFix, ModuleKey, errorForModule, errorForModuleWithFix\n@docs ElmJsonKey, errorForElmJson, errorForElmJsonWithFix\n@docs ReadmeKey, errorForReadme, errorForReadmeWithFix\n@docs ExtraFileKey, errorForExtraFile, errorForExtraFileWithFix\n@docs globalError, configurationError\n@docs ReviewError, errorRuleName, errorMessage, errorDetails, errorRange, errorFilePath, errorTarget, errorFixes, errorFixFailure\n\n\n## Configuring exceptions\n\nThere are situations where you don't want review rules to report errors:\n\n1. You copied and updated over an external library because one of your needs wasn't met, and you don't want to modify it more than necessary.\n2. Your project contains generated source code, over which you have no control or for which you do not care that some rules are enforced (like the reports of unused variables).\n3. You want to introduce a rule progressively, because there are too many errors in the project for you to fix in one go. You can then ignore the parts of the project where the problem has not yet been solved, and fix them as you go.\n4. You wrote a rule that is very specific and should only be applied to a portion of your code.\n5. You wish to disable some rules for tests files (or enable some only for tests).\n\nYou can use the following functions to ignore errors in directories or files, or only report errors found in specific directories or files.\n\n**NOTE**: Even though they can be used to disable any errors, I **strongly recommend against**\ndoing so if you are not in the situations listed above. I highly recommend you\nleave a comment explaining the reason why you use these functions, or to\ncommunicate with your colleagues if you see them adding exceptions without\nreason or seemingly inappropriately.\n\n@docs ignoreErrorsForDirectories, ignoreErrorsForFiles, filterErrorsForFiles\n\n\n## Extract information\n\nAs you might have seen so far, `elm-review` has quite a nice way of traversing the files of a project and collecting data.\n\nWhile you have only seen the tool be used to report errors, you can also use it to extract information from\nthe codebase. You can use this to gain insight into your codebase, or provide information to other tools to enable\npowerful integrations.\n\nYou can read more about how to use this in [_Extract information_ in the README](./#extract-information), and you can\nfind the tools to extract data below.\n\n@docs withDataExtractor, preventExtract\n\n\n# Running rules\n\n@docs reviewV3, reviewV2, review, ProjectData, ruleName, ruleProvidesFixes, ruleKnowsAboutIgnoredFiles, ruleRequestedFiles, withRuleId, getConfigurationError\n\n\n# Internals\n\n@docs Required, Forbidden\n\n","unions":[{"name":"ContextCreator","comment":" Create a module context from a project context or the other way around.\nUse functions like [`withModuleName`](#withModuleName) to request more information.\n","args":["from","to"],"cases":[]},{"name":"Direction","comment":" **@deprecated**\n\nThis is used in [`withDeclarationVisitor`](#withDeclarationVisitor) and [`withDeclarationVisitor`](#withDeclarationVisitor),\nwhich are deprecated and will be removed in the next major version. This type will be removed along with them.\n\nTo replicate the same behavior, take a look at\n\n - [`withDeclarationEnterVisitor`](#withDeclarationEnterVisitor) and [`withDeclarationExitVisitor`](#withDeclarationExitVisitor).\n - [`withExpressionEnterVisitor`](#withExpressionEnterVisitor) and [`withExpressionExitVisitor`](#withExpressionExitVisitor).\n\n**/@deprecated**\n\nRepresents whether a node is being traversed before having seen its children (`OnEnter`ing the node), or after (`OnExit`ing the node).\n\nWhen visiting the AST, declaration and expression nodes are visited twice: once\nwith `OnEnter`, before the children of the node are visited, and once with\n`OnExit`, after the children of the node have been visited.\nIn most cases, you'll only want to handle the `OnEnter` case, but there are cases\nwhere you'll want to visit a [`Node`](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Node#Node)\nafter having seen its children.\n\nFor instance, if you are trying to detect the unused variables defined inside\nof a let expression, you will want to collect the declaration of variables,\nnote which ones are used, and at the end of the block report the ones that weren't used.\n\n expressionVisitor : Node Expression -> Direction -> Context -> ( List (Rule.Error {}), Context )\n expressionVisitor node direction context =\n case ( direction, Node.value node ) of\n ( Rule.OnEnter, Expression.FunctionOrValue moduleName name ) ->\n ( [], markVariableAsUsed context name )\n\n -- Find variables declared in let expression\n ( Rule.OnEnter, Expression.LetExpression letBlock ) ->\n ( [], registerVariables context letBlock )\n\n -- When exiting the let expression, report the variables that were not used.\n ( Rule.OnExit, Expression.LetExpression _ ) ->\n ( unusedVariables context |> List.map createError, context )\n\n _ ->\n ( [], context )\n\n","args":[],"cases":[["OnEnter",[]],["OnExit",[]]]},{"name":"ElmJsonKey","comment":" A key to be able to report an error for the `elm.json` file. You need this\nkey in order to use the [`errorForElmJson`](#errorForElmJson) function. This is\nto prevent creating errors for it if you have not visited it.\n\nYou can get a `ElmJsonKey` using the [`withElmJsonProjectVisitor`](#withElmJsonProjectVisitor) function.\n\n","args":[],"cases":[]},{"name":"Error","comment":" Represents an error found by a [`Rule`](#Rule). These are created by the rules.\n","args":["scope"],"cases":[]},{"name":"ExtraFileKey","comment":" A key to be able to report an error for an extra file. You need this\nkey in order to use the [`errorForReadmeWithFix`](#errorForReadmeWithFix) function. This is\nto prevent creating errors for it if you have not visited it.\n\nYou can get a `ExtraFileKey` using the [`withExtraFilesProjectVisitor`](#withExtraFilesProjectVisitor) function.\n\n","args":[],"cases":[]},{"name":"Forbidden","comment":" Used for phantom type constraints. You can safely ignore this type.\n","args":[],"cases":[]},{"name":"Metadata","comment":" Metadata for the module being visited.\n\n**@deprecated**: More practical functions have been made available since the introduction of this type.\n\nDo not store the metadata directly in your context. Prefer storing the individual pieces of information.\n\n","args":[],"cases":[]},{"name":"ModuleKey","comment":" A key to be able to report an error for a specific module. You need such a\nkey in order to use the [`errorForModule`](#errorForModule) function. This is to\nprevent creating errors for modules you have not visited, or files that do not exist.\n\nYou can get a `ModuleKey` from the `fromProjectToModule` and `fromModuleToProject`\nfunctions that you define when using [`newProjectRuleSchema`](#newProjectRuleSchema).\n\n","args":[],"cases":[]},{"name":"ModuleRuleSchema","comment":" Represents a schema for a module [`Rule`](#Rule).\n\nStart by using [`newModuleRuleSchema`](#newModuleRuleSchema), then add visitors to look at the parts of the code you are interested in.\n\n import Review.Rule as Rule exposing (Rule)\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"NoDebug\" ()\n |> Rule.withSimpleExpressionVisitor expressionVisitor\n |> Rule.fromModuleRuleSchema\n\n","args":["schemaState","moduleContext"],"cases":[]},{"name":"ProjectData","comment":" Internal cache about the project.\n","args":[],"cases":[]},{"name":"ProjectRuleSchema","comment":" Represents a schema for a project [`Rule`](#Rule).\n\nSee the documentation for [`newProjectRuleSchema`](#newProjectRuleSchema) for\nhow to create a project rule.\n\n","args":["schemaState","projectContext","moduleContext"],"cases":[]},{"name":"ReadmeKey","comment":" A key to be able to report an error for the `README.md` file. You need this\nkey in order to use the [`errorForReadme`](#errorForReadme) function. This is\nto prevent creating errors for it if you have not visited it.\n\nYou can get a `ReadmeKey` using the [`withReadmeProjectVisitor`](#withReadmeProjectVisitor) function.\n\n","args":[],"cases":[]},{"name":"Required","comment":" Used for phantom type constraints. You can safely ignore this type.\n","args":[],"cases":[]},{"name":"Rule","comment":" Represents a construct able to analyze a project and report\nunwanted patterns.\n\nYou can create [module rules](#creating-a-module-rule) or [project rules](#creating-a-project-rule).\n\n","args":[],"cases":[]}],"aliases":[{"name":"ReviewError","comment":" Represents an error found by a [`Rule`](#Rule). These are the ones that will\nbe reported to the user.\n\nIf you are building a [`Rule`](#Rule), you shouldn't have to use this.\n\n","args":[],"type":"Review.Error.ReviewError"}],"values":[{"name":"configurationError","comment":" Creates a rule that will **only** report a configuration error, which stops `elm-review` from reviewing the project\nuntil the user has addressed the issue.\n\nWhen writing rules, some of them may take configuration arguments that specify what exactly the rule should do.\nI recommend to define custom types to limit the possibilities of what can be considered valid and invalid configuration,\nso that the user gets information from the compiler when the configuration is unexpected.\n\nUnfortunately it is not always possible or practical to let the type system forbid invalid possibilities, and you may need to\nmanually parse or validate the arguments.\n\n rule : SomeCustomConfiguration -> Rule\n rule config =\n case parseFunctionName config.functionName of\n Nothing ->\n Rule.configurationError \"RuleName\"\n { message = config.functionName ++ \" is not a valid function name\"\n , details =\n [ \"I was expecting functionName to be a valid Elm function name.\"\n , \"When that is not the case, I am not able to function as expected.\"\n ]\n }\n\n Just functionName ->\n Rule.newModuleRuleSchema \"RuleName\" ()\n |> Rule.withExpressionEnterVisitor (expressionVisitor functionName)\n |> Rule.fromModuleRuleSchema\n\nWhen you need to look at the project before determining whether something is actually a configuration error, for instance\nwhen reporting that a targeted function does not fit some criteria (unexpected arguments, ...), you should go for more\nusual errors like [`error`](#error) or potentially [`globalError`](#globalError). [`error`](#error) would be better because\nit will give the user a starting place to fix the issue.\n\nBe careful that the rule name is the same for the rule and for the configuration error.\n\nThe `message` and `details` represent the [message you want to display to the user](#a-helpful-error-message-and-details).\nThe `details` is a list of paragraphs, and each item will be visually separated\nwhen shown to the user. The details may not be empty, and this will be enforced\nby the tests automatically.\n\n","type":"String.String -> { message : String.String, details : List.List String.String } -> Review.Rule.Rule"},{"name":"error","comment":" Create an [`Error`](#Error). Use it when you find a pattern that the rule should forbid.\n\nThe `message` and `details` represent the [message you want to display to the user].\nThe `details` is a list of paragraphs, and each item will be visually separated\nwhen shown to the user. The details may not be empty, and this will be enforced\nby the tests automatically.\n\n error : Node a -> Error {}\n error node =\n Rule.error\n { message = \"Remove the use of `Debug` before shipping to production\"\n , details = [ \"The `Debug` module 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.\" ]\n }\n (Node.range node)\n\nThe [`Range`] corresponds to the location where the error should be shown, i.e. where to put the squiggly lines in an editor.\nIn most cases, you can get it using [`Node.range`].\n\n[message you want to display to the user]: #a-helpful-error-message-and-details\n\n[`Range`]: https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Range\n[`Node.range`]: https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Node#range\n\n","type":"{ message : String.String, details : List.List String.String } -> Elm.Syntax.Range.Range -> Review.Rule.Error {}"},{"name":"errorDetails","comment":" Get the error details of an [`Error`](#Error).\n","type":"Review.Rule.ReviewError -> List.List String.String"},{"name":"errorFilePath","comment":" Get the file path of an [`Error`](#Error).\n","type":"Review.Rule.ReviewError -> String.String"},{"name":"errorFixFailure","comment":" Get the reason why the fix for an error failed when its available automatic fix was attempted and deemed incorrect.\n\nNote that if the review process was not run in fix mode previously, then this will return `Nothing`.\n\n","type":"Review.Rule.ReviewError -> Maybe.Maybe Review.Fix.Problem"},{"name":"errorFixes","comment":" Get the automatic [`fixes`](./Review-Fix#Fix) of an [`Error`](#Error), if it\ndefined any.\n","type":"Review.Rule.ReviewError -> Maybe.Maybe (List.List Review.Fix.Fix)"},{"name":"errorForElmJson","comment":" Create an [`Error`](#Error) for the `elm.json` file.\n\nYou will need an [`ElmJsonKey`](#ElmJsonKey), which you can get from the [`withElmJsonProjectVisitor`](#withElmJsonProjectVisitor)\nfunction.\n\nThe second argument is a function that takes the `elm.json` content as a raw string,\nand returns the error details. Using the raw string, you should try and find the\nmost fitting [`Range`](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Range)\npossible for the error.\n\n","type":"Review.Rule.ElmJsonKey -> (String.String -> { message : String.String, details : List.List String.String, range : Elm.Syntax.Range.Range }) -> Review.Rule.Error scope"},{"name":"errorForElmJsonWithFix","comment":" Create an [`Error`](#Error) for the `elm.json` file.\n\nYou will need an [`ElmJsonKey`](#ElmJsonKey), which you can get from the [`withElmJsonProjectVisitor`](#withElmJsonProjectVisitor)\nfunction.\n\nThe second argument is a function that takes the `elm.json` content as a raw string,\nand returns the error details. Using the raw string, you should try and find the\nmost fitting [`Range`](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Range)\npossible for the error.\n\nThe third argument is a function that takes the [`elm.json`](https://package.elm-lang.org/packages/elm/project-metadata-utils/latest/Elm-Project)\nand returns a different one that will be suggested as a fix. If the function returns `Nothing`, no fix will be applied.\n\nThe `elm.json` will be the same as the one you got from [`withElmJsonProjectVisitor`](#withElmJsonProjectVisitor), use either depending on what you find most practical.\n\n","type":"Review.Rule.ElmJsonKey -> (String.String -> { message : String.String, details : List.List String.String, range : Elm.Syntax.Range.Range }) -> (Elm.Project.Project -> Maybe.Maybe Elm.Project.Project) -> Review.Rule.Error scope"},{"name":"errorForExtraFile","comment":" Create an [`Error`](#Error) for an extra file.\n\nYou will need an [`ExtraFileKey`](#ExtraFileKey), which you can get from the [`withExtraFilesProjectVisitor`](#withExtraFilesProjectVisitor)\nfunction.\n\n","type":"Review.Rule.ExtraFileKey -> { message : String.String, details : List.List String.String } -> Elm.Syntax.Range.Range -> Review.Rule.Error scope"},{"name":"errorForExtraFileWithFix","comment":" Just like [`errorForExtraFile`](#errorForExtraFile), create an [`Error`](#Error) for an extra file, but\nprovides an automatic fix that the user can apply.\n\nTake a look at [`Review.Fix`](./Review-Fix) to know more on how to makes fixes.\n\nIf the list of fixes is empty, then it will give the same error as if you had\ncalled [`errorForExtraFile`](#errorForExtraFile) instead.\n\n**Note**: Each fix applies on a location in the file, defined by a range. To avoid an\nunpredictable result, those ranges may not overlap. The order of the fixes does\nnot matter.\n\n","type":"Review.Rule.ExtraFileKey -> { message : String.String, details : List.List String.String } -> Elm.Syntax.Range.Range -> List.List Review.Fix.Fix -> Review.Rule.Error scope"},{"name":"errorForModule","comment":" Just like [`error`](#error), create an [`Error`](#Error) but for a specific module, instead of the module that is being\nvisited.\n\nYou will need a [`ModuleKey`](#ModuleKey), which you can get from the `fromProjectToModule` and `fromModuleToProject`\nfunctions that you define when using [`newProjectRuleSchema`](#newProjectRuleSchema).\n\n","type":"Review.Rule.ModuleKey -> { message : String.String, details : List.List String.String } -> Elm.Syntax.Range.Range -> Review.Rule.Error scope"},{"name":"errorForModuleWithFix","comment":" Just like [`errorForModule`](#errorForModule), create an [`Error`](#Error) for a specific module, but\nprovides an automatic fix that the user can apply.\n\nTake a look at [`Review.Fix`](./Review-Fix) to know more on how to makes fixes.\n\nIf the list of fixes is empty, then it will give the same error as if you had\ncalled [`errorForModule`](#errorForModule) instead.\n\n**Note**: Each fix applies on a location in the code, defined by a range. To avoid an\nunpredictable result, those ranges may not overlap. The order of the fixes does\nnot matter.\n\n","type":"Review.Rule.ModuleKey -> { message : String.String, details : List.List String.String } -> Elm.Syntax.Range.Range -> List.List Review.Fix.Fix -> Review.Rule.Error scope"},{"name":"errorForReadme","comment":" Create an [`Error`](#Error) for the `README.md` file.\n\nYou will need an [`ReadmeKey`](#ReadmeKey), which you can get from the [`withReadmeProjectVisitor`](#withReadmeProjectVisitor)\nfunction.\n\n","type":"Review.Rule.ReadmeKey -> { message : String.String, details : List.List String.String } -> Elm.Syntax.Range.Range -> Review.Rule.Error scope"},{"name":"errorForReadmeWithFix","comment":" Just like [`errorForReadme`](#errorForReadme), create an [`Error`](#Error) for the `README.md` file, but\nprovides an automatic fix that the user can apply.\n\nTake a look at [`Review.Fix`](./Review-Fix) to know more on how to makes fixes.\n\nIf the list of fixes is empty, then it will give the same error as if you had\ncalled [`errorForReadme`](#errorForReadme) instead.\n\n**Note**: Each fix applies on a location in the file, defined by a range. To avoid an\nunpredictable result, those ranges may not overlap. The order of the fixes does\nnot matter.\n\n","type":"Review.Rule.ReadmeKey -> { message : String.String, details : List.List String.String } -> Elm.Syntax.Range.Range -> List.List Review.Fix.Fix -> Review.Rule.Error scope"},{"name":"errorMessage","comment":" Get the error message of an [`Error`](#Error).\n","type":"Review.Rule.ReviewError -> String.String"},{"name":"errorRange","comment":" Get the [`Range`](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Range)\nof an [`Error`](#Error).\n","type":"Review.Rule.ReviewError -> Elm.Syntax.Range.Range"},{"name":"errorRuleName","comment":" Get the name of the rule that triggered this [`Error`](#Error).\n","type":"Review.Rule.ReviewError -> String.String"},{"name":"errorTarget","comment":" Get the target of an [`Error`](#Error).\n","type":"Review.Rule.ReviewError -> Review.Error.Target"},{"name":"errorWithFix","comment":" Creates an [`Error`](#Error), just like the [`error`](#error) function, but\nprovides an automatic fix that the user can apply.\n\n import Review.Fix as Fix\n\n error : Node a -> Error {}\n error node =\n Rule.errorWithFix\n { message = \"Remove the use of `Debug` before shipping to production\"\n , details = [ \"The `Debug` module 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.\" ]\n }\n (Node.range node)\n [ Fix.removeRange (Node.range node) ]\n\nTake a look at [`Review.Fix`](./Review-Fix) to know more on how to makes fixes.\n\nIf the list of fixes is empty, then it will give the same error as if you had\ncalled [`error`](#error) instead.\n\n**Note**: Each fix applies on a location in the code, defined by a range. To avoid an\nunpredictable result, those ranges may not overlap. The order of the fixes does\nnot matter.\n\n","type":"{ message : String.String, details : List.List String.String } -> Elm.Syntax.Range.Range -> List.List Review.Fix.Fix -> Review.Rule.Error {}"},{"name":"filterErrorsForFiles","comment":" Filter the files to report errors for.\n\nUse it to control precisely which files the rule applies or does not apply to. For example, you\nmight have written a rule that should only be applied to one specific file.\n\n config : List Rule\n config =\n [ Some.Rule.rule\n |> Rule.filterErrorsForFiles (\\path -> path == \"src/Some/File.elm\")\n , Some.Other.Rule.rule\n ]\n\nIf you want to specify a condition for all of your rules, you can apply\n`filterErrorsForFiles` like this:\n\n config : List Rule\n config =\n [ Some.Rule.For.Tests.rule\n , Some.Other.Rule.rule\n ]\n |> List.map (Rule.filterErrorsForFiles (String.startsWith \"tests/\"))\n\nThe received paths will be relative to the `elm.json` file, just like the ones for the\n`elm.json`'s `source-directories`, and will be formatted in the Unix style `src/Some/File.elm`.\n\nYou can apply `filterErrorsForFiles` several times for a rule, the conditions will get\ncompounded, following the behavior of `List.filter`.\n\nWhen [`ignoreErrorsForFiles`](#ignoreErrorsForFiles) or [`ignoreErrorsForDirectories`](#ignoreErrorsForDirectories)\nare used in combination with this function, all constraints are observed.\n\nYou can also use it when writing a rule. We can hardcode in the rule that a rule\nis only applicable to a folder, like `src/Api/` for instance. The following example\nforbids using strings with hardcoded URLs, but only in the `src/Api/` folder.\n\n import Elm.Syntax.Expression as Expression exposing (Expression)\n import Elm.Syntax.Node as Node exposing (Node)\n import Review.Rule as Rule exposing (Rule)\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"NoHardcodedURLs\" ()\n |> Rule.withSimpleExpressionVisitor expressionVisitor\n |> Rule.fromModuleRuleSchema\n |> Rule.filterErrorsForFiles (String.startsWith \"src/Api/\")\n\n expressionVisitor : Node Expression -> List (Rule.Error {})\n expressionVisitor node =\n case Node.value node of\n Expression.Literal string ->\n if isUrl string then\n [ Rule.error\n { message = \"Do not use hardcoded URLs in the API modules\"\n , details = [ \"Hardcoded URLs should never make it to production. Please refer to the documentation of the `Endpoint` module.\" ]\n }\n (Node.range node)\n ]\n\n else\n []\n\n _ ->\n []\n\n","type":"(String.String -> Basics.Bool) -> Review.Rule.Rule -> Review.Rule.Rule"},{"name":"fromModuleRuleSchema","comment":" Create a [`Rule`](#Rule) from a configured [`ModuleRuleSchema`](#ModuleRuleSchema).\n","type":"Review.Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } moduleContext -> Review.Rule.Rule"},{"name":"fromProjectRuleSchema","comment":" Create a [`Rule`](#Rule) from a configured [`ProjectRuleSchema`](#ProjectRuleSchema).\n","type":"Review.Rule.ProjectRuleSchema { schemaState | withModuleContext : Review.Rule.Forbidden, hasAtLeastOneVisitor : () } projectContext moduleContext -> Review.Rule.Rule"},{"name":"getConfigurationError","comment":" Get the configuration error for a rule.\n\nYou should not have to use this when writing a rule. You might be looking for [`configurationError`](#configurationError) instead.\n\n","type":"Review.Rule.Rule -> Maybe.Maybe { message : String.String, details : List.List String.String }"},{"name":"globalError","comment":" Create an [`Error`](#Error) that is not attached to any specific location in the project.\n\nThis can be useful when needing to report problems that are not tied to any file. For instance for reporting missing elements like a module that was expected to be there.\n\nThis is however **NOT** the recommended way when it is possible to attach an error to a location (even if it is simply the module name of a file's module declaration),\nbecause [giving hints to where the problem is] makes it easier for the user to solve it.\n\nThe `message` and `details` represent the [message you want to display to the user].\nThe `details` is a list of paragraphs, and each item will be visually separated\nwhen shown to the user. The details may not be empty, and this will be enforced\nby the tests automatically.\n\n error : String -> Error scope\n error moduleName =\n Rule.globalError\n { message = \"Could not find module \" ++ moduleName\n , details =\n [ \"You mentioned the module \" ++ moduleName ++ \" in the configuration of this rule, but it could not be found.\"\n , \"This likely means you misconfigured the rule or the configuration has become out of date with recent changes in your project.\"\n ]\n }\n\n[giving hints to where the problem is]: #the-smallest-section-of-code-that-makes-sense\n[message you want to display to the user]: #a-helpful-error-message-and-details\n\n[`Range`]: https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Range\n[`Node.range`]: https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Node#range\n\n","type":"{ message : String.String, details : List.List String.String } -> Review.Rule.Error scope"},{"name":"ignoreErrorsForDirectories","comment":" Ignore the errors reported for modules in specific directories of the project.\n\nUse it when you don't want to get review errors for generated source code or for\nlibraries that you forked and copied over to your project.\n\n config : List Rule\n config =\n [ Some.Rule.rule\n |> Rule.ignoreErrorsForDirectories [ \"generated-source/\", \"vendor/\" ]\n , Some.Other.Rule.rule\n ]\n\nIf you want to ignore some directories for all of your rules, you can apply\n`ignoreErrorsForDirectories` like this:\n\n config : List Rule\n config =\n [ Some.Rule.rule\n , Some.Other.Rule.rule\n ]\n |> List.map (Rule.ignoreErrorsForDirectories [ \"generated-source/\", \"vendor/\" ])\n\nThe paths should be relative to the `elm.json` file, just like the ones for the\n`elm.json`'s `source-directories`.\n\nYou can apply `ignoreErrorsForDirectories`several times for a rule, to add more\nignored directories.\n\nYou can also use it when writing a rule. We can hardcode in the rule that a rule\nis not applicable to a folder, like `tests/` for instance. The following example\nforbids using `Debug.todo` anywhere in the code, except in tests.\n\n import Elm.Syntax.Expression as Expression exposing (Expression)\n import Elm.Syntax.Node as Node exposing (Node)\n import Review.Rule as Rule exposing (Rule)\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"NoDebugEvenIfImported\" DebugLogWasNotImported\n |> Rule.withSimpleExpressionVisitor expressionVisitor\n |> Rule.fromModuleRuleSchema\n |> Rule.ignoreErrorsForDirectories [ \"tests/\" ]\n\n expressionVisitor : Node Expression -> List (Rule.Error {})\n expressionVisitor node =\n case Node.value node of\n Expression.FunctionOrValue [ \"Debug\" ] \"todo\" ->\n [ Rule.error\n { message = \"Remove the use of `Debug.todo` before shipping to production\"\n , details = [ \"`Debug.todo` 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.\" ]\n }\n (Node.range node)\n ]\n\n _ ->\n []\n\n","type":"List.List String.String -> Review.Rule.Rule -> Review.Rule.Rule"},{"name":"ignoreErrorsForFiles","comment":" Ignore the errors reported for specific file paths.\nUse it when you don't want to review generated source code or files from external\nsources that you copied over to your project and don't want to be touched.\n\n config : List Rule\n config =\n [ Some.Rule.rule\n |> Rule.ignoreErrorsForFiles [ \"src/Some/File.elm\" ]\n , Some.Other.Rule.rule\n ]\n\nIf you want to ignore some files for all of your rules, you can apply\n`ignoreErrorsForFiles` like this:\n\n config : List Rule\n config =\n [ Some.Rule.rule\n , Some.Other.Rule.rule\n ]\n |> List.map (Rule.ignoreErrorsForFiles [ \"src/Some/File.elm\" ])\n\nThe paths should be relative to the `elm.json` file, just like the ones for the\n`elm.json`'s `source-directories`.\n\nYou can apply `ignoreErrorsForFiles` several times for a rule, to add more\nignored files.\n\nYou can also use it when writing a rule. We can simplify the example from [`withModuleDefinitionVisitor`](#withModuleDefinitionVisitor)\nby hardcoding an exception into the rule (that forbids the use of `Html.button` except in the \"Button\" module).\n\n import Elm.Syntax.Expression as Expression exposing (Expression)\n import Elm.Syntax.Module as Module exposing (Module)\n import Elm.Syntax.Node as Node exposing (Node)\n import Review.Rule as Rule exposing (Rule)\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"NoHtmlButton\"\n |> Rule.withSimpleExpressionVisitor expressionVisitor\n |> Rule.fromModuleRuleSchema\n |> Rule.ignoreErrorsForFiles [ \"src/Button.elm\" ]\n\n expressionVisitor : Node Expression -> List (Rule.Error {})\n expressionVisitor node context =\n case Node.value node of\n Expression.FunctionOrValue [ \"Html\" ] \"button\" ->\n [ Rule.error\n { message = \"Do not use `Html.button` directly\"\n , details = [ \"At fruits.com, we've built a nice `Button` module that suits our needs better. Using this module instead of `Html.button` ensures we have a consistent button experience across the website.\" ]\n }\n (Node.range node)\n ]\n\n _ ->\n []\n\n","type":"List.List String.String -> Review.Rule.Rule -> Review.Rule.Rule"},{"name":"initContextCreator","comment":" Initialize a new context creator.\n\n contextCreator : Rule.ContextCreator () Context\n contextCreator =\n Rule.initContextCreator\n (\\moduleName () ->\n { moduleName = moduleName\n\n -- ...other fields\n }\n )\n |> Rule.withModuleName\n\n","type":"(from -> to) -> Review.Rule.ContextCreator from to"},{"name":"isInSourceDirectories","comment":" Learn whether the current module is in the \"source-directories\" of the project. You can use this information to\nknow whether the module is part of the tests or of the production code.\n\n**@deprecated**: Use the more practical [`withIsInSourceDirectories`](#withIsInSourceDirectories) instead.\n\n","type":"Review.Rule.Metadata -> Basics.Bool"},{"name":"moduleNameFromMetadata","comment":" Get the module name of the current module.\n\n**@deprecated**: Use the more practical [`withModuleName`](#withModuleName) instead.\n\n","type":"Review.Rule.Metadata -> Elm.Syntax.ModuleName.ModuleName"},{"name":"moduleNameNodeFromMetadata","comment":" Get the [`Node`](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Node#Node) to the module name of the current module.\n\n**@deprecated**: Use the more practical [`withModuleNameNode`](#withModuleNameNode) instead.\n\n","type":"Review.Rule.Metadata -> Elm.Syntax.Node.Node Elm.Syntax.ModuleName.ModuleName"},{"name":"newModuleRuleSchema","comment":" Creates a schema for a module rule. Will require adding module visitors\ncalling [`fromModuleRuleSchema`](#fromModuleRuleSchema) to create a usable\n[`Rule`](#Rule). Use \"with\\*\" functions from this module, like\n[`withSimpleExpressionVisitor`](#withSimpleExpressionVisitor) or [`withSimpleImportVisitor`](#withSimpleImportVisitor)\nto make it report something.\n\nThe first argument is the rule name. I _highly_ recommend naming it just like the\nmodule name (including all the `.` there may be).\n\nThe second argument is the initial `moduleContext`, i.e. the data that the rule will\naccumulate as the module will be traversed, and allows the rule to know/remember\nwhat happens in other parts of the module. If you don't need a context, I\nrecommend specifying `()`, and using functions from this module with names\nstarting with \"withSimple\".\n\n module My.Rule.Name exposing (rule)\n\n import Review.Rule as Rule exposing (Rule)\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"My.Rule.Name\" ()\n |> Rule.withSimpleExpressionVisitor expressionVisitor\n |> Rule.withSimpleImportVisitor importVisitor\n |> Rule.fromModuleRuleSchema\n\nIf you do need information from other parts of the module, then you should specify\nan initial context, and I recommend using \"with\\*\" functions without \"Simple\" in\ntheir name, like [`withExpressionEnterVisitor`](#withExpressionEnterVisitor),\n[`withImportVisitor`](#withImportVisitor) or [`withFinalModuleEvaluation`](#withFinalModuleEvaluation).\n\n import Review.Rule as Rule exposing (Rule)\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"NoUnusedVariables\" initialContext\n |> Rule.withExpressionEnterVisitor expressionVisitor\n |> Rule.withImportVisitor importVisitor\n |> Rule.fromModuleRuleSchema\n\n type alias Context =\n { declaredVariables : List String\n , usedVariables : List String\n }\n\n initialContext : Context\n initialContext =\n { declaredVariables = [], usedVariables = [] }\n\n","type":"String.String -> moduleContext -> Review.Rule.ModuleRuleSchema { canCollectProjectData : () } moduleContext"},{"name":"newModuleRuleSchemaUsingContextCreator","comment":" Same as [`newModuleRuleSchema`](#newModuleRuleSchema), except that you can request for data to help initialize the context.\n\n module My.Rule.Name exposing (rule)\n\n import Review.Rule as Rule exposing (Rule)\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"My.Rule.Name\" ()\n |> Rule.withSimpleExpressionVisitor expressionVisitor\n |> Rule.withSimpleImportVisitor importVisitor\n |> Rule.fromModuleRuleSchema\n\nIf you do need information from other parts of the module, then you should specify\nan initial context, and I recommend using \"with\\*\" functions without \"Simple\" in\ntheir name, like [`withExpressionEnterVisitor`](#withExpressionEnterVisitor),\n[`withImportVisitor`](#withImportVisitor) or [`withFinalModuleEvaluation`](#withFinalModuleEvaluation).\n\n import Review.Rule as Rule exposing (Rule)\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchemaUsingContextCreator \"Rule.Name\" contextCreator\n -- visitors\n |> Rule.fromModuleRuleSchema\n\n contextCreator : Rule.ContextCreator () Context\n contextCreator =\n Rule.initContextCreator\n (\\isInSourceDirectories () ->\n { hasTodoBeenImported = False\n , hasToStringBeenImported = False\n , isInSourceDirectories = isInSourceDirectories\n }\n )\n |> Rule.withIsInSourceDirectories\n\n","type":"String.String -> Review.Rule.ContextCreator () moduleContext -> Review.Rule.ModuleRuleSchema {} moduleContext"},{"name":"newProjectRuleSchema","comment":" Creates a schema for a project rule. Will require adding project visitors and calling\n[`fromProjectRuleSchema`](#fromProjectRuleSchema) to create a usable [`Rule`](#Rule).\n\nThe first argument is the rule name. I _highly_ recommend naming it just like the\nmodule name (including all the `.` there may be).\n\nThe second argument is the initial `projectContext`, i.e. the data that the rule will\naccumulate as the project will be traversed, and allows the rule to know/remember\nwhat happens in other parts of the project.\n\n**NOTE**: Do not store functions, JSON values or regular expressions in your project context, as they will be\ncompared internally, which [may cause Elm to crash](https://package.elm-lang.org/packages/elm/core/latest/Basics#==).\n\nProject rules traverse the project in the following order:\n\n - Read and/or report errors in project files\n - The `elm.json` file, visited by [`withElmJsonProjectVisitor`](#withElmJsonProjectVisitor)\n - The `README.md` file, visited by [`withReadmeProjectVisitor`](#withReadmeProjectVisitor)\n - Extra files that are not analyzed by default, visited by [`withExtraFilesProjectVisitor`](#withExtraFilesProjectVisitor)\n - The definition for dependencies, visited by [`withDependenciesProjectVisitor`](#withDependenciesProjectVisitor)\n - The Elm modules one by one, visited by [`withModuleVisitor`](#withModuleVisitor),\n following the same traversal order as for module rules but without reading the project files (`elm.json`, ...).\n - A final evaluation when all modules have been visited, using [`withFinalProjectEvaluation`](#withFinalProjectEvaluation)\n\nEvaluating/visiting a node means two things:\n\n - Detecting patterns and reporting errors\n - Collecting data in a \"context\", which will be either a `projectContext` or a `moduleContext` depending on the part of the project being visited, to have more information available in a later\n part of the traversal evaluation.\n\n","type":"String.String -> projectContext -> Review.Rule.ProjectRuleSchema { canAddModuleVisitor : (), withModuleContext : Review.Rule.Forbidden } projectContext moduleContext"},{"name":"preventExtract","comment":" Make this error prevent extracting data using [`withDataExtractor`](#withDataExtractor).\n\nUse this if the rule extracts data and an issue is discovered that would make the extraction\noutput incorrect data.\n\n Rule.error\n { message = \"...\"\n , details = [ \"...\" ]\n }\n (Node.range node)\n |> Rule.preventExtract\n\n","type":"Review.Rule.Error a -> Review.Rule.Error a"},{"name":"providesFixesForModuleRule","comment":" Let `elm-review` know that this rule may provide fixes in the reported errors.\n\nThis information is hard for `elm-review` to deduce on its own, but can be very useful for improving the performance of\nthe tool while running in fix mode.\n\nIf your rule is a project rule, then you should use [`providesFixesForProjectRule`](#providesFixesForProjectRule) instead.\n\n","type":"Review.Rule.ModuleRuleSchema schemaState moduleContext -> Review.Rule.ModuleRuleSchema schemaState moduleContext"},{"name":"providesFixesForProjectRule","comment":" Let `elm-review` know that this rule may provide fixes in the reported errors.\n\nThis information is hard for `elm-review` to deduce on its own, but can be very useful for improving the performance of\nthe tool while running in fix mode.\n\nIf your rule is a module rule, then you should use [`providesFixesForModuleRule`](#providesFixesForModuleRule) instead.\n\n","type":"Review.Rule.ProjectRuleSchema schemaState projectContext moduleContext -> Review.Rule.ProjectRuleSchema schemaState projectContext moduleContext"},{"name":"review","comment":" **DEPRECATED:** Use [`reviewV2`](#reviewV2) instead.\n\nReview a project and gives back the errors raised by the given rules.\n\nNote that you won't need to use this function when writing a rule. You should\nonly need it if you try to make `elm-review` run in a new environment.\n\n import Review.Project as Project exposing (Project)\n import Review.Rule as Rule exposing (Rule)\n\n config : List Rule\n config =\n [ Some.Rule.rule\n , Some.Other.Rule.rule\n ]\n\n project : Project\n project =\n Project.new\n |> Project.addModule { path = \"src/A.elm\", source = \"module A exposing (a)\\na = 1\" }\n |> Project.addModule { path = \"src/B.elm\", source = \"module B exposing (b)\\nb = 1\" }\n\n doReview =\n let\n ( errors, rulesWithCachedValues ) =\n Rule.review rules project\n in\n doSomethingWithTheseValues\n\nThe resulting `List Rule` is the same list of rules given as input, but with an\nupdated internal cache to make it faster to re-run the rules on the same project.\nIf you plan on re-reviewing with the same rules and project, for instance to\nreview the project after a file has changed, you may want to store the rules in\nyour `Model`.\n\nThe rules are functions, so doing so will make your model unable to be\nexported/imported with `elm/browser`'s debugger, and may cause a crash if you try\nto compare them or the model that holds them.\n\n","type":"List.List Review.Rule.Rule -> Review.Project.Internal.Project -> ( List.List Review.Rule.ReviewError, List.List Review.Rule.Rule )"},{"name":"reviewV2","comment":" Review a project and gives back the errors raised by the given rules.\n\nNote that you won't need to use this function when writing a rule. You should\nonly need it if you try to make `elm-review` run in a new environment.\n\n import Review.Project as Project exposing (Project)\n import Review.Rule as Rule exposing (Rule)\n\n config : List Rule\n config =\n [ Some.Rule.rule\n , Some.Other.Rule.rule\n ]\n\n project : Project\n project =\n Project.new\n |> Project.addModule { path = \"src/A.elm\", source = \"module A exposing (a)\\na = 1\" }\n |> Project.addModule { path = \"src/B.elm\", source = \"module B exposing (b)\\nb = 1\" }\n\n doReview =\n let\n { errors, rules, projectData } =\n -- Replace `config` by `rules` next time you call reviewV2\n -- Replace `Nothing` by `projectData` next time you call reviewV2\n Rule.reviewV2 config Nothing project\n in\n doSomethingWithTheseValues\n\nThe resulting `List Rule` is the same list of rules given as input, but with an\nupdated internal cache to make it faster to re-run the rules on the same project.\nIf you plan on re-reviewing with the same rules and project, for instance to\nreview the project after a file has changed, you may want to store the rules in\nyour `Model`.\n\nThe rules are functions, so doing so will make your model unable to be\nexported/imported with `elm/browser`'s debugger, and may cause a crash if you try\nto compare them or the model that holds them.\n\n","type":"List.List Review.Rule.Rule -> Maybe.Maybe Review.Rule.ProjectData -> Review.Project.Internal.Project -> { errors : List.List Review.Rule.ReviewError, rules : List.List Review.Rule.Rule, projectData : Maybe.Maybe Review.Rule.ProjectData }"},{"name":"reviewV3","comment":" Review a project and gives back the errors raised by the given rules.\n\nNote that you won't need to use this function when writing a rule. You should\nonly need it if you try to make `elm-review` run in a new environment.\n\n import Review.Project as Project exposing (Project)\n import Review.Rule as Rule exposing (Rule)\n\n config : List Rule\n config =\n [ Some.Rule.rule\n , Some.Other.Rule.rule\n ]\n\n project : Project\n project =\n Project.new\n |> Project.addModule { path = \"src/A.elm\", source = \"module A exposing (a)\\na = 1\" }\n |> Project.addModule { path = \"src/B.elm\", source = \"module B exposing (b)\\nb = 1\" }\n\n doReview =\n let\n { errors, rules, projectData, extracts } =\n -- Replace `config` by `rules` next time you call reviewV2\n -- Replace `Nothing` by `projectData` next time you call reviewV2\n Rule.reviewV3 config Nothing project\n in\n doSomethingWithTheseValues\n\nThe resulting `List Rule` is the same list of rules given as input, but with an\nupdated internal cache to make it faster to re-run the rules on the same project.\nIf you plan on re-reviewing with the same rules and project, for instance to\nreview the project after a file has changed, you may want to store the rules in\nyour `Model`.\n\nThe rules are functions, so doing so will make your model unable to be\nexported/imported with `elm/browser`'s debugger, and may cause a crash if you try\nto compare them or the model that holds them.\n\n","type":"Review.Options.ReviewOptions -> List.List Review.Rule.Rule -> Review.Project.Internal.Project -> { errors : List.List Review.Rule.ReviewError, fixedErrors : Dict.Dict String.String (List.List Review.Rule.ReviewError), rules : List.List Review.Rule.Rule, project : Review.Project.Internal.Project, extracts : Dict.Dict String.String Json.Encode.Value }"},{"name":"ruleKnowsAboutIgnoredFiles","comment":" Indicates whether the rule knows about which files are ignored.\n\nYou should not have to use this when writing a rule.\n\n","type":"Review.Rule.Rule -> Basics.Bool"},{"name":"ruleName","comment":" Get the name of a rule.\n\nYou should not have to use this when writing a rule.\n\n","type":"Review.Rule.Rule -> String.String"},{"name":"ruleProvidesFixes","comment":" Indicates whether the rule provides fixes.\n\nYou should not have to use this when writing a rule.\n\n","type":"Review.Rule.Rule -> Basics.Bool"},{"name":"ruleRequestedFiles","comment":" Get the patterns for extra files that this rule requested.\n\nYou should not have to use this when writing a rule.\n\n","type":"Review.Rule.Rule -> List.List { files : List.List { pattern : String.String, included : Basics.Bool }, excludedDirectories : List.List String.String }"},{"name":"withCaseBranchEnterVisitor","comment":" Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will visit the module's\ncase branches when entering the branch.\n\nThe visitor can be very useful if you need to change the context when inside a case branch.\n\nThe visitors would be called in the following order (ignore the expression visitor if you don't have one):\n\n x =\n case evaluated of\n Pattern1 ->\n expression1\n\n Pattern2 ->\n expression2\n\n1. Expression visitor (enter) for the entire case expression.\n2. Expression visitor (enter then exit) for `evaluated`\n3. Case branch visitor (enter) for `( Pattern1, expression1 )`\n4. Expression visitor (enter then exit) for `expression1`\n5. Case branch visitor (exit) for `( Pattern1, expression1 )`\n6. Case branch visitor (enter) for `( Pattern2, expression2 )`\n7. Expression visitor (enter then exit) for `expression2`\n8. Case branch visitor (exit) for `( Pattern2, expression2 )`\n9. Expression visitor (exit) for the entire case expression.\n\nYou can use [`withCaseBranchExitVisitor`](#withCaseBranchExitVisitor) to visit the node on exit.\n\n import Elm.Syntax.Expression as Expression exposing (Expression)\n import Elm.Syntax.Node as Node exposing (Node)\n import Elm.Syntax.Pattern exposing (Pattern)\n import Review.Rule as Rule exposing (Rule)\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"NoUnusedCaseVariables\" ( [], [] )\n |> Rule.withExpressionEnterVisitor expressionVisitor\n |> Rule.withCaseBranchEnterVisitor caseBranchEnterVisitor\n |> Rule.withCaseBranchExitVisitor caseBranchExitVisitor\n |> Rule.fromModuleRuleSchema\n\n type alias Context =\n ( List String, List (List String) )\n\n expressionVisitor : Node Expression -> Context -> ( List (Rule.Error {}), Context )\n expressionVisitor node (( scope, parentScopes ) as context) =\n case context of\n Expression.FunctionOrValue [] name ->\n ( [], ( name :: used, parentScopes ) )\n\n _ ->\n ( [], context )\n\n caseBranchEnterVisitor : Node Expression.LetBlock -> ( Node Pattern, Node Expression ) -> Context -> List ( Rule.Error {}, Context )\n caseBranchEnterVisitor _ _ ( scope, parentScopes ) =\n -- Entering a new scope every time we enter a new branch\n ( [], ( [], scope :: parentScopes ) )\n\n caseBranchExitVisitor : Node Expression.LetBlock -> ( Node Pattern, Node Expression ) -> Context -> List ( Rule.Error {}, Context )\n caseBranchExitVisitor _ ( pattern, _ ) ( scope, parentScopes ) =\n -- Exiting the current scope every time we enter a new branch, and reporting the patterns that weren't used\n let\n namesFromPattern =\n findNamesFromPattern pattern\n\n ( unusedPatterns, unmatchedUsed ) =\n findUnused namesFromPattern scope\n\n newScopes =\n case parentScopes of\n head :: tail ->\n ( unmatchedUsed ++ head, tail )\n\n [] ->\n ( unmatched, [] )\n in\n ( List.map errorForUnused unusedPatterns, newScopes )\n\nFor convenience, the entire case expression is passed as the first argument.\n\n","type":"(Elm.Syntax.Node.Node Elm.Syntax.Expression.CaseBlock -> ( Elm.Syntax.Node.Node Elm.Syntax.Pattern.Pattern, Elm.Syntax.Node.Node Elm.Syntax.Expression.Expression ) -> moduleContext -> ( List.List (Review.Rule.Error {}), moduleContext )) -> Review.Rule.ModuleRuleSchema schemaState moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } moduleContext"},{"name":"withCaseBranchExitVisitor","comment":" Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will visit the module's\ncase branches when exiting the branch.\n\nSee the documentation for [`withCaseBranchEnterVisitor`](#withCaseBranchEnterVisitor) for explanations and an example.\n\n","type":"(Elm.Syntax.Node.Node Elm.Syntax.Expression.CaseBlock -> ( Elm.Syntax.Node.Node Elm.Syntax.Pattern.Pattern, Elm.Syntax.Node.Node Elm.Syntax.Expression.Expression ) -> moduleContext -> ( List.List (Review.Rule.Error {}), moduleContext )) -> Review.Rule.ModuleRuleSchema schemaState moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } moduleContext"},{"name":"withCommentsVisitor","comment":" Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will visit the module's comments, collect data in\nthe `context` and/or report patterns.\n\nThis visitor will give you access to the list of comments (in source order) in\nthe module all at once. Note that comments that are parsed as documentation comments by\n[`elm-syntax`](https://package.elm-lang.org/packages/stil4m/elm-syntax/latest/)\nare not included in this list.\n\nAs such, the following comments are included (✅) / excluded (❌):\n\n - ✅ Module documentation (`{-| -}`)\n - ✅ Port documentation comments (`{-| -}`)\n - ✅ Top-level comments not internal to a function/type/etc.\n - ✅ Comments internal to a function/type/etc.\n - ❌ Function/type/type alias documentation comments (`{-| -}`)\n\nTip: If you do not need to collect data in this visitor, you may wish to use the\nsimpler [`withSimpleCommentsVisitor`](#withSimpleCommentsVisitor) function.\n\nTip: If you only need to access the module documentation, you should use\n[`withModuleDocumentationVisitor`](#withModuleDocumentationVisitor) instead.\n\n","type":"(List.List (Elm.Syntax.Node.Node String.String) -> moduleContext -> ( List.List (Review.Rule.Error {}), moduleContext )) -> Review.Rule.ModuleRuleSchema schemaState moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } moduleContext"},{"name":"withContextFromImportedModules","comment":" Allows the rule to have access to the context of the modules imported by the\ncurrently visited module. You can use for instance to know what is exposed in a\ndifferent module.\n\nWhen you finish analyzing a module, the `moduleContext` is turned into a `projectContext`\nthrough [`fromModuleToProject`](#newProjectRuleSchema). Before analyzing a module,\nthe `projectContext`s of its imported modules get folded into a single one\nstarting with the initial context (that may have visited the\n[`elm.json` file](#withElmJsonProjectVisitor) and/or the [project's dependencies](#withDependenciesProjectVisitor))\nusing [`foldProjectContexts`](#newProjectRuleSchema).\n\nIf there is information about another module that you wish to access, you should\ntherefore store it in the `moduleContext`, and have it persist when transitioning\nto a `projectContext` and back to a `moduleContext`.\n\nYou can only access data from imported modules, not from modules that import the\ncurrent module. If you need to do so, I suggest collecting all the information\nyou need, and re-evaluate if from [the final project evaluation function](#withFinalProjectEvaluation).\n\nIf you don't use this function, you will only be able to access the contents of\nthe initial context. The benefit is that when re-analyzing the project, after a\nfix or when a file was changed in watch mode, much less work will need to be done\nand the analysis will be much faster, because we know other files won't influence\nthe results of other modules' analysis.\n\n","type":"Review.Rule.ProjectRuleSchema schemaState projectContext moduleContext -> Review.Rule.ProjectRuleSchema schemaState projectContext moduleContext"},{"name":"withDataExtractor","comment":" Extract arbitrary data from the codebase, which can be accessed by running\n\n```bash\nelm-review --report=json --extract\n```\n\nand by reading the value at `<output>.extracts[\"YourRuleName\"]` in the output.\n\n import Json.Encode\n import Review.Rule as Rule exposing (Rule)\n\n rule : Rule\n rule =\n Rule.newProjectRuleSchema \"Some.Rule.Name\" initialContext\n -- visitors to collect information...\n |> Rule.withDataExtractor dataExtractor\n |> Rule.fromProjectRuleSchema\n\n dataExtractor : ProjectContext -> Json.Encode.Value\n dataExtractor projectContext =\n Json.Encode.list\n (\\thing ->\n Json.Encode.object\n [ ( \"name\", Json.Encode.string thing.name )\n , ( \"value\", Json.Encode.int thing.value )\n ]\n )\n projectContext.things\n\n","type":"(projectContext -> Json.Encode.Value) -> Review.Rule.ProjectRuleSchema schemaState projectContext moduleContext -> Review.Rule.ProjectRuleSchema schemaState projectContext moduleContext"},{"name":"withDeclarationEnterVisitor","comment":" Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will visit the module's\n[declaration statements](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Declaration)\n(`someVar = add 1 2`, `type Bool = True | False`, `port output : Json.Encode.Value -> Cmd msg`),\ncollect data and/or report patterns. The declarations will be visited in the order of their definition.\n\nThe following example forbids exposing a function or a value without it having a\ntype annotation.\n\n import Elm.Syntax.Declaration as Declaration exposing (Declaration)\n import Elm.Syntax.Exposing as Exposing\n import Elm.Syntax.Module as Module exposing (Module)\n import Elm.Syntax.Node as Node exposing (Node)\n import Review.Rule as Rule exposing (Rule)\n\n type ExposedFunctions\n = All\n | OnlySome (List String)\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"NoMissingDocumentationForExposedFunctions\" (OnlySome [])\n |> Rule.withModuleDefinitionVisitor moduleDefinitionVisitor\n |> Rule.withDeclarationEnterVisitor declarationVisitor\n |> Rule.fromModuleRuleSchema\n\n moduleDefinitionVisitor : Node Module -> ExposedFunctions -> ( List (Rule.Error {}), ExposedFunctions )\n moduleDefinitionVisitor node context =\n case Node.value node |> Module.exposingList of\n Exposing.All _ ->\n ( [], All )\n\n Exposing.Explicit exposedValues ->\n ( [], OnlySome (List.filterMap exposedFunctionName exposedValues) )\n\n exposedFunctionName : Node Exposing.TopLevelExpose -> Maybe String\n exposedFunctionName value =\n case Node.value value of\n Exposing.FunctionExpose functionName ->\n Just functionName\n\n _ ->\n Nothing\n\n declarationVisitor : Node Declaration -> ExposedFunctions -> ( List (Rule.Error {}), ExposedFunctions )\n declarationVisitor node direction context =\n case Node.value node of\n Declaration.FunctionDeclaration { documentation, declaration } ->\n let\n functionName : String\n functionName =\n Node.value declaration |> .name |> Node.value\n in\n if documentation == Nothing && isExposed context functionName then\n ( [ Rule.error\n { message = \"Exposed function \" ++ functionName ++ \" is missing a type annotation\"\n , details =\n [ \"Type annotations are very helpful for people who use the module. It can give a lot of information without having to read the contents of the function.\"\n , \"To add a type annotation, add a line like `\" functionName ++ \" : ()`, and replace the `()` by the type of the function. If you don't replace `()`, the compiler should give you a suggestion of what the type should be.\"\n ]\n }\n (Node.range node)\n ]\n , context\n )\n\n else\n ( [], context )\n\n _ ->\n ( [], context )\n\n isExposed : ExposedFunctions -> String -> Bool\n isExposed exposedFunctions name =\n case exposedFunctions of\n All ->\n True\n\n OnlySome exposedList ->\n List.member name exposedList\n\nTip: If you do not need to collect or use the `context` in this visitor, you may wish to use the\nsimpler [`withSimpleDeclarationVisitor`](#withSimpleDeclarationVisitor) function.\n\n","type":"(Elm.Syntax.Node.Node Elm.Syntax.Declaration.Declaration -> moduleContext -> ( List.List (Review.Rule.Error {}), moduleContext )) -> Review.Rule.ModuleRuleSchema schemaState moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } moduleContext"},{"name":"withDeclarationExitVisitor","comment":" Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will visit the module's\n[declaration statements](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Declaration)\n(`someVar = add 1 2`, `type Bool = True | False`, `port output : Json.Encode.Value -> Cmd msg`),\ncollect data and/or report patterns. The declarations will be visited in the order of their definition.\n\nThe following example reports unused parameters from top-level declarations.\n\n import Elm.Syntax.Declaration as Declaration exposing (Declaration)\n import Elm.Syntax.Expression as Expression exposing (Expression)\n import Elm.Syntax.Node as Node exposing (Node)\n import Review.Rule as Rule exposing (Rule)\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"NoDebugEvenIfImported\" DebugLogWasNotImported\n |> Rule.withDeclarationEnterVisitor declarationEnterVisitor\n |> Rule.withDeclarationExitVisitor declarationExitVisitor\n -- Omitted, but this marks parameters as used\n |> Rule.withExpressionEnterVisitor expressionVisitor\n |> Rule.fromModuleRuleSchema\n\n declarationEnterVisitor : Node Declaration -> Context -> ( List (Rule.Error {}), Context )\n declarationEnterVisitor node context =\n case Node.value node of\n Declaration.FunctionDeclaration function ->\n ( [], registerArguments context function )\n\n _ ->\n ( [], context )\n\n declarationExitVisitor : Node Declaration -> Context -> ( List (Rule.Error {}), Context )\n declarationExitVisitor node context =\n case Node.value node of\n -- When exiting the function expression, report the parameters that were not used.\n Declaration.FunctionDeclaration function ->\n ( unusedParameters context |> List.map createError, removeArguments context )\n\n _ ->\n ( [], context )\n\n","type":"(Elm.Syntax.Node.Node Elm.Syntax.Declaration.Declaration -> moduleContext -> ( List.List (Review.Rule.Error {}), moduleContext )) -> Review.Rule.ModuleRuleSchema schemaState moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } moduleContext"},{"name":"withDeclarationListVisitor","comment":" Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will visit the module's\n[declaration statements](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Declaration)\n(`someVar = add 1 2`, `type Bool = True | False`, `port output : Json.Encode.Value -> Cmd msg`),\nto collect data and/or report patterns. The declarations will be in the same\norder that they appear in the source code.\n\nIt is similar to [withDeclarationVisitor](#withDeclarationVisitor), but the\nvisitor used with this function is called before the visitor added with\n[withDeclarationVisitor](#withDeclarationVisitor). You can use this visitor in\norder to look ahead and add the module's types and variables into your context,\nbefore visiting the contents of the module using [withDeclarationVisitor](#withDeclarationVisitor)\nand [withExpressionEnterVisitor](#withExpressionEnterVisitor). Otherwise, using\n[withDeclarationVisitor](#withDeclarationVisitor) is probably a simpler choice.\n\n","type":"(List.List (Elm.Syntax.Node.Node Elm.Syntax.Declaration.Declaration) -> moduleContext -> ( List.List (Review.Rule.Error {}), moduleContext )) -> Review.Rule.ModuleRuleSchema schemaState moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } moduleContext"},{"name":"withDeclarationVisitor","comment":" **@deprecated**\n\nUse [`withDeclarationEnterVisitor`](#withDeclarationEnterVisitor) and [`withDeclarationExitVisitor`](#withDeclarationExitVisitor) instead.\nIn the next major version, this function will be removed and [`withDeclarationEnterVisitor`](#withDeclarationEnterVisitor) will be renamed to `withDeclarationVisitor`.\n\n**/@deprecated**\n\nAdd a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will visit the module's\n[declaration statements](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Declaration)\n(`someVar = add 1 2`, `type Bool = True | False`, `port output : Json.Encode.Value -> Cmd msg`),\ncollect data and/or report patterns. The declarations will be visited in the order of their definition.\n\nContrary to [`withSimpleDeclarationVisitor`](#withSimpleDeclarationVisitor), the\nvisitor function will be called twice with different [`Direction`](#Direction)\nvalues. It will be visited with `OnEnter`, then the children will be visited,\nand then it will be visited again with `OnExit`. If you do not check the value of\nthe `Direction` parameter, you might end up with duplicate errors and/or an\nunexpected `moduleContext`. Read more about [`Direction` here](#Direction).\n\nThe following example forbids exposing a function or a value without it having a\ntype annotation.\n\n import Elm.Syntax.Declaration as Declaration exposing (Declaration)\n import Elm.Syntax.Exposing as Exposing\n import Elm.Syntax.Module as Module exposing (Module)\n import Elm.Syntax.Node as Node exposing (Node)\n import Review.Rule as Rule exposing (Rule)\n\n type ExposedFunctions\n = All\n | OnlySome (List String)\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"NoMissingDocumentationForExposedFunctions\" (OnlySome [])\n |> Rule.withModuleDefinitionVisitor moduleDefinitionVisitor\n |> Rule.withDeclarationVisitor declarationVisitor\n |> Rule.fromModuleRuleSchema\n\n moduleDefinitionVisitor : Node Module -> ExposedFunctions -> ( List (Rule.Error {}), ExposedFunctions )\n moduleDefinitionVisitor node context =\n case Node.value node |> Module.exposingList of\n Exposing.All _ ->\n ( [], All )\n\n Exposing.Explicit exposedValues ->\n ( [], OnlySome (List.filterMap exposedFunctionName exposedValues) )\n\n exposedFunctionName : Node Exposing.TopLevelExpose -> Maybe String\n exposedFunctionName value =\n case Node.value value of\n Exposing.FunctionExpose functionName ->\n Just functionName\n\n _ ->\n Nothing\n\n declarationVisitor : Node Declaration -> Rule.Direction -> ExposedFunctions -> ( List (Rule.Error {}), ExposedFunctions )\n declarationVisitor node direction context =\n case ( direction, Node.value node ) of\n ( Rule.OnEnter, Declaration.FunctionDeclaration { documentation, declaration } ) ->\n let\n functionName : String\n functionName =\n Node.value declaration |> .name |> Node.value\n in\n if documentation == Nothing && isExposed context functionName then\n ( [ Rule.error\n { message = \"Exposed function \" ++ functionName ++ \" is missing a type annotation\"\n , details =\n [ \"Type annotations are very helpful for people who use the module. It can give a lot of information without having to read the contents of the function.\"\n , \"To add a type annotation, add a line like `\" functionName ++ \" : ()`, and replace the `()` by the type of the function. If you don't replace `()`, the compiler should give you a suggestion of what the type should be.\"\n ]\n }\n (Node.range node)\n ]\n , context\n )\n\n else\n ( [], context )\n\n _ ->\n ( [], context )\n\n isExposed : ExposedFunctions -> String -> Bool\n isExposed exposedFunctions name =\n case exposedFunctions of\n All ->\n True\n\n OnlySome exposedList ->\n List.member name exposedList\n\nTip: If you do not need to collect or use the `context` in this visitor, you may wish to use the\nsimpler [`withSimpleDeclarationVisitor`](#withSimpleDeclarationVisitor) function.\n\n","type":"(Elm.Syntax.Node.Node Elm.Syntax.Declaration.Declaration -> Review.Rule.Direction -> moduleContext -> ( List.List (Review.Rule.Error {}), moduleContext )) -> Review.Rule.ModuleRuleSchema schemaState moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } moduleContext"},{"name":"withDependenciesModuleVisitor","comment":" Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will examine the project's\n[dependencies](./Review-Project-Dependency).\n\nYou can use this look at the modules contained in dependencies, which can make the rule very precise when it targets\nspecific functions.\n\n","type":"(Dict.Dict String.String Review.Project.Dependency.Dependency -> moduleContext -> moduleContext) -> Review.Rule.ModuleRuleSchema { schemaState | canCollectProjectData : () } moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | canCollectProjectData : () } moduleContext"},{"name":"withDependenciesProjectVisitor","comment":" Add a visitor to the [`ProjectRuleSchema`](#ProjectRuleSchema) which will examine the project's\n[dependencies](./Review-Project-Dependency).\n\nIt works exactly like [`withDependenciesModuleVisitor`](#withDependenciesModuleVisitor). The visitor will be called before any\nmodule is evaluated.\n\n","type":"(Dict.Dict String.String Review.Project.Dependency.Dependency -> projectContext -> ( List.List (Review.Rule.Error { useErrorForModule : () }), projectContext )) -> Review.Rule.ProjectRuleSchema schemaState projectContext moduleContext -> Review.Rule.ProjectRuleSchema { schemaState | hasAtLeastOneVisitor : () } projectContext moduleContext"},{"name":"withDirectDependenciesModuleVisitor","comment":" Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will examine the project's\ndirect [dependencies](./Review-Project-Dependency).\n\nYou can use this look at the modules contained in dependencies, which can make the rule very precise when it targets\nspecific functions.\n\n","type":"(Dict.Dict String.String Review.Project.Dependency.Dependency -> moduleContext -> moduleContext) -> Review.Rule.ModuleRuleSchema { schemaState | canCollectProjectData : () } moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | canCollectProjectData : () } moduleContext"},{"name":"withDirectDependenciesProjectVisitor","comment":" Add a visitor to the [`ProjectRuleSchema`](#ProjectRuleSchema) which will examine the project's\ndirect [dependencies](./Review-Project-Dependency).\n\nIt works exactly like [`withDependenciesModuleVisitor`](#withDependenciesModuleVisitor). The visitor will be called before any\nmodule is evaluated.\n\n","type":"(Dict.Dict String.String Review.Project.Dependency.Dependency -> projectContext -> ( List.List (Review.Rule.Error { useErrorForModule : () }), projectContext )) -> Review.Rule.ProjectRuleSchema schemaState projectContext moduleContext -> Review.Rule.ProjectRuleSchema { schemaState | hasAtLeastOneVisitor : () } projectContext moduleContext"},{"name":"withElmJsonModuleVisitor","comment":" Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will visit the project's\n[`elm.json`](https://package.elm-lang.org/packages/elm/project-metadata-utils/latest/Elm-Project) file.\n\nThe following example forbids exposing a module in an \"Internal\" directory in your `elm.json` file.\n\n import Elm.Module\n import Elm.Project\n import Elm.Syntax.Module as Module exposing (Module)\n import Elm.Syntax.Node as Node exposing (Node)\n import Review.Rule as Rule exposing (Rule)\n\n type alias Context =\n Maybe Elm.Project.Project\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"DoNoExposeInternalModules\" Nothing\n |> Rule.withElmJsonModuleVisitor elmJsonVisitor\n |> Rule.withModuleDefinitionVisitor moduleDefinitionVisitor\n |> Rule.fromModuleRuleSchema\n\n elmJsonVisitor : Maybe Elm.Project.Project -> Context -> Context\n elmJsonVisitor elmJson context =\n elmJson\n\n moduleDefinitionVisitor : Node Module -> Context -> ( List (Rule.Error {}), Context )\n moduleDefinitionVisitor node context =\n let\n moduleName : List String\n moduleName =\n Node.value node |> Module.moduleName\n in\n if List.member \"Internal\" moduleName then\n case context of\n Just (Elm.Project.Package { exposed }) ->\n let\n exposedModules : List String\n exposedModules =\n case exposed of\n Elm.Project.ExposedList names ->\n names\n |> List.map Elm.Module.toString\n\n Elm.Project.ExposedDict fakeDict ->\n fakeDict\n |> List.concatMap Tuple.second\n |> List.map Elm.Module.toString\n in\n if List.member (String.join \".\" moduleName) exposedModules then\n ( [ Rule.error \"Do not expose modules in `Internal` as part of the public API\" (Node.range node) ], context )\n\n else\n ( [], context )\n\n _ ->\n ( [], context )\n\n else\n ( [], context )\n\n","type":"(Maybe.Maybe Elm.Project.Project -> moduleContext -> moduleContext) -> Review.Rule.ModuleRuleSchema { schemaState | canCollectProjectData : () } moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | canCollectProjectData : () } moduleContext"},{"name":"withElmJsonProjectVisitor","comment":" Add a visitor to the [`ProjectRuleSchema`](#ProjectRuleSchema) which will visit the project's\n[`elm.json`](https://package.elm-lang.org/packages/elm/project-metadata-utils/latest/Elm-Project) file.\n\nIt works exactly like [`withElmJsonModuleVisitor`](#withElmJsonModuleVisitor).\nThe visitor will be called before any module is evaluated.\n\n","type":"(Maybe.Maybe { elmJsonKey : Review.Rule.ElmJsonKey, project : Elm.Project.Project } -> projectContext -> ( List.List (Review.Rule.Error { useErrorForModule : () }), projectContext )) -> Review.Rule.ProjectRuleSchema schemaState projectContext moduleContext -> Review.Rule.ProjectRuleSchema { schemaState | hasAtLeastOneVisitor : () } projectContext moduleContext"},{"name":"withExpressionEnterVisitor","comment":" Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will visit the module's\n[expressions](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Expression)\n(`1`, `True`, `add 1 2`, `1 + 2`), collect data in the `context` and/or report patterns.\nThe expressions are visited in pre-order depth-first search, meaning that an\nexpression will be visited, then its first child, the first child's children\n(and so on), then the second child (and so on).\n\nContrary to [`withExpressionVisitor`](#withExpressionVisitor), the\nvisitor function will be called only once, when the expression is \"entered\",\nmeaning before its children are visited.\n\nThe following example forbids the use of `Debug.log` even when it is imported like\n`import Debug exposing (log)`.\n\n import Elm.Syntax.Exposing as Exposing exposing (TopLevelExpose)\n import Elm.Syntax.Expression as Expression exposing (Expression)\n import Elm.Syntax.Import exposing (Import)\n import Elm.Syntax.Node as Node exposing (Node)\n import Review.Rule as Rule exposing (Rule)\n\n type Context\n = DebugLogWasNotImported\n | DebugLogWasImported\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"NoDebugEvenIfImported\" DebugLogWasNotImported\n |> Rule.withImportVisitor importVisitor\n |> Rule.withExpressionEnterVisitor expressionVisitor\n |> Rule.fromModuleRuleSchema\n\n importVisitor : Node Import -> Context -> ( List (Rule.Error {}), Context )\n importVisitor node context =\n case ( Node.value node |> .moduleName |> Node.value, (Node.value node).exposingList |> Maybe.map Node.value ) of\n ( [ \"Debug\" ], Just (Exposing.All _) ) ->\n ( [], DebugLogWasImported )\n\n ( [ \"Debug\" ], Just (Exposing.Explicit exposedFunctions) ) ->\n let\n isLogFunction : Node Exposing.TopLevelExpose -> Bool\n isLogFunction exposeNode =\n case Node.value exposeNode of\n Exposing.FunctionExpose \"log\" ->\n True\n\n _ ->\n False\n in\n if List.any isLogFunction exposedFunctions then\n ( [], DebugLogWasImported )\n\n else\n ( [], DebugLogWasNotImported )\n\n _ ->\n ( [], DebugLogWasNotImported )\n\n expressionVisitor : Node Expression -> Context -> ( List (Rule.Error {}), Context )\n expressionVisitor node context =\n case context of\n DebugLogWasNotImported ->\n ( [], context )\n\n DebugLogWasImported ->\n case Node.value node of\n Expression.FunctionOrValue [] \"log\" ->\n ( [ Rule.error\n { message = \"Remove the use of `Debug` before shipping to production\"\n , details = [ \"The `Debug` module 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.\" ]\n }\n (Node.range node)\n ]\n , context\n )\n\n _ ->\n ( [], context )\n\nTip: If you do not need to collect or use the `context` in this visitor, you may wish to use the\nsimpler [`withSimpleExpressionVisitor`](#withSimpleExpressionVisitor) function.\n\n","type":"(Elm.Syntax.Node.Node Elm.Syntax.Expression.Expression -> moduleContext -> ( List.List (Review.Rule.Error {}), moduleContext )) -> Review.Rule.ModuleRuleSchema schemaState moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } moduleContext"},{"name":"withExpressionExitVisitor","comment":" Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will visit the module's\n[expressions](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Expression)\n(`1`, `True`, `add 1 2`, `1 + 2`), collect data in the `context` and/or report patterns.\nThe expressions are visited in pre-order depth-first search, meaning that an\nexpression will be visited, then its first child, the first child's children\n(and so on), then the second child (and so on).\n\nContrary to [`withExpressionEnterVisitor`](#withExpressionEnterVisitor), the\nvisitor function will be called when the expression is \"exited\",\nmeaning after its children are visited.\n\n import Elm.Syntax.Expression as Expression exposing (Expression)\n import Elm.Syntax.Node as Node exposing (Node)\n import Review.Rule as Rule exposing (Rule)\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"NoDebugEvenIfImported\" DebugLogWasNotImported\n |> Rule.withExpressionEnterVisitor expressionEnterVisitor\n |> Rule.withExpressionExitVisitor expressionExitVisitor\n |> Rule.fromModuleRuleSchema\n\n expressionEnterVisitor : Node Expression -> Context -> ( List (Rule.Error {}), Context )\n expressionEnterVisitor node context =\n case Node.value node of\n Expression.FunctionOrValue moduleName name ->\n ( [], markVariableAsUsed context name )\n\n -- Find variables declared in let expression\n Expression.LetExpression letBlock ->\n ( [], registerVariables context letBlock )\n\n _ ->\n ( [], context )\n\n expressionExitVisitor : Node Expression -> Context -> ( List (Rule.Error {}), Context )\n expressionExitVisitor node context =\n case Node.value node of\n -- When exiting the let expression, report the variables that were not used.\n Expression.LetExpression _ ->\n ( unusedVariables context |> List.map createError, removeVariables context )\n\n _ ->\n ( [], context )\n\n","type":"(Elm.Syntax.Node.Node Elm.Syntax.Expression.Expression -> moduleContext -> ( List.List (Review.Rule.Error {}), moduleContext )) -> Review.Rule.ModuleRuleSchema schemaState moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } moduleContext"},{"name":"withExpressionVisitor","comment":" **@deprecated**\n\nUse [`withExpressionEnterVisitor`](#withExpressionEnterVisitor) and [`withExpressionExitVisitor`](#withExpressionExitVisitor) instead.\nIn the next major version, this function will be removed and [`withExpressionEnterVisitor`](#withExpressionEnterVisitor) will be renamed to `withExpressionVisitor`.\n\n**/@deprecated**\n\nAdd a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will visit the module's\n[expressions](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Expression)\n(`1`, `True`, `add 1 2`, `1 + 2`), collect data in the `context` and/or report patterns.\nThe expressions are visited in pre-order depth-first search, meaning that an\nexpression will be visited, then its first child, the first child's children\n(and so on), then the second child (and so on).\n\nContrary to [`withSimpleExpressionVisitor`](#withSimpleExpressionVisitor), the\nvisitor function will be called twice with different [`Direction`](#Direction)\nvalues. It will be visited with `OnEnter`, then the children will be visited,\nand then it will be visited again with `OnExit`. If you do not check the value of\nthe `Direction` parameter, you might end up with duplicate errors and/or an\nunexpected `moduleContext`. Read more about [`Direction` here](#Direction).\n\nThe following example forbids the use of `Debug.log` even when it is imported like\n`import Debug exposing (log)`.\n\n import Elm.Syntax.Exposing as Exposing exposing (TopLevelExpose)\n import Elm.Syntax.Expression as Expression exposing (Expression)\n import Elm.Syntax.Import exposing (Import)\n import Elm.Syntax.Node as Node exposing (Node)\n import Review.Rule as Rule exposing (Rule)\n\n type Context\n = DebugLogWasNotImported\n | DebugLogWasImported\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"NoDebugEvenIfImported\" DebugLogWasNotImported\n |> Rule.withImportVisitor importVisitor\n |> Rule.withExpressionVisitor expressionVisitor\n |> Rule.fromModuleRuleSchema\n\n importVisitor : Node Import -> Context -> ( List (Rule.Error {}), Context )\n importVisitor node context =\n case ( Node.value node |> .moduleName |> Node.value, (Node.value node).exposingList |> Maybe.map Node.value ) of\n ( [ \"Debug\" ], Just (Exposing.All _) ) ->\n ( [], DebugLogWasImported )\n\n ( [ \"Debug\" ], Just (Exposing.Explicit exposedFunctions) ) ->\n let\n isLogFunction : Node Exposing.TopLevelExpose -> Bool\n isLogFunction exposeNode =\n case Node.value exposeNode of\n Exposing.FunctionExpose \"log\" ->\n True\n\n _ ->\n False\n in\n if List.any isLogFunction exposedFunctions then\n ( [], DebugLogWasImported )\n\n else\n ( [], DebugLogWasNotImported )\n\n _ ->\n ( [], DebugLogWasNotImported )\n\n expressionVisitor : Node Expression -> Rule.Direction -> Context -> ( List (Error {}), Context )\n expressionVisitor node direction context =\n case context of\n DebugLogWasNotImported ->\n ( [], context )\n\n DebugLogWasImported ->\n case ( direction, Node.value node ) of\n ( Rule.OnEnter, Expression.FunctionOrValue [] \"log\" ) ->\n ( [ Rule.error\n { message = \"Remove the use of `Debug` before shipping to production\"\n , details = [ \"The `Debug` module 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.\" ]\n }\n (Node.range node)\n ]\n , context\n )\n\n _ ->\n ( [], context )\n\nTip: If you do not need to collect or use the `context` in this visitor, you may wish to use the\nsimpler [`withSimpleExpressionVisitor`](#withSimpleExpressionVisitor) function.\n\n","type":"(Elm.Syntax.Node.Node Elm.Syntax.Expression.Expression -> Review.Rule.Direction -> moduleContext -> ( List.List (Review.Rule.Error {}), moduleContext )) -> Review.Rule.ModuleRuleSchema schemaState moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } moduleContext"},{"name":"withExtraFilesModuleVisitor","comment":" Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) to visit files that `elm-review`\ndoesn't analyze by default.\n\nThe visitor function will be called with all the files matching the file patterns.\n\nThe following example rule reads a project's `.css` files to extract all the mentioned CSS classes,\nthen finds calls to `Html.Attributes.class` in the Elm code (such as `Html.Attributes.class \"big-red-button\"`)\nand reports errors when the classes given as argument are unknown.\n\n import Dict exposing (Dict)\n import Elm.Syntax.Expression as Expression exposing (Expression)\n import Elm.Syntax.Node as Node exposing (Node)\n import Elm.Syntax.Range exposing (Range)\n import Regex exposing (Regex)\n import Review.FilePattern as FilePattern\n import Review.Rule as Rule exposing (Rule)\n import Set exposing (Set)\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"Css.NoUnknownCssClasses\" initialContext\n |> Rule.withExtraFilesModuleVisitor cssFilesVisitor\n [ FilePattern.include \"**/*.css\" ]\n |> Rule.withExpressionEnterVisitor expressionVisitor\n |> Rule.fromModuleRuleSchema\n\n type alias Context =\n { knownCssClasses : Set String\n }\n\n initialContext : Context\n initialContext =\n { knownCssClasses = Set.empty\n }\n\n cssClassRegex : Regex\n cssClassRegex =\n Regex.fromString \"\\\\.([\\\\w-_]+)\"\n |> Maybe.withDefault Regex.never\n\n cssFilesVisitor : Dict String String -> Context -> Context\n cssFilesVisitor files context =\n { knownCssClasses =\n files\n |> Dict.values\n |> List.concatMap (\\cssSource -> Regex.find cssClassRegex cssSource)\n |> List.map (\\m -> String.dropLeft 1 m.match)\n |> Set.fromList\n }\n\n expressionVisitor : Node Expression -> Context -> ( List (Rule.Error {}), Context )\n expressionVisitor node context =\n case Node.value node of\n Expression.Application [ function, firstArg ] ->\n case Node.value function of\n Expression.FunctionOrValue [ \"Html\", \"Attributes\" ] \"class\" ->\n case Node.value firstArg of\n Expression.Literal stringLiteral ->\n ( stringLiteral\n |> String.split \" \"\n |> List.filterMap (checkForUnknownCssClass context.knownCssClasses (Node.range firstArg))\n , context\n )\n\n _ ->\n ( [], context )\n\n _ ->\n ( [], context )\n\n _ ->\n ( [], context )\n\n checkForUnknownCssClass : Set String -> Range -> String -> Maybe (Rule.Error {})\n checkForUnknownCssClass knownCssClasses range class =\n if Set.member class knownCssClasses then\n Nothing\n\n else\n Just\n (Rule.error\n { message = \"Unknown CSS class \" ++ class\n , details =\n [ \"This CSS class does not appear in the project's `.css` files.\"\n , \"Could it be that you misspelled the name of the class, or that the class recently got removed?\"\n ]\n }\n range\n )\n\n","type":"(Dict.Dict String.String String.String -> moduleContext -> moduleContext) -> List.List Review.FilePattern.FilePattern -> Review.Rule.ModuleRuleSchema { schemaState | canCollectProjectData : () } moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | canCollectProjectData : () } moduleContext"},{"name":"withExtraFilesProjectVisitor","comment":" Add a visitor to the [`ProjectRuleSchema`](#ProjectRuleSchema) to visit files that `elm-review`\ndoesn't analyze by default.\n\nThe visitor function will be called with all the files matching the file patterns.\n\nThe following example rule reads a project's `.css` files to extract all the mentioned CSS classes,\nthen finds calls to `Html.Attributes.class` in the Elm code (such as `Html.Attributes.class \"big-red-button\"`)\nand reports errors when the classes given as argument are unknown.\n\n import Dict exposing (Dict)\n import Elm.Syntax.Expression as Expression exposing (Expression)\n import Elm.Syntax.Node as Node exposing (Node)\n import Elm.Syntax.Range exposing (Range)\n import Regex exposing (Regex)\n import Review.FilePattern as FilePattern\n import Review.Rule as Rule exposing (Rule)\n import Set exposing (Set)\n\n rule : Rule\n rule =\n Rule.newProjectRuleSchema \"NoUnusedCssClasses\" initialProjectContext\n |> Rule.withExtraFilesProjectVisitor cssFilesVisitor\n [ FilePattern.include \"**/*.css\" ]\n |> Rule.withModuleVisitor moduleVisitor\n |> Rule.withModuleContextUsingContextCreator\n { fromProjectToModule = fromProjectToModule\n , fromModuleToProject = fromModuleToProject\n , foldProjectContexts = foldProjectContexts\n }\n |> Rule.withFinalProjectEvaluation finalEvaluation\n |> Rule.fromProjectRuleSchema\n\n moduleVisitor : Rule.ModuleRuleSchema {} ModuleContext -> Rule.ModuleRuleSchema { hasAtLeastOneVisitor : () } ModuleContext\n moduleVisitor schema =\n schema\n |> Rule.withExpressionEnterVisitor expressionVisitor\n\n type alias ProjectContext =\n { cssFiles :\n Dict\n String\n { fileKey : Rule.ExtraFileKey\n , classes : Set String\n }\n , usedCssClasses : Set String\n }\n\n type alias ModuleContext =\n { usedCssClasses : Set String\n }\n\n initialProjectContext : ProjectContext\n initialProjectContext =\n { cssFiles = Dict.empty\n , usedCssClasses = Set.empty\n }\n\n fromProjectToModule : Rule.ContextCreator ProjectContext ModuleContext\n fromProjectToModule =\n Rule.initContextCreator (\\_ -> { usedCssClasses = Set.empty })\n\n fromModuleToProject : Rule.ContextCreator ModuleContext ProjectContext\n fromModuleToProject =\n Rule.initContextCreator\n (\\{ usedCssClasses } ->\n { cssFiles = Dict.empty\n , usedCssClasses = usedCssClasses\n }\n )\n\n foldProjectContexts : ProjectContext -> ProjectContext -> ProjectContext\n foldProjectContexts newContext previousContext =\n { cssFiles = previousContext.cssFiles\n , usedCssClasses = Set.union newContext.usedCssClasses previousContext.usedCssClasses\n }\n\n cssClassRegex : Regex\n cssClassRegex =\n Regex.fromString \"\\\\.([\\\\w-_]+)\"\n |> Maybe.withDefault Regex.never\n\n cssFilesVisitor : Dict String { fileKey : Rule.ExtraFileKey, content : String } -> ProjectContext -> ( List (Rule.Error { useErrorForModule : () }), ProjectContext )\n cssFilesVisitor files context =\n ( []\n , { context\n | cssFiles =\n Dict.map\n (\\_ { fileKey, content } ->\n { fileKey = fileKey\n , classes =\n Regex.find cssClassRegex content\n |> List.map (\\m -> String.dropLeft 1 m.match)\n |> Set.fromList\n }\n )\n files\n }\n )\n\n expressionVisitor : Node Expression -> ModuleContext -> ( List (Rule.Error {}), ModuleContext )\n expressionVisitor node context =\n case Node.value node of\n Expression.Application [ function, firstArg ] ->\n case Node.value function of\n Expression.FunctionOrValue [ \"Html\", \"Attributes\" ] \"class\" ->\n case Node.value firstArg of\n Expression.Literal stringLiteral ->\n let\n usedCssClasses : List String\n usedCssClasses =\n String.split \" \" stringLiteral\n in\n ( []\n , { context | usedCssClasses = List.foldl Set.insert context.usedCssClasses usedCssClasses }\n )\n\n _ ->\n ( [], context )\n\n _ ->\n ( [], context )\n\n _ ->\n ( [], context )\n\n finalEvaluation : ProjectContext -> List (Rule.Error { useErrorForModule : () })\n finalEvaluation context =\n context.cssFiles\n |> Dict.toList\n |> List.filterMap (\\( filePath, file ) -> reportUnusedClasses context.usedCssClasses filePath file)\n\n reportUnusedClasses : Set String -> String -> { a | fileKey : Rule.ExtraFileKey, classes : Set String } -> Maybe (Rule.Error { useErrorForModule : () })\n reportUnusedClasses usedCssClasses filePath { fileKey, classes } =\n let\n unusedClasses : Set String\n unusedClasses =\n Set.diff classes usedCssClasses\n in\n if Set.isEmpty unusedClasses then\n Nothing\n\n else\n Just\n (Rule.errorForExtraFile fileKey\n { message = \"Found unused CSS classes in \" ++ filePath\n , details =\n [ \"This file declared the usage of some CSS classes for which I could not any usage in the Elm codebase. Please check that no typo was made in the name of the classes, and remove them if they still seem unused.\"\n , \"Here are the classes that seem unused: \" ++ String.join \" \" (Set.toList unusedClasses)\n ]\n }\n { start = { row = 1, column = 1 }, end = { row = 1, column = 100000 } }\n )\n\n","type":"(Dict.Dict String.String { fileKey : Review.Rule.ExtraFileKey, content : String.String } -> projectContext -> ( List.List (Review.Rule.Error { useErrorForModule : () }), projectContext )) -> List.List Review.FilePattern.FilePattern -> Review.Rule.ProjectRuleSchema schemaState projectContext moduleContext -> Review.Rule.ProjectRuleSchema { schemaState | hasAtLeastOneVisitor : () } projectContext moduleContext"},{"name":"withFilePath","comment":" Request the file path for this module, relative to the project's `elm.json`.\n\nUsing [`newModuleRuleSchemaUsingContextCreator`](#newModuleRuleSchemaUsingContextCreator):\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchemaUsingContextCreator \"YourRuleName\" initialContext\n |> Rule.withExpressionEnterVisitor expressionVisitor\n |> Rule.fromModuleRuleSchema\n\n initialContext : Rule.ContextCreator () Context\n initialContext =\n Rule.initContextCreator\n (\\filePath () -> { filePath = filePath })\n |> Rule.withFilePath\n\nUsing [`withModuleContextUsingContextCreator`](#withModuleContextUsingContextCreator) in a project rule:\n\n rule : Rule\n rule =\n Rule.newProjectRuleSchema \"YourRuleName\" initialProjectContext\n |> Rule.withModuleVisitor moduleVisitor\n |> Rule.withModuleContextUsingContextCreator\n { fromProjectToModule = fromProjectToModule\n , fromModuleToProject = fromModuleToProject\n , foldProjectContexts = foldProjectContexts\n }\n\n fromModuleToProject : Rule.ContextCreator () Context\n fromModuleToProject =\n Rule.initContextCreator\n (\\filePath () -> { filePath = filePath })\n |> Rule.withFilePath\n\n","type":"Review.Rule.ContextCreator String.String (from -> to) -> Review.Rule.ContextCreator from to"},{"name":"withFinalModuleEvaluation","comment":" Add a function that makes a final evaluation of the module based only on the\ndata that was collected in the `moduleContext`. This can be useful if you can't or if\nit is hard to determine something as you traverse the module.\n\nThe following example forbids importing both `Element` (`elm-ui`) and\n`Html.Styled` (`elm-css`). Note that this is the same one written in the example\nfor [`withImportVisitor`](#withImportVisitor), but using [`withFinalModuleEvaluation`](#withFinalModuleEvaluation).\n\n import Dict as Dict exposing (Dict)\n import Elm.Syntax.Import exposing (Import)\n import Elm.Syntax.Node as Node exposing (Node)\n import Elm.Syntax.Range exposing (Range)\n import Review.Rule as Rule exposing (Rule)\n\n type alias Context =\n Dict (List String) Range\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"NoUsingBothHtmlAndHtmlStyled\" Dict.empty\n |> Rule.withImportVisitor importVisitor\n |> Rule.withFinalModuleEvaluation finalEvaluation\n |> Rule.fromModuleRuleSchema\n\n importVisitor : Node Import -> Context -> ( List (Rule.Error {}), Context )\n importVisitor node context =\n ( [], Dict.insert (Node.value node |> .moduleName |> Node.value) (Node.range node) context )\n\n finalEvaluation : Context -> List (Rule.Error {})\n finalEvaluation context =\n case ( Dict.get [ \"Element\" ] context, Dict.get [ \"Html\", \"Styled\" ] context ) of\n ( Just elmUiRange, Just _ ) ->\n [ Rule.error\n { message = \"Do not use both `elm-ui` and `elm-css`\"\n , details = [ \"At fruits.com, we use `elm-ui` in the dashboard application, and `elm-css` in the rest of the code. We want to use `elm-ui` in our new projects, but in projects using `elm-css`, we don't want to use both libraries to keep things simple.\" ]\n }\n elmUiRange\n ]\n\n _ ->\n []\n\n","type":"(moduleContext -> List.List (Review.Rule.Error {})) -> Review.Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } moduleContext"},{"name":"withFinalProjectEvaluation","comment":" Add a function that makes a final evaluation of the project based only on the\ndata that was collected in the `projectContext`. This can be useful if you can't report something until you have visited\nall the modules in the project.\n\nIt works similarly [`withFinalModuleEvaluation`](#withFinalModuleEvaluation).\n\n**NOTE**: Do not create errors using the [`error`](#error) function using `withFinalProjectEvaluation`, but using [`errorForModule`](#errorForModule)\ninstead. When the project is evaluated in this function, you are not in the \"context\" of an Elm module (the idiomatic \"context\", not `projectContext` or `moduleContext`).\nThat means that if you call [`error`](#error), we won't know which module to associate the error to.\n\n","type":"(projectContext -> List.List (Review.Rule.Error { useErrorForModule : () })) -> Review.Rule.ProjectRuleSchema schemaState projectContext moduleContext -> Review.Rule.ProjectRuleSchema schemaState projectContext moduleContext"},{"name":"withFullAst","comment":" Request the full [AST](https://en.wikipedia.org/wiki/Abstract_syntax_tree) for the current module.\n\nThis can be useful if you wish to avoid initializing the module context with dummy data future node visits can replace them.\n\nFor instance, if you wish to know what is exposed from a module, you may need to visit the module definition and then\nthe list of declarations. If you need this information earlier on, you will have to provide dummy data at context\ninitialization and store some intermediary data.\n\nUsing the full AST, you can simplify the implementation by computing the data in the context creator, without the use of visitors.\n\n contextCreator : Rule.ContextCreator () Context\n contextCreator =\n Rule.initContextCreator\n (\\ast () ->\n { exposed = collectExposed ast.moduleDefinition ast.declarations\n\n -- ...other fields\n }\n )\n |> Rule.withFullAst\n\n","type":"Review.Rule.ContextCreator Elm.Syntax.File.File (from -> to) -> Review.Rule.ContextCreator from to"},{"name":"withImportVisitor","comment":" Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will visit the module's\n[import statements](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Import)\n(`import Html as H exposing (div)`) in order of their definition, collect data\nin the `context` and/or report patterns.\n\nThe following example forbids importing both `Element` (`elm-ui`) and\n`Html.Styled` (`elm-css`).\n\n import Elm.Syntax.Import exposing (Import)\n import Elm.Syntax.Node as Node exposing (Node)\n import Review.Rule as Rule exposing (Rule)\n\n type alias Context =\n { elmUiWasImported : Bool\n , elmCssWasImported : Bool\n }\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"NoUsingBothHtmlAndHtmlStyled\" initialContext\n |> Rule.withImportVisitor importVisitor\n |> Rule.fromModuleRuleSchema\n\n initialContext : Context\n initialContext =\n { elmUiWasImported = False\n , elmCssWasImported = False\n }\n\n error : Node Import -> Error {}\n error node =\n Rule.error\n { message = \"Do not use both `elm-ui` and `elm-css`\"\n , details = [ \"At fruits.com, we use `elm-ui` in the dashboard application, and `elm-css` in the rest of the code. We want to use `elm-ui` in our new projects, but in projects using `elm-css`, we don't want to use both libraries to keep things simple.\" ]\n }\n (Node.range node)\n\n importVisitor : Node Import -> Context -> ( List (Rule.Error {}), Context )\n importVisitor node context =\n case Node.value node |> .moduleName |> Node.value of\n [ \"Element\" ] ->\n if context.elmCssWasImported then\n ( [ error node ]\n , { context | elmUiWasImported = True }\n )\n\n else\n ( [ error node ]\n , { context | elmUiWasImported = True }\n )\n\n [ \"Html\", \"Styled\" ] ->\n if context.elmUiWasImported then\n ( [ error node ]\n , { context | elmCssWasImported = True }\n )\n\n else\n ( [ error node ]\n , { context | elmCssWasImported = True }\n )\n\n _ ->\n ( [], context )\n\nThis example was written in a different way in the example for [`withFinalModuleEvaluation`](#withFinalModuleEvaluation).\n\nTip: If you do not need to collect or use the `context` in this visitor, you may wish to use the\nsimpler [`withSimpleImportVisitor`](#withSimpleImportVisitor) function.\n\n","type":"(Elm.Syntax.Node.Node Elm.Syntax.Import.Import -> moduleContext -> ( List.List (Review.Rule.Error {}), moduleContext )) -> Review.Rule.ModuleRuleSchema schemaState moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } moduleContext"},{"name":"withIsFileIgnored","comment":" Request to know whether the errors for the current module has been ignored for this particular rule.\nThis may be useful to reduce the amount of work related to ignored files — like collecting unnecessary data or reporting\nerrors — when that will ignored anyway.\n\nNote that for module rules, ignored files will be skipped automatically anyway.\n\n contextCreator : Rule.ContextCreator () Context\n contextCreator =\n Rule.initContextCreator\n (\\isFileIgnored () ->\n { isFileIgnored = isFileIgnored\n\n -- ...other fields\n }\n )\n |> Rule.withIsFileIgnored\n\n","type":"Review.Rule.ContextCreator Basics.Bool (from -> to) -> Review.Rule.ContextCreator from to"},{"name":"withIsInSourceDirectories","comment":" Request to know whether the current module is in the \"source-directories\" of the project. You can use this information to\nknow whether the module is part of the tests or of the production code.\n\n contextCreator : Rule.ContextCreator () Context\n contextCreator =\n Rule.initContextCreator\n (\\isInSourceDirectories () ->\n { isInSourceDirectories = isInSourceDirectories\n\n -- ...other fields\n }\n )\n |> Rule.withIsInSourceDirectories\n\n","type":"Review.Rule.ContextCreator Basics.Bool (from -> to) -> Review.Rule.ContextCreator from to"},{"name":"withLetDeclarationEnterVisitor","comment":" Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will visit the module's\nlet declarations branches when entering the declaration.\n\nThe visitor can be very useful if you need to change the context when inside a let declaration.\n\nThe visitors would be called in the following order (ignore the expression visitor if you don't have one):\n\n x =\n let\n declaration1 =\n expression1\n\n declaration2 =\n expression2\n in\n letInValue\n\n1. Expression visitor (enter) for the entire let expression.\n2. Let declaration visitor (enter) for `( declaration1, expression1 )`\n3. Expression visitor (enter then exit) for `expression1`\n4. Let declaration visitor (exit) for `( declaration1, expression1 )`\n5. Let declaration visitor (enter) for `( declaration2, expression2 )`\n6. Expression visitor (enter then exit) for `expression2`\n7. Let declaration visitor (exit) for `( declaration2, expression2 )`\n8. Expression visitor (enter then exit) for `letInValue`\n9. Expression visitor (exit) for the entire let expression.\n\nYou can use [`withLetDeclarationExitVisitor`](#withLetDeclarationExitVisitor) to visit the node on exit.\n\n import Elm.Syntax.Expression as Expression exposing (Expression)\n import Elm.Syntax.Node as Node exposing (Node)\n import Review.Rule as Rule exposing (Rule)\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"NoUnusedLetFunctionParameters\" ( [], [] )\n |> Rule.withExpressionEnterVisitor expressionVisitor\n |> Rule.withLetDeclarationEnterVisitor letDeclarationEnterVisitor\n |> Rule.withLetDeclarationExitVisitor letDeclarationExitVisitor\n |> Rule.fromModuleRuleSchema\n\n type alias Context =\n ( List String, List (List String) )\n\n expressionVisitor : Node Expression -> Context -> ( List (Rule.Error {}), Context )\n expressionVisitor node (( scope, parentScopes ) as context) =\n case context of\n Expression.FunctionOrValue [] name ->\n ( [], ( name :: used, parentScopes ) )\n\n _ ->\n ( [], context )\n\n letDeclarationEnterVisitor : Node Expression.LetBlock -> Node Expression.LetDeclaration -> Context -> List ( Rule.Error {}, Context )\n letDeclarationEnterVisitor _ letDeclaration (( scope, parentScopes ) as context) =\n case Node.value letDeclaration of\n Expression.LetFunction _ ->\n ( [], ( [], scope :: parentScopes ) )\n\n Expression.LetDestructuring _ ->\n ( [], context )\n\n letDeclarationExitVisitor : Node Expression.LetBlock -> Node Expression.LetDeclaration -> Context -> List ( Rule.Error {}, Context )\n letDeclarationExitVisitor _ letDeclaration (( scope, parentScopes ) as context) =\n case Node.value letDeclaration of\n Expression.LetFunction _ ->\n let\n namesFromPattern =\n findNamesFromArguments letFunction\n\n ( unusedArguments, unmatchedUsed ) =\n findUnused namesFromPattern scope\n\n newScopes =\n case parentScopes of\n head :: tail ->\n ( unmatchedUsed ++ head, tail )\n\n [] ->\n ( unmatched, [] )\n in\n ( List.map errorForUnused unusedArguments, newScopes )\n\n Expression.LetDestructuring _ ->\n ( [], context )\n\nFor convenience, the entire let expression is passed as the first argument.\n\n","type":"(Elm.Syntax.Node.Node Elm.Syntax.Expression.LetBlock -> Elm.Syntax.Node.Node Elm.Syntax.Expression.LetDeclaration -> moduleContext -> ( List.List (Review.Rule.Error {}), moduleContext )) -> Review.Rule.ModuleRuleSchema schemaState moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } moduleContext"},{"name":"withLetDeclarationExitVisitor","comment":" Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will visit the module's\nlet declarations branches when entering the declaration.\n\nSee the documentation for [`withLetDeclarationEnterVisitor`](#withLetDeclarationEnterVisitor) for explanations and an example.\n\n","type":"(Elm.Syntax.Node.Node Elm.Syntax.Expression.LetBlock -> Elm.Syntax.Node.Node Elm.Syntax.Expression.LetDeclaration -> moduleContext -> ( List.List (Review.Rule.Error {}), moduleContext )) -> Review.Rule.ModuleRuleSchema schemaState moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } moduleContext"},{"name":"withMetadata","comment":" Request metadata about the module.\n\n**@deprecated**: Use more practical functions like\n\n - [`withModuleName`](#withModuleName)\n - [`withModuleNameNode`](#withModuleNameNode)\n - [`withIsInSourceDirectories`](#withIsInSourceDirectories)\n\n","type":"Review.Rule.ContextCreator Review.Rule.Metadata (from -> to) -> Review.Rule.ContextCreator from to"},{"name":"withModuleContext","comment":" Specify, if the project rule has a [module visitor](#withModuleVisitor), how to:\n\n - convert a project context to a module context, through [`fromProjectToModule`]\n - convert a module context to a project context, through [`fromModuleToProject`]\n - fold (merge) project contexts, through [`foldProjectContexts`]\n\n**NOTE**: I suggest reading the section about [`foldProjectContexts`] carefully,\nas it is one whose implementation you will need to do carefully.\n\nIn project rules, we separate the context related to the analysis of the project\nas a whole and the context related to the analysis of a single module into a\n`projectContext` and a `moduleContext` respectively. We do this because in most\nproject rules you won't need all the data from the `projectContext` to analyze a\nmodule, and some data from the module context will not make sense inside the\nproject context.\n\nWhen visiting modules, `elm-review` follows a kind of map-reduce architecture.\nThe idea is the following: it starts with an initial `projectContext` and collects data\nfrom project-related files into it. Then, it visits every module with an initial\n`moduleContext` derived from a `projectContext`. At the end of a module's visit,\nthe final `moduleContext` will be transformed (\"map\") to a `projectContext`.\nAll or some of the `projectContext`s will then be folded into a single one,\nbefore being used in the [final project evaluation] or to compute another module's\ninitial `moduleContext`.\n\nThis will help make the result of the review as consistent as possible, by\nhaving the results be independent of the order the modules are visited. This also\ngives internal guarantees as to what needs to be re-computed when re-analyzing\nthe project, which leads to huge performance boosts in watch mode or after fixes\nhave been applied.\n\nThe following sections will explain each function, and will be summarized by an\nexample.\n\n\n### `fromProjectToModule`\n\nThe initial `moduleContext` of the module visitor is computed using `fromProjectToModule`\nfrom a `projectContext`. By default, this `projectContext` will be the result of\nvisiting the project-related files (`elm.json`, `README.md`, ...).\nIf [`withContextFromImportedModules`] was used, then the value will be this last\n`projectContext`, folded with each imported module's resulting `projectContext`,\nusing [`foldProjectContexts`].\n\nThe [`ModuleKey`] will allow you to report errors for this specific module\nusing [`errorForModule`](#errorForModule) from the [final project evaluation] or\nwhile visiting another module. If you plan to do that, you should store this in\nthe `moduleContext`. You can also get it from [`fromModuleToProject`], so choose\nwhat's most convenient.\n\nThe [`Node`] containing the module name is passed for convenience, so you don't\nhave to visit the module definition just to get the module name. Just like what\nit is in [`elm-syntax`](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-ModuleName),\nthe value will be `[ \"My\", \"Module\" ]` if the module name is `My.Module`.\n\n\n### `fromModuleToProject`\n\nWhen a module has finished being analyzed, the final `moduleContext` will be\nconverted into a `projectContext`, so that it can later be folded with the other\nproject contexts using `foldProjectContexts`. The resulting `projectContext`\nwill be fed into the [final project evaluation] and potentially into\n[`fromProjectToModule`] for modules that import the current one.\n\nSimilarly to `fromProjectToModule`, the [`Node`] containing the module name and\nthe [`ModuleKey`] are passed for convenience, so you don't have to store them in\nthe `moduleContext` only to store them in the `projectContext`.\n\n\n### `foldProjectContexts`\n\nThis function folds two `projectContext` into one. This function requires a few\ntraits to always be true.\n\n - `projectContext`s should be \"merged\" together, not \"subtracted\". If for instance\n you want to detect the unused exports of a module, do not remove a declared\n export when you have found it used. Instead, store and accumulate the declared\n and used functions (both probably as `Set`s or `Dict`s), and in the final evaluation,\n filter out the declared functions if they are in the set of used functions.\n - The order of folding should not matter: `foldProjectContexts b (foldProjectContexts a initial)`\n should equal `foldProjectContexts a (foldProjectContexts b initial)`.\n [`List.concat`](https://package.elm-lang.org/packages/elm/core/latest/List#concat).\n - Folding an element twice into another should give the same result as folding\n it once. In other words, `foldProjectContexts a (foldProjectContexts a initial)`\n should equal `foldProjectContexts a initial`. You will likely need to use functions\n like [`Set.union`](https://package.elm-lang.org/packages/elm/core/latest/Set#union)\n and [`Dict.union`](https://package.elm-lang.org/packages/elm/core/latest/Dict#union)\n over addition and functions like\n [`List.concat`](https://package.elm-lang.org/packages/elm/core/latest/List#concat).\n\nIt is not necessary for the function to be commutative (i.e. that\n`foldProjectContexts a b` equals `foldProjectContexts b a`). It is fine to take\nthe value from the \"initial\" `projectContext` and ignore the other one, especially\nfor data computed in the project-related visitors (for which you will probably\ndefine a dummy value in the `fromModuleToProject` function). If it helps, imagine\nthat the second argument is the initial `projectContext`, or that it is an accumulator\njust like in `List.foldl`.\n\n\n### Summary example - Reporting unused exported functions\n\nAs an example, we will write a rule that reports functions that get exported\nbut are unused in the rest of the project.\n\n import Review.Rule as Rule exposing (Rule)\n\n rule : Rule\n rule =\n Rule.newProjectRuleSchema \"NoUnusedExportedFunctions\" initialProjectContext\n -- Omitted, but this will collect the list of exposed modules for packages.\n -- We don't want to report functions that are exposed\n |> Rule.withElmJsonProjectVisitor elmJsonVisitor\n |> Rule.withModuleVisitor moduleVisitor\n |> Rule.withModuleContext\n { fromProjectToModule = fromProjectToModule\n , fromModuleToProject = fromModuleToProject\n , foldProjectContexts = foldProjectContexts\n }\n |> Rule.withFinalProjectEvaluation finalEvaluationForProject\n |> Rule.fromProjectRuleSchema\n\n moduleVisitor :\n Rule.ModuleRuleSchema {} ModuleContext\n -> Rule.ModuleRuleSchema { hasAtLeastOneVisitor : () } ModuleContext\n moduleVisitor schema =\n schema\n -- Omitted, but this will collect the exposed functions\n |> Rule.withModuleDefinitionVisitor moduleDefinitionVisitor\n -- Omitted, but this will collect uses of exported functions\n |> Rule.withExpressionEnterVisitor expressionVisitor\n\n type alias ProjectContext =\n { -- Modules exposed by the package, that we should not report\n exposedModules : Set ModuleName\n , exposedFunctions :\n -- An entry for each module\n Dict\n ModuleName\n { -- To report errors in this module\n moduleKey : Rule.ModuleKey\n\n -- An entry for each function with its location\n , exposed : Dict String Range\n }\n , used : Set ( ModuleName, String )\n }\n\n type alias ModuleContext =\n { isExposed : Bool\n , exposed : Dict String Range\n , used : Set ( ModuleName, String )\n }\n\n initialProjectContext : ProjectContext\n initialProjectContext =\n { exposedModules = Set.empty\n , modules = Dict.empty\n , used = Set.empty\n }\n\n fromProjectToModule : Rule.ModuleKey -> Node ModuleName -> ProjectContext -> ModuleContext\n fromProjectToModule moduleKey moduleName projectContext =\n { isExposed = Set.member (Node.value moduleName) projectContext.exposedModules\n , exposed = Dict.empty\n , used = Set.empty\n }\n\n fromModuleToProject : Rule.ModuleKey -> Node ModuleName -> ModuleContext -> ProjectContext\n fromModuleToProject moduleKey moduleName moduleContext =\n { -- We don't care about this value, we'll take\n -- the one from the initial context when folding\n exposedModules = Set.empty\n , exposedFunctions =\n if moduleContext.isExposed then\n -- If the module is exposed, don't collect the exported functions\n Dict.empty\n\n else\n -- Create a dictionary with all the exposed functions, associated to\n -- the module that was just visited\n Dict.singleton\n (Node.value moduleName)\n { moduleKey = moduleKey\n , exposed = moduleContext.exposed\n }\n , used = moduleContext.used\n }\n\n foldProjectContexts : ProjectContext -> ProjectContext -> ProjectContext\n foldProjectContexts newContext previousContext =\n { -- Always take the one from the \"initial\" context,\n -- which is always the second argument\n exposedModules = previousContext.exposedModules\n\n -- Collect the exposed functions from the new context and the previous one.\n -- We could use `Dict.merge`, but in this case, that doesn't change anything\n , exposedFunctions = Dict.union newContext.modules previousContext.modules\n\n -- Collect the used functions from the new context and the previous one\n , used = Set.union newContext.used previousContext.used\n }\n\n finalEvaluationForProject : ProjectContext -> List (Rule.Error { useErrorForModule : () })\n finalEvaluationForProject projectContext =\n -- Implementation of `unusedFunctions` omitted, but it returns the list\n -- of unused functions, along with the associated module key and range\n unusedFunctions projectContext\n |> List.map\n (\\{ moduleKey, functionName, range } ->\n Rule.errorForModule moduleKey\n { message = \"Function `\" ++ functionName ++ \"` is never used\"\n , details = [ \"<Omitted>\" ]\n }\n range\n )\n\n[`ModuleKey`]: #ModuleKey\n[`Node`]: https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Node#Node\n[`fromProjectToModule`]: #-fromprojecttomodule-\n[`fromModuleToProject`]: #-frommoduletoproject-\n[`foldProjectContexts`]: #-foldprojectcontexts-\n[final project evaluation]: #withFinalProjectEvaluation\n[`withContextFromImportedModules`]: #withContextFromImportedModules\n\n","type":"{ fromProjectToModule : Review.Rule.ModuleKey -> Elm.Syntax.Node.Node Elm.Syntax.ModuleName.ModuleName -> projectContext -> moduleContext, fromModuleToProject : Review.Rule.ModuleKey -> Elm.Syntax.Node.Node Elm.Syntax.ModuleName.ModuleName -> moduleContext -> projectContext, foldProjectContexts : projectContext -> projectContext -> projectContext } -> Review.Rule.ProjectRuleSchema { schemaState | canAddModuleVisitor : (), withModuleContext : Review.Rule.Required } projectContext moduleContext -> Review.Rule.ProjectRuleSchema { schemaState | hasAtLeastOneVisitor : (), withModuleContext : Review.Rule.Forbidden } projectContext moduleContext"},{"name":"withModuleContextUsingContextCreator","comment":" Use a [`ContextCreator`](#ContextCreator) to initialize your `moduleContext` and `projectContext`. This will allow\nyou to request more information\n\n import Review.Rule as Rule exposing (Rule)\n\n rule : Rule\n rule =\n Rule.newProjectRuleSchema \"NoMissingSubscriptionsCall\" initialProjectContext\n |> Rule.withModuleVisitor moduleVisitor\n |> Rule.withModuleContextUsingContextCreator\n { fromProjectToModule = fromProjectToModule\n , fromModuleToProject = fromModuleToProject\n , foldProjectContexts = foldProjectContexts\n }\n |> Rule.fromProjectRuleSchema\n\n fromProjectToModule : Rule.ContextCreator ProjectContext ModuleContext\n fromProjectToModule =\n Rule.initContextCreator\n (\\projectContext ->\n { -- something\n }\n )\n\n fromModuleToProject : Rule.ContextCreator ModuleContext ProjectContext\n fromModuleToProject =\n Rule.initContextCreator\n (\\moduleKey moduleName moduleContext ->\n { moduleKeys = Dict.singleton moduleName moduleKey\n }\n )\n |> Rule.withModuleKey\n |> Rule.withModuleName\n\n","type":"{ fromProjectToModule : Review.Rule.ContextCreator projectContext moduleContext, fromModuleToProject : Review.Rule.ContextCreator moduleContext projectContext, foldProjectContexts : projectContext -> projectContext -> projectContext } -> Review.Rule.ProjectRuleSchema { schemaState | canAddModuleVisitor : (), withModuleContext : Review.Rule.Required } projectContext moduleContext -> Review.Rule.ProjectRuleSchema { schemaState | hasAtLeastOneVisitor : (), withModuleContext : Review.Rule.Forbidden } projectContext moduleContext"},{"name":"withModuleDefinitionVisitor","comment":" Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will visit the module's\n[module definition](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Module) (`module SomeModuleName exposing (a, b)`), collect data in the `context` and/or report patterns.\n\nThe following example forbids the use of `Html.button` except in the \"Button\" module.\nThe example is simplified to only forbid the use of the `Html.button` expression.\n\n import Elm.Syntax.Expression as Expression exposing (Expression)\n import Elm.Syntax.Module as Module exposing (Module)\n import Elm.Syntax.Node as Node exposing (Node)\n import Review.Rule as Rule exposing (Rule)\n\n type Context\n = HtmlButtonIsAllowed\n | HtmlButtonIsForbidden\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"NoHtmlButton\" HtmlButtonIsForbidden\n |> Rule.withModuleDefinitionVisitor moduleDefinitionVisitor\n |> Rule.withExpressionEnterVisitor expressionVisitor\n |> Rule.fromModuleRuleSchema\n\n moduleDefinitionVisitor : Node Module -> Context -> ( List (Rule.Error {}), Context )\n moduleDefinitionVisitor node context =\n if (Node.value node |> Module.moduleName) == [ \"Button\" ] then\n ( [], HtmlButtonIsAllowed )\n\n else\n ( [], HtmlButtonIsForbidden )\n\n expressionVisitor : Node Expression -> Context -> ( List (Rule.Error {}), Context )\n expressionVisitor node context =\n case context of\n HtmlButtonIsAllowed ->\n ( [], context )\n\n HtmlButtonIsForbidden ->\n case Node.value node of\n Expression.FunctionOrValue [ \"Html\" ] \"button\" ->\n ( [ Rule.error\n { message = \"Do not use `Html.button` directly\"\n , details = [ \"At fruits.com, we've built a nice `Button` module that suits our needs better. Using this module instead of `Html.button` ensures we have a consistent button experience across the website.\" ]\n }\n (Node.range node)\n ]\n , context\n )\n\n _ ->\n ( [], context )\n\n _ ->\n ( [], context )\n\nTip: If you do not need to collect data in this visitor, you may wish to use the\nsimpler [`withSimpleModuleDefinitionVisitor`](#withSimpleModuleDefinitionVisitor) function.\n\nTip: The rule above is very brittle. What if `button` was imported using `import Html exposing (button)` or `import Html exposing (..)`, or if `Html` was aliased (`import Html as H`)? Then the rule above would\nnot catch and report the use `Html.button`. To handle this, check out [`withModuleNameLookupTable`](#withModuleNameLookupTable).\n\n","type":"(Elm.Syntax.Node.Node Elm.Syntax.Module.Module -> moduleContext -> ( List.List (Review.Rule.Error {}), moduleContext )) -> Review.Rule.ModuleRuleSchema schemaState moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } moduleContext"},{"name":"withModuleDocumentation","comment":" Request the module documentation. Modules don't always have a documentation.\nWhen that is the case, the module documentation will be `Nothing`.\n\n contextCreator : Rule.ContextCreator () Context\n contextCreator =\n Rule.initContextCreator\n (\\moduleDocumentation () ->\n { moduleDocumentation = moduleDocumentation\n\n -- ...other fields\n }\n )\n |> Rule.withModuleDocumentation\n\n","type":"Review.Rule.ContextCreator (Maybe.Maybe (Elm.Syntax.Node.Node String.String)) (from -> to) -> Review.Rule.ContextCreator from to"},{"name":"withModuleDocumentationVisitor","comment":" Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will visit the module's documentation, collect data in\nthe `context` and/or report patterns.\n\nThis visitor will give you access to the module documentation comment. Modules don't always have a documentation.\nWhen that is the case, the visitor will be called with the `Nothing` as the module documentation.\n\n","type":"(Maybe.Maybe (Elm.Syntax.Node.Node String.String) -> moduleContext -> ( List.List (Review.Rule.Error {}), moduleContext )) -> Review.Rule.ModuleRuleSchema schemaState moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } moduleContext"},{"name":"withModuleKey","comment":" Request the [module key](#ModuleKey) for this module.\n\n rule : Rule\n rule =\n Rule.newProjectRuleSchema \"NoMissingSubscriptionsCall\" initialProjectContext\n |> Rule.withModuleVisitor moduleVisitor\n |> Rule.withModuleContextUsingContextCreator\n { fromProjectToModule = fromProjectToModule\n , fromModuleToProject = fromModuleToProject\n , foldProjectContexts = foldProjectContexts\n }\n\n fromModuleToProject : Rule.ContextCreator () Context\n fromModuleToProject =\n Rule.initContextCreator\n (\\moduleKey () -> { moduleKey = moduleKey })\n |> Rule.withModuleKey\n\n","type":"Review.Rule.ContextCreator Review.Rule.ModuleKey (from -> to) -> Review.Rule.ContextCreator from to"},{"name":"withModuleName","comment":" Request the name of the module.\n\n contextCreator : Rule.ContextCreator () Context\n contextCreator =\n Rule.initContextCreator\n (\\moduleName () ->\n { moduleName = moduleName\n\n -- ...other fields\n }\n )\n |> Rule.withModuleName\n\n","type":"Review.Rule.ContextCreator Elm.Syntax.ModuleName.ModuleName (from -> to) -> Review.Rule.ContextCreator from to"},{"name":"withModuleNameLookupTable","comment":" Requests the module name lookup table for the types and functions inside a module.\n\nWhen encountering a `Expression.FunctionOrValue ModuleName String` (among other nodes where we refer to a function or value),\nthe module name available represents the module name that is in the source code. But that module name can be an alias to\na different import, or it can be empty, meaning that it refers to a local value or one that has been imported explicitly\nor implicitly. Resolving which module the type or function comes from can be a bit tricky sometimes, and I recommend against\ndoing it yourself.\n\n`elm-review` computes this for you already. Store this value inside your module context, then use\n[`ModuleNameLookupTable.moduleNameFor`](./Review-ModuleNameLookupTable#moduleNameFor) or\n[`ModuleNameLookupTable.moduleNameAt`](./Review-ModuleNameLookupTable#moduleNameAt) to get the name of the module the\ntype or value comes from.\n\n import Review.ModuleNameLookupTable as ModuleNameLookupTable exposing (ModuleNameLookupTable)\n\n type alias Context =\n { lookupTable : ModuleNameLookupTable }\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchemaUsingContextCreator \"NoHtmlButton\" initialContext\n |> Rule.withExpressionEnterVisitor expressionVisitor\n |> Rule.fromModuleRuleSchema\n |> Rule.ignoreErrorsForFiles [ \"src/Colors.elm\" ]\n\n initialContext : Rule.ContextCreator () Context\n initialContext =\n Rule.initContextCreator\n (\\lookupTable () -> { lookupTable = lookupTable })\n |> Rule.withModuleNameLookupTable\n\n expressionVisitor : Node Expression -> Context -> ( List (Error {}), Context )\n expressionVisitor node context =\n case Node.value node of\n Expression.FunctionOrValue _ \"color\" ->\n if ModuleNameLookupTable.moduleNameFor context.lookupTable node == Just [ \"Css\" ] then\n ( [ Rule.error\n { message = \"Do not use `Css.color` directly, use the Colors module instead\"\n , details = [ \"We made a module which contains all the available colors of our design system. Use the functions in there instead.\" ]\n }\n (Node.range node)\n ]\n , context\n )\n\n else\n ( [], context )\n\n _ ->\n ( [], context )\n\nNote: If you have been using [`elm-review-scope`](https://github.com/jfmengels/elm-review-scope) before, you should use this instead.\n\n","type":"Review.Rule.ContextCreator Review.ModuleNameLookupTable.ModuleNameLookupTable (from -> to) -> Review.Rule.ContextCreator from to"},{"name":"withModuleNameNode","comment":" Request the node corresponding to the name of the module.\n\n contextCreator : Rule.ContextCreator () Context\n contextCreator =\n Rule.initContextCreator\n (\\moduleNameNode () ->\n { moduleNameNode = moduleNameNode\n\n -- ...other fields\n }\n )\n |> Rule.withModuleNameNode\n\n","type":"Review.Rule.ContextCreator (Elm.Syntax.Node.Node Elm.Syntax.ModuleName.ModuleName) (from -> to) -> Review.Rule.ContextCreator from to"},{"name":"withModuleVisitor","comment":" Add a visitor to the [`ProjectRuleSchema`](#ProjectRuleSchema) which will\nvisit the project's Elm modules.\n\nA module visitor behaves like a module rule, except that it won't visit the\nproject files, as those have already been seen by other visitors for project rules (such\nas [`withElmJsonProjectVisitor`](#withElmJsonProjectVisitor)).\n\n`withModuleVisitor` takes a function that takes an already initialized module\nrule schema and adds visitors to it, using the same functions as for building a\n[`ModuleRuleSchema`](#ModuleRuleSchema).\n\nWhen you use `withModuleVisitor`, you will be required to use [`withModuleContext`](#withModuleContext),\nin order to specify how to create a `moduleContext` from a `projectContext` and vice-versa.\n\n","type":"(Review.Rule.ModuleRuleSchema {} moduleContext -> Review.Rule.ModuleRuleSchema { moduleSchemaState | hasAtLeastOneVisitor : () } moduleContext) -> Review.Rule.ProjectRuleSchema { projectSchemaState | canAddModuleVisitor : () } projectContext moduleContext -> Review.Rule.ProjectRuleSchema { projectSchemaState | canAddModuleVisitor : (), withModuleContext : Review.Rule.Required } projectContext moduleContext"},{"name":"withReadmeModuleVisitor","comment":" Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will visit\nthe project's `README.md` file.\n","type":"(Maybe.Maybe String.String -> moduleContext -> moduleContext) -> Review.Rule.ModuleRuleSchema { schemaState | canCollectProjectData : () } moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | canCollectProjectData : () } moduleContext"},{"name":"withReadmeProjectVisitor","comment":" Add a visitor to the [`ProjectRuleSchema`](#ProjectRuleSchema) which will visit\nthe project's `README.md` file.\n\nIt works exactly like [`withReadmeModuleVisitor`](#withReadmeModuleVisitor).\nThe visitor will be called before any module is evaluated.\n\n","type":"(Maybe.Maybe { readmeKey : Review.Rule.ReadmeKey, content : String.String } -> projectContext -> ( List.List (Review.Rule.Error { useErrorForModule : () }), projectContext )) -> Review.Rule.ProjectRuleSchema schemaState projectContext moduleContext -> Review.Rule.ProjectRuleSchema { schemaState | hasAtLeastOneVisitor : () } projectContext moduleContext"},{"name":"withRuleId","comment":" Assign an id to a rule. This id should be unique.\n\n config =\n [ rule1, rule2, rule3 ]\n |> List.indexedMap Rule.withUniqueId\n\nYou should not have to use this when writing a rule.\n\n","type":"Basics.Int -> Review.Rule.Rule -> Review.Rule.Rule"},{"name":"withSimpleCommentsVisitor","comment":" Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will visit the module's comments.\n\nThis visitor will give you access to the list of comments (in source order) in\nthe module all at once. Note that comments that are parsed as documentation comments by\n[`elm-syntax`](https://package.elm-lang.org/packages/stil4m/elm-syntax/latest/)\nare not included in this list.\n\nAs such, the following comments are included (✅) / excluded (❌):\n\n - ✅ Module documentation (`{-| -}`)\n - ✅ Port documentation comments (`{-| -}`)\n - ✅ Top-level comments not internal to a function/type/etc.\n - ✅ Comments internal to a function/type/etc.\n - ❌ Function/type/type alias documentation comments (`{-| -}`)\n\nThe following example forbids words like \"TODO\" appearing in a comment.\n\n import Elm.Syntax.Node as Node exposing (Node)\n import Elm.Syntax.Range exposing (Range)\n import Review.Rule as Rule exposing (Rule)\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"NoTodoComment\" ()\n |> Rule.withSimpleCommentsVisitor commentsVisitor\n |> Rule.fromModuleRuleSchema\n\n commentsVisitor : List (Node String) -> List (Rule.Error {})\n commentsVisitor comments =\n comments\n |> List.concatMap\n (\\commentNode ->\n String.indexes \"TODO\" (Node.value commentNode)\n |> List.map (errorAtPosition (Node.range commentNode))\n )\n\n errorAtPosition : Range -> Int -> Error {}\n errorAtPosition range index =\n Rule.error\n { message = \"TODO needs to be handled\"\n , details = [ \"At fruits.com, we prefer not to have lingering TODO comments. Either fix the TODO now or create an issue for it.\" ]\n }\n -- Here you would ideally only target the TODO keyword\n -- or the rest of the line it appears on,\n -- so you would change `range` using `index`.\n range\n\nNote: `withSimpleCommentsVisitor` is a simplified version of [`withCommentsVisitor`](#withCommentsVisitor),\nwhich isn't passed a `context` and doesn't return one. You can use `withCommentsVisitor` even if you use \"non-simple with\\*\" functions.\n\n","type":"(List.List (Elm.Syntax.Node.Node String.String) -> List.List (Review.Rule.Error {})) -> Review.Rule.ModuleRuleSchema schemaState moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } moduleContext"},{"name":"withSimpleDeclarationVisitor","comment":" Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will visit the module's\n[declaration statements](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Declaration)\n(`someVar = add 1 2`, `type Bool = True | False`, `port output : Json.Encode.Value -> Cmd msg`)\nand report patterns. The declarations will be visited in the order of their definition.\n\nThe following example forbids declaring a function or a value without a type\nannotation.\n\n import Elm.Syntax.Declaration as Declaration exposing (Declaration)\n import Elm.Syntax.Node as Node exposing (Node)\n import Review.Rule as Rule exposing (Rule)\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"NoMissingTypeAnnotation\" ()\n |> Rule.withSimpleDeclarationVisitor declarationVisitor\n |> Rule.fromModuleRuleSchema\n\n declarationVisitor : Node Declaration -> List (Rule.Error {})\n declarationVisitor node =\n case Node.value node of\n Declaration.FunctionDeclaration { signature, declaration } ->\n case signature of\n Just _ ->\n []\n\n Nothing ->\n let\n functionName : String\n functionName =\n declaration |> Node.value |> .name |> Node.value\n in\n [ Rule.error\n { message = \"Missing type annotation for `\" ++ functionName ++ \"`\"\n , details =\n [ \"Type annotations are very helpful for people who read your code. It can give a lot of information without having to read the contents of the function. When encountering problems, the compiler will also give much more precise and helpful information to help you solve the problem.\"\n , \"To add a type annotation, add a line like `\" functionName ++ \" : ()`, and replace the `()` by the type of the function. If you don't replace `()`, the compiler should give you a suggestion of what the type should be.\"\n ]\n }\n (Node.range node)\n ]\n\n _ ->\n []\n\nNote: `withSimpleDeclarationVisitor` is a simplified version of [`withDeclarationEnterVisitor`](#withDeclarationEnterVisitor),\nwhich isn't passed a `context` and doesn't return one either. You can use `withSimpleDeclarationVisitor` even if you use \"non-simple with\\*\" functions.\n\n","type":"(Elm.Syntax.Node.Node Elm.Syntax.Declaration.Declaration -> List.List (Review.Rule.Error {})) -> Review.Rule.ModuleRuleSchema schemaState moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } moduleContext"},{"name":"withSimpleExpressionVisitor","comment":" Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will visit the module's\n[expressions](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Expression)\n(`1`, `True`, `add 1 2`, `1 + 2`). The expressions are visited in pre-order\ndepth-first search, meaning that an expression will be visited, then its first\nchild, the first child's children (and so on), then the second child (and so on).\n\nThe following example forbids using the Debug module.\n\n import Elm.Syntax.Expression as Expression exposing (Expression)\n import Elm.Syntax.Node as Node exposing (Node)\n import Review.Rule as Rule exposing (Rule)\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"NoDebug\" ()\n |> Rule.withSimpleExpressionVisitor expressionVisitor\n |> Rule.fromModuleRuleSchema\n\n expressionVisitor : Node Expression -> List (Rule.Error {})\n expressionVisitor node =\n case Node.value node of\n Expression.FunctionOrValue moduleName fnName ->\n if List.member \"Debug\" moduleName then\n [ Rule.error\n { message = \"Remove the use of `Debug` before shipping to production\"\n , details = [ \"The `Debug` module 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.\" ]\n }\n (Node.range node)\n ]\n\n else\n []\n\n _ ->\n []\n\nNote: `withSimpleExpressionVisitor` is a simplified version of [`withExpressionEnterVisitor`](#withExpressionEnterVisitor),\nwhich isn't passed a `context` and doesn't return one either. You can use `withSimpleExpressionVisitor` even if you use \"non-simple with\\*\" functions.\n\n","type":"(Elm.Syntax.Node.Node Elm.Syntax.Expression.Expression -> List.List (Review.Rule.Error {})) -> Review.Rule.ModuleRuleSchema schemaState moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } moduleContext"},{"name":"withSimpleImportVisitor","comment":" Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will visit the module's [import statements](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Import) (`import Html as H exposing (div)`) in order of their definition and report patterns.\n\nThe following example forbids using the core Html package and suggests using\n`elm-css` instead.\n\n import Elm.Syntax.Import exposing (Import)\n import Elm.Syntax.Node as Node exposing (Node)\n import Review.Rule as Rule exposing (Rule)\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"NoCoreHtml\" ()\n |> Rule.withSimpleImportVisitor importVisitor\n |> Rule.fromModuleRuleSchema\n\n importVisitor : Node Import -> List (Rule.Error {})\n importVisitor node =\n let\n moduleName : List String\n moduleName =\n node\n |> Node.value\n |> .moduleName\n |> Node.value\n in\n case moduleName of\n [ \"Html\" ] ->\n [ Rule.error\n { message = \"Use `elm-css` instead of the core HTML package.\"\n , details =\n [ \"At fruits.com, we chose to use the `elm-css` package (https://package.elm-lang.org/packages/rtfeldman/elm-css/latest/Css) to build our HTML and CSS rather than the core Html package. To keep things simple, we think it is best to not mix these different libraries.\"\n , \"The API is very similar, but instead of using the `Html` module, use the `Html.Styled`. CSS is then defined using the Html.Styled.Attributes.css function (https://package.elm-lang.org/packages/rtfeldman/elm-css/latest/Html-Styled-Attributes#css).\"\n ]\n }\n (Node.range node)\n ]\n\n _ ->\n []\n\nNote: `withSimpleImportVisitor` is a simplified version of [`withImportVisitor`](#withImportVisitor),\nwhich isn't passed a `context` and doesn't return one. You can use `withSimpleImportVisitor` even if you use \"non-simple with\\*\" functions.\n\n","type":"(Elm.Syntax.Node.Node Elm.Syntax.Import.Import -> List.List (Review.Rule.Error {})) -> Review.Rule.ModuleRuleSchema schemaState moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } moduleContext"},{"name":"withSimpleModuleDefinitionVisitor","comment":" Add a visitor to the [`ModuleRuleSchema`](#ModuleRuleSchema) which will visit the module's [module definition](https://package.elm-lang.org/packages/stil4m/elm-syntax/7.2.1/Elm-Syntax-Module) (`module SomeModuleName exposing (a, b)`) and report patterns.\n\nThe following example forbids having `_` in any part of a module name.\n\n import Elm.Syntax.Module as Module exposing (Module)\n import Elm.Syntax.Node as Node exposing (Node)\n import Review.Rule as Rule exposing (Rule)\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchema \"NoUnderscoreInModuleName\" ()\n |> Rule.withSimpleModuleDefinitionVisitor moduleDefinitionVisitor\n |> Rule.fromModuleRuleSchema\n\n moduleDefinitionVisitor : Node Module -> List (Rule.Error {})\n moduleDefinitionVisitor node =\n if List.any (String.contains \"_\") (Node.value node |> Module.moduleName) then\n [ Rule.error\n { message = \"Do not use `_` in a module name\"\n , details = [ \"By convention, Elm modules names use Pascal case (like `MyModuleName`). Please rename your module using this format.\" ]\n }\n (Node.range node)\n ]\n\n else\n []\n\nNote: `withSimpleModuleDefinitionVisitor` is a simplified version of [`withModuleDefinitionVisitor`](#withModuleDefinitionVisitor),\nwhich isn't passed a `context` and doesn't return one. You can use `withSimpleModuleDefinitionVisitor` even if you use \"non-simple with\\*\" functions.\n\n","type":"(Elm.Syntax.Node.Node Elm.Syntax.Module.Module -> List.List (Review.Rule.Error {})) -> Review.Rule.ModuleRuleSchema schemaState moduleContext -> Review.Rule.ModuleRuleSchema { schemaState | hasAtLeastOneVisitor : () } moduleContext"},{"name":"withSourceCodeExtractor","comment":" Requests access to a function that gives you the source code at a given range.\n\n rule : Rule\n rule =\n Rule.newModuleRuleSchemaUsingContextCreator \"YourRuleName\" initialContext\n |> Rule.withExpressionEnterVisitor expressionVisitor\n |> Rule.fromModuleRuleSchema\n\n type alias Context =\n { extractSourceCode : Range -> String\n }\n\n initialContext : Rule.ContextCreator () Context\n initialContext =\n Rule.initContextCreator\n (\\extractSourceCode () -> { extractSourceCode = extractSourceCode })\n |> Rule.withSourceCodeExtractor\n\nThe motivation for this capability was for allowing to provide higher-quality fixes, especially where you'd need to **move** or **copy**\ncode from one place to another (example: [when switching the branches of an if expression](https://github.com/jfmengels/elm-review/blob/master/tests/NoNegationInIfCondition.elm)).\n\nI discourage using this functionality to explore the source code, as the different visitor functions make for a nicer\nexperience.\n\n","type":"Review.Rule.ContextCreator (Elm.Syntax.Range.Range -> String.String) (from -> to) -> Review.Rule.ContextCreator from to"}],"binops":[]},{"name":"Review.Test","comment":" Module that helps you test your rules, using [`elm-test`](https://package.elm-lang.org/packages/elm-explorations/test/latest/).\n\n import Review.Test\n import Test exposing (Test, describe, test)\n import The.Rule.You.Want.To.Test exposing (rule)\n\n tests : Test\n tests =\n describe \"The.Rule.You.Want.To.Test\"\n [ test \"should not report anything when <condition>\" <|\n \\() ->\n \"\"\"module A exposing (..)\n a = foo n\"\"\"\n |> Review.Test.run rule\n |> Review.Test.expectNoErrors\n , test \"should report Debug.log use\" <|\n \\() ->\n \"\"\"module A exposing (..)\n a = Debug.log \"some\" \"message\" \"\"\"\n |> Review.Test.run rule\n |> Review.Test.expectErrors\n [ Review.Test.error\n { message = \"Remove the use of `Debug` before shipping to production\"\n , details = [ \"Details about the error\" ]\n , under = \"Debug.log\"\n }\n ]\n ]\n\nAUTRE CHOSE\n\n\n# Strategies for effective testing\n\n\n## Use Test-Driven Development\n\nWriting a rule is a process that works really well with the Test-Driven\nDevelopment process loop, which is:\n\n - Before writing any code, write a failing test.\n - Run the test and make sure that it is failing, otherwise you can't be\n sure that the test is well-written.\n - Write the simplest (almost stupid) code to make the test pass\n - Run the tests again and make sure that the test is passing, and that you\n didn't break any previous tests\n - Optionally, refactor your code but be sure not to change the behavior of the\n implementation. You should not add support for new patterns, as you will\n want to write tests for those first.\n\nThen repeat for every pattern you wish to handle.\n\n\n## Have a good title\n\nA good test title explains\n\n - what is tested - Probably the rule, but making it explicit\n in a [`describe`](https://package.elm-lang.org/packages/elm-explorations/test/latest/Test#describe)\n might improve your test report. Or maybe you are testing a sub-part of the rule,\n and you can name it explicitly.\n - what should happen: (not) reporting an error, fix <something> by <doing something>, ...\n - when: what is the situation that this test sets up?\n\nIdeally, by only reading through the test titles, someone else should be able to\nrewrite the rule you are testing.\n\n\n## What should you test?\n\nYou should test the scenarios where you expect the rule to report something. At\nthe same time, you should also test when it shouldn't. I encourage writing tests\nto make sure that things that are similar to what you want to report are not\nreported.\n\nFor instance, if you wish to report uses of variables named `foo`, write a test\nthat ensures that the use of variables named differently does not get reported.\n\nTests are pretty cheap, and in the case of rules, it is probably better to have\ntoo many tests rather than too few, since the behavior of a rule rarely changes\ndrastically.\n\n\n# Design goals\n\nIf you are interested, you can read\n[the design goals](https://github.com/jfmengels/elm-review/blob/master/documentation/design/test-module.md)\nfor this module.\n\n\n# Running tests\n\n@docs ReviewResult, run, runWithProjectData, runOnModules, runOnModulesWithProjectData\n\n\n# Making assertions\n\n@docs ExpectedError, expectNoErrors, expectErrors, error, atExactly, whenFixed, expectErrorsForModules, expectErrorsForElmJson, expectErrorsForReadme, expectErrorsForExtraFile\n@docs expectGlobalErrors\n@docs expectConfigurationError\n@docs expectDataExtract\n@docs ignoredFilesImpactResults\n\n\n## Composite assertions\n\n@docs expect, ReviewExpectation\n@docs moduleErrors, globalErrors, elmJsonErrors, readmeErrors, extraFileErrors, dataExtract\n\n\n# Deprecated\n\n@docs expectGlobalAndLocalErrors, expectGlobalAndModuleErrors\n\n","unions":[{"name":"ExpectedError","comment":" An expectation for an error. Use [`error`](#error) to create one.\n","args":[],"cases":[]},{"name":"ReviewExpectation","comment":" Expectation of something that the rule will report or do.\n\nCheck out the functions below to create these, and then pass them to [`Review.Test.expect`](#expect).\n\n","args":[],"cases":[]},{"name":"ReviewResult","comment":" The result of running a rule on a `String` containing source code.\n","args":[],"cases":[]}],"aliases":[],"values":[{"name":"atExactly","comment":" Precise the exact position where the error should be shown to the user. This\nis only necessary when the `under` field is ambiguous.\n\n`atExactly` takes a record with start and end positions.\n\n tests : Test\n tests =\n describe \"The.Rule.You.Want.To.Test\"\n [ test \"should report multiple Debug.log calls\" <|\n \\() ->\n \"\"\"module A exposing (..)\n a = Debug.log \"foo\" z\n b = Debug.log \"foo\" z\n \"\"\"\n |> Review.Test.run rule\n |> Review.Test.expectErrors\n [ Review.Test.error\n { message = \"Remove the use of `Debug` before shipping to production\"\n , details = [ \"Details about the error\" ]\n , under = \"Debug.log\"\n }\n |> Review.Test.atExactly { start = { row = 4, column = 5 }, end = { row = 4, column = 14 } }\n , Review.Test.error\n { message = \"Remove the use of `Debug` before shipping to production\"\n , details = [ \"Details about the error\" ]\n , under = \"Debug.log\"\n }\n |> Review.Test.atExactly { start = { row = 5, column = 5 }, end = { row = 5, column = 14 } }\n ]\n ]\n\nTip: By default, do not use this function. If the test fails because there is some\nambiguity, the test error will give you a recommendation of what to use as a parameter\nof `atExactly`, so you do not have to bother writing this hard-to-write argument yourself.\n\n","type":"{ start : { row : Basics.Int, column : Basics.Int }, end : { row : Basics.Int, column : Basics.Int } } -> Review.Test.ExpectedError -> Review.Test.ExpectedError"},{"name":"dataExtract","comment":" Expect the rule to produce a specific data extract. To be used along with [`Review.Test.expect`](#expect).\n\nIf you expect the rule not to report any errors, then you may want to use [`expectDataExtract`](#expectDataExtract) which is simpler.\n\nNote: You do not need to match the exact formatting of the JSON object, though the order of fields does need to match.\n\n import Review.Test\n import Test exposing (Test, describe, test)\n import The.Rule.You.Want.To.Test exposing (rule)\n\n tests : Test\n tests =\n describe \"The.Rule.You.Want.To.Test\"\n [ test \"should extract even if there are errors\" <|\n \\() ->\n [ \"\"\"module A.B exposing (..)\n import B\n a = 1\n b = 2\n c = 3\n \"\"\"\n , \"\"\"module B exposing (..)\n x = 1\n y = 2\n z = 3\n \"\"\"\n ]\n |> Review.Test.runOnModules rule\n |> Review.Test.expect\n [ Review.Test.dataExtract \"\"\"\n {\n \"foo\": \"bar\",\n \"other\": [ 1, 2, 3 ]\n }\"\"\"\n ]\n ]\n\n","type":"String.String -> Review.Test.ReviewExpectation"},{"name":"elmJsonErrors","comment":" Assert that the rule reported some errors for the `elm.json` file, by specifying which ones. To be used along with [`Review.Test.expect`](#expect).\n\nIf you expect only errors for `elm.json`, then you may want to use [`expectErrorsForElmJson`](#expectErrorsForElmJson) which is simpler.\n\n import Review.Project as Project exposing (Project)\n import Review.Test\n import Test exposing (Test, test)\n import The.Rule.You.Want.To.Test exposing (rule)\n\n someTest : Test\n someTest =\n test \"report an error when a module is unused\" <|\n \\() ->\n let\n project : Project\n project =\n Project.new\n |> Project.addElmJson elmJsonToConstructManually\n in\n \"\"\"\n module ModuleA exposing (a)\n a = 1\"\"\"\n |> Review.Test.runWithProjectData project rule\n |> Review.Test.expect\n [ Review.Test.elmJson\n [ Review.Test.error\n { message = \"Unused dependency `author/package`\"\n , details = [ \"Dependency should be removed\" ]\n , under = \"author/package\"\n }\n ]\n ]\n\nAssert which errors are reported using [`error`](#error). The test will fail if\na different number of errors than expected are reported, or if the message or the\nlocation is incorrect.\n\n","type":"List.List Review.Test.ExpectedError -> Review.Test.ReviewExpectation"},{"name":"error","comment":" Create an expectation for an error.\n\n`message` should be the message you're expecting to be shown to the user.\n\n`under` is the part of the code where you are expecting the error to be shown to\nthe user. If it helps, imagine `under` to be the text under which the squiggly\nlines will appear if the error appeared in an editor.\n\n tests : Test\n tests =\n describe \"The.Rule.You.Want.To.Test\"\n [ test \"should report Debug.log use\" <|\n \\() ->\n \"\"\"module A exposing (..)\n a = Debug.log \"some\" \"message\\\"\"\"\"\n |> Review.Test.run rule\n |> Review.Test.expectErrors\n [ Review.Test.error\n { message = \"Remove the use of `Debug` before shipping to production\"\n , details = [ \"Details about the error\" ]\n , under = \"Debug.log\"\n }\n ]\n ]\n\nIf there are multiple locations where the value of `under` appears, the test will\nfail unless you use [`atExactly`](#atExactly) to remove any ambiguity of where the\nerror should be used.\n\n","type":"{ message : String.String, details : List.List String.String, under : String.String } -> Review.Test.ExpectedError"},{"name":"expect","comment":" Expect multiple outputs for tests.\n\nFunctions such as [`expectErrors`](#expectErrors) and [`expectGlobalErrors`](#expectGlobalErrors) work well, but\nin some situations a rule will report multiple things: module errors, global errors, errors for `elm.json` or the\nREADME, or even extract data.\n\nWhen you have multiple expectations to make for a module, use this function.\n\n import Review.Test\n import Test exposing (Test, describe, test)\n import The.Rule.You.Want.To.Test exposing (rule)\n\n tests : Test\n tests =\n describe \"The.Rule.You.Want.To.Test\"\n [ test \"should ...\" <|\n \\() ->\n [ \"\"\"module A.B exposing (..)\n import B\n a = 1\n b = 2\n c = 3\n \"\"\"\n , \"\"\"module B exposing (..)\n x = 1\n y = 2\n z = 3\n \"\"\"\n ]\n |> Review.Test.runOnModules rule\n |> Review.Test.expect\n [ Review.Test.globalErrors [ { message = \"message\", details = [ \"details\" ] } ]\n , Review.Test.moduleErrors \"A.B\" [ { message = \"message\", details = [ \"details\" ] } ]\n , Review.Test.dataExtract \"\"\"\n {\n \"foo\": \"bar\",\n \"other\": [ 1, 2, 3 ]\n }\"\"\"\n ]\n ]\n\n","type":"List.List Review.Test.ReviewExpectation -> Review.Test.ReviewResult -> Expect.Expectation"},{"name":"expectConfigurationError","comment":" Assert that the rule will report a configuration error.\n\n import Review.Test\n import Test exposing (Test, test)\n import The.Rule.You.Want.To.Test exposing (rule)\n\n someTest : Test\n someTest =\n test \"should report a configuration error when argument is empty\" <|\n \\() ->\n rule \"\"\n |> Review.Test.expectConfigurationError\n { message = \"Configuration argument should not be empty\"\n , details = [ \"Some details\" ]\n }\n\n","type":"{ message : String.String, details : List.List String.String } -> Review.Rule.Rule -> Expect.Expectation"},{"name":"expectDataExtract","comment":" Expect the rule to produce a specific data extract.\n\nIf you expect the rule to also report errors, then you should use the [`Review.Test.expect`](#expect) and [`dataExtract`](#dataExtract) functions.\n\nNote: You do not need to match the exact formatting of the JSON object, though the order of fields does need to match.\n\n import Review.Test\n import Test exposing (Test, describe, test)\n import The.Rule.You.Want.To.Test exposing (rule)\n\n tests : Test\n tests =\n test \"should extract the list of fields\" <|\n \\() ->\n \"\"\"module A exposing (..)\n a = 1\n b = 2\n \"\"\"\n |> Review.Test.run rule\n |> Review.Test.expectDataExtract \"\"\"\n {\n \"fields\": [ \"a\", \"b\" ]\n }\"\"\"\n\n","type":"String.String -> Review.Test.ReviewResult -> Expect.Expectation"},{"name":"expectErrors","comment":" Assert that the rule reported some errors, by specifying which ones.\n\nAssert which errors are reported using [`error`](#error). The test will fail if\na different number of errors than expected are reported, or if the message or the\nlocation is incorrect.\n\n import Review.Test\n import Test exposing (Test, describe, test)\n import The.Rule.You.Want.To.Test exposing (rule)\n\n tests : Test\n tests =\n describe \"The.Rule.You.Want.To.Test\"\n [ test \"should report Debug.log use\" <|\n \\() ->\n \"\"\"module A exposing (..)\n a = Debug.log \"some\" \"message\"\n \"\"\"\n |> Review.Test.run rule\n |> Review.Test.expectErrors\n [ Review.Test.error\n { message = \"Remove the use of `Debug` before shipping to production\"\n , details = [ \"Details about the error\" ]\n , under = \"Debug.log\"\n }\n ]\n ]\n\n","type":"List.List Review.Test.ExpectedError -> Review.Test.ReviewResult -> Expect.Expectation"},{"name":"expectErrorsForElmJson","comment":" Assert that the rule reported some errors for the `elm.json` file, by specifying which ones.\n\nIf you expect the rule to report other kinds of errors or extract data, then you should use the [`Review.Test.expect`](#expect) and [`elmJsonErrors`](#elmJsonErrors) functions.\n\n import Review.Project as Project exposing (Project)\n import Review.Test\n import Test exposing (Test, test)\n import The.Rule.You.Want.To.Test exposing (rule)\n\n someTest : Test\n someTest =\n test \"report an error when a module is unused\" <|\n \\() ->\n let\n project : Project\n project =\n Project.new\n |> Project.addElmJson elmJsonToConstructManually\n in\n \"\"\"\n module ModuleA exposing (a)\n a = 1\"\"\"\n |> Review.Test.runWithProjectData project rule\n |> Review.Test.expectErrorsForElmJson\n [ Review.Test.error\n { message = \"Unused dependency `author/package`\"\n , details = [ \"Dependency should be removed\" ]\n , under = \"author/package\"\n }\n ]\n\nAssert which errors are reported using [`error`](#error). The test will fail if\na different number of errors than expected are reported, or if the message or the\nlocation is incorrect.\n\n","type":"List.List Review.Test.ExpectedError -> Review.Test.ReviewResult -> Expect.Expectation"},{"name":"expectErrorsForExtraFile","comment":" Assert that the rule reported some errors for an extra file, by specifying which ones.\n\nIf you expect the rule to report other kinds of errors or extract data, then you should use the [`Review.Test.expect`](#expect) and [`extraFileErrors`](#extraFileErrors) functions.\n\n import Review.Project as Project exposing (Project)\n import Review.Test\n import Test exposing (Test, test)\n import The.Rule.You.Want.To.Test exposing (rule)\n\n someTest : Test\n someTest =\n test \"report an error when a module is unused\" <|\n \\() ->\n let\n project : Project\n project =\n Project.new\n |> Project.addExtraFile { path = \"some-file.ext\", context = \"some string\" }\n in\n \"\"\"\n module ModuleA exposing (a)\n a = 1\"\"\"\n |> Review.Test.runWithProjectData project rule\n |> Review.Test.expectErrorsForExtraFile \"some-file.ext\"\n [ Review.Test.error\n { message = \"Some message\"\n , details = [ \"Some details\" ]\n , under = \"some string\"\n }\n ]\n\nAssert which errors are reported using [`error`](#error). The test will fail if\na different number of errors than expected are reported, or if the message or the\nlocation is incorrect.\n\n","type":"String.String -> List.List Review.Test.ExpectedError -> Review.Test.ReviewResult -> Expect.Expectation"},{"name":"expectErrorsForModules","comment":" Assert that the rule reported some errors, by specifying which ones and the\nmodule for which they were reported.\n\nThis is the same as [`expectErrors`](#expectErrors), but for when you used\n[`runOnModules`](#runOnModules) or [`runOnModulesWithProjectData`](#runOnModulesWithProjectData).\nto create the test. When using those, the errors you expect need to be associated\nwith a module. If we don't specify this, your tests might pass because you\nexpected the right errors, but they may be reported for the wrong module!\n\nIf you expect the rule to report other kinds of errors or extract data, then you should use the [`Review.Test.expect`](#expect) and [`moduleErrors`](#moduleErrors) functions.\n\nThe expected errors are tupled: the first element is the module name\n(for example: `List` or `My.Module.Name`) and the second element is the list of\nerrors you expect to be reported.\n\nAssert which errors are reported using [`error`](#error). The test will fail if\na different number of errors than expected are reported, or if the message or the\nlocation is incorrect.\n\n import Review.Test\n import Test exposing (Test, test)\n import The.Rule.You.Want.To.Test exposing (rule)\n\n someTest : Test\n someTest =\n test \"should report an error when a module uses `Debug.log`\" <|\n \\() ->\n [ \"\"\"\n module ModuleA exposing (a)\n a = 1\"\"\", \"\"\"\n module ModuleB exposing (a)\n a = Debug.log \"log\" 1\"\"\" ]\n |> Review.Test.runOnModules rule\n |> Review.Test.expectErrorsForModules\n [ ( \"ModuleB\"\n , [ Review.Test.error\n { message = \"Remove the use of `Debug` before shipping to production\"\n , details = [ \"Details about the error\" ]\n , under = \"Debug.log\"\n }\n ]\n )\n ]\n\n","type":"List.List ( String.String, List.List Review.Test.ExpectedError ) -> Review.Test.ReviewResult -> Expect.Expectation"},{"name":"expectErrorsForReadme","comment":" Assert that the rule reported some errors for the `README.md` file, by specifying which ones.\n\nIf you expect the rule to report other kinds of errors or extract data, then you should use the [`Review.Test.expect`](#expect) and [`readmeErrors`](#readmeErrors) functions.\n\n import Review.Project as Project exposing (Project)\n import Review.Test\n import Test exposing (Test, test)\n import The.Rule.You.Want.To.Test exposing (rule)\n\n someTest : Test\n someTest =\n test \"report an error when a module is unused\" <|\n \\() ->\n let\n project : Project\n project =\n Project.new\n |> Project.addReadme { path = \"README.md\", context = \"# Project\\n...\" }\n in\n \"\"\"\n module ModuleA exposing (a)\n a = 1\"\"\"\n |> Review.Test.runWithProjectData project rule\n |> Review.Test.expectErrorsForReadme\n [ Review.Test.error\n { message = \"Invalid link\"\n , details = [ \"README contains an invalid link\" ]\n , under = \"htt://example.com\"\n }\n ]\n\nAssert which errors are reported using [`error`](#error). The test will fail if\na different number of errors than expected are reported, or if the message or the\nlocation is incorrect.\n\n","type":"List.List Review.Test.ExpectedError -> Review.Test.ReviewResult -> Expect.Expectation"},{"name":"expectGlobalAndLocalErrors","comment":" **@deprecated** Use [`Review.Test.expect`](#expect) instead.\n\nAssert that the rule reported some [global errors](./Review-Rule#globalError) and [local](./Review-Test#ExpectedError) errors, by specifying which ones.\n\nUse this function when you expect both local and global errors for a particular test, and when you are using [`run`](#run) or [`runWithProjectData`](#runWithProjectData).\nWhen using [`runOnModules`](#runOnModules) or [`runOnModulesWithProjectData`](#runOnModulesWithProjectData), use [`expectGlobalAndModuleErrors`](#expectGlobalAndModuleErrors) instead.\n\nIf you only have local or global errors, you should instead use [`expectErrors`](#expectErrors) or [`expectGlobalErrors`](#expectGlobalErrors) respectively.\n\nThis function works in the same way as [`expectErrors`](#expectErrors) and [`expectGlobalErrors`](#expectGlobalErrors).\n\n","type":"{ local : List.List Review.Test.ExpectedError, global : List.List { message : String.String, details : List.List String.String } } -> Review.Test.ReviewResult -> Expect.Expectation"},{"name":"expectGlobalAndModuleErrors","comment":" **@deprecated** Use [`Review.Test.expect`](#expect) instead.\n\nAssert that the rule reported some errors for modules and global errors, by specifying which ones.\n\nUse this function when you expect both local and global errors for a particular test, and when you are using [`runOnModules`](#runOnModules) or [`runOnModulesWithProjectData`](#runOnModulesWithProjectData).\nWhen using[`run`](#run) or [`runWithProjectData`](#runWithProjectData), use [`expectGlobalAndLocalErrors`](#expectGlobalAndLocalErrors) instead.\n\nIf you only have local or global errors, you should instead use [`expectErrorsForModules`](#expectErrorsForModules) or [`expectGlobalErrors`](#expectGlobalErrors) respectively.\n\nThis function works in the same way as [`expectErrorsForModules`](#expectErrorsForModules) and [`expectGlobalErrors`](#expectGlobalErrors).\n\n","type":"{ global : List.List { message : String.String, details : List.List String.String }, modules : List.List ( String.String, List.List Review.Test.ExpectedError ) } -> Review.Test.ReviewResult -> Expect.Expectation"},{"name":"expectGlobalErrors","comment":" Assert that the rule reported some [global errors](./Review-Rule#globalError), by specifying which ones.\n\nIf you expect the rule to report other kinds of errors or extract data, then you should use the [`Review.Test.expect`](#expect) and [`globalErrors`](#globalErrors) functions.\n\nAssert which errors are reported using records with the expected message and details. The test will fail if\na different number of errors than expected are reported, or if the message or details is incorrect.\n\n import Review.Test\n import Test exposing (Test, test)\n import The.Rule.You.Want.To.Test exposing (rule)\n\n someTest : Test\n someTest =\n test \"should report a global error when the specified module could not be found\" <|\n \\() ->\n \"\"\"\n module ModuleA exposing (a)\n a = 1\"\"\"\n |> Review.Test.run (rule \"ModuleB\")\n |> Review.Test.expectGlobalErrors\n [ { message = \"Could not find module ModuleB\"\n , details =\n [ \"You mentioned the module ModuleB in the configuration of this rule, but it could not be found.\"\n , \"This likely means you misconfigured the rule or the configuration has become out of date with recent changes in your project.\"\n ]\n }\n ]\n\n","type":"List.List { message : String.String, details : List.List String.String } -> Review.Test.ReviewResult -> Expect.Expectation"},{"name":"expectNoErrors","comment":" Assert that the rule reported no errors. Note, this is equivalent to using [`expectErrors`](#expectErrors)\nlike `expectErrors []`.\n\n import Review.Test\n import Test exposing (Test, describe, test)\n import The.Rule.You.Want.To.Test exposing (rule)\n\n tests : Test\n tests =\n describe \"The.Rule.You.Want.To.Test\"\n [ test \"should not report anything when <condition>\" <|\n \\() ->\n \"\"\"module A exposing (..)\n a = foo n\"\"\"\n |> Review.Test.run rule\n |> Review.Test.expectNoErrors\n ]\n\n","type":"Review.Test.ReviewResult -> Expect.Expectation"},{"name":"extraFileErrors","comment":" Assert that the rule reported some errors for a specific extra file. To be used along with [`Review.Test.expect`](#expect).\n\nIf you expect only errors for one file, then you may want to use [`expectErrorsForExtraFile`](#expectErrorsForExtraFile) which is simpler.\n\n import Review.Project as Project\n import Review.Test\n import Test exposing (Test, describe, test)\n import The.Rule.You.Want.To.Test exposing (rule)\n\n tests : Test\n tests =\n describe \"The.Rule.You.Want.To.Test\"\n [ test \"should extract even if there are errors\" <|\n \\() ->\n let\n project : Project\n project =\n Project.new\n |> Project.addExtraFile { path = \"my-file.ext\", context = \"some string\" }\n in\n \"\"\"module ModuleA exposing (a)\n a = 1\"\"\"\n |> Review.Test.runWithProjectData project rule\n |> Review.Test.expect\n [ Review.Test.extraFileErrors\n [ Review.Test.error\n { message = \"Some message\"\n , details = [ \"Some details\" ]\n , under = \"some string\"\n }\n ]\n ]\n ]\n\n","type":"String.String -> List.List Review.Test.ExpectedError -> Review.Test.ReviewExpectation"},{"name":"globalErrors","comment":" Assert that the rule reported some [global errors](./Review-Rule#globalError), by specifying which ones. To be used along with [`Review.Test.expect`](#expect).\n\nIf you expect only global errors, then you may want to use [`expectGlobalErrors`](#expectGlobalErrors) which is simpler.\n\nAssert which errors are reported using records with the expected message and details. The test will fail if\na different number of errors than expected are reported, or if the message or details is incorrect.\n\n import Review.Test\n import Test exposing (Test, test)\n import The.Rule.You.Want.To.Test exposing (rule)\n\n someTest : Test\n someTest =\n test \"should report a global error when the specified module could not be found\" <|\n \\() ->\n \"\"\"\n module ModuleA exposing (a)\n a = 1\"\"\"\n |> Review.Test.run (rule \"ModuleB\")\n |> Review.Test.expect\n [ Review.Test.globalErrors\n [ { message = \"Could not find module ModuleB\"\n , details =\n [ \"You mentioned the module ModuleB in the configuration of this rule, but it could not be found.\"\n , \"This likely means you misconfigured the rule or the configuration has become out of date with recent changes in your project.\"\n ]\n }\n ]\n ]\n\n","type":"List.List { message : String.String, details : List.List String.String } -> Review.Test.ReviewExpectation"},{"name":"ignoredFilesImpactResults","comment":" Indicates to the test that the knowledge of ignored files (through [`Review.Rule.withIsFileIgnored`](Review-Rule#withIsFileIgnored))\ncan impact results, and that that is done on purpose.\n\nBy default, `elm-review` assumes that the knowledge of which files are ignored will only be used to improve performance,\nand not to impact the results of the rule.\n\nTesting that your rule behaves as expected in all your scenarios and with or without some files being ignored can be\nvery hard. As such, the testing framework will automatically — if you've used `withIsFileIgnored` — run the rule again\nbut with some of the files being ignored (it will in practice test out all the combinations) and ensure that the results\nstat the same with or without ignored files.\n\nIf your rule uses this information to change the results (report less or more errors, give different details in the error\nmessage, ...), then you can use this function to tell the test not to attempt re-running and expecting the same results.\nIn this case, you should write tests where some of the files are ignored yourself.\n\n test \"report an error when...\" <|\n \\() ->\n [ \"\"\"\n module ModuleA exposing (a)\n a = 1\"\"\", \"\"\"\n module ModuleB exposing (a)\n a = Debug.log \"log\" 1\"\"\" ]\n |> Review.Test.runOnModules rule\n |> Review.Test.ignoredFilesImpactResults\n |> Review.Test.expect whatYouExpect\n\n","type":"Review.Test.ReviewResult -> Review.Test.ReviewResult"},{"name":"moduleErrors","comment":" Assert that the rule reported some errors for modules, by specifying which ones. To be used along with [`Review.Test.expect`](#expect).\n\nIf you expect only module errors, then you may want to use [`expectErrorsForModules`](#expectErrorsForModules) which is simpler.\n\n test \"report an error when a module is unused\" <|\n \\() ->\n [ \"\"\"\n module ModuleA exposing (a)\n a = 1\"\"\", \"\"\"\n module ModuleB exposing (a)\n a = Debug.log \"log\" 1\"\"\" ]\n |> Review.Test.runOnModules rule\n |> Review.Test.expect\n [ Review.Test.moduleErrors \"ModuleB\"\n [ Review.Test.error\n { message = \"Remove the use of `Debug` before shipping to production\"\n , details = [ \"Details about the error\" ]\n , under = \"Debug.log\"\n }\n ]\n ]\n\nAssert which errors are reported using [`error`](#error). The test will fail if\na different number of errors than expected are reported, or if the message or the\nlocation is incorrect.\n\n","type":"String.String -> List.List Review.Test.ExpectedError -> Review.Test.ReviewExpectation"},{"name":"readmeErrors","comment":" Assert that the rule reported some errors for the `README.md` file. To be used along with [`Review.Test.expect`](#expect).\n\nIf you expect only errors for `README.md`, then you may want to use [`expectErrorsForReadme`](#expectErrorsForReadme) which is simpler.\n\n import Review.Project as Project exposing (Project)\n import Review.Test\n import Test exposing (Test, describe, test)\n import The.Rule.You.Want.To.Test exposing (rule)\n\n tests : Test\n tests =\n describe \"The.Rule.You.Want.To.Test\"\n [ test \"should extract even if there are errors\" <|\n \\() ->\n let\n project : Project\n project =\n Project.new\n |> Project.addReadme { path = \"README.md\", context = \"# Project\\n...\" }\n in\n \"\"\"module ModuleA exposing (a)\n a = 1\"\"\"\n |> Review.Test.runWithProjectData project rule\n |> Review.Test.expect\n [ Review.Test.readme\n [ Review.Test.error\n { message = \"Invalid link\"\n , details = [ \"README contains an invalid link\" ]\n , under = \"htt://example.com\"\n }\n ]\n ]\n ]\n\n","type":"List.List Review.Test.ExpectedError -> Review.Test.ReviewExpectation"},{"name":"run","comment":" Run a `Rule` on a `String` containing source code. You can then use\n[`expectNoErrors`](#expectNoErrors) or [`expectErrors`](#expectErrors) to assert\nthe errors reported by the rule.\n\n import My.Rule exposing (rule)\n import Review.Test\n import Test exposing (Test, test)\n\n someTest : Test\n someTest =\n test \"test title\" <|\n \\() ->\n \"\"\"\n module SomeModule exposing (a)\n a = 1\"\"\"\n |> Review.Test.run rule\n |> Review.Test.expectNoErrors\n\nThe source code needs to be syntactically valid Elm code. If the code\ncan't be parsed, the test will fail regardless of the expectations you set on it.\n\nNote that to be syntactically valid, you need at least a module declaration at the\ntop of the file (like `module A exposing (..)`) and one declaration (like `a = 1`).\nYou can't just have an expression like `1 + 2`.\n\nNote: This is a simpler version of [`runWithProjectData`](#runWithProjectData).\nIf your rule is interested in project related details, then you should use\n[`runWithProjectData`](#runWithProjectData) instead.\n\n","type":"Review.Rule.Rule -> String.String -> Review.Test.ReviewResult"},{"name":"runOnModules","comment":" Run a `Rule` on several modules. You can then use\n[`expectNoErrors`](#expectNoErrors) or [`expectErrorsForModules`](#expectErrorsForModules) to assert\nthe errors reported by the rule.\n\nThis is the same as [`run`](#run), but you can pass several modules.\nThis is especially useful to test rules created with\n[`Review.Rule.newProjectRuleSchema`](./Review-Rule#newProjectRuleSchema), that look at\nseveral files, and where the context of the project is important.\n\n import My.Rule exposing (rule)\n import Review.Test\n import Test exposing (Test, test)\n\n someTest : Test\n someTest =\n test \"test title\" <|\n \\() ->\n [ \"\"\"\n module A exposing (a)\n a = 1\"\"\", \"\"\"\n module B exposing (a)\n a = 1\"\"\" ]\n |> Review.Test.runOnModules rule\n |> Review.Test.expectNoErrors\n\nThe source codes need to be syntactically valid Elm code. If the code\ncan't be parsed, the test will fail regardless of the expectations you set on it.\n\nNote that to be syntactically valid, you need at least a module declaration at the\ntop of each file (like `module A exposing (..)`) and one declaration (like `a = 1`).\nYou can't just have an expression like `1 + 2`.\n\nNote: This is a simpler version of [`runOnModulesWithProjectData`](#runOnModulesWithProjectData).\nIf your rule is interested in project related details, then you should use\n[`runOnModulesWithProjectData`](#runOnModulesWithProjectData) instead.\n\n","type":"Review.Rule.Rule -> List.List String.String -> Review.Test.ReviewResult"},{"name":"runOnModulesWithProjectData","comment":" Run a `Rule` on several modules. You can then use\n[`expectNoErrors`](#expectNoErrors) or [`expectErrorsForModules`](#expectErrorsForModules) to assert\nthe errors reported by the rule.\n\nThis is basically the same as [`run`](#run), but you can pass several modules.\nThis is especially useful to test rules created with\n[`Review.Rule.newProjectRuleSchema`](./Review-Rule#newProjectRuleSchema), that look at\nseveral modules, and where the context of the project is important.\n\n import My.Rule exposing (rule)\n import Review.Project as Project exposing (Project)\n import Review.Test\n import Test exposing (Test, test)\n\n someTest : Test\n someTest =\n test \"test title\" <|\n \\() ->\n let\n project : Project\n project =\n Project.new\n |> Project.addElmJson elmJsonToConstructManually\n in\n [ \"\"\"\n module A exposing (a)\n a = 1\"\"\", \"\"\"\n module B exposing (a)\n a = 1\"\"\" ]\n |> Review.Test.runOnModulesWithProjectData project rule\n |> Review.Test.expectNoErrors\n\nThe source codes need to be syntactically valid Elm code. If the code\ncan't be parsed, the test will fail regardless of the expectations you set on it.\n\nNote that to be syntactically valid, you need at least a module declaration at the\ntop of each file (like `module A exposing (..)`) and one declaration (like `a = 1`).\nYou can't just have an expression like `1 + 2`.\n\nNote: This is a more complex version of [`runOnModules`](#runOnModules). If your rule is not\ninterested in project related details, then you should use [`runOnModules`](#runOnModules) instead.\n\n","type":"Review.Project.Project -> Review.Rule.Rule -> List.List String.String -> Review.Test.ReviewResult"},{"name":"runWithProjectData","comment":" Run a `Rule` on a `String` containing source code, with data about the\nproject loaded, such as the contents of `elm.json` file.\n\n import My.Rule exposing (rule)\n import Review.Project as Project exposing (Project)\n import Review.Test\n import Test exposing (Test, test)\n\n someTest : Test\n someTest =\n test \"test title\" <|\n \\() ->\n let\n project : Project\n project =\n Project.new\n |> Project.addElmJson elmJsonToConstructManually\n in\n \"\"\"module SomeModule exposing (a)\n a = 1\"\"\"\n |> Review.Test.runWithProjectData project rule\n |> Review.Test.expectNoErrors\n\nThe source code needs to be syntactically valid Elm code. If the code\ncan't be parsed, the test will fail regardless of the expectations you set on it.\n\nNote that to be syntactically valid, you need at least a module declaration at the\ntop of the file (like `module A exposing (..)`) and one declaration (like `a = 1`).\nYou can't just have an expression like `1 + 2`.\n\nNote: This is a more complex version of [`run`](#run). If your rule is not\ninterested in project related details, then you should use [`run`](#run) instead.\n\n","type":"Review.Project.Project -> Review.Rule.Rule -> String.String -> Review.Test.ReviewResult"},{"name":"whenFixed","comment":" Create an expectation that the error provides an automatic fix, meaning that it used\nfunctions like [`errorWithFix`](./Review-Rule#errorWithFix), and an expectation of what the source\ncode should be after the error's fix have been applied.\n\nIn the absence of `whenFixed`, the test will fail if the error provides a fix.\nIn other words, you only need to use this function if the error provides a fix.\n\n tests : Test\n tests =\n describe \"The.Rule.You.Want.To.Test\"\n [ test \"should report multiple Debug.log calls\" <|\n \\() ->\n \"\"\"module A exposing (..)\n a = 1\n b = Debug.log \"foo\" 2\n \"\"\"\n |> Review.Test.run rule\n |> Review.Test.expectErrors\n [ Review.Test.error\n { message = \"Remove the use of `Debug` before shipping to production\"\n , details = [ \"Details about the error\" ]\n , under = \"Debug.log\"\n }\n |> Review.Test.whenFixed \"\"\"module SomeModule exposing (b)\n a = 1\n b = 2\n \"\"\"\n ]\n ]\n\n","type":"String.String -> Review.Test.ExpectedError -> Review.Test.ExpectedError"}],"binops":[]},{"name":"Review.Test.Dependencies","comment":" Pre-built dependencies that you can use for your tests.\n\nIf you are looking for a specific dependency not provided by this list, you can create one yourself.\nIf you only care about a few types or functions, you can re-create them\nmanually using the API in [`elm/project-metadata-utils`](https://package.elm-lang.org/packages/elm/project-metadata-utils/1.0.0/Elm-Project).\nIf you need the complete dependency of an existing package, with comments and everything, that is surprisingly difficult, so I made [this\nscript to generate dependencies](https://github.com/jfmengels/elm-review/blob/master/create-dependency/index.js#L1-L12) to make that easier.\n\n\n## Dependencies\n\n@docs projectWithElmCore\n@docs elmCore, elmHtml, elmParser, elmUrl\n\n","unions":[],"aliases":[],"values":[{"name":"elmCore","comment":" Dependency for `elm/core`. It contains operators.\n\nIt is present by default in `elm-review` tests when you use [`Review.Test.run`](./Review-Test#run) or\n[`Review.Test.runOnModules`](./Review-Test#runOnModules), or when you create a new project starting with [`projectWithElmCore`](#projectWithElmCore).\n\nNote that if you create a new project using [`Review.Project.new`](./Review-Project#new), you'll have to manually add it\nagain with [`Review.Project.addDependency`](./Review-Project#addDependency) if you so wish to.\n\n","type":"Review.Project.Dependency.Dependency"},{"name":"elmHtml","comment":" Dependency for `elm/html`.\n","type":"Review.Project.Dependency.Dependency"},{"name":"elmParser","comment":" Dependency for `elm/parser`. It contains operators.\n","type":"Review.Project.Dependency.Dependency"},{"name":"elmUrl","comment":" Dependency for `elm/url`. It contains operators.\n","type":"Review.Project.Dependency.Dependency"},{"name":"projectWithElmCore","comment":" A project that only contains the `elm/core` dependency.\n","type":"Review.Project.Project"}],"binops":[]}] |