Архитектура 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-кода на уровне компилятора.