mirror of
https://github.com/jfmengels/elm-review.git
synced 2024-11-23 14:55:35 +03:00
104 lines
3.0 KiB
Elm
104 lines
3.0 KiB
Elm
module NoImportingEverything exposing (rule, Configuration)
|
|
|
|
{-| Forbid importing everything from a module.
|
|
|
|
|
|
# Rule and configuration
|
|
|
|
@docs rule, Configuration
|
|
|
|
-}
|
|
|
|
import Elm.Syntax.Exposing as Exposing
|
|
import Elm.Syntax.Import exposing (Import)
|
|
import Elm.Syntax.Node as Node exposing (Node)
|
|
import Elm.Syntax.Range exposing (Range)
|
|
import Review.Rule as Rule exposing (Error, Rule)
|
|
|
|
|
|
{-| Configuration for the rule.
|
|
-}
|
|
type alias Configuration =
|
|
{ exceptions : List String }
|
|
|
|
|
|
{-| Forbid importing everything from a module. Doing so can be confusing,
|
|
especially to newcomers when the exposed functions and types are unknown to them.
|
|
|
|
A preferred pattern is to import functions by name (`import Html exposing (div, span)`)
|
|
or using qualified imports (`import Html`, then `Html.div`). If the module name
|
|
is too long, don't forget that you can do qualified imports using an alias
|
|
(`import Html.Attributes as Attr`).
|
|
|
|
You can make exceptions for some modules by adding them to the `exceptions`
|
|
field, like `{ exceptions = [ "Html", "Html.Attributes" ] }`. The name should be
|
|
the exact name of the import. Allowing importing everything from `Html` will not
|
|
allow the same thing for `Html.Events`, unless explicitly specified.
|
|
|
|
config =
|
|
[ NoImportingEverything.rule { exceptions = [] }
|
|
]
|
|
|
|
|
|
## Fail
|
|
|
|
import Html exposing (..)
|
|
|
|
|
|
## Success
|
|
|
|
-- NoImportingEverything.rule { exceptions = [] }
|
|
import Html exposing (div, p, textarea)
|
|
|
|
-- NoImportingEverything.rule { exceptions = [ "Html" ] }
|
|
import Html exposing (..)
|
|
|
|
|
|
# When not to use this rule
|
|
|
|
If you prefer importing most of your modules using `exposing (..)`, then you
|
|
should not use this rule.
|
|
|
|
-}
|
|
rule : Configuration -> Rule
|
|
rule config =
|
|
Rule.newModuleRuleSchema "NoImportingEverything" ()
|
|
|> Rule.withSimpleImportVisitor (importVisitor config)
|
|
|> Rule.fromModuleRuleSchema
|
|
|
|
|
|
error : Range -> String -> Error {}
|
|
error range name =
|
|
Rule.error
|
|
{ message = "Do not expose everything from " ++ name
|
|
, details =
|
|
[ "Exposing `(..)` from a module means making all its exposed functions and types available in the file's namespace. This makes it hard to tell which module a function or type comes from."
|
|
, "A preferred pattern is to import functions by name (`import Html exposing (div, span)`) or to use qualified imports (`import Html`, then `Html.div`). If the module name is too long, you can give an alias to the imported module (`import Html.Attributes as Attr`)."
|
|
]
|
|
}
|
|
range
|
|
|
|
|
|
importVisitor : Configuration -> Node Import -> List (Error {})
|
|
importVisitor config node =
|
|
let
|
|
{ moduleName, exposingList } =
|
|
Node.value node
|
|
|
|
name : String
|
|
name =
|
|
moduleName
|
|
|> Node.value
|
|
|> String.join "."
|
|
in
|
|
if List.member name config.exceptions then
|
|
[]
|
|
|
|
else
|
|
case exposingList |> Maybe.map Node.value of
|
|
Just (Exposing.All range) ->
|
|
[ error range name ]
|
|
|
|
_ ->
|
|
[]
|