@babel/parser
Для того, чтобы определить в каких версиях браузеров код будет работать и какие функции будут недоступны в соответствии с выбранными целевыми версиями, необходимо уметь находить элементы AST в базах данных. Для этого можно построить структуру маппинга нод дерева на записи в БД.
Каждая нода AST представляет из себя объект с полем type
, а также фиксированным набором полей в зависимости от ее типа.
Во всех примерах такие поля, как start
, end
, loc
и др. скрыты для представления только необходимой информации.
for (let i = 0; i < 10; i++) {}
{
"type": "ForStatement",
"init": {},
"test": {},
"update": {},
"body": {}
}
Эту ноду однозначно можно определить как цикл for
, т.к. тип ForStatement
не имеет альтернатив, т.к. for of
и for in
имеют другие типы — ForOfStatement
и ForInStatement
.
let a = 1;
{
"type": "VariableDeclaration",
"declarations": [],
"kind": "let"
}
В этом случае не получится однозначно определить, какая конструкция встретилась, только по типу. Необходимо посмотреть в поле kind
— там могут быть значения var | let | const
.
Array.from()
{
"type": "ExpressionStatement",
"expression": {
"type": "CallExpression",
"callee": {
"type": "MemberExpression",
"object": {
"type": "Identifier",
"name": "Array"
},
"computed": false,
"property": {
"type": "Identifier",
"name": "from"
}
},
"arguments": []
}
}
Чтобы определить, что вызываемая функция from
является методом массива, необходимо подняться к его родителю по дереву и посмотреть информацию об объекте, на котором происходит вызов.
Как видно из примеров, на данный момент не получится однозначно определять используемые возможности языка, опираясь только на типы нод AST. Поэтому нужно объявить их внутреннее представление — идентификаторы. Тогда VariableDeclaration
будет иметь 3 варианта: VarVariableDeclaration
, LetVariableDeclaration
и ConstVariableDeclaration
.
Чтобы определить, какой идентификатор соответствует рассматриваемой ноде, лучше всего использовать подход pattern matching — заключается это в том, что будем использовать декларативное описание шаблона, а затем проверять все ноды на соответствие описанным шаблонам.
Далее необходимо связать найденный идентификатор с информацией из базы данных поддержки в браузерах и рантаймах. Для этого будет использоваться еще одна структура:
{
"InternalKey": "path.to.data",
}
Ключами такого объекта будут внутренние идентификаторы, а значениями пути по объектам баз данных. Так, например, чтобы найти информацию про цикл for
необходимо из корня БД перейти в раздел javascript
, затем statements
и далее for
. Задачей этого исследования является анализ только JavaScript кода, поэтому будем считать, что корнем является объект javascript
. Итого, путь будет выглядеть как statements.for
. А все вместе "ForStatement": "statements.for"
. Именно такая структура описана в файле compatMapping.json [WIP].
import babel from '@babel/parser';
import fs from 'node:fs';
const data = fs.readFileSync('path/to/file.js', {
encoding: 'utf-8',
});
const AST = babel.parse(data, {
sourceType: 'module',
});
WIP