preface
While there are plenty of useful ESLint plugins out there, as projects evolve iteratively, you may run into situations where your existing ESLint plugins won’t be enough for your current team. In this case, you will need to create your own ESLint plugin.
In this article I’ll take you through the general history of the various Lint tools, then step by step create your own ESLint plug-in and teach you how to use the AST abstract syntax tree to make the rules for this plug-in.
To give you an idea of how ESLint works.
Objectives & knowledge points involved
The purpose of this ESLint plugin is to disable console.time() in project development.
- AST Abstract syntax tree
- ESLint
- Npm release
- Unit testing
Plug-in scaffolding construction
Here we use Yeoman and Generator-ESLint to build the plug-in’s scaffolding code. Installation:
npm install -g yo generator-eslint
Copy the code
Eslint-plugin-demofortutorial:
mkdir eslint-plugin-demofortutorial
cd eslint-plugin-demofortutorial
Copy the code
Initialize the ESLint plugin’s project structure:
Yo eslint:plugin // Build an initial directory structureCopy the code
The directory structure of the file is as follows:
. ├ ─ ─ the README. Md ├ ─ ─ lib │ ├ ─ ─ index. The js │ └ ─ ─ rules ├ ─ ─ package. The json └ ─ ─ tests └ ─ ─ lib └ ─ ─ rulesCopy the code
Install dependencies:
npm install
Copy the code
At this point, the environment is set up.
Create rules
Terminal execution:
Yo ESLint :rule // Generates the default ESLint rule template fileCopy the code
.├ ─ ├─ exercises, ├─ exercises, exercises, exercises, exercises, exercises, exercises, exercises, exercises, exercises, exercises // Multiple rules can be built under this directory, This paper will take only one rule to explain │ └ ─ ─ no - the console - time. Js ├ ─ ─ package. The json └ ─ ─ tests / / unit test └ ─ ─ lib └ ─ ─ rules └ ─ ─ no - the console - time. JsCopy the code
In the above structure, we need to develop the Eslint plugin in the./lib/ directory, which is where the rules define it.
Use of AST in ESLint
Before you can formally write the ESLint plugin, you need to understand how ESLint works. If you don’t know how to configure ESLint in your project, click on the official documentation.
In corporate team projects, different developers write different source code, so in ESLint, how to analyze the source code written by each person?
As developers, we need to know how to use abstraction when faced with this kind of problem! So what about the abstraction of Javascript?
Yes, it’s the AST (Abstract Syntax Tree), the graph you’ve seen hundreds of times.
In ESLint, esprima is used by default to parse Javascript statements we write, generate abstract syntax trees, intercept them to see if they conform to the way we write them, and display errors, warnings, or passes. The core of ESLint is rules, and the core of defining rules is using the AST for validation. Each rule is independent of each other and can be set to disable off, warn warn⚠️ and error❌, as well as pass normally without any warning.
Rule creation
With the relationship between ESLint and the AST covered above, we can move on to developing specific rules. Lib /rules/no-console-time.js
/**
* @fileoverview no console.time()
* @author Allan91
*/
"use strict";
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = {
meta: {
docs: {
description: "no console.time()",
category: "Fill me in",
recommended: false
},
fixable: null, // or "code" or "whitespace"
schema: [
// fill in your schema
]
},
create: function(context) { // variables should be defined here //---------------------------------------------------------------------- // Helpers //---------------------------------------------------------------------- // any helperfunctions should go here or else delete this section
//----------------------------------------------------------------------
// Public
//----------------------------------------------------------------------
return{ // give me methods }; }};Copy the code
This file provides a template for writing rules. Each rule corresponds to an exportable Node module. It consists of two parts: Meta and Create.
- Meta represents the metadata for this rule, such as its category, document, schema for accepted parameters, and so on.
- Create: If meta says what we want to do, then create says how the rule will analyze the code;
Create returns an object where the most common key name is a selector in the AST abstract syntax tree, where we can get the selected content and then make some judgment about the selected content to see if it meets our rules. If not, we can use context.report to throw a problem, and ESLint will use our configuration to display the thrown content differently.
For details about how to set parameters, see the official documents
The ESLint plugin created in this article is designed to prevent developers from using console.time() in their projects. Let’s look at this code in the abstract syntax tree:
We will use the following to determine if the code contains console.time:
So we write the rules in lib/rules/no-console-time.js according to the AST (abstract syntax) above:
/** * @fileoverview no console.time() * @author Allan91 */
"use strict";
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = {
meta: {
docs: {
description: "no console.time()".category: "Fill me in".recommended: false
},
fixable: null.// or "code" or "whitespace"
schema: [
// fill in your schema].// Error message description
messages: {
avoidMethod: "console method '{{name}}' is forbidden.",}},create: function(context) {
return {
// The key name is the selector name in ast
'CallExpression MemberExpression': (node) = > {
// If the following conditions are met in the AST, context.report() is used as an external warning ⚠️
if (node.property.name === 'time' && node.object.name === 'console') {
context.report({
node,
messageId: 'avoidMethod'.data: {
name: 'time',}}); }}}; }};Copy the code
Lib /index.js:
"use strict";
module.exports = {
rules: {
'no-console-time': require('./rules/no-console-time'),
},
configs: {
recommended: {
rules: {
'demofortutorial/no-console-time': 2, // the eslint-plugin prefix can be omitted},},},};Copy the code
The Eslint plug-in is now created. All you need to do next is publish the project to the NPM platform. The root directory executes:
npm publish
Copy the code
Open the NPM platform and search for the Node package eslint-plugin-Demofortutorial published above.
How to use
Install the package in the project you need after publishing:
npm install eslint-plugin-demofortutorial -D
Copy the code
Then configure it in.eslintrc.js:
"extends": [
"eslint:recommended"."plugin:eslint-plugin-demofortutorial/recommended",]."plugins": [
'demofortutorial'].Copy the code
If you do not have an.eslintrc.js file, run the following command to generate it:
npm install -g eslint
eslint --init
Copy the code
At this point, if you write console.time in the JS file of the current project, the following effect will occur:
Unit testing (perfect)
This is still a “work-in-progress” for a complete NPM package, and we need to write unit tests to ensure its integrity and security.
To complete the unit tests, write the following code in./tests/lib/rules/no-console-time.js:
'use strict';
// ------------------------------------------------------------------------------
// Requirements
// ------------------------------------------------------------------------------
let rule = require('.. /.. /.. /lib/rules/no-console-time');
let RuleTester = require('eslint').RuleTester;
// ------------------------------------------------------------------------------
// Tests
// ------------------------------------------------------------------------------
let ruleTester = new RuleTester({
parserOptions: {
ecmaVersion: 10,
},
});
ruleTester.run('no-console-time', rule, {valid: [// Valid example'_.time({a:1}); '."_.time('abc');"."_.time(['a', 'b', 'c']);"."lodash.time('abc');".'lodash.time({a:1}); '.'abc.time'."lodash.time(['a', 'b', 'c']);",], invalid: [// invalid example {code:'console.time()',
errors: [
{
messageId: 'avoidMethod',
},
],
},
{
code: "console.time.call({}, 'hello')",
errors: [
{
messageId: 'avoidMethod',
},
],
},
{
code: "console.time.apply({}, ['hello'])",
errors: [
{
messageId: 'avoidMethod',
},
],
},
{
code: 'console.time.call(new Int32Array([1, 2, 3, 4, 5])); ',
errors: 1,
},
],
});
Copy the code
The above test code is described in detail in the official documentation.
The root directory executes:
npm run test
Copy the code
At this point, the development of the package is complete. Other rule development is similar, as you can continue to write other specifications, such as ️console.log(), debugger warnings, and so on.
other
Unit test syntax parsing error because the project that automatically generates ESLint relies on the VERSION of ESLint that is still in phase 3.x:
'Parsing error: Invalid ecmaVersion.'
Copy the code
It is recommended to upgrade the package to “ESLint “: “^5.16.0”.
The above.
Check out the project repository on Github
View packages published on Npm
Zhuanlan.zhihu.com/p/32297243 en.wikipedia.org/wiki/Lint_ (… Octoverse.github.com/ medium.com/@anton/why- jslint.com… www.nczonline.net/blog/2013/0… Eslint.org JSCS. Info github.com/babel/babel… Github.com/yannickcr/e… www.nczonline.net/blog/2016/0… medium.com/@markelog/j…
Extracurricular knowledge: A brief history of Lint
Lint is a tool for solving all sorts of problems caused by sloppy code. For example, mixing == and === can cause some strange problems.
JSLint and JSHint
In 2002, Douglas Crockford developed what was probably the first syntax checking tool for JavaScript, JSLint, which was open-source in 2010.
JSLint has certainly saved JavaScript developers a lot of time troubleshooting code errors since its launch. But the problem with JSLint is obvious — it’s almost unconfigurable, and all the code styles and rules are built in; Add to that Douglas Crockford’s fine tradition of “use it as you please”, not compromising open configuration with developers or changing the rules as he sees fit. So Anton Kovalyov quipped, “JSLint just makes your code look more like Douglas Crockford”, and in 2011 the original Fork project developed JSHint. “Why I Forked JSLint to JSHint”
JSHint is configurable, relatively well-documented and developer-friendly. Pretty soon everyone switched from JSLint to JSHint.
The birth of ESLint
Everyone turned to JSHint as a code inspection tool of choice for the next few years, but the turning point came in 2013, when Zakas realized that JSHint couldn’t meet his rule-making needs, and after discussing it with Anton, it was impossible to implement it on JSHint. Zakas also envisions the creation of an AST-based Lint. In June 2013, Zakas released a new Lint tool, ESLint. “Introducing ESLint”
ESLint earlier source code:
var ast = esprima.parse(text, { loc: true, range: true }),
walk = astw(ast);
walk(function(node) {
api.emit(node.type, node);
});
return messages;
Copy the code
ESLint counter attack
The emergence of ESLint did not dent JSHint’s dominance. Because the former is the use of AST processing rules, with Esprima parsing code, the execution speed is much slower than JSHint only need one step. Secondly, there were already many editors supporting JSHint, and the ecosystem was strong enough. What really turned ESLint on its head was the advent of ECMAScript 6.
In June 2015, THE ES2015 specification was officially released. However, since its release, there has been very limited support for the latest standards in the browsers on the market. If you want to get an early taste of the latest standard syntax, you can rely on tools like Babel to compile code to ES5 or lower, as well as experimental features. However, JSHint is not supported in the short term, and ESLint only needs the appropriate parser to continue checking Lint. The Babel team developed an alternative to the default parser for ESLint, now known as babel-ESLint, which made ESLint the first Lint tool to support the ES6 syntax.
Also in 2015, React became more and more widely used, and JSX, which was born shortly after, became more and more popular. ESLint itself also does not support JSX syntax. However, because of extensibility, eslint-plugin-React was introduced so that ESLint could also support react specific rules at the time.
In 2016, the JSCS development team decided that ESLint and JSCS implementation principles were too similar and the issues needed to be addressed were the same, so they merged into ESLint and stopped maintaining JSCS.
Current major Lint tools on the market and trends:
ESLint has since become the dominant front-end tool to replace JSHint.