How to create a custom ESlint plugin

How to create a custom ESLint plugin for function prefix | Rahul Sharma (DevsMitra)

Recently our development team decided to enforce the role for function naming. Meaning, all function name should start with the prefix defined in the eslint rule.
Instead of giving some random names to the function, strict developers follow some pre-defined conventions.

Example:

<button onclick=”someFunction()”>Login</button>
function someFunction() {}
<button onclick=”onLogin()”>Login</button>
function onLogin() {}

In the HTML button click, we can give any name we want. but when we read the code, the second function makes more sense. Let’s write a plugin that will warn us about wrong function naming.

JavaScript Naming Convention Best Practices

Boolean: is, are, has

Events: init, pre, on, post

verb as a prefix: get, set, post, put, push, apply, calculate, compute, to, etc.

We’ll be using eslint for this project.

ESLint Introduction:

ESLint statically analyzes your code to quickly find problems. ESLint is built into most text editors and you can run ESLint as part of your continuous integration pipeline.

Definition referred from eslint official site, Check more details about ESlint here

Prerequisite:

  1. Make sure you have installed the latest Node.js ( Download link )
  2. Basic knowledge of javascript, eslint
  3. Code editor (vs code)

There are 2 sections to this article in the

Section 1. We’ll be creating a Node.js project and setup eslint for it. If you have already created a project and eslint setup. you can skip this section and directly jump into section 2.

Section 2. We’ll create an eslint plugin and use that in the project.

Section 1: Setup Node.js project

Step 1:

Open the terminal and run the following command

mkdir my-lint //creating directory
cd my-lint

Step 2:

Initialize the Node.js project using the following command from the terminal

npm init

My package.json looks like this.

package.json:

{
"name": "my-lint",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}

Step 3:

It’s time to add ESLint dependencies

npm install -D eslint

Add eslint script to the package.json

{
"name": "my-lint",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"lint": "eslint src/**/*.js"
},
"devDependencies": {
"eslint": "^7.21.0"
},
"author": "",
"license": "ISC"
}

Step 4:

Next, We have to create a .eslintrc.js with the following configuration - this is similar to what you already do in your apps:

module.exports = {
parserOptions: {
ecmaVersion: 2018,
},
extends: ["eslint:recommended"],
plugins: [],
rules: {},
};

Step 5:

Create src and packagesthe directory in the root directory.

Create a src/index.js file inside the src directory and add the following code to it.

My index.js looks like this

const someFunction = () => {
console.log("Hello World");
};
someFunction();

My project structure looks like this

How to create an eslint plugin to check funcion prefix in the javascript | devsmitra (Rahul Sharma)
How to create an eslint plugin to check funcion prefix in the javascript | devsmitra (Rahul Sharma)

You can run the npm run lint or yarn lint to check eslint working or not.

So far we have created the Node.js project and setup eslint for it.

Section 2: Create eslint plugin

An ESLint rule contains 2 main parts:

  • meta: an object where we will specify the usage of our rule.
  • create: a function that will return an object with all the methods that ESLint will use to parse our statement. Each method returned is an AST(Abstract Syntax Tree) node.

NOTE: Plugin should follow name format of eslint-plugin-<plugin-name>

Let’s get started…

Step 1:

Create a eslintthe directory in your packages directory. (you can any name you want)

Run the following command in your terminal

cd packages/eslintnpm init // I'm giving project name to eslint-plugin-my-lint

Step 2:

Create an index.js file inside the packages/eslint directory.

const {onFuncPrefixMatchingCreate}= require("./funcPrefixMatching");module.exports = {
rules: {
"func-prefix-matching": {
create: onFuncPrefixMatchingCreate,
},
},
};

Don’t worry about funcPrefixMatching import will be creating that in the next step.

Step 3:

Create a javascript file called funcPrefixMatching.js in your packages/eslint directory, put the below code in it:

const rulePrefix = ["is", "pre", "on", "post", "get", "set"];const isValidName = (name, { prefix, exclude }) => {
const isValid = (prefix) => name.indexOf(prefix) === 0;
return exclude.some(isValid) || prefix.some(isValid);
};
const onFuncPrefixMatchingCreate = (context) => {
const { options } = context;
const {include = [], exclude = [] } = options[0]||{};
return {
Identifier: (node) => {
if (node.parent.init &&
node.parent.init.type === "ArrowFunctionExpression"
// You can add more checks here
) {

const { name } = node;
const allPrefix = [...include, ...rulePrefix].sort();
// Sorting is optional

if (!isValidName(name, { prefix: allPrefix, exclude })) {
context.report(node, `${name} should start with ${allPrefix.join(", ")}.`);
}
}
},
};
};
module.exports = { onFuncPrefixMatchingCreate };

Step 5:

It’s time to add our ESLint plugin to the dependencies

npm i file:packages/eslint -D

Step 6:

Update .eslintrc.js

module.exports = {
parserOptions: {
ecmaVersion: 2018,
},
extends: ["eslint:recommended"],
plugins: ["my-lint"],
rules: {
"my-lint/func-prefix-matching":
[ 1, { include: [], exclude: [] } ]
// We can include or exclude prefix
// You can add more option here like message, ignore case etc.
},
};

Step 7:

Time to check our plugin.

How to create an eslint plugin to check funcion prefix in the javascript | devsmitra (Rahul Sharma)
How to create an eslint plugin to check funcion prefix in the javascript | devsmitra (Rahul Sharma)

Custom prefix

module.exports = {
parserOptions: {
ecmaVersion: 2018,
},
extends: ["eslint:recommended"],
plugins: ["my-lint"],
rules: {
"my-lint/func-prefix-matching":
[ 1, {
include: ["to"],
exclude: ["excludeSomeFunction"],

message: ""
}
]
},
};

index.js

// Custom include
const toSomeFunction = () => {
console.log("Hello");
};
// Custom exclude
const excludeSomeFunction = () => {
console.log("Hello");
};
toSomeFunction();
excludeSomeFunction();

Working without error. 😎

Reference: Working with Plugins — ESLint — Pluggable JavaScript linter

Got any questions or additional? please leave a comment.

Thank you for reading 😊

Github Repo:

https://github.com/devsmitra/func-prefix-matching

I’m a software engineer who specializes in JavaScript, Node.js, React.js, Angular, Angular.js, Express.js, Typescript, and MongoDB.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store