AST (Abstract Syntax Tree) в контексте SWC представляет собой строго типизированную структуру, описывающую синтаксис исходного JavaScript/TypeScript кода на уровне узлов языка. Внутренняя реализация AST ориентирована на максимальную скорость парсинга и последующей трансформации, что определяет её отличие от более универсальных, но менее производительных моделей вроде ESTree.
В основе лежит пакет swc_ecma_ast, задающий набор структур
данных, где каждый синтаксический элемент представлен отдельным типом
узла с фиксированным набором полей. Архитектура AST в SWC оптимизирована
под Rust-реализацию компилятора, однако концептуально сохраняет
совместимость с экосистемой JavaScript.
Каждый узел AST в SWC имеет общую концепцию: он описывает конкретную грамматическую конструкцию и содержит метаданные позиции в исходном коде.
Ключевые элементы любого узла:
span — диапазон символов в исходном коде (start/end
позиции)
Пример общей модели:
pub struct Ident {
pub span: Span,
pub sym: JsWord,
pub optional: bool,
}
span играет критическую роль не только для source maps, но
и для трансформаций, где важно сохранять корректные привязки к
оригинальному коду.
Корневым элементом AST является Program, который определяет
тип исходного файла:
Script — классический JavaScript без модулей
Module — ECMAScript module
Внутри Module находится список ModuleItem,
который может включать:
ModuleDecl (импорт/экспорт/декларации)
Stmt (операторы верхнего уровня)
Структура верхнего уровня:
Program
├── Module
│ ├── ModuleItem[]
│ │ ├── ModuleDecl
│ │ └── Stmt
└── Script
└── Stmt[]
Такое разделение позволяет строго различать контексты исполнения, что важно для корректной трансформации ESM ↔︎ CJS.
Выражения формируют одну из наиболее насыщенных частей AST. В SWC они
представлены enum Expr, содержащим множество вариантов.
Ident — идентификатор
Lit — литералы (строки, числа, булевы значения)
CallExpr — вызовы функций
MemberExpr — доступ к свойствам объекта
ArrowExpr — стрелочные функции
FnExpr — функциональные выражения
ObjectLit — объектные литералы
ArrayLit — массивы
BinExpr — бинарные операции
UnaryExpr — унарные операции
CondExpr — тернарные выражения
{
"type": "CallExpression",
"callee": {
"type": "Identifier",
"value": "parse"
},
"arguments": [
{
"type": "StringLiteral",
"value": "code"
}
]
}
CallExpr содержит:
callee — вызываемое выражение
args — список аргументов
type_args — generics (для TS)
Операторы (Statements) формируют основную структуру исполнения.
Основной enum: Stmt
Decl — объявления (function, class, var, let, const)
ExprStmt — выражения как операторы
BlockStmt — блоки кода
IfStmt — условные конструкции
ForStmt, WhileStmt, DoWhileStmt
ReturnStmt
SwitchStmt
ThrowStmt
TryStmt
{
"type": "BlockStatement",
"stmts": [
{
"type": "ReturnStatement",
"argument": {
"type": "NumericLiteral",
"value": 42
}
}
]
}
BlockStmt играет ключевую роль в нормализации управления потоком при трансформациях.
Декларативные узлы представлены отдельной категорией Decl,
включающей:
ClassDecl
FnDecl
VarDecl
TsInterfaceDecl
TsTypeAliasDecl
TsEnumDecl
{
"type": "VariableDeclaration",
"kind": "let",
"decls": [
{
"id": {
"type": "Identifier",
"value": "x"
},
"init": {
"type": "NumericLiteral",
"value": 10
}
}
]
}
Ключевой особенностью является разделение kind и списка
decls, что позволяет представлять множественные объявления
в одном операторе.
Функции представлены двумя основными узлами:
FnDecl — именованные функции
FnExpr — функциональные выражения
ArrowExpr — стрелочные функции
{
"type": "FunctionDeclaration",
"identifier": {
"type": "Identifier",
"value": "sum"
},
"params": [
{
"type": "Identifier",
"value": "a"
},
{
"type": "Identifier",
"value": "b"
}
],
"body": {
"type": "BlockStatement",
"stmts": []
}
}
Особое значение имеет разделение params и
body, что позволяет проводить независимые трансформации
параметров (например, для TypeScript или Babel-подобных преобразований).
AST SWC включает нативную поддержку TypeScript через дополнительные узлы:
TsType
TsExprWithTypeArgs
TsInterfaceDecl
TsTypeAliasDecl
TsEnumDecl
{
"type": "TsTypeReference",
"typeName": {
"type": "Identifier",
"value": "Promise"
},
"typeParams": {
"params": [
{
"type": "TsKeywordType",
"kind": "TsStringKeyword"
}
]
}
}
TypeScript-расширения не влияют на runtime-структуру JavaScript, но критически важны для трансформаций и удаления типов.
Идентификаторы (Ident) являются базовым строительным блоком
AST.
pub struct Ident {
pub span: Span,
pub sym: JsWord,
pub optional: bool,
}
sym — имя символа
optional — используется в optional chaining и параметрах
SWC AST не хранит полноценную таблицу символов внутри узлов, но структура позволяет внешним passes строить scope graph.
Литералы представлены через Lit:
Особенность заключается в том, что литералы хранятся без дополнительной нормализации, сохраняя исходное представление там, где это возможно (например, строки с разными кавычками).
Бинарные и унарные операции представлены компактными структурами:
{
"type": "BinaryExpression",
"operator": "+",
"left": { "type": "NumericLiteral", "value": 1 },
"right": { "type": "NumericLiteral", "value": 2 }
}
Поддерживаемые операторы включают:
AST SWC моделирует управление потоком через специализированные узлы:
{
"type": "IfStatement",
"test": { "type": "BooleanLiteral", "value": true },
"consequent": { "type": "BlockStatement", "stmts": [] },
"alternate": null
}
Содержит:
init
test
update
body
Такая структура позволяет гибко преобразовывать циклы в другие формы (например, генераторы или async-итераторы).
Модульная система AST включает:
ImportDecl
ExportDecl
ExportDefaultDecl
ExportNamedDecl
{
"type": "ImportDeclaration",
"specifiers": [
{
"type": "ImportDefaultSpecifier",
"local": { "value": "React" }
}
],
"source": {
"value": "react"
}
}
Модель импорта разделяет спецификаторы и источник, что упрощает tree-shaking и анализ зависимостей.
AST в SWC проектируется как структура, которая активно клонируется и трансформируется в ходе проходов (passes). Вместо мутирования узлов часто создаются новые экземпляры с частично изменёнными полями.
Ключевые подходы:
Span является критическим компонентом всей AST-системы.
Он содержит:
Используется для:
Архитектура AST ориентирована на производительность:
Это обеспечивает высокую скорость парсинга и трансформации, особенно на больших кодовых базах.
В отличие от более абстрактных AST моделей, используемых в JS-инструментах, структура SWC:
Это делает её особенно эффективной в задачах транспиляции и бандлинга.