Skip to content

Rule idea: forbid elements by name #19

@jfmengels

Description

@jfmengels

What the rule should do:

Report usages of specific values/functions/types/modules by name.

What problems does it solve:

Making it much easier to forbid the usage of certain elements, lowering the entry to use elm-review.

Example of things the rule would report:

Given configuration like

RuleNameTBD.rule
  [ { value = "Html.img"
    , message = "Use Accessibility.img or Accessibility.decorativeImg instead of Html.img"
    , details = [ "...some explanations as to why..." ]
    }
  ]

then this rule would report references to Html.img with the message and details defined above.

When (not) to enable this rule:

When you don't have specific things you want to forbid or move away from.

I am looking for:

I have plenty of questions around this rule, and could use a lot of feedback!

  1. Collision with NoDeprecated

The NoDeprecated rule in this same package has quite a bit of overlap with this proposal. For instance, you can forbid a function defined in your codebase by either tagging it as deprecated, or by using this rule by explicitly targeting the function by name.

Which one to use becomes a bit of an unclear decision. We can probably merge the two ideas, but then it shouldn't be called NoDeprecated. There is definitely some overlap, but it's also not a perfect overlap.

  1. Need for exceptions

A common use-case for this rule is to forbid something in favor of a custom solution. For instance, you could define a new Button module and then forbid the Html.button function. But you would still want to support the usage of Html.button in this one module. So each restriction likely needs to be configured with exceptions. Except that you can't use the existing Review.Rule.ignoreErrorsFor* functions as that would make the exceptions apply to unrelated forbidden elements.

Unless you use the rule multiple times, which is possible (but potentially confusing for people who come from ESLint where that's not possible because redefining a rule overrides it).

  1. Suppressions

One thing that I've noticed with NoDeprecated is that when you're using elm-review's suppression system (which the rule is pretty much meant to), you can get a large amount of suppressions (we have over a 1000 at work), and it can be a bit hard to figure out which deprecated functions are responsible for most suppressed usages. I have a proof of concept to use --extract to help give that insight, which could help a bit.

I'm thinking that if we have one rule with plenty of these restrictions and we suppress that, then once again it would be hard to tell which functions are still used a lot and which ones don't have any issues.

  1. There probably needs quite a few configuration options to forbid functions vs types (and especially record type constructors) vs modules vs dependencies vs other things. The proposed API above only works for functions and/or types, but depending on the scope, we might want more.
    These could also be split into multiple new rules.

  2. Maybe I'm overthinking or over-engineering this rule, and it would be nice to have a simpler rule (or way of writing this rule), for instance that would only forbid a single element. But that then becomes annoying if you have plenty of related functions you want to forbid.

  3. I also need a good rule name.

I'm thinking NoForbiddenReferences or something. I do find the double negation a bit confusing though, so maybe only ForbiddenReferences.
ESLint has multiple "no-restricted-*" rules, like "no-restrict-syntax" and "no-restricted-globals" which are close. But I have found the name very confusing for years.

That said, if we decide to limit this rule to forbidding a single element, then the rule name should likely be configurable by the user of the rule, as that is a somewhat important part of an elm-review error. But the module containing this rule would still need to be named 😄

  1. I'm thinking I could in the documentation of the rule show the entire implementation of the rule, so that if someone wants to extend the rule a bit, then they can easily do so with that example as the source code. Does that sound like a good idea?

Thoughts and ideas welcome 🙏

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions