Статья впервые опубликована на:GitHub.com/US TB-Вуд, умри, о ты…
написать впереди
Ядром многих инструментов и библиотек, таких как Babel, Webpack, vue-cli и esLint, является проверка и анализ кода с помощью концепции абстрактного синтаксического дерева. AST используется в самых разных сценариях внешнего интерфейса.Например, в vue.js первым шагом в процессе преобразования шаблона, который мы написали в коде, в функцию рендеринга, является синтаксический анализ строки шаблона для генерации AST. Многие синтаксисы JS не подходят для понимания неподходящих программ, чтобы дать разработчикам лучший опыт программирования. Поэтому необходимо преобразовать исходный код в AST, чтобы он был более подходящим для анализа программы.Компилятор браузера обычно преобразует исходный код в AST для дальнейшего анализа и других операций. Понимая концепцию AST, очень полезно иметь глубокое понимание некоторых фреймворков и инструментов во внешнем интерфейсе.
Эта статья будет заключаться из следующих разделов:
- Сценарии использования AST
- Определение АСТ
- Парсер JavaScript (три оси)
- Преобразование стрелочных функций с помощью AST
- Плагин babel для предварительных вычислений с использованием AST
Сценарии использования AST
- Проверка синтаксиса кода, проверка стиля кода, форматирование кода, подсветка кода, подсказки об ошибках кода, автодополнение кода и т. д.
- Например, JSLint, JSHint для проверки ошибок кода или стиля, поиска возможных ошибок.
- Подсказки IDE об ошибках, форматирование, выделение, автозаполнение и т. д.
- обфускация кода
- UglifyJS2 и т. д.
- Оптимизировать и изменить код, изменить структуру кода, чтобы добиться желаемой структуры
- Инструменты упаковки кода webpack, rollup и т. д.
- Преобразование между спецификациями кода, такими как CommonJS, AMD, CMD, UMD и т. д.
- Конвертируйте CoffeeScript, TypeScript, JSX и т. д. в собственный Javascript
Определение АСТ
- Официальное определение АСТ:
В информатике абстрактное синтаксическое дерево (сокращенно абстрактное синтаксическое дерево или AST) или синтаксическое дерево (синтаксическое дерево) представляет собой древовидное представление абстрактной синтаксической структуры исходного кода, в частности исходного кода языка программирования. .
Вот онлайн-конвертер AST:преобразователь АСТ. Формат кода, преобразованного в AST, примерно такой, как показано на следующем рисунке:
Формат JSON после преобразования в AST примерно такой:
{
"type": "Program",
"start": 0,
"end": 16,
"body": [
{
"type": "FunctionDeclaration",
"start": 0,
"end": 16,
"id": {
"type": "Identifier",
"start": 9,
"end": 12,
"name": "ast"
},
"expression": false,
"generator": false,
"params": [],
"body": {
"type": "BlockStatement",
"start": 14,
"end": 16,
"body": []
}
}
],
"sourceType": "module"
}
Поле типа в строковой форме указывает тип узла. Например, «BlockStatement», «Identifier», «BinaryExpression» и т. д. Каждый тип узла определяет некоторые свойства для описания типа узла. Затем вы можете анализировать другие операции через эти узлы.
Парсер JavaScript (три оси)
-
JavaScript Parser, парсер, который преобразует исходный код js в абстрактное синтаксическое дерево.
-
Браузер преобразует исходный код js в абстрактное синтаксическое дерево с помощью парсера, а затем преобразует его в байт-код или напрямую сгенерирует машинный код.
-
Вообще говоря, каждый движок js будет иметь свой собственный формат абстрактного синтаксического дерева, движок Chrome v8, движок Firefox SpiderMonkey и т. д. MDN предоставляет подробное описание формата SpiderMonkey AST, который является отраслевым стандартом.
Трехсторонний топор JS Parser
1. Преобразовать исходный код в AST через esprima
let esprima = require('esprima');
let code = 'function ast(){}';
let ast = esprima.parse(code);
console.log(ast);
После установки через npm i esprima -S запуск приведенного выше кода выведет:
Script {
type: 'Program',
body:
[ FunctionDeclaration {
type: 'FunctionDeclaration',
id: [Identifier],
params: [],
body: [BlockStatement],
generator: false,
expression: false,
async: false } ],
sourceType: 'script' }
2. Пройдите и обновите AST через estraverse.
let esprima = require('esprima');
let estraverse = require('estraverse');
let code = 'function ast(){}';
let ast = esprima.parse(code);
estraverse.traverse(ast, {
enter(node) {
console.log('enter', node.type)
if (node.type == 'Indentifier') {
node.name += 'enter';
}
},
leave(node) {
console.log('leave', node.type)
if (node.type == 'Indentifier') {
node.name += 'leave';
}
}
})
console.log(ast);
После установки через npm i estraverse -S запуск приведенного выше кода выведет:
Script {
type: 'Program',
body:
[ FunctionDeclaration {
type: 'FunctionDeclaration',
id: [Identifier],
params: [],
body: [BlockStatement],
generator: false,
expression: false,
async: false } ],
sourceType: 'script' }
3. Восстановите AST в исходный код через escodegen.
t esprima = require('esprima');
let estraverse = require('estraverse');
let escodegen = require('escodegen');
let code = 'function ast(){}';
let ast = esprima.parse(code);
estraverse.traverse(ast, {
enter(node) {
console.log('enter', node.type)
if (node.type == 'Identifier') {
node.name += '_enter';
}
},
leave(node) {
console.log('leave', node.type)
if (node.type == 'Identifier') {
node.name += '_leave';
}
}
});
let result = escodegen.generate(ast)
console.log(result);
После установки через npm i escodegen -S выполнение приведенного выше кода выведет:
function ast_enter_leave() {
}
Таким образом, положить
function ast() {
}
Изменено на:
function ast_enter_leave() {
}
конверсионная стрелочная функция
Используйте babel-core (основная библиотека babel, реализация основного механизма преобразования) и babel-types (может реализовать суждение о типах, генерировать узлы AST и т. д.) и AST для преобразования
let sum = (a, b) => a + b
Измените его на:
let sum = function(a, b) {
return a + b
}
Код реализации выглядит следующим образом:
// babel核心库,实现核心的转换引擎
let babel = require('babel-core');
// 可以实现类型判断,生成AST节点等
let types = require('babel-types');
let code = `let sum = (a, b) => a + b`;
// let sum = function(a, b) {
// return a + b
// }
// 这个访问者可以对特定类型的节点进行处理
let visitor = {
ArrowFunctionExpression(path) {
console.log(path.type);
let node = path.node;
let expression = node.body;
let params = node.params;
let returnStatement = types.returnStatement(expression);
let block = types.blockStatement([
returnStatement
]);
let func = types.functionExpression(null,params, block,false, false);
path.replaceWith(func);
}
}
let arrayPlugin = { visitor }
// babel内部会把代码先转成AST, 然后进行遍历
let result = babel.transform(code, {
plugins: [
arrayPlugin
]
})
console.log(result.code);
Плагин babel для предварительных вычислений с использованием AST
Код реализации выглядит следующим образом:
// 预计算简单表达式的插件
let code = `const result = 1000 * 60 * 60`;
let babel = require('babel-core');
let types= require('babel-types');
let visitor = {
BinaryExpression(path) {
let node = path.node;
if (!isNaN(node.left.value) && ! isNaN(node.right.value)) {
let result = eval(node.left.value + node.operator + node.right.value);
result = types.numericLiteral(result);
path.replaceWith(result);
let parentPath = path.parentPath;
// 如果此表达式的parent也是一个表达式的话,需要递归计算
if (path.parentPath.node.type == 'BinaryExpression') {
visitor.BinaryExpression.call(null, path.parentPath)
}
}
}
}
let cal = babel.transform(code, {
plugins: [
{visitor}
]
});
Справочная статья
Абстрактное синтаксическое дерево AST
Абстрактное синтаксическое дерево JS, которое вы можете понять с первого взгляда
Углубленный Вавилон, этого достаточно
Курс обучения фронтенд-архитектора Everest
Можете обратить внимание на мой паблик-аккаунт «Muchen Classmate», фермера на гусиной фабрике, который обычно записывает какие-то банальные мелочи, технологии, жизнь, инсайты и срастается.