Ограничения работы с AST через JS API

Архитектура SWC принципиально ориентирована на высокопроизводительный разбор и трансформацию кода на стороне Rust-ядра, тогда как JavaScript API выступает тонким слоем над нативной реализацией. Это разделение создаёт ряд ограничений, которые становятся заметны при работе с AST через JS-интерфейсы, особенно в задачах глубоких преобразований, статического анализа и построения кастомных трансформационных пайплайнов.

JS API в SWC не является равноправным участником архитектуры компилятора. Он функционирует как сериализационный мост между нативным AST, представленным структурами Rust, и объектами JavaScript. Такой подход накладывает фундаментальное ограничение: любое взаимодействие с AST проходит через преобразование данных в промежуточное представление.

В результате:

  • теряется часть низкоуровневой информации о структуре узлов;
  • увеличивается стоимость доступа к дереву;
  • возникает необходимость копирования данных между контекстами памяти Rust и V8;
  • отсутствует возможность прямой мутации внутренних структур компилятора.

Даже при визуальной полноте AST в JS, его семантическая глубина может быть уже частично упрощена на этапе сериализации.

Потеря точности в модели AST

AST, доступный через JS API, не всегда эквивалентен внутреннему представлению. Некоторые узлы проходят нормализацию перед экспортом:

  • сглаживаются синтаксические вариации;
  • объединяются эквивалентные конструкции;
  • удаляются вспомогательные метаданные, используемые только в фазах компиляции Rust-ядра.

Особенно заметно это при работе с:

  • шаблонными литералами и их вложенными выражениями;
  • деструктуризацией сложных объектов;
  • TypeScript-специфичными конструкциями;
  • JSX-элементами с неявными преобразованиями.

В JS-слое такие узлы часто уже представлены в «канонической» форме, что исключает возможность восстановления исходной синтаксической вариативности.

Ограничения системы span-ов и source map данных

Одним из ключевых элементов AST в SWC являются span-ы — структуры, описывающие позицию узла в исходном коде. При работе через JS API наблюдаются следующие ограничения:

  • span может быть неполным или нормализованным;
  • часть служебных span-ов недоступна на уровне JS;
  • точность привязки к исходному коду зависит от стадии пайплайна;
  • при трансформациях span-ы могут пересоздаваться без сохранения исходной семантики.

Это напрямую влияет на:

  • генерацию source maps;
  • инструменты форматирования;
  • анализ покрытия кода;
  • обратную трассировку ошибок.

В отличие от Rust-API, где span-ы интегрированы в каждую стадию компиляции, JS-обёртка работает с их упрощённой проекцией.

Ограниченная мутабельность AST

JS API предоставляет удобные visitor-модели, однако они реализуют концепцию копирующих трансформаций. Это означает, что:

  • узлы не изменяются in-place в оригинальном дереве;
  • каждое преобразование создаёт новую структуру AST;
  • отсутствует доступ к внутренним оптимизациям Rust, основанным на заимствованиях и владении (ownership model).

Следствием становится:

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

Особенно критично это проявляется в трансформациях, где требуется накопительное изменение состояния дерева.

Ограниченность типов узлов и их представления

JS API оперирует строго ограниченным набором типов AST, которые синхронизированы с публичным интерфейсом SWC. Однако внутренняя модель значительно богаче. Часть узлов:

  • не экспортируется в JS вообще;
  • объединяется с другими типами;
  • представляется через унифицированные конструкции (например, expression wrappers).

Это приводит к тому, что:

  • невозможно реализовать полный контроль над синтаксическими нюансами;
  • некоторые конструкции TypeScript теряют специфику при экспорте;
  • плагины не могут различать внутренние вариации узлов, доступные в Rust.

Таким образом JS API представляет не полный AST, а его «контрактную проекцию».

Ограничения системы плагинов

Плагинная модель JS в SWC существенно отличается от Rust-плагинов. Основные ограничения:

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

JS-плагины работают исключительно в рамках трансформационного слоя, что исключает:

  • кастомные стратегии лексического анализа;
  • модификации поведения parser pipeline;
  • глубокую интеграцию с системой типов TypeScript.

Фактически JS API ограничен уровнем AST-in / AST-out без доступа к промежуточным IR-структурам.

Производительность и стоимость межъязыкового взаимодействия

Даже при высокой скорости Rust-ядра узким местом становится граница между языками. Основные издержки:

  • сериализация AST в структуру, совместимую с V8;
  • десериализация обратно в Rust при обратной передаче;
  • копирование больших графов узлов;
  • GC-давление в JavaScript-контексте.

При увеличении размера проекта:

  • стоимость одного прохода растёт нелинейно;
  • многократные трансформации становятся дорогими;
  • память потребляется непропорционально объёму исходного кода.

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

Ограничения в работе с идентификаторами и символической информацией

Символьная информация в SWC частично хранится в Rust-ядре и не полностью экспортируется в JS. В результате:

  • отсутствует полноценная таблица символов;
  • невозможно надёжно отслеживать области видимости на уровне JS API;
  • референсные связи между узлами могут быть упрощены.

Это создаёт сложности при реализации:

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

JS-уровень опирается на локальную структуру AST, а не на глобальную семантическую модель.

Несовместимость с некоторыми оптимизациями компилятора

Внутренний pipeline SWC содержит оптимизации, которые выполняются до или после JS-слоя. Из-за этого:

  • трансформации JS-плагинов могут выполняться после ключевых оптимизаций;
  • изменения AST не всегда проходят повторную нормализацию;
  • некоторые оптимизации «не видят» изменений, внесённых JS-кодом.

Это приводит к расхождению между ожидаемым и фактическим результатом трансформаций.

Ограниченная обратная совместимость и стабильность API

JS API SWC подвержен изменениям, связанным с эволюцией Rust-ядра. Поскольку:

  • AST структура тесно связана с внутренними типами;
  • сериализация зависит от текущей реализации;
  • контракт между слоями не полностью стабилен,

возникает риск:

  • несовместимости между версиями;
  • изменения структуры узлов без изменения семантики API;
  • деградации поведения плагинов при обновлении.

Особенно это заметно при переходе между минорными версиями, где внутренние структуры Rust могут быть переработаны без существенных изменений JS-обёртки.

Ограничения дебаггинга и трассировки

Отладка AST-преобразований через JS API осложняется тем, что:

  • отсутствует прямое отображение на внутренние Rust-структуры;
  • промежуточные состояния AST не всегда доступны;
  • source maps могут не отражать реальные трансформации дерева;
  • stack trace JS-кода не связан с фазами компиляции.

Это затрудняет:

  • поиск причин некорректных трансформаций;
  • анализ порядка применения visitor-ов;
  • диагностику расхождений между входным и выходным кодом.

Итоговая характеристика ограничений слоя JS API

JS API в SWC следует рассматривать как высокоуровневый интерфейс для типовых трансформаций AST, а не как полноценную среду компиляторного уровня. Его ограничения формируются тремя основными факторами:

  • архитектурным разделением между Rust-ядром и JS-обёрткой;
  • упрощением AST при сериализации;
  • отсутствием доступа к внутренним фазам компиляции и символической модели.

Эти факторы определяют границы применимости JS API в задачах анализа и трансформации JavaScript-кода на уровне компилятора.