question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Change Request: Allow multiple configs of a rule - PR made

See original GitHub issue

ESLint version

v8.9.0

What problem do you want to solve?

Eslint currently does not (easily) allow for a rule to be applied more than once with different configurations.

Example rule config with suggested feature:

"settings": {
    "alternative-rule-appendices": ["-rule-duplicate"]
},
"rules": {
    "max-lines": [
        "warn",
        {
            "max": 350,
            "skipBlankLines": true,
            "skipComments": false
        }
    ],
    "max-lines-rule-duplicate": [ // This rule gets interpreted as being named max-lines
        "error",
        {
            "max": 450,
            "skipBlankLines": true,
            "skipComments": false
        }
    ],
}

Others have sought this feature before, but have either had their request rejected, not found a solution, or not documented their solution (links in no particular order): https://stackoverflow.com/questions/34077756/including-both-errors-and-warnings-for-same-eslint-rule https://stackoverflow.com/questions/53331483/eslint-error-and-warning-for-the-same-rule-with-different-options https://github.com/eslint/eslint/issues/6776 https://github.com/eslint/eslint/issues/11089 https://github.com/eslint/eslint/discussions/14688

I personally wanted this feature for the reason in the example. Files above 350 lines should be considered for refactoring while files <450 should definitely be refactored as a rule - with exceptions needing explicit approval and justification.

Edit: Disregard the stricken sections and their code blocks - look at the bottom or the pull request instead.

What do you think is the correct solution?

Add the following to line 1188 in function getRule in lib/linter/linter.js

if (ruleId.slice(-4) === '-alt') {
    let id = ruleId.slice(0, -4)
    return (
        (slots.lastConfigArray && slots.lastConfigArray.pluginRules.get(id)) ||
        slots.ruleMap.get(id)
    );
}

the resulting function would look like:

function getRule(slots, ruleId) {
    if (ruleId.slice(-4) === '-alt') {
        let id = ruleId.slice(0, -4)
        return (
            (slots.lastConfigArray && slots.lastConfigArray.pluginRules.get(id)) ||
            slots.ruleMap.get(id)
        );
    }
    return (
        (slots.lastConfigArray && slots.lastConfigArray.pluginRules.get(ruleId)) ||
        slots.ruleMap.get(ruleId)
    );
}

This change works in my setup, but I have not run further tests. I just wanted to share my solution as it seemed some others wanted one. I believe it has potential for being backwards-compatible and low maintenance, but I leave final say to the experts.

Participation

Additional comments

As I’m sure you can tell, this change can be modified to allow more rule copies - however I’m not sure of the performance impact, nor the amount of use it would get. Just change line 1188-1189 to:

if (ruleId.slice(-2) in ['-1', '-2', '-3']) {
    let id = ruleId.slice(0, -2)

There might very well be much more elegant or performant solutions - I am very, very new to JS relative to most of you I’m sure.

Edits

Edit: To add thoughts from the exchange with @ljharb below: An ideal solution would probably be to add a new setting to the config. Default is an empty array, and in config you enter a list of strings to check for in rules as above. This allows the end user to adapt to eventual conflicts with plugin rule names.

str.slice(idx) in [arr] doesn’t work for that though, and I can’t think of an easy way to only check the end of the rule name string when the string it is checked against is of unknown/dynamic length. Like I wrote - there is probably an elegant solution, but I could use some help.

Edit 2: Where userDefinedArray is the array of strings specified in config file, and default is an empty array.

function getRule(slots, ruleId) {
    for (let i = 0; i < userDefinedArray.length; i++) {
        const userDefStr = userDefinedArray[i]
        if (ruleID.endsWith(userDefStr)) {
            const index = ruleID.lastIndexOf(userDefStr);
            const id = ruleID.slice(0, index)
            return (
                (slots.lastConfigArray && slots.lastConfigArray.pluginRules.get(id)) ||
                slots.ruleMap.get(id)
            );
        }
    }
    return (
        (slots.lastConfigArray && slots.lastConfigArray.pluginRules.get(ruleId)) ||
        slots.ruleMap.get(ruleId)
    );
}

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:11 (5 by maintainers)

github_iconTop GitHub Comments

3reactions
nzakascommented, Feb 23, 2022

Thanks for all the work and discussion that was put into this. We aren’t making any changes to the current config system while we are working on a new one.

In the new system, it’s possible to create multiple references to the same rule as long as you provide a unique name. You can include multiple copies of the same plugin with different namespaces to allow you to specify plugin rules more than once: https://github.com/eslint/rfcs/tree/main/designs/2019-config-simplification#plugins-specifying-their-own-namespaces

All we would need to do is expose core rules in some way that allows you to treat them like another plugin and the problem is solved.

3reactions
aladdin-addcommented, Feb 21, 2022

I do see its value, e.g. for the rules like no-restricted-xx:


"no-restricted-imports": [ "error", "assert"], // to forbid node builtins
"no-restricted-imports": [ "warn", "understore"], // to warn underscore (lodash preferred)

however i don’t think it’s the right way to go. Just a thought: good to have a straightforward way(doesn’t have to be in eslint core) to help users wrap an existing rule to a new one. e.g.

const no_underscore = wrap("no-restricted-imports", ["underscore"]).

so, you can use and config the new rule.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Merge request approval rules - GitLab Docs
Edit an approval rule · Go to your project and select Settings > Merge requests. · In the Merge request approvals section, scroll...
Read more >
Add a custom rule to a work item type - Azure DevOps Services
In this article. Prerequisites; Open Settings>Process; Add a custom rule; Delete or disable a rule; Related articles.
Read more >
Configuration Options - Renovate Docs
If enabled Renovate tries to determine PR assignees by matching rules defined ... the Renovate configuration migration pull request would make this change:....
Read more >
What Is AWS Config? - AWS Config - AWS Documentation
Use conformance packs, or a collection of AWS Config rules and remediation ... having to monitor these changes by polling the calls made...
Read more >
Understanding and configuring Cloudflare Page Rules (Page ...
Edit a page rule · To enable or disable a rule, click the On/Off toggle. · To modify the URL pattern, settings, and...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found