Creating an ESLint Plugin

Björn Tegelund
4 min readMar 17, 2016

--

There are a lot of useful ESLint plugins out there. At Tumblbug, we are fans of eslint-config-airbnb and eslint-plugin-react. However, as a project grows, you might start feeling the need for adding custom rules to ensure that your developers are following best practices. In this blog post, I’ll be going over creating a custom ESLint plugin and writing a simple rule for it.

Setup

We’ll begin by installing Yeoman and the handy generator-eslint, which provides all the boiler-plate code needed to create our plugin:

npm install -g yo
npm install -g generator-eslint

Next, we create a directory for our plugin and initialize it:

mkdir eslint-plugin-tutorial
cd eslint-plugin-tutorial
yo eslint:plugin? What is your name? ...
? What is the plugin ID? tutorial
? Type a short description of this plugin: ...
? Does this plugin contain custom ESLint rules? Yes
? Does this plugin contain one or more processors? No
npm install

Rule Creation

Now it’s time to create our first rule! We’re going to be making a rule that prohibits code like:

var _ = require('your favorite fp library');

as this brings too much code into the current module and makes it difficult to perform tree-shaking.

Let’s begin by generating our rule! The generator-eslint plugin has a generator for this as well.

yo eslint:rule? What is your name? ...
? Where will this rule be published? ESLint Plugin
? What is the rule ID? no-full-fp-lib
? Type a short description of this rule: ...
? Type a short example of the code that will fail: var _ = require('your favorite fp library');

To actually write our rule, we’re going to need to know a bit about how JavaScript is parsed. ESLint uses a JavaScript parser called Espree to generate an abstract syntax tree (AST) from JavaScript code. Rules can then “listen” for certain types of nodes in the tree and when a matching node is discovered, rules are invoked to check whether any action needs to be taken. Luckily, there’s a handy site available for turning JavaScript code into an AST, called astexplorer. As we’ll be using the default Espree parser in ESLint to parse our code, it’s a good idea to change parser from the default ‘Acorn’ to ‘Espree’.

The following AST is generated by the code we want to prohibit:

This AST provides us with all the information needed to create our rule. First off, we can see that the nodes we are interested in are of the type VariableDeclaration, which contains a list of VariableDeclarator. We can implement our rule by looking at each VariableDeclarator and specifically check for an id with name = _ and an init where the callee is require. I recommend consulting the ESLint documentation for a more in-depth explanation on writing rules.

Turning the above rule logic into code, we get:

Testing

We can easily test our rule by installing Mocha and editing our test script in package.json:

“scripts”: {
“test”: “mocha ./tests/**/*.js”
},

We already have some code generated by generator-eslint, so all we have to do is fill in the error message, type, and add a couple of valid examples!

Running mocha using:

npm run test

We see that all our tests pass!

ES6+

Writing and testing rules for ES6 is a bit more difficult, as additional configuration is needed to get everything running. We can still use AST explorer to generate an AST, but make sure that the appropriate ecmaVersion is selected under parser options.

Writing the equivalent code in ES6, we now want to prohibit imports such as:

import _ from 'my favorite fp lib';

We write the rule using the same logic as earlier, and end up with the following:

To test this, we need to provide ESLint with some additional configuration for it to know how to run our rule. First off, as we’re now using ES6, we have to set the ecmaVersion to 6, and as our rule uses import, we also have to set a flag to enable this. A more extensive list of the different features that can be used is available on ESLints documentation.

We now end up with the following test code:

Running npm run test, we see that our rule is doing its job correctly!

Wrapping Up

Now that our rule is written and tested, all that remains is wrapping up our package.

As ESLint does not enable any rules by default, we will probably want to export a config that enables our new rule:

This recommended config can then be used by configuring our other projects to extend it.

All that’s left now is to optionally publish our package to npm, and to install and use it in our other projects!

Take a look at the project repository on Github.

Happy linting!

Update: much thanks to Ilya Volodin for sharing a lot of useful resources! This post is now much simpler than it originally was!

--

--