How to create a custom ESlint plugin
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:
- Make sure you have installed the latest Node.js ( Download link )
- Basic knowledge of javascript, eslint
- 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 packages
the 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
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 eslint
the 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.
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: