AST 叫虚拟语法树(Abstract Syntax Tree)它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。之所以说语法是“抽象”的,是因为这里的语法并不会表示出真实语法中出现的每个细节。
大白话来讲:就是通过这种方式可以去解剖你身上的所有细节来描述你的身体。
注意:抽象语法树并不是单纯指在前端存在,其实所有的语言都可以抽象成语法树,它只是一种语法分析的结果
https://astexplorer.net/
利用这个网站我们可以很清晰的看到各种语言的 AST 结构
这里我们只针对JavaScript如何去转化成AST,可以使用两款插件acorn
和recast
,
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.parse(code) //解析
recast.print(ast).code //还原
ESLint是一个用来识别 ECMAScript 并且按照规则给出报告的代码检测工具,使用它可以避免低级错误和统一代码的风格。如果每次在代码提交之前都进行一次eslint代码检查,就不会因为某个字段未定义为undefined或null这样的错误而导致服务崩溃,可以有效的控制项目代码的质量。
在许多方面,它和 JSLint、JSHint 相似,除了少数的例外:
因此,在介绍ESLint之前需要先明白AST的相关知识。
官方是非常欢迎开发者参与到ESLint插件的制作,为此官方提供了一个脚手架便于开发者快速开发插件—— yeoman
如何参与ESLint插件贡献
如何制作插件
npm install -g yo generator-eslint
yo eslint:plugin
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
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(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