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-рантайма.