ESLint disable single line and code blocks

ESLint is a must have tool the editor as well as in your CI setup as it greatly improves code quality, however, sometimes you need to disable some rules.

JavaScript is a dynamically typed programming language and as such your editor will not have strict rules to figure out any issues with your code. Linters are handy all-in-one tools that checks your code writing style consistency, syntax errors as well as unused code and more. The one to rule them all in the JavaScript world is ESLint.

Disable ESLint rules on a single line

In some situations you may need to disable some linter rules on a single line. The syntax for this is:
// eslint-disable-line <rule1, rule2>.

So for example:

// TODO: refactor and rename this function to reduce complexity
function wayToComplicated_functionWith_mixed_namingStyle() { // eslint-disable-line complexity, camelcase
  // way to many nested if-statements and loops
}

You could skip specifying which rules to disable, but doing this is really really bad as you might now miss other mistakes that you have made on that same line. Speaking from bad debugging experiences, there is never really a good reason to do this.

Disable ESLint rules in a specific block of code

Sometimes you have a complete block where you need to disable rules. This I find most common in template code (HTML templates inside JavaScript files), in tests with large fixtures and possibly if re-using external code without refactoring it (which is probably bad practice anyway as you need to understand your code!).

The syntax for this is /* eslint-disable <rule1, rule2> */ and then /* eslint-enable <rule1, rule2> */ as soon as possible, again if you name exceptions the point is that the exceptions should be precise and as few as possible, else they would become the new norm.

Here is an example of a test with long lines that tests the purifyHTML function that we created in the XSS JavaScript injection post:

import {render} from 'lit-html/lib/render';
import {html} from 'lit-html/lit-html';

import {purifyHTML} from './purifyHTML';

describe('purifyHTML', () => {
  it('should filter out any target="_blank" from tags due to tabnapping security issues', () => {
    /* eslint-disable max-len */ // <-- Allow long lines starting from here
    const input = `<p>Lorem ipsum dolor sit <a target="_blank" href="https://writingjavascript.com/keep-your-html-output-secure-and-clean-from-xss-javascript-injection" title="Keep your HTML output secure and clean from XSS JavaScript injection">keep your html output secure</a> amet dolor sit amet, consectetur adip</p>`;


    const expectedOutput = `<p>Lorem ipsum dolor sit <a href="https://writingjavascript.com/keep-your-html-output-secure-and-clean-from-xss-javascript-injection" title="Keep your HTML output secure and clean from XSS JavaScript injection">keep your html output secure</a> amet dolor sit amet, consectetur adip</p>`;
    /* eslint-enable max-len */ // <-- Remove ling line rules exception here

    const renderTarget = document.createElement('div');
    render(html`${purifyHTML(input)}`, renderTarget);

    const purifiedHTML = container.innerHTML.replace(/<!---->/g, '').replace(/\s+/g, ' ').trim();

    expect(purifiedHTML).to.equal(expectedOutput);
  });
});

When to change my ESLint rules and when to make an exception?

As always you need to find your style, but I usually like starting by setting the ESLint rules as strict as possible using the npm package eslint-config-strict

I add this to my projects .eslintrc;

{
  "extends": ["strict", "strict/browser"]
}

Then whenever I find a conflict with those rules I consider:

  1. Can I write this in a rule compliant way?
  2. Is the current rule setup wrong/to strict and should it be changed? Check with the rest of your team/contributors.
  3. Is this a special case where the rules should be broken? (most common for me in embedded HTML templates or in tests)

It is important to find a good set of rules that works for the entire team working with that project. A good way can be to use rule sets from other external parties (like for example eslint-config-strict) to avoid to lengthy internal team discussions.

Once you know your rules and strive to comply with them you will probably feel when you have gone to far with your eslint-disable and eslint-disable-line statements.

I'm still not sure when to disable ESLint rules and when to update my rules

Okay, it can be a bit painful getting started with choosing the rules. I still would recommend taking those steps. If you want to see a more complete example that has been working for me see below:

{
  "extends": ["strict", "strict/browser"],
  "plugins": ["html", "json"],
  "parserOptions": {
    "ecmaVersion": 2018
  },
  "env": {
    "es6": true,
    "mocha": true
  },
  "globals": {
    "expect": true
  },
  "rules": {
    "camelcase": [
      "error"
    ],
    "id-match": ["error", "^([A-Za-z]+[A-Za-z0-9]*|[A-Z][A-Z_0-9]*[A-Z0-9])$", {"onlyDeclarations": true}],
    "id-length": [2, {
        "min": 3,
        "max": 50,
        "exceptions": ["ui", "i", "x", "y", "id", "d", "dx", "dy", "d3", "is", "fs"],
        "properties": "never"
      }
    ],
    "no-mixed-operators": 0,
    "no-use-before-define": "off",
    "no-debugger": "warn",
    "no-underscore-dangle": 0,
    "no-invalid-this": 0,
    "no-warning-comments": 0,
    "no-return-assign": "off",
    "filenames/match-regex": 0,
    "filenames/match-exported": 0,
    "comma-dangle": ["error", "never"],
    "object-curly-spacing": ["error", "never"],
    "array-bracket-spacing": ["error", "never"],
    "array-bracket-newline": 0,
    "array-element-newline": 0,
    "no-process-env": 0,
    "no-sync": 0,
    "init-declarations": 0,
    "no-magic-numbers": 0,
    "template-curly-spacing": ["error", "never"],
    "callback-return": 0,
    "no-undefined": 0,
    "no-console": 0,
    "global-require": 0,
    "consistent-this": 0,
    "prefer-destructuring": 0,
    "class-methods-use-this": 0,
    "func-style":"off",
    "id-blacklist": [
      2, "httpCallback", "err", "cb", "callback", "array", "func", "object", "string", "num", "number",
      "foo", "bar", "baz", "bang", "biz", "bong", "tmp", "temp", "thing", "that", "self"
    ]
  }
}

Note that this exact setup will probably not work 100% for your project, try to find a set of rules that helps you spot errors and too complex code in your project. Also some plugins will be needed to use this rule setup, but the linter should tell you when ran which ones might be missing for you.

That is all! Now keep you code, clean and nice and tidy!