[AST] to teach you how to write articles Eslint plug

Foreword

Although now there are many practical ESLint plug, but as the project continues to iterative development, you may encounter plug-ins have been ESLint can not meet the current situation of the development team. At this time, you need to create a ESLint own plug-ins.

In this paper I will take you to understand the general history of various Lint tool, and then step by step to create a ESLint your own plug-ins, and teach you how to use the ASTabstract syntax tree to develop the rules of the plugin.

In order to take you through the realization of the principle of ESLint.

Extra-curricular knowledge: A Brief History Lint

Lint code is not strict in order to solve various problems caused by a tool. For example, ==and ===mixed-use can lead to some strange problems.

JSLint and JSHint

In 2002, Douglas Crockford developed what may be the first testing tools for JavaScript syntax - and open source in 2010 JSLint,.

After JSLint market, many JavaScript developers did help to save a lot of time to troubleshoot the error codes. But the problem is also very obvious JSLint - almost non-configurable , all code style and good rules are built; coupled with Douglas Crockford respected Road Department "do not like to use" the fine tradition, will not compromise the open configuration to developers or modify the rules he felt was right. So Anton Kovalyov Tucao: "JSLint is to make your code more like the style of Douglas Crockford it", and in 2011, the original project was developed Fork JSHint. "Why I forked JSLint to JSHint"

JSHint feature is configurable , but the document also relatively well, but also to the developer-friendly. Soon he turned to JSHint from JSLint.

The birth of ESLint

In later years it will JSHint choice as a code detection tools, but the turning point in 2013, Zakas found JSHint unable to meet their own needs rules, and after discussion and Anton found it impossible to achieve on JShint, while Zakas invention also envisaged based on ASTthe lint. So in June 2013, Zakas released a new lint tool --ESLint. "Introducing ESLint"

ESLint early Source :

var ast = esprima.parse(text, { loc: true, range: true }),
    walk = astw(ast);

walk(function(node) {
    api.emit(node.type, node);
});

return messages;
复制代码

ESLint counter-attack

ESLint did not appear to shake the dominance of JSHint. Since the former is the use of AST handling rules, with Esprima parsing code, execution speed than only one step to get a lot of JSHint slow ; secondly that time there have been many editors of JSHint support efforts to improve the ecological strong enough. What really ESLint counter-attack is ECMAScript 6the appearance.

June 2015, ES2015 specification released. But after the release, the market situation browser support for the latest standards is extremely limited. If you want to advance to experience the latest standards of grammar, they rely on Babeltools like code compiled into ES5 even lower version, and some experimental features can also be converted by Babel. But this time JSHint unable to provide short-term support, and ESLint only need a suitable parser can continue to check the lint. Babel is ESLint team has developed a tool instead of the default parser, now we have seen babel-eslint, it makes ESLint become the first to support ES6 syntax lint tool.

Also in 2015, React more and more widely, born near the JSX has become even more popular. ESLint itself does not support JSX syntax. But because of scalability, eslint-plugin-reactthe emergence of ESLint also gave support to React-specific rules.

2016, JSCS development team believes ESLint and JSCS implementation principle too similar, and problems to be solved are also the same, the final choice to merge ESLint, and to discontinue the maintenance of JSCS.

Currently on the market mainstream lint tools and trends:

 

Since then ESLint dominate the political arena, become mainstream front-end tool of alternative JSHint.

Goals & involves knowledge

This article ESLintplugin goal is to disable in project development: console.time().

  • AST abstract syntax tree
  • ESLint
  • Npm release
  • unit test

Plug-building scaffolding

Here we use yeoman and generator-eslint to build scaffolding plug-in code. installation:

npm install -g yo generator-eslint
复制代码

Local New Folder eslint-plugin-demofortutorial:

mkdir eslint-plugin-demofortutorial
cd eslint-plugin-demofortutorial
复制代码

Initialization ESLint plug-in project structure:

yo eslint:plugin // 搭建一个初始化的目录结构
复制代码

 

 

At this point the directory structure of the file is:

.
├── README.md
├── lib
│   ├── index.js
│   └── rules
├── package.json
└── tests
    └── lib
        └── rules
复制代码

Installation depends:

npm install
复制代码

So far, environmental set up is completed.

Create Rule

Terminal to execute:

yo eslint:rule // 生成默认 eslint rule 模版文件
复制代码

 

At this point the project structure:

 

.
├── README.md
├── docs // 使用文档
│   └── rules
│       └── no-console-time.md
├── lib // eslint 规则开发
│   ├── index.js
│   └── rules // 此目录下可以构建多个规则,本文只拿一个规则来讲解
│       └── no-console-time.js
├── package.json
└── tests // 单元测试
    └── lib
        └── rules
            └── no-console-time.js
复制代码

The above structure, we need to continue to develop Eslint ./lib/ directory plug-ins, here is the definition of the position of its rules.

AST is used in ESLint

In formal writing ESLintbefore the plug-in, you need to understand the next ESLintworks. Which ESLintuse we should all be familiar, not to explain here, you can click on the official documents do not understand how to configure ESLint in the project .

In the company's project development team, different developers write the source code is not the same, then in the ESLintmiddle, how to analyze each person to write the source code it?

