Linting Configuration
November 5, 2022 ยท View on GitHub
Elm Language Server has built-in support for linting. All linting rules are enabled by default. If you want to disable a rule you can disable them by placing a configuration file in your project.
The linting system was based on Elm-Analyse, and the cofiguration:
<workspace-root>/elm-analyse.json
Example Configuration
This is the default configuration, with all checks enabled:
{
"checks": {
"BooleanCase": true,
"DropConcatOfLists": true,
"DropConsOfItemAndList": true,
"NoUncurriedPrefix": true,
"MapNothingToNothing": true,
"SingleFieldRecord": true,
"UnnecessaryListConcat": true,
"UnnecessaryPortModule": true,
"UnusedImport": true,
"UnusedImportAlias": true,
"UnusedImportedVariable": true,
"UnusedPatternVariable": true,
"UnusedTopLevel": true,
"UnusedTypeAlias": true,
"UnusedValueConstructor": true,
"UnusedVariable": true,
"UseConsOverConcat": true,
"MissingTypeAnnotation": true
},
"excludedPaths": []
}
Exclude paths
You can exclude certain files and folders from being linted by adding their path to
excludedPaths in elm-analyse.json.
Example:
"excludedPaths" : [
"src/Vendor",
"src/App/FileThatShouldNotBeLinted.elm"
],
Checks
BooleanCase
If you case over a boolean value, it is more idiomatic to use an if-expression.
Example rule violation:
thing : Boolean -> String
thing x =
case x of
True ->
"Hello"
False ->
"Goodbye"
DropConcatOfLists
If you concatenate two list literals [...] ++ [...], then you can merge them into one list.
Example rule violation:
foo : List Int
foo =
[ 1, 2, 3 ] ++ [ 4, 5, 6]
DropConsOfItemAndList
If you cons an item to a literal list (x :: [1, 2, 3]), then you can just put the item into the list.
Example rule violation:
foo : List Int
foo =
1 :: [ 2, 3, 4]
NoUncurriedPrefix
It's not needed to use an operator in prefix notation when you apply both arguments directly.
Example rule violation:
hello : String
hello =
(++) "Hello " "World"
MapNothingToNothing
Do not map a Nothing to Nothing with a case expression. Use andThen or map instead.
Example rule violation:
greet : Maybe String -> Maybe String
greet x =
case x of
Nothing ->
Nothing
Just x ->
Just ("Hello " ++ x)
SingleFieldRecord
Using a record is obsolete if you only plan to store a single field in it.
Example rule violation:
type Model =
Model { input : String }
UnnecessaryListConcat
You should not use List.concat to concatenate literal lists. Just join the lists together.
Example rule violation:
foo : List Int
foo =
List.concat [ [ 1, 2 ,3 ], [ a, b, c] ]
UnnecessaryPortModule
Don't use the port keyword if you do not need it.
Example rule violation:
port module Foo exposing (notAPort)
notAPort : Int
notAPort = 1
UnusedImport
Imports that have no meaning should be removed.
Example rule violation:
module Foo exposing (main)
import Html exposing (Html, text)
import SomeOtherModule
main : Html a
main =
text "Hello"
UnusedImportAlias
You defined an alias for an import (import Foo as F), but it turns out you never use it.
Example rule violation:
module Foo exposing (main)
import Html as H exposing (Html, text)
main : Html a
main =
text "Hello"
UnusedImportedVariable
When a function is imported from a module but is unused, it is better to remove it.
Example rule violation:
module Foo exposing (thing)
import Html exposing (Html, div, text)
main : Html a
main =
text "Hello World!"
UnusedPatternVariable
Variables in pattern matching that are unused should be replaced with '_' or left out completely.
Example rule violation:
greetRecord {name, age} = "Hello " ++ name
greetTuple (name, age) = "Hello " ++ name
greetConstructor (Person name age) = "Hello " ++ name
UnusedTopLevel
Functions and values that are unused in a module and not exported are dead code.
Example rule violation:
module Foo exposing (thing)
thing : Int
thing =
1
unusedThing : String -> String
unusedThing x =
"Hello " ++ x
UnusedTypeAlias
You defined a type alias, but you do not use it in any signature or expose it.
Example rule violation:
module Foo exposing (main)
import Html exposing (Html, text, Html)
type alias SomeUnusedThing =
{ name : String }
main : Html a
main =
text "Hello World"
UnusedValueConstructor
Value constructors which are not exposed and used should be eliminated.
Example rule violation:
module Greet exposing (Color, red, blue)
type Color
= Blue
| Red
| Green
red : Color
red = Red
blue : Color
blue = Blue
UnusedVariable
Variables that are not used could be removed or marked as '_'.
Example rule violation:
module Foo exposing (foo)
foo : String -> Int
foo x =
1
UseConsOverConcat
If you concatenate two lists, but the right hand side is a single element list, then you should use the cons operator ::.
Example rule violation:
foo : List String
foo =
[ "a" ] ++ [ "b", "c" ]
MissingTypeAnnotation
Type annotations are required on top-level declarations.
Example rule violation:
module Foo exposing (foo)
foo = 1
Note: This check was called "NoTopLevelSignature" in Elm-Analyse.
Compatibility with Elm Analyse
The linter was inspired by the tool Elm-Analyse by Mats Stijlaart, and existing elm-analyse configuration should be fully compatible with ElmLS.
While Elm Language Server does not use Elm-Analyse direct, the check names and descriptions are inspired by it.
We have deliberately excluded some checks that are supported by Elm-Analyse. Either they did not fit well with ElmLS or the issues they check are automatically fixed by elm-format.
ElmLS does also not support the TriggerWords property from Elm-Analyses and will just ignore it.