Create a custom eslint rule with typescript

Volodymyr Yepishev - Apr 2 '21 - - Dev Community

Creating custom eslint rules can often come handy. I enjoy using typescript, so I decided I'd share a way how to use its superpowers to create custom eslint rules.

Step one

Create a repo and initialise an npm package in it:

mkdir my-awesome-eslint-rule && cd my-awesome-eslint-rule && npm init -y
Enter fullscreen mode Exit fullscreen mode

Make sure your package name starts with eslint-plugin-, 'cos this is the way, i.e.:

{
    "name": "eslint-plugin-my-awesome-rule",
    ...
Enter fullscreen mode Exit fullscreen mode

Install the dependencies (we won't touch @types/estree in this tutorial, but it's quite handy for types when writing eslint rules, so I keep it here):

npm i -D  @types/eslint @types/estree @types/node tsup typescript
Enter fullscreen mode Exit fullscreen mode

Basically we're installing three packages with types definitions, typescript and a the simplest and fastest way to bundle your TypeScript libraries :)

Step two

We'll be seriously developing, so we'll have a src and dist folders, for the source and produced output respectively, so let's configure our package.json accordingly:

{
    "name": "eslint-plugin-my-awesome-rule",
    "main": "./dist/index.js",
    "files": [
    "dist/**"
    ],
    ...
Enter fullscreen mode Exit fullscreen mode

Now let's create the src folder with an index.ts file as the entry point to our future rule:

module.exports = {
    rules: {
        // our rules will go here
    },
};
Enter fullscreen mode Exit fullscreen mode

Step three

Let's create a silly simple rule in our src folder. Note, that a rule is a function that accepts context and returns rule listener. Both these types we can get from the eslint.
For the sake of demonstration let's create a rule that questions every import:

// ./src/my-awesome-rule.ts
import { Rule } from "eslint";

export function myAwesomeRule(context: Rule.RuleContext): Rule.RuleListener {
    return {
        ImportDeclaration(node) {
            context.report({
                node,
                message: 'Are you sure about this?'
            })
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Now let's import it into our entry file and plug it in:

// ./src/index.ts
import { myAwesomeRule } from './my-awesome-rule';

module.exports = {
    rules: {
      'my-silly-rule': {
        create: myAwesomeRule,
      },
    },
};
Enter fullscreen mode Exit fullscreen mode

Step four

Let's transpile it to js to make it usable. Add a build command to the scripts section in the package.json file. We'll be using tsup, which is absolutely awesome for this:

...
"scripts": {
    "build": "tsup src/index.ts --no-splitting --minify"
},
...
Enter fullscreen mode Exit fullscreen mode

Run the command to get a minified tiny version of your rule in dist folder.

Step five

Install and enjoy, you can install it directly from the dist folder, run npm pack to create an archive with your new rule or publish it to npm with npm publish.
After installing, don't forget to plug it into your .eslintrc, by adding it to the plugins section and activating its rule:

{
    "plugins": ["my-awesome-rule"],
    "rules": {
      "my-awesome-rule/my-silly-rule": "warn"
    }
  ...

Enter fullscreen mode Exit fullscreen mode

Have fun :)

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .