【前端进阶】什么是AST?什么是ESLint?如何快速发布自定义ESLint插件?

什么是AST

AST 叫虚拟语法树(Abstract Syntax Tree)它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。之所以说语法是“抽象”的,是因为这里的语法并不会表示出真实语法中出现的每个细节。

大白话来讲:就是通过这种方式可以去解剖你身上的所有细节来描述你的身体。

注意:抽象语法树并不是单纯指在前端存在,其实所有的语言都可以抽象成语法树,它只是一种语法分析的结果

例如这段python代码:
在这里插入图片描述
AST解析:
在这里插入图片描述

AST在线可视化网站

https://astexplorer.net/

利用这个网站我们可以很清晰的看到各种语言的 AST 结构

代码如何转化AST

这里我们只针对JavaScript如何去转化成AST,可以使用两款插件acornrecast

  • acorn
    acron 代码比较精简,且 webpack 和 eslint 都依赖 acorn

acorn基本使用

import * as acorn from 'acorn';  //引入
const code = 'xxx';				//解析代码块
const ast = acorn.parse(code, options)			//解析

options的定义如下

如果你学过Ts应该就很清楚下面的参数在讲什么,简单来说除了ecmaVersion是必填参数,其他都是可选参数,ecmaVersion代表你的代码是属于es的哪一个版本,如果为6,那么es5的代码就不支持了解析了。

ecmaVersion ECMA 版本,默认时 es7

locations 默认为 false,设置为 true 时节点会携带一个 loc 对象来表示当前开始与结束的行数。

onComment 回调函数,每当代码执行到注释的时候都会触发,可以获取当前的注释内容

interface Options {
    
    
    ecmaVersion: 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 'latest'
    sourceType?: 'script' | 'module'
    onInsertedSemicolon?: (lastTokEnd: number, lastTokEndLoc?: Position) => void
    onTrailingComma?: (lastTokEnd: number, lastTokEndLoc?: Position) => void
    allowReserved?: boolean | 'never'
    allowReturnOutsideFunction?: boolean
    allowImportExportEverywhere?: boolean
    allowAwaitOutsideFunction?: boolean
    allowSuperOutsideMethod?: boolean
    allowHashBang?: boolean
    locations?: boolean
    onToken?: ((token: Token) => any) | Token[]
    onComment?: ((
      isBlock: boolean, text: string, start: number, end: number, startLoc?: Position,
      endLoc?: Position
    ) => void) | Comment[]
    ranges?: boolean
    program?: Node
    sourceFile?: string
    directSourceFile?: string
    preserveParens?: boolean
  }

还原

import * as astring from 'astring'; //引入
 
const code = astring.generate(ast);		//ast
  • recast

recast也是类似的。

recast.parse(code) //解析
recast.print(ast).code  //还原

什么是ESLint

ESLint是一个用来识别 ECMAScript 并且按照规则给出报告的代码检测工具,使用它可以避免低级错误和统一代码的风格。如果每次在代码提交之前都进行一次eslint代码检查,就不会因为某个字段未定义为undefined或null这样的错误而导致服务崩溃,可以有效的控制项目代码的质量。

在许多方面,它和 JSLint、JSHint 相似,除了少数的例外:

  • ESLint 使用 Espree 解析 JavaScript
  • ESLint 使用 AST 去分析代码中的模式
  • ESLint 是完全插件化的。每一个规则都是一个插件并且你可以在运行时添加更多的规则。

因此,在介绍ESLint之前需要先明白AST的相关知识。

ESLint解析原理

在这里插入图片描述

  • 解析:将源代码解析成AST
  • 遍历:遍历每个选择器两次
  • 回调:根据规则触发回调
  • 生成:修改AST,生成代码

如何制作ESLint插件

官方是非常欢迎开发者参与到ESLint插件的制作,为此官方提供了一个脚手架便于开发者快速开发插件—— yeoman

如何参与ESLint插件贡献
如何制作插件

安装yeoman

npm install -g yo generator-eslint

创建插件

yo eslint:plugin

在这里插入图片描述

创建规则

在这里插入图片描述

目录结构

在这里插入图片描述

实现警告console.error()方法

1.修改lib/rules/no-console-error.js文件

/**
 * @fileoverview no console.error() in your code
 * @author yjian
 */
