elm-review*

An Elm linter with custom rules

Jeroen Engels (Yeuroune)

Elm Paris

2019

*probable new name.

You'll see "elm-lint" in some slides

Situation

We have a great Elm application.

It's working well and it never crashes.

But we have trouble having a consistent color palette.

viewUserName : String -> Html msg
viewUserName userName =
    span 
        [ Attr.css [ Css.color (Css.hex "#222") ] ]
        [ text userName ]

viewAge : Int -> Html msg
viewAge age =
    span 
        [ Attr.css [ Css.color (Css.hex "#333") ] ]
        [ text (String.from Int age) ]
import Ui.Color as Color

viewUserName : String -> Html msg
viewUserName userName =
    span 
        [ Attr.css [ Css.color Color.darkGrey ] ]
        [ text userName ]

viewAge : Int -> Html msg
viewAge age =
    span 
        [ Attr.css [ Css.color Color.darkGrey ] ]
        [ text (String.from Int age) ]
module Ui.Color exposing (darkGrey, andOtherColors)

import Css

darkGrey : Color
darkGrey =
  Css.hex "#222"

"We now have a single module for

all of our colors, and we removed superfluous colors.

Because of that, we are sure to have consistent colors everywhere."

New pull request comes in

view : Model -> Html Msg
view model =
    div []
        [ ...
        , Button.button UserAddedItem "Add"
            |> Button.withColor (Css.hex "00FF00")
            |> Button.toHtml
        ]

Communication problem

How do we prevent this from happening?

Static code analysis

If you can detect the problem just by reading the code, static code analysis can help.

Rule of thumb

elm-review*

*Name pending your feedback

elm-review : List Rule -> YourProject -> List Error

Configuration

-- LintConfig.elm
module LintConfig exposing (config)

import Lint.Rule exposing (Rule)
import NoDefiningColorsOutsideOfUiColor


config : List Rule
config =
    [ NoDefiningColorsOutsideOfUiColor.rule
    ]
cd <your-project>
# Creates lint/elm.json and lint/LintConfig.elm
elm-lint init

This rule is specific to your team

rule : Rule
rule =
    Rule.newSchema "NoDefiningColorsOutsideOfUiColor"
        |> Rule.withSimpleExpressionVisitor expressionVisitor
        |> Rule.fromSchema

expressionVisitor : Node Expression -> List Error
expressionVisitor node =
    case Node.value node of
        -- "Application" means function call
        Expression.Application (function :: arguments) ->
            case Node.value function of
                -- "FunctionOrValue" means a variable
                Expression.FunctionOrValue [ "Css" ] "hex" ->
                    [ Rule.error
                        { message = "Do not define colors outside of Ui.Color"
                        , details =
                            [ "At fruits.com, we try to have all the colors in our application defined in the Ui.Color file. This helps us to have a consistent color palette across the application."
                            , "You should define this color in the Ui.Color module, and import it to use it at this location. Do check whether the color does not already exist though."
                            ]
                        }
                        (Node.range node)
                    ]
                _ ->
                    []
        _ ->
            []

You can now have guarantees that you didn't have before

 

Handles (part of) the communication with your team

No built-in rules (See why)

  • Custom rules

  • ​Rules from the Elm package registry

cd <your-project>/lint/
elm install @jfmengels/lint-unused
elm install @jfmengels/lint-debug

Thank you!

Elm package: https://package.elm-lang.org/packages/jfmengels/elm-lint/latest/

 

NPM: npm install @jfmengels/elm-lint


Live demo: https://elm-lint.now.sh

elm-review (Paris Meetup 2019)

By Jeroen Engels

elm-review (Paris Meetup 2019)

  • 503