DEV Community

Cover image for Enforcing ESLint rules: A guide to taming codebase chaos
Corentin Doue for Theodo

Posted on

Enforcing ESLint rules: A guide to taming codebase chaos

In the dynamic world of javascript development, ESLint plays a vital role in maintaining code quality. When developers install ESLint or introduce new rules, it often reveals tons of errors. How to manage them?

📝 TL;DR

  1. Use errors to make the rules blocking and enforce it in your CI.
  2. Comment out all existing ESLint errors using a script like eslint-disable-inserter.
  3. Merge this as soon as possible to prevent new errors from being added.
  4. Then fix the errors at your own pace.

⚠️ The temptation of the Warnings️

When developers first face ESLint errors, the volume of violations across files can be daunting. Some may be tempted to convert these errors into warnings to quickly pass the linter without addressing the underlying issues.

This is a bad practice, nothing will prevent new errors from being added. The developers will not know what is an acceptable warning or an error disguised as a warning.

⚔️ Another Pitfall: Try to fix them all at once

Some developers can be tempted to fix all existing errors before applying new ESLint rules to the codebase. While this approach seems logical, it often results in massive pull requests that are challenging to review and rebase. As developers work to resolve errors, others may simultaneously introduce new ones, making it an endless battle.

🤖 A Better Approach: eslint-disable-inserter

To address this issue and ease new rule usage, I created eslint-disable-inserter, a npm package that simplifies commenting existing ESLint errors.

GitHub logo CorentinDoue / eslint-disable-inserter

Inserts eslint-ignore comments automatically

eslint-disable-inserter

Easily insert eslint-disable-next-line comments into your code.

npm version CI-CD

When moving to a new ESLint config, or when adopting ESLint for the first time it's common to have tons of violations that you want to silence for now.

This library exposes a helpful utility, eslint-disable-inserter, that will do all the heavy lifting, and insert // eslint-disable-next-line ... or {/* eslint-disable-next-line ... */} comments into your code.

It handles JSX detection, and will insert the correct comment in the correct places.

This utility is idempotent, so it can be used each time you add a new ESlint rule.

Example (Before/After)

With the following file, which has some violations and a existing comment:

export const MyComponent = () => {
  let count = 0
  count += 1
  const messages: any = undefined
  return (
    <div>
      <h1>MyComponent</h1>
      <p>Count: {
…
Enter fullscreen mode Exit fullscreen mode

How eslint-disable-inserter Works

eslint-disable-inserter automatically inserts // eslint-disable-next-line ... or {/* eslint-disable-next-line ... */} comments into your code, silencing existing ESLint errors. It handles JSX detection and is idempotent, allowing repeated use without duplicates.

Example: Transforming Code

Suppose you have the following TypeScript file with ESLint violations:

export const MyComponent = () => {
  let count = 0;
  count += 1;
  const messages: any = undefined;
  return (
    <div>
      <h1>MyComponent</h1>
      <p>Count: {count + messages.myMessage}</p>
      {/* eslint-disable-next-line eqeqeq -- my comment */}
      <p>Is Zero: {count == 0 ? messages.yes : messages.no}</p>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

Running the following command:

eslint --format json . | eslint-disable-inserter
Enter fullscreen mode Exit fullscreen mode

Will transform the file to:

export const MyComponent = () => {
  let count = 0;
  count += 1;
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- FIXME
  const messages: any = undefined;
  return (
    <div>
      <h1>MyComponent</h1>
      {/* eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- FIXME */}
      <p>Count: {count + messages.myMessage}</p>
      {/* eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, eqeqeq -- FIXME my comment */}
      <p>Is Zero: {count == 0 ? messages.yes : messages.no}</p>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

♻️ Fix them all at your own pace

You have explicit comments for all existing ESLint errors. And no more errors will be added.

You can now decide with your team how you will handle this legacy and how to fix them.

You can visualize the size of the task with another package I created: eslint-disabled-stats

GitHub logo CorentinDoue / eslint-disabled-stats

Compute statistics about the eslint rules disabled

eslint-disabled-stats

Compute statistics about the eslint rules disabled

npm version CI-CD

It could be useful to track the correction of legacy eslint errors commented with a tool such as https://github.com/CorentinDoue/eslint-disable-inserter on your codebase.

The number of analyzed files and number of analyzed lines could be useful to track the evolution of the eslint errors compared to the evolution of the codebase.

Usage

$ npx eslint-disabled-stats -g -p "example/**/*.(js|ts)"

ℹ Analysing 2 files...
✔ Statistics computed

Rules disabled by rule:
• prefer-const: 1
• eqeqeq: 1
• curly: 1
• ALL_RULES: 1

Rules disabled by file:
• example/index.ts: 3
• example/legacy/legacy-file.js: 1

Total rules disabled:  4

Analysed files:        2
Analysed lines:        19

✔ Done

Options

  • The --pattern / -p flag allows specifying the glob pattern of files on which the statistics are computed The default pattern is **/*.(js|ts|jsx|tsx)

  • The --quiet / -q flag makes the console output lighter The details of the errors by…

$ npx eslint-disabled-stats -g -p "example/**/*.(js|ts)"

ℹ Analysing 2 files...
✔ Statistics computed

Rules disabled by rule:
• prefer-const: 1
• eqeqeq: 1
• curly: 1
• ALL_RULES: 1

Rules disabled by file:
• example/index.ts: 3
• example/legacy/legacy-file.js: 1

Total rules disabled:  4

Analysed files:        2
Analysed lines:        19

✔ Done
Enter fullscreen mode Exit fullscreen mode

Depending on the estimated time to fix the errors, you can fix them by batch or opt for the Boy Scout approach.

With the Boy Scout approach, you leave the codebase cleaner after your intervention.

You fix the errors as you encounter them in your daily work. You will fix them when you have context on the code, and this will reduce the risk of regression.

Make sure to not accept any Pull Request with commented ESLint errors to ensure a continuous improvement of your codebase quality. Some tools can help you to automate this part of the review, such as Danger JS.

You can also use IDE extensions such as TODO highlight or TODO Tree to make visible and track the remaining errors directly in your IDE.

🚀 Conclusion

Enforcing ESLint rules from day one is a pivotal step towards codebase excellence. By leveraging the strategies discussed in this article, you can pave the way for a cleaner, more maintainable codebase.

But the journey doesn't end here. If you have questions or want to share your experiences, don't hesitate to reach out on X/Twitter or GitHub

Top comments (1)

Collapse
 
thesanjeevsharma profile image
Sanjeev Sharma

I am definitely gonna try it. Thanks!