"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
    
    
  meta: {
    
    
    type: 'problem', // `problem`, `suggestion`, or `layout`
    docs: {
    
      //文档描述
      description: "no console.error() in your code",
      recommended: false,
      url: null, // URL to the documentation page for this rule
    },
    fixable: null, // Or `code` or `whitespace`
    schema: [], // Add a schema if the rule has options
    // 报错信息描述
    messages: {
    
    
      avoidMethod: "'{
    
    {name}}' function of console is forbidden in code",
    },
  },

  create(context) {
    
    
    return {
    
    
      // 'MemberExpression'  这个就是AST的节点选择器,在遍历AST时,如果命中该选择器,就会触发回调
      // 关于选择器的名称,我们可以事先在 https://astexplorer.net/ 中找到目标解析器然后将其作为key即可
      //  这里的选择器会在AST"自上至下"过程中触发,如果希望是"自下至上"过程中触发,需要加':exit'即MemberExpression:exit
      'MemberExpression': (node) => {
    
    
        // 如果在AST遍历中满足以下条件,就用 context.report() 进行对外警告⚠️
        if (node.property.name === 'error' && node.object.name === 'console') {
    
    
            context.report({
    
    
                node,
                messageId: 'avoidMethod', //错误类型
                data: {
    
    
                    name: node.property.name,  //这里的name会传递到上面的messages中的name,类似于vue的双向绑定
                },
            });
        }
      },
    };
  },
};

2.导出规则lib/rules/index

/**
 * @fileoverview 自定义eslint规则
 * @author yjian
 */
"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// Plugin Definition
//------------------------------------------------------------------------------


// import all rules in lib/rules
module.exports = {
    
    
  rules: {
    
    
  	  // 项目在使用时,对应的规则名称
      'no-console-error': require('./rules/no-console-error'),
  },
  configs: {
    
    
      recommended: {
    
    
          rules: {
    
    
              'demo/no-console-error': 2, // 可以省略 eslint-plugin 前缀
          },
      },
  },
}

3.单元测试./tests/lib/rules/no-console-error.js

/**
 * @fileoverview 不允许使用 console.time()
 * @author lzx
 */
"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

const rule = require("../../../lib/rules/no-console-time"),
  RuleTester = require("eslint").RuleTester;


//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------

const ruleTester = new RuleTester();
ruleTester.run("no-console-error", rule, {
    
    
  valid: [
    // give me some code that won't trigger a warning
  ],

  invalid: [
    {
    
    
      code: "console.error('test');",
      errors: [{
    
     message: "Fill me in.", type: "Me too" }],
    },
  ],
});

4.最后执行测试

npm run test

npm发布

如何注册

https://www.npmjs.com/

登录官网,输入用户名,邮箱和密码,完成邮箱校验之后即注册成功,过程需要梯子。

如何登录

输入命令:需要梯子,需要修改npm地址

npm login

输入成功之后,会提示你输入用户名,密码和邮箱,同样需要校验之后就登录成功了,
可以通过npm whoami命令去查看是否登录成功,如果成功,即会弹出用户名。

注意:输入密码的时候,命令行可能是空的,这是正常的,只需要确保密码正确能进入下一步即可

发布

npm publish

在这里插入图片描述
可以在下方链接查看到,
在这里插入图片描述

https://www.npmjs.com/settings/用户名/packages

应用

安装eslint

npm i eslint --save-dev

安装eslint插件

npm install eslint-plugin-noconsole --save-dev

初始化配置

npx eslint --init

配置

{
    
    
    "plugins": [
    	// 这是此前使用yo eslint:plugin 生成自定义插件的ID
        "diylint"
    ],
    extends: ["plugin:ecdemo/recommended"],
}

问题

如果你在使用npm login命令出现了以下错误,说明你的npm镜像地址不是原生地址,需要进行更换

Unexpected token < in JSON at position 0 while parsing near '<html>

解决方案:

npm set registry https://registry.npmjs.org/

推荐使用nrm进行镜像源地址的管理,请看下方说明!

nrm

nrm(npm registry manager )是npm的镜像源管理工具,可以通过nrm方便切换镜像源。

nvm是一个可以便捷切换node版本的工具,与nrm类似

下载

npm install -g nrm

查看可用镜像源

// 显示当前可使用的镜像源列表
nrm ls
* npm -------- https://registry.npmjs.org/
  yarn ------- https://registry.yarnpkg.com/
  cnpm ------- http://r.cnpmjs.org/
  taobao ----- https://registry.npm.taobao.org/
  nj --------- https://registry.nodejitsu.com/
  npmMirror -- https://skimdb.npmjs.com/registry/
  edunpm ----- http://registry.enpmjs.org/

切换镜像源

nrm use taobao

结束

想必,你应该大致清楚,babel是如何做到es6语法转es5,ESLint又是如何做到规则校验的。如果要进一步深入了解,还需要清楚,代码和AST之间是如何互相转化的。

参考文章

如何注册npm账号

ESLint简介

https://blog.csdn.net/qq_33396780/article/details/129935377

https://blog.csdn.net/KlausLily/article/details/124486883

https://blog.csdn.net/WTUDAN/article/details/127383560

猜你喜欢

转载自blog.csdn.net/m0_46983722/article/details/131551828