parse и parseSync: получение AST

В экосистеме SWC разбор исходного кода реализован как этап трансформации текста программы в структурированное представление — AST (Abstract Syntax Tree). Именно через AST функции parse и parseSync предоставляют доступ к синтаксическому дереву, которое затем используется для анализа, трансформации и генерации кода.

AST в SWC представляет собой строго типизированную и иерархическую модель программы, где каждый узел соответствует синтаксической конструкции языка: модулям, объявлениям, выражениям, операторам, литералам и прочим элементам. В отличие от текстового представления, AST устраняет неоднозначность и делает возможной детальную работу с кодом на уровне структуры.

Основные компоненты AST включают:

  • Program — корневой узел, представляющий весь файл
  • Module — модульный контейнер ECMAScript
  • Statement — инструкции (if, for, return и др.)
  • Expression — выражения (вызовы, бинарные операции, идентификаторы)
  • Pattern — шаблоны деструктуризации
  • Decl — объявления переменных, функций, классов

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

Сигнатура функции обычно выглядит следующим образом:

import { parse } from "@swc/core";

const ast = await parse(code, {
  syntax: "ecmascript",
  target: "es2022",
  jsx: true,
  decorators: false,
  dynamicImport: true
});

Первый аргумент — исходный код в виде строки. Второй — объект конфигурации парсера.

Ключевые параметры конфигурации:

  • syntax — определяет диалект языка:

    • “ecmascript”
    • “typescript”
    • “typescript” с поддержкой JSX
  • jsx — включает поддержку JSX-синтаксиса

  • decorators — включает поддержку декораторов

  • dynamicImport — разрешает динамический import()

  • target — уровень трансляции ECMAScript

Асинхронная природа parse связана с тем, что SWC может быть встроен в окружения, где обработка выполняется в параллельных потоках или через нативные биндинги Rust, что позволяет не блокировать event loop при обработке больших файлов.

Результатом выполнения parse является AST-объект, соответствующий структуре ECMAScript модуля. Этот объект может быть передан в трансформеры SWC или использован для анализа кода.

parseSync: синхронный разбор исходного кода

Функция parseSync выполняет ту же задачу, но в синхронном режиме. Она возвращает AST напрямую, без использования Promise. Это делает её предпочтительной в контекстах, где требуется предсказуемое выполнение без асинхронных переходов.

Пример использования:

import { parseSync } from "@swc/core";

const ast = parseSync(code, {
  syntax: "typescript",
  tsx: true,
  decorators: true
});

Синхронный парсер особенно полезен в следующих сценариях:

  • CLI-инструменты
  • этапы сборки, где допустима блокировка потока
  • тестовые окружения
  • скрипты миграции кода

Несмотря на синхронный интерфейс, внутренняя реализация SWC остаётся высокопроизводительной благодаря Rust-ядру, что делает разбор даже больших файлов значительно быстрее традиционных JavaScript-парсеров.

Структура возвращаемого AST

AST, возвращаемый parse и parseSync, строго структурирован и соответствует спецификации SWC AST.

Пример упрощённой структуры:

{
  "type": "Module",
  "body": [
    {
      "type": "FunctionDeclaration",
      "identifier": {
        "value": "sum"
      },
      "params": [
        {
          "pat": {
            "type": "Identifier",
            "value": "a"
          }
        }
      ]
    }
  ]
}

Каждый узел содержит:

  • type — тип синтаксической конструкции
  • span — информацию о позиции в исходном коде (start, end)
  • дополнительные поля, зависящие от типа узла

Поле span играет ключевую роль при трансформации кода, позволяя точно сопоставлять AST-узлы с исходными фрагментами текста.

Различия parse и parseSync в архитектурном контексте

Разделение на асинхронный и синхронный API отражает архитектурную гибкость SWC:

  • parse интегрируется в асинхронные пайплайны и позволяет масштабировать обработку
  • parseSync минимизирует накладные расходы на управление асинхронностью

При этом оба метода используют общий парсерный движок, поэтому различие заключается только в способе вызова и возврата результата, а не в логике анализа.

Работа с TypeScript и JSX

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

При разборе TypeScript-кода AST включает дополнительные узлы:

  • TSInterfaceDeclaration
  • TSTypeAnnotation
  • TSTypeReference
  • TSEnumDeclaration

JSX-деревья включают:

  • JSXElement
  • JSXOpeningElement
  • JSXAttribute
  • JSXExpressionContainer

Пример парсинга TypeScript:

import { parseSync } from "@swc/core";

const ast = parseSync(`
  interface User {
    id: number;
    name: string;
  }
`, {
  syntax: "typescript"
});

Использование AST для анализа кода

После получения AST становится возможным:

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

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

Позиционная информация и span

Каждый узел AST содержит span, описывающий границы исходного фрагмента:

  • start — начальная позиция
  • end — конечная позиция
  • ctxt — контекстный идентификатор

Эта информация позволяет:

  • восстанавливать исходный код из AST
  • выполнять точечные замены
  • формировать source maps при трансформации

Ошибки парсинга

При некорректном синтаксисе SWC генерирует структурированную ошибку, содержащую:

  • тип ошибки
  • позицию в коде
  • ожидаемые токены

Пример:

try {
  parseSync("const a = ", { syntax: "ecmascript" });
} catch (e) {
  console.log(e.message);
}

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

Производительность парсинга

Ключевым преимуществом SWC является реализация парсера на Rust. Это обеспечивает:

  • отсутствие GC-накладных расходов на этапе парсинга
  • предсказуемую задержку обработки
  • эффективное использование многопоточности на уровне нативного кода

При больших кодовых базах разница с JavaScript-парсерами становится особенно заметной, что делает SWC предпочтительным выбором в современных сборочных системах.