Отладка плагинов

SWC строится вокруг модульного компиляционного конвейера, где каждый этап преобразования AST может быть расширен через плагины на Rust или WebAssembly. Плагин в SWC — это функция трансформации дерева синтаксического анализа, работающая на уровне swc_ecma_ast, с доступом к контексту компиляции через swc_common.

Типовой жизненный цикл плагина включает:

  • разбор исходного кода в AST;
  • применение трансформаций;
  • генерацию кода обратно в строку;
  • опциональное формирование source map.

Отладка в такой архитектуре требует понимания того, на каком именно этапе происходит искажение данных: парсинг, трансформация или кодогенерация.


Базовые принципы отладки трансформаций AST

Основная сложность плагинов SWC заключается в том, что входные и выходные данные представлены не строками, а структурированными узлами AST. Ошибки редко проявляются напрямую — чаще они выражаются в некорректной структуре дерева или нарушении инвариантов.

Ключевые источники проблем:

  • некорректное изменение узлов без обновления span;
  • потеря информации о позициях токенов;
  • нарушение владения узлами (ownership) при клонировании;
  • неверная обработка Expr, Stmt, ModuleItem.

Отладка начинается с изоляции трансформации: плагин должен быть минимизирован до одной операции над узлом.


Использование логирования внутри плагина

Rust-плагины SWC не имеют классического console.log, поэтому применяется стандартная инфраструктура логирования Rust:

  • eprintln! для быстрого вывода в stderr;
  • println! при запуске через CLI;
  • tracing для структурированного логирования.

Пример диагностического вывода:

eprintln!("Visiting node: {:?}", &expr);

Однако прямой вывод AST быстро становится нечитабельным. Более эффективный подход — логирование отдельных характеристик:

  • тип узла (Expr::Call, Stmt::If);
  • span (node.span.lo, node.span.hi);
  • упрощённое представление через Debug или кастомный форматтер.

Работа со span-данными и диагностика позиций

Одна из ключевых причин некорректного поведения плагинов — нарушение Span. SWC использует Span для связи AST с исходным кодом.

При трансформациях важно:

  • сохранять исходные Span при клонировании;
  • использовать DUMMY_SP только для синтетических узлов;
  • не смешивать spans из разных модулей.

Типичная ошибка:

Expr::Ident(Ident {
    span: DUMMY_SP,
    sym: "value".into(),
    ..
})

Такой код ломает source map и делает отладку почти невозможной.

Корректный подход — наследование span от ближайшего контекстного узла.


Инструментирование трансформаций через visitor-паттерн

SWC активно использует паттерн Visitor для обхода AST. Отладка строится вокруг переопределения методов:

  • visit_expr
  • visit_stmt
  • visit_module_item

Диагностическая версия visitor часто включает:

  • лог входа в узел;
  • лог выхода после трансформации;
  • сравнение входного и выходного узла.

Пример:

fn visit_expr(&mut self, n: Expr) -> Expr {
    eprintln!("IN: {:?}", n);

    let transformed = n;

    eprintln!("OUT: {:?}", transformed);

    transformed
}

Такой подход позволяет локализовать точку искажения данных.


Использование swc_common errors для диагностики

Модуль swc_common предоставляет систему ошибок, интегрированную в компиляционный контекст.

Основные инструменты:

  • Handler для накопления ошибок;
  • SpanLabel для указания точных позиций;
  • emit_diagnostic для расширенной информации.

Пример генерации ошибки:

handler
    .struct_span_err(span, "Invalid transformation")
    .note("Expected identifier but found expression")
    .emit();

Это особенно важно при разработке сложных трансформаций, где ошибка должна быть привязана к исходному коду.


Отладка через промежуточный вывод AST

При сложных плагинах эффективна стратегия многоступенчатого дампа AST:

  1. входной AST;
  2. AST после каждого прохода;
  3. финальный AST перед генерацией кода.

Для сериализации используется swc_ecma_codegen или serde-подобные инструменты.

Пример упрощённого дампа:

eprintln!("{}", debug_ast(&module));

или через кодогенерацию:

let mut buf = Vec::new();
let mut gen = Emitter::new(&mut buf, None, false, false);
gen.emit_module(&module)?;

Проблемы владения (ownership) и клонирования узлов

Rust-основа SWC делает владение критическим фактором отладки. Частые ошибки:

  • использование перемещённого значения AST;
  • повторное использование узла без клонирования;
  • частичное клонирование без вложенных структур.

Типичный симптом — panic в глубине visit_* методов.

Корректная стратегия:

  • использовать .clone() для узлов перед модификацией;
  • избегать ручного пересоздания сложных структур;
  • проверять вложенные Box<T> и Vec<T>.

Отладка WASM-плагинов

WASM-плагины добавляют дополнительный слой сложности: ограниченную наблюдаемость и отсутствие стандартного stderr в привычном виде.

Основные подходы:

  • использование console_error_panic_hook;
  • прокидывание логов через host environment;
  • сериализация промежуточных данных в строку.

Пример:

web_sys::console::log_1(&format!("{:?}", node).into());

Также важно учитывать, что оптимизация WASM может убирать часть логики, если она не используется явно.


Изоляция трансформаций и минимальные тест-кейсы

Ключевой метод диагностики — воспроизведение ошибки на минимальном коде.

Стратегия:

  • сокращение входного файла до минимального примера;
  • отключение всех плагинов кроме проблемного;
  • фиксация версии SWC;
  • добавление snapshot-тестов.

Snapshot-тесты позволяют сравнивать AST до и после трансформации:

assert_eq!(format!("{:?}", output), snapshot);

Диагностика через source map

Ошибки в source map часто маскируют реальные проблемы трансформации. Проверка включает:

  • корректность диапазонов lo/hi;
  • соответствие количества строк;
  • отсутствие пересечений span.

При подозрении на повреждение source map полезно отключить его генерацию и сравнить поведение кода.


Паттерны типичных ошибок плагинов

На практике повторяются следующие классы проблем:

  • утечка структуры AST при частичной модификации узлов;
  • некорректная рекурсия в visitor;
  • пропуск вызова visit_children;
  • изменение узлов без учёта контекста module/script;
  • смешивание mutable и immutable обходов.

Диагностика этих проблем сводится к контролю обхода дерева и строгому соблюдению порядка трансформаций.


Практическая стратегия комплексной отладки

Эффективная модель отладки SWC-плагинов строится вокруг трёх уровней:

  • структурный уровень: проверка AST до и после прохода;
  • поведенческий уровень: логирование посещённых узлов;
  • системный уровень: контроль span, source map и ownership.

Совмещение этих уровней позволяет локализовать ошибку до конкретного узла и конкретной операции трансформации.