Работа с AST в SWC предполагает прямое конструирование синтаксических узлов (nodes), соответствующих внутренней структуре дерева разбора. Каждый узел представляет собой строго типизированный объект, описывающий конкретную синтаксическую конструкцию: идентификатор, литерал, выражение, объявление, оператор и так далее. Создание новых узлов является ключевым этапом трансформаций, когда необходимо генерировать код, а не только изменять существующий.
AST в SWC строится как набор вложенных объектов. Каждый узел содержит:
Пример общей структуры:
{
type: "Identifier",
value: "x",
span: { start: 0, end: 1 }
}
Поле span критично для корректной работы трансформаций,
source maps и диагностики.
Идентификатор является базовым строительным блоком большинства выражений.
const id = {
type: "Identifier",
value: "myVariable",
span: { start: 0, end: 0 }
};
Идентификаторы используются в объявлениях переменных, функциях, свойствах объектов и выражениях.
Литералы описывают фиксированные значения: числа, строки, булевы значения.
const num = {
type: "NumericLiteral",
value: 42,
span: { start: 0, end: 0 }
};
const str = {
type: "StringLiteral",
value: "hello",
span: { start: 0, end: 0 }
};
const bool = {
type: "BooleanLiteral",
value: true,
span: { start: 0, end: 0 }
};
Литералы часто используются как листья AST и редко содержат вложенные структуры.
Бинарные выражения описывают операции между двумя операндами.
const expr = {
type: "BinaryExpression",
operator: "+",
left: {
type: "Identifier",
value: "a",
span: { start: 0, end: 0 }
},
right: {
type: "NumericLiteral",
value: 10,
span: { start: 0, end: 0 }
},
span: { start: 0, end: 0 }
};
Типичные операторы:
+, -, *, /
===, !==
<, >, <=,
>=
Бинарные выражения активно применяются при оптимизациях и переписывании выражений.
Переменные в SWC представлены через VariableDeclaration и
VariableDeclarator.
const decl = {
type: "VariableDeclaration",
kind: "const",
declare: false,
declarations: [
{
type: "VariableDeclarator",
id: {
type: "Identifier",
value: "x",
span: { start: 0, end: 0 }
},
init: {
type: "NumericLiteral",
value: 10,
span: { start: 0, end: 0 }
}
}
],
span: { start: 0, end: 0 }
};
VariableDeclarator связывает идентификатор и
инициализирующее выражение.
Функциональные узлы включают параметры, тело и имя.
const func = {
type: "FunctionDeclaration",
identifier: {
type: "Identifier",
value: "sum",
span: { start: 0, end: 0 }
},
params: [
{
type: "Parameter",
pat: {
type: "Identifier",
value: "a",
span: { start: 0, end: 0 }
}
},
{
type: "Parameter",
pat: {
type: "Identifier",
value: "b",
span: { start: 0, end: 0 }
}
}
],
body: {
type: "BlockStatement",
stmts: [
{
type: "ReturnStatement",
argument: {
type: "BinaryExpression",
operator: "+",
left: {
type: "Identifier",
value: "a",
span: { start: 0, end: 0 }
},
right: {
type: "Identifier",
value: "b",
span: { start: 0, end: 0 }
},
span: { start: 0, end: 0 }
}
}
]
},
span: { start: 0, end: 0 }
};
Функции являются одними из наиболее сложных узлов из-за вложенности параметров и блоков.
const block = {
type: "BlockStatement",
stmts: []
};
const ret = {
type: "ReturnStatement",
argument: {
type: "NumericLiteral",
value: 0,
span: { start: 0, end: 0 }
}
};
const ifStmt = {
type: "IfStatement",
test: {
type: "BinaryExpression",
operator: ">",
left: { type: "Identifier", value: "x", span: { start: 0, end: 0 } },
right: { type: "NumericLiteral", value: 0, span: { start: 0, end: 0 } },
span: { start: 0, end: 0 }
},
consequent: {
type: "BlockStatement",
stmts: []
},
alternate: null
};
Объекты строятся через ObjectExpression и
KeyValueProperty.
const obj = {
type: "ObjectExpression",
properties: [
{
type: "KeyValueProperty",
key: {
type: "Identifier",
value: "a",
span: { start: 0, end: 0 }
},
value: {
type: "NumericLiteral",
value: 1,
span: { start: 0, end: 0 }
}
}
]
};
const arr = {
type: "ArrayExpression",
elements: [
{
expression: {
type: "NumericLiteral",
value: 1,
span: { start: 0, end: 0 }
}
},
{
expression: {
type: "NumericLiteral",
value: 2,
span: { start: 0, end: 0 }
}
}
]
};
В трансформационных плагинах SWC новые узлы обычно создаются внутри visitor-функций. Возвращаемое значение полностью заменяет текущий узел.
export default function transformer() {
return {
Program(program) {
return {
...program,
body: [
{
type: "VariableDeclaration",
kind: "const",
declare: false,
declarations: [
{
type: "VariableDeclarator",
id: {
type: "Identifier",
value: "injected",
span: program.span
},
init: {
type: "StringLiteral",
value: "generated",
span: program.span
}
}
],
span: program.span
},
...program.body
]
};
}
};
}
Создание новых узлов часто основано на копировании существующих с изменениями:
function cloneIdentifier(id, newName) {
return {
...id,
value: newName
};
}
Такой подход сохраняет структуру, но изменяет смысловые поля.
Неправильное или пустое значение span может приводить к:
Часто используется переиспользование span родительского узла:
span: parent.span
Создание сложных узлов всегда сводится к композиции базовых:
Эта иерархия позволяет строить произвольные синтаксические конструкции без ограничения по глубине.