SiriusStarr / elm-review-pipeline-styles / ReviewPipelineStyles

Review Rule

rule : List (PipelineRule ()) -> Review.Rule.Rule

Reports pipelines that are not valid by user-defined rules. For example, the usage of <| or the usage of excessively-long |> pipelines.

config =
    [ ReviewPipelineStyles.rule
        [ forbid leftPizzaPipelines
            |> andCallThem "forbidden <| pipeline"
        , forbid rightPizzaPipelines
            |> that (haveMoreStepsThan 10)
            |> andCallThem "overly long |> pipeline"
        ]
    ]

This rule works with the following pipeline types:

Fail

By the above config:

a =
    Just <| foo bar

b =
    foo
        |> bar
        |> baz
        |> a
        |> b
        |> c
        |> d
        |> e
        |> f
        |> g
        |> h
        |> i
        |> j
        |> k

Success

By the above config:

a =
    foo bar
        |> Just

b =
    foo
        |> bar
        |> baz
        |> a
        |> b
        |> c
        |> d

When (not) to enable this rule

This rule is useful when you have strong opinions about how functions should be composed/applied and/or want to enforce consistent code style in a project.

This rule is not useful if you don't care what sorts of pipelines are used in a project.

Try it out

You can try this rule out by running the following command:

elm-review --template SiriusStarr/elm-review-pipeline-styles/example --rules ReviewPipelineStyles

Premade Rules

Check out the ReviewPipelineStyles.Premade module for some ready-to-go, common PipelineRules as well as how to construct them.

Config


type PipelineRule pipelineType

Configuration of this rule is in the form of a list of PipelineRules. It should be noted that these are hierarchical, i.e. only the first matching error will be generated in the event that a pipeline would generate multiple errors.

To create a new PipelineRule, use forbid, then a pipeline type, then the desired predicates and error. If no predicates are provided, the rule matches all pipelines of that type. For example, to entirely forbid <| in your project, you could use:

forbid leftPizzaPipelines
    |> andCallThem "forbidden <| pipeline"

Or, to forbid only |> pipelines that are extremely long, you could use:

forbid rightPizzaPipelines
    |> that (haveMoreStepsThan 10)
    |> andCallThem "overly long |> pipeline"

Fixes can be added using andTryToFixThemBy, e.g.

forbid leftPizzaPipelines
    |> that (haveMoreStepsThan 10)
    -- Adding fixes vvvv
    |> andTryToFixThemBy convertingToRightPizza
    -- Adding fixes ^^^^
    |> andCallThem "<| pipeline with several steps"

For the available fixes (or to make custom ones), check out ReviewPipelineStyles.Fixes.

forbid : Predicates.Operator pipelineType -> PipelineRule pipelineType

Forbid certain pipelines.

that : Predicates.Predicate pipelineType -> PipelineRule pipelineType -> PipelineRule pipelineType

Limit (blacklist) forbidden pipelines to those that match a specific predicate.

forbid rightPizzaPipelines
    |> that spanMultipleLines

Note that if that is used multiple times, it is equivalent to using or. For example, the following two rules are equivalent:

forbid rightPizzaPipelines
    |> that
        (spanMultipleLines
            |> or (haveMoreStepsThan 5)
        )

forbid rightPizzaPipelines
    |> that spanMultipleLines
    |> that (haveMoreStepsThan 5)

exceptThoseThat : Predicates.Predicate pipelineType -> PipelineRule pipelineType -> PipelineRule pipelineType

Exclude (whitelist) pipelines that match a predicate from being forbidden.

forbid rightPizzaPipelines
    |> that spanMultipleLines
    |> exceptThoseThat (haveMoreStepsThan 5)

Note that if exceptThoseThat is used multiple times, it is equivalent to using or. For example, the following two rules are equivalent:

forbid leftPizzaPipelines
    |> exceptThoseThat
        (doNot spanMultipleLines
            |> or (haveFewerStepsThan 2)
        )

forbid rightPizzaPipelines
    |> exceptThoseThat (doNot spanMultipleLines)
    |> exceptThoseThat (haveFewerStepsThan 2)

Failures

andCallThem : String -> PipelineRule anyType -> PipelineRule ()

Provide a descriptive name for this type of failing pipeline. This will appear in the elm-review error generated and should give you a sense of what's wrong and how to fix it. Either this or andReportCustomError must be the last thing in your rule.

andReportCustomError : String -> List String -> PipelineRule anyType -> PipelineRule ()

Provide a fully custom error message for failing pipelines, with both message and details. Either this or andCallThem must be the last thing in your rule.

Fixes

andTryToFixThemBy : Fixes.PipelineFix pipelineType -> PipelineRule pipelineType -> PipelineRule pipelineType

Add fixes to a PipelineRule.

Pipeline Types

rightPizzaPipelines : Predicates.Operator Predicates.ApplicationPipeline

The right "pizza" operator is right function application, i.e. |>. An example of this pipeline is below:

foo
    |> bar
    |> baz

leftPizzaPipelines : Predicates.Operator Predicates.ApplicationPipeline

The left "pizza" operator is left function application, i.e. <|. An example of this pipeline is below:

foo <| bar <| baz

rightCompositionPipelines : Predicates.Operator Predicates.CompositionPipeline

The right composition operator is right function composition, i.e. >>. An example of this pipeline is below:

foo
    >> bar
    >> baz

leftCompositionPipelines : Predicates.Operator Predicates.CompositionPipeline

The left composition operator is left function composition, i.e. <<. An example of this pipeline is below:

foo << bar << baz

parentheticalApplicationPipelines : Predicates.Operator Predicates.ApplicationPipeline

Parenthetical application is actually the absence of a pipeline, but rather successive function calls using parentheses, e.g.

foo (bar (baz (i (j k))))