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.
When encountering a Expression.FunctionOrValue ModuleName String
(among other nodes where we refer to a function or value),
the module name available represents the module name that is in the source code. But that module name can be an alias to
a different import, or it can be empty, meaning that it refers to a local value or one that has been imported explicitly
or implicitly. Resolving which module the type or function comes from can be a bit tricky sometimes, and I recommend against
doing it yourself.
elm-review
computes this for you already. Store this value inside your module context, then use
ModuleNameLookupTable.moduleNameFor
or
ModuleNameLookupTable.moduleNameAt
to get the name of the module the
type or value comes from.
Internal.ModuleNameLookupTable
Associates positions in the AST of a module to the name of the module that the contained variable or type originates from.
moduleNameFor : ModuleNameLookupTable -> Elm.Syntax.Node.Node a -> Maybe Elm.Syntax.ModuleName.ModuleName
Returns the name of the module the type, value, or operator referred to by this Node
was defined in.
The 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):
Expression.FunctionOrValue
nodeForTheName
in Expression.RecordUpdateExpression nodeForTheName modifiers
nodeForTheName
in TypeAnnotation.Typed nodeForTheName args
Pattern.NamedPattern
Expression.PrefixOperator
Expression.OperatorApplication
expressionVisitor : Node Expression -> Context -> ( List (Error {}), Context )
expressionVisitor node context =
case Node.value node of
Expression.FunctionOrValue _ "color" ->
if ModuleNameLookupTable.moduleNameFor context.lookupTable node == Just [ "Css" ] then
( [ Rule.error
{ message = "Do not use `Css.color` directly, use the Colors module instead"
, details = [ "We made a module which contains all the available colors of our design system. Use the functions in there instead." ]
}
(Node.range node)
]
, context
)
else
( [], context )
_ ->
( [], context )
Note: If using a Range
is easier in your situation than using a Node
, use moduleNameAt
instead.
moduleNameAt : ModuleNameLookupTable -> Elm.Syntax.Range.Range -> Maybe Elm.Syntax.ModuleName.ModuleName
Returns the name of the module the type, value, or operator referred to by this Range
.
The 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):
Expression.FunctionOrValue
nodeForTheName
in Expression.RecordUpdateExpression nodeForTheName modifiers
nodeForTheName
in TypeAnnotation.Typed nodeForTheName args
Pattern.NamedPattern
Expression.PrefixOperator
Expression.OperatorApplication
expressionVisitor : Node Expression -> Context -> ( List (Error {}), Context )
expressionVisitor node context =
case Node.value node of
Expression.RecordUpdateExpr (Node range name) _ ->
case ModuleNameLookupTable.moduleNameAt context.lookupTable range of
Just moduleName ->
( [], markVariableAsUsed ( moduleName, name ) context )
Nothing ->
( [], context )
_ ->
( [], context )
Note: If using a Node
is easier in your situation than using a Range
, use moduleNameFor
instead.
fullModuleNameFor : ModuleNameLookupTable -> Elm.Syntax.Node.Node a -> Maybe Elm.Syntax.ModuleName.ModuleName
This is the same as moduleNameFor
, except that the function will return the current module name
if the type or value was defined in this module, instead of Just []
.
createForTests : Elm.Syntax.ModuleName.ModuleName -> List ( Elm.Syntax.Range.Range, Elm.Syntax.ModuleName.ModuleName ) -> ModuleNameLookupTable
Creates a module name lookup table from a list of ranges and module names. The first argument is the name of the module in which this lookup table would be used.
NOTE: This is only meant to be used for testing purposes, not for direct use in rules.
This can be useful if you want to test individual functions that take a ModuleNameLookupTable
as an argument.
ModuleNameLookupTable.createForTests [ "My", "Module" ] []