Using declarations

## Использование декларации `using` в SWC и обработка Explicit Resource Management ### Синтаксис `using` и `await using` в JavaScript Декларации управления ресурсами относятся к спецификации **Explicit Resource Management** и вводят два ключевых оператора: ```javascript using resource = createResource(); await using asyncResource = await createAsyncResource(); ``` Ключевая особенность конструкции заключается в автоматическом вызове метода освобождения ресурса при выходе из области видимости, независимо от причины завершения блока: нормальное выполнение, исключение или ранний `return`. Механизм опирается на специальные символы: * `Symbol.dispose` — синхронное освобождение ресурса * `Symbol.asyncDispose` — асинхронное освобождение ресурса Пример объекта, совместимого с `using`: ```javascript class FileHandle { constructor(path) { this.path = path; } [Symbol.dispose]() { console.log("sync dispose:", this.path); } async [Symbol.asyncDispose]() { console.log("async dispose:", this.path); } } ``` --- ### Поведение `using` в рантайме Конструкция: ```javascript { using db = openConnection(); db.query("SEL ECT * FROM users"); } ``` трансформируется в эквивалент с гарантированным освобождением: ```javascript { const db = openConnection(); try { db.query("SEL ECT * FR OM users"); } finally { db[Symbol.dispose]?.(); } } ``` Для `await using` добавляется асинхронное ожидание: ```javascript { await using db = await openConnection(); db.query("SEL ECT * FR OM users"); } ``` Эквивалент: ```javascript { const db = await openConnection(); try { db.query("SELECT * fr om users"); } finally { await db[Symbol.asyncDispose]?.(); } } ``` --- ### Поддержка `using declarations` в SWC SWC реализует поддержку современных ECMAScript proposals через модуль трансформации `@swc/core`. Обработка `using` относится к категории **экспериментальных трансформаций синтаксиса управления ресурсами**. Ключевой принцип работы SWC: * парсинг нового синтаксиса через `jsc.parser` * преобразование AST * генерация совместимого JavaScript для целевой среды --- ### Включение поддержки в конфигурации SWC Основная настройка выполняется через `.swcrc`. ```json { "jsc": { "parser": { "syntax": "ecmascript", "experimental": { "plugins": [] } }, "transform": {} } } ``` Для включения поддержки explicit resource management используется флаг трансформаций (в зависимости от версии SWC): ```json { "jsc": { "parser": { "syntax": "ecmascript" }, "transform": { "legacyDecorator": false } }, "env": { "targets": { "chrome": "90" } } } ``` В актуальных версиях SWC поддержка `using` может включаться через feature-gate трансформеров, связанных с stage proposals. --- ### Общая модель трансформации в SWC При обработке `using` SWC выполняет следующие шаги: 1. **Идентификация декларации** * `using` или `await using` в VariableDeclaration 2. **Определение типа ресурса** * синхронный (`Symbol.dispose`) * асинхронный (`Symbol.asyncDispose`) 3. **Инъекция блока `try/finally`** 4. **Добавление вызова dispose** --- ### Преобразование AST: логика SWC Упрощённая модель трансформации: ```javascript function transformUsing(node) { if (node.kind === "using") { return wrapWithTryFinally(node, false); } if (node.kind === "await using") { return wrapWithTryFinally(node, true); } } ``` Результирующая структура: ```javascript BlockStatement { body: [ VariableDeclaration, TryStatement { block, finalizer } ] } ``` --- ### Обработка области видимости Особенность SWC-трансформации заключается в строгом соблюдении **лексической области видимости**. Ресурс должен быть уничтожен: * при выходе из блока `{ ... }` * при исключении * при `break` / `continue` (внутри циклов) * при `return` из функции Пример: ```javascript function run() { using lock = acquireLock(); for (let i = 0; i < 10; i++) { if (i === 5) return; } } ``` SWC обязан преобразовать это в каскад `try/finally` для каждой управляющей ветки, обеспечивая корректное освобождение ресурса. --- ### Вложенные `using` декларации При нескольких ресурсах SWC формирует вложенные `try/finally` или объединённый финализатор. ```javascript { using a = resourceA(); using b = resourceB(); } ``` Преобразование: ```javascript { const a = resourceA(); try { const b = resourceB(); try { } finally { b[Symbol.dispose]?.(); } } finally { a[Symbol.dispose]?.(); } } ``` --- ### Асинхронные ресурсы и `await using` `await using` требует поддержки `Promise`-цепочек в финализаторе: ```javascript { await using conn = await connect(); } ``` SWC генерирует: ```javascript { const conn = await connect(); try { } finally { await conn[Symbol.asyncDispose]?.(); } } ``` Особенность: финализатор становится `async`, даже если исходный блок синхронный. --- ### Совместимость с целевыми средами SWC используется для downlevel-компиляции в окружения, где: * отсутствует поддержка `using` * отсутствуют `Symbol.dispose` / `Symbol.asyncDispose` * требуется ES2019 или ниже В таких случаях SWC всегда транспилирует конструкцию в `try/finally`, полностью эмулируя поведение. --- ### Взаимодействие с TypeScript При использовании SWC вместе с TypeScript: ```json { "jsc": { "parser": { "syntax": "typescript" } } } ``` `using` поддерживается как часть TypeScript 5+ синтаксиса. SWC обрабатывает его на уровне AST, не завися от типизации, поскольку: * типы удаляются на этапе трансформации * управление ресурсами реализуется чисто синтаксически --- ### Особенности генерации кода SWC при трансформации стремится: * минимизировать вложенность `try/finally` * избегать лишних временных переменных * сохранять семантику порядка освобождения ресурсов Порядок всегда строго обратный: ```javascript using a = ... using b = ... ``` Освобождение: ```javascript dispose(b) dispose(a) ``` --- ### Потенциальные ограничения трансформации При сложных конструкциях могут возникать нюансы: * ресурсы в условных блоках требуют отдельного scope * `return` внутри `try` приводит к дополнительным промежуточным переменным * оптимизация кода может быть отключена для сохранения корректности `finally` --- ### Использование в пайплайне сборки SWC часто используется как замена Babel, и `using declarations` обрабатываются на этапе трансформации вместе с другими современными фичами: * optional chaining * nullish coalescing * decorators (в зависимости от версии) * class fields Пайплайн: 1. Parse (ECMAScript/TypeScript) 2. Transform (including using declarations) 3. Minify (optional) 4. Emit JS --- ### Семантика безопасности ресурсов Ключевая гарантия, реализуемая через SWC-трансформацию: * отсутствие утечек ресурсов при исключениях * детерминированное освобождение * единый механизм для sync и async ресурсов Механизм `using` становится аналогом `RAII` в среде JavaScript, а SWC обеспечивает его переносимость в любые версии ECMAScript-рантайма.