作为开发者,面对这类问题,我们必须懂得要使用 抽象的手段 !那么 Javascript 的抽象性如何体现呢?

没错,就是 AST (Abstract Syntax Tree(抽象语法树)),再祭上那张看了几百遍的图。

 

 

ESLint 中,默认使用 esprima 来解析我们书写的 Javascript 语句,让其生成抽象语法树,然后去 拦截 检测是否符合我们规定的书写方式,最后让其展示报错、警告或正常通过。 ESLint 的核心就是规则(rules),而定义规则的核心就是利用 AST 来做校验。每条规则相互独立,可以设置禁用off、警告warn⚠️和报错error❌,当然还有正常通过不用给任何提示。

规则创建

上面讲完了 ESLintAST 的关系之后,我们可以正式进入开发具体规则。先来看之前生成的 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 helper functions should go here or else delete this section //---------------------------------------------------------------------- // Public //---------------------------------------------------------------------- return { // give me methods }; } }; 复制代码

这个文件给出了书写规则的模版,一个规则对应一个可导出的 node 模块,它由 metacreate 两部分组成。

  • meta 代表了这条规则的元数据,如其类别,文档,可接收的参数的 schema 等等。
  • create:如果说 meta 表达了我们想做什么,那么 create 则用表达了这条 rule 具体会怎么分析代码;

Create 返回一个对象,其中最常见的键名AST抽象语法树中的选择器,在该选择器中,我们可以获取对应选中的内容,随后我们可以针对选中的内容作一定的判断,看是否满足我们的规则。如果不满足,可用 context.report 抛出问题,ESLint 会利用我们的配置对抛出的内容做不同的展示。

具体参数配置详情见官方文档

本文创建的 ESLint 插件是为了不让开发者在项目中使用 console.time(),先看看这段代码在抽象语法树中的展现:

 

 

其中,我们将会利用以下内容作为判断代码中是否含有 console.time:

 

那么我们根据上面的AST(抽象语法书)在 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 ], // 报错信息描述 messages: { avoidMethod: "console method '{{name}}' is forbidden.", }, }, create: function(context) { return { // 键名为ast中选择器名 'CallExpression MemberExpression': (node) => { // 如果在ast中满足以下条件,就用 context.report() 进行对外警告⚠️ if (node.property.name === 'time' && node.object.name === 'console') { context.report({ node, messageId: 'avoidMethod', data: { name: 'time', }, }); } }, }; } }; 复制代码

再修改 lib/index.js

"use strict";

module.exports = {
    rules: {
        'no-console-time': require('./rules/no-console-time'),
    },
    configs: {
        recommended: {
            rules: {
                'demofortutorial/no-console-time': 2, // 可以省略 eslint-plugin 前缀
            },
        },
    },
};
复制代码

至此,Eslint 插件创建完成。接下去你需要做的就是将此项目发布到 npm平台。 根目录执行:

npm publish
复制代码

 

 

打开npm平台,可以搜索到上面发布的 eslint-plugin-demofortutorial 这个 Node 包。

 

如何使用

发布完之后在你需要的项目中安装这个包:

npm install eslint-plugin-demofortutorial -D
复制代码

然后在 .eslintrc.js 中配置:

"extends": [
    "eslint:recommended",
    "plugin:eslint-plugin-demofortutorial/recommended",
],
"plugins": [
    'demofortutorial' ], 复制代码

如果之前没有.eslintrc.js 文件,可以执行下面命令生成:

npm install -g eslint
eslint --init
复制代码

此时,如果在当前项目的 JS 文件中书写 console.time,会出现如下效果:

 

 

单元测试(完善)

对于完整的 npm 包来说,上面还只算是个“半成品”,我们需要写单元测试来保证它的完整性和安全性。

Finishing the test unit, in ./tests/lib/rules/no-console-time.jsthe preparation of the following code:

'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: [ // 合法示例 '_.time({a:1});', "_.time('abc');", "_.time(['a', 'b', 'c']);", "lodash.time('abc');", 'lodash.time({a:1});', 'abc.time', "lodash.time(['a', 'b', 'c']);", ], invalid: [ // 不合法示例 { 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, }, ], }); 复制代码

The above test code details, see the official documentation .

The root of execution:

npm run test
复制代码

 

 

So far, the development of this package complete. Other rules are also similar development, such as you can continue to develop other specifications, such as ️ console.log(), debuggerwarning and so on.

other

Since the automatic generation of ESLintproject-dependent eslintversion 3.x still in the stage, unit testing would cause parsing error as follows:

'Parsing error: Invalid ecmaVersion.'
复制代码

This package is recommended to upgrade "eslint": "^5.16.0".



the above.

View project repository on Github

View published on Npm package





References:

zhuanlan.zhihu.com/p/32297243 en.wikipedia.org/wiki/Lint_(… octoverse.github.com/ jslint.com medium.com/@anton/why-… 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…


Author: Allan91
link: https: //juejin.im/post/5d91be23f265da5ba532a07e
Source: Nuggets
copyright reserved by the authors. Commercial reprint please contact the author authorized, non-commercial reprint please indicate the source.

Guess you like

Origin www.cnblogs.com/ygunoil/p/11958827.html