webpack和Lint等不少的工具和库的核心都是经过Abstract Syntax Tree抽象语法树这个概念来实现对代码的检查、分析等操做的node
这些工具的原理都是经过JavaScript Parser把代码转化为一颗抽象语法树(AST),这颗树定义了代码的结构,经过操纵这颗树,咱们能够精准的定位到声明语句、赋值语句、运算语句等等,实现对代码的分析、优化、变动等操做webpack
在计算机科学中,抽象语法树(abstract syntax tree或者缩写为AST),或者语法树(syntax tree),是源代码的抽象语法结构的树状表现形式,这里特指编程语言的源代码。web
Javascript的语法是为了给开发者更好的编程而设计的,可是不适合程序的理解。因此须要转化为AST来更适合程序分析,浏览器编译器通常会把源码转化为AST来进行进一步的分析等其余操做。编程
// 重命名
let esprima = require('esprima');
var estraverse = require('estraverse');
var escodegen = require("escodegen");
let code = 'function ast(){}';
let ast=esprima.parse(code);
let indent=0;
function pad() {
return ' '.repeat(indent);
}
estraverse.traverse(ast,{
enter(node) {
console.log(pad()+node.type);
if(node.type == 'FunctionDeclaration'){
node.id.name = 'ast_rename';
}
indent+=2;
},
leave(node) {
indent-=2;
console.log(pad()+node.type);
}
});
let generated = escodegen.generate(ast);
console.log(generated);
复制代码
@babel/core、babel-types浏览器
转换前bash
const sum = (a,b)=>a+b
babel
转换后编程语言
var sum = function sum(a, b) { return a + b; };
ide
代码实现函数
let babel = require('@babel/core');
let t = require('babel-types');
const code = `const sum = (a,b)=>a+b`;
// path.node 父节点
// path.parentPath 父路径
let transformArrowFunctions = {
visitor: {
ArrowFunctionExpression: (path, state) => {
let node = path.node;
let id = path.parent.id;
let params = node.params;
let body=t.blockStatement([
t.returnStatement(node.body)
]);
let functionExpression = t.functionExpression(id,params,body,false,false);
path.replaceWith(functionExpression);
}
}
}
const result = babel.transform(code, {
plugins: [transformArrowFunctions]
});
console.log(result.code);
复制代码
转换前
class Person {
constructor(name) {
this.name=name;
}
getName() {
return this.name;
}
}
复制代码
转换后
function Person(name) {
this.name=name;
}
Person.prototype.getName=function () {
return this.name;
}
复制代码
实现
let babel = require('@babel/core');
let t=require('babel-types');
let source=`
class Person {
constructor(name) {
this.name=name;
}
getName() {
return this.name;
}
}
`;
let ClassPlugin={
visitor: {
ClassDeclaration(path) {
let node=path.node;
let id=node.id;
let constructorFunction = t.functionDeclaration(id,[],t.blockStatement([]),false,false);
let methods=node.body.body;
let functions = [];
methods.forEach(method => {
if (method.kind == 'constructor') {
constructorFunction = t.functionDeclaration(id,method.params,method.body,false,false);
functions.push(constructorFunction);
} else {
let memberObj=t.memberExpression(t.memberExpression(id,t.identifier('prototype')),method.key);
let memberFunction = t.functionExpression(id,method.params,method.body,false,false);
let assignment = t.assignmentExpression('=',memberObj,memberFunction);
functions.push(assignment);
}
});
if (functions.length ==1) {
path.replaceWith(functions[0]);
} else {
path.replaceWithMultiple(functions);
}
}
}
}
const result = babel.transform(source,{
plugins:[
ClassPlugin
]
});
console.log(result.code);
复制代码