Skip to content

feat(transformer): support lowering accessor with legacy decorators#20348

Merged
graphite-app[bot] merged 1 commit intomainfrom
feat/lower-accessor-legacy-decorators
Mar 18, 2026
Merged

feat(transformer): support lowering accessor with legacy decorators#20348
graphite-app[bot] merged 1 commit intomainfrom
feat/lower-accessor-legacy-decorators

Conversation

@Dunqing
Copy link
Member

@Dunqing Dunqing commented Mar 13, 2026

Summary

Closes #20133

  • Lower decorated accessor properties to private backing field + getter/setter pair when experimentalDecorators is enabled, matching TypeScript's classFields.ts transformAutoAccessor
  • Only accessors with decorators are lowered — undecorated accessors are left as-is
  • Support computed accessor keys (e.g. @dec accessor [expr]) via temp var to ensure the key expression is evaluated only once
  • Accessor lowering runs in enter_class (Decorator plugin) so es2022 class-properties can further transform the generated private fields
  • Decorators are transferred from the accessor to the generated getter, so the legacy decorator transform emits _decorate() calls

Transform example

// Input
class C {
  @dec accessor prop: string = "hello";
  @dec accessor [expr]: any;
}
// Output (without class-properties)
var _a = expr;
class C {
  #_prop_accessor_storage = "hello";
  get prop() { return this.#_prop_accessor_storage; }
  set prop(value) { this.#_prop_accessor_storage = value; }
  #_a;
  get [_a]() { return this.#_a; }
  set [_a](value) { this.#_a = value; }
}
babelHelpers.decorate([dec], C.prototype, "prop", null);
babelHelpers.decorate([dec], C.prototype, _a, null);

Test plan

  • New test oxc/accessor — decorated accessors without class-properties plugin (instance, static, initialized, computed key)
  • New test oxc/accessor-with-class-properties — full pipeline with class-properties plugin (private fields transformed to WeakMap/brand patterns)
  • New test decoratorOnClassAccessorProperty1 — instance, static, and initialized accessor properties with decorators
  • Existing decoratorOnClassProperty13 output updated for accessor lowering
  • Undecorated accessors are not lowered (oxc-13284.js coverage test passes)
  • cargo clippy, just fmt clean

🤖 Generated with Claude Code

@github-actions github-actions bot added A-transformer Area - Transformer / Transpiler C-enhancement Category - New feature or request labels Mar 13, 2026
@Dunqing Dunqing force-pushed the feat/lower-accessor-legacy-decorators branch from ad82294 to 22c68b2 Compare March 15, 2026 14:59
@codspeed-hq
Copy link

codspeed-hq bot commented Mar 15, 2026

Merging this PR will not alter performance

✅ 49 untouched benchmarks
⏩ 7 skipped benchmarks1


Comparing feat/lower-accessor-legacy-decorators (9106abf) with main (4ae3f3f)

Open in CodSpeed

Footnotes

  1. 7 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@Dunqing Dunqing force-pushed the feat/lower-accessor-legacy-decorators branch from fcf7f6b to 8ba153d Compare March 16, 2026 08:29
@Dunqing Dunqing marked this pull request as ready for review March 16, 2026 08:38
@Dunqing Dunqing requested a review from overlookmotel as a code owner March 16, 2026 08:38
@Dunqing Dunqing requested a review from sapphi-red March 16, 2026 08:38
@Dunqing Dunqing force-pushed the feat/lower-accessor-legacy-decorators branch from 8ba153d to c77e1c5 Compare March 18, 2026 04:31
Copy link
Member Author

Dunqing commented Mar 18, 2026


How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • 0-merge - adds this PR to the back of the merge queue
  • hotfix - for urgent changes, fast-track this PR to the front of the merge queue

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@Dunqing Dunqing force-pushed the feat/lower-accessor-legacy-decorators branch 2 times, most recently from a9f3b9c to df15346 Compare March 18, 2026 04:57
@Dunqing Dunqing requested a review from sapphi-red March 18, 2026 05:05
@Dunqing Dunqing force-pushed the feat/lower-accessor-legacy-decorators branch 2 times, most recently from 4c5ccb8 to 2f7fe91 Compare March 18, 2026 06:15
@Dunqing
Copy link
Member Author

Dunqing commented Mar 18, 2026

I think it is good to go, merging now. Feel free to leave comments. I will follow up on it

@Dunqing Dunqing added the 0-merge Merge with Graphite Merge Queue label Mar 18, 2026
Copy link
Member Author

Dunqing commented Mar 18, 2026

Merge activity

@Dunqing Dunqing marked this pull request as draft March 18, 2026 06:54
@Dunqing Dunqing force-pushed the feat/lower-accessor-legacy-decorators branch from 3b8bddd to 0d8aded Compare March 18, 2026 07:16
@Dunqing Dunqing marked this pull request as ready for review March 18, 2026 07:18
…#20348)

## Summary

Closes #20133

- Lower decorated `accessor` properties to private backing field + getter/setter pair when `experimentalDecorators` is enabled, matching TypeScript's `classFields.ts` `transformAutoAccessor`
- Only accessors with decorators are lowered — undecorated accessors are left as-is
- Support computed accessor keys (e.g. `@dec accessor [expr]`) via temp var to ensure the key expression is evaluated only once
- Accessor lowering runs in `enter_class` (Decorator plugin) so es2022 class-properties can further transform the generated private fields
- Decorators are transferred from the accessor to the generated getter, so the legacy decorator transform emits `_decorate()` calls

### Transform example

```ts
// Input
class C {
  @dec accessor prop: string = "hello";
  @dec accessor [expr]: any;
}
```

```js
// Output (without class-properties)
var _a = expr;
class C {
  #_prop_accessor_storage = "hello";
  get prop() { return this.#_prop_accessor_storage; }
  set prop(value) { this.#_prop_accessor_storage = value; }
  #_a;
  get [_a]() { return this.#_a; }
  set [_a](value) { this.#_a = value; }
}
babelHelpers.decorate([dec], C.prototype, "prop", null);
babelHelpers.decorate([dec], C.prototype, _a, null);
```

## Test plan

- [x] New test `oxc/accessor` — decorated accessors without class-properties plugin (instance, static, initialized, computed key)
- [x] New test `oxc/accessor-with-class-properties` — full pipeline with class-properties plugin (private fields transformed to WeakMap/brand patterns)
- [x] New test `decoratorOnClassAccessorProperty1` — instance, static, and initialized accessor properties with decorators
- [x] Existing `decoratorOnClassProperty13` output updated for accessor lowering
- [x] Undecorated accessors are not lowered (`oxc-13284.js` coverage test passes)
- [x] `cargo clippy`, `just fmt` clean

🤖 Generated with [Claude Code](https://claude.com/claude-code)
@graphite-app graphite-app bot force-pushed the feat/lower-accessor-legacy-decorators branch from 52e2c22 to 7215d9e Compare March 18, 2026 07:45
@graphite-app graphite-app bot merged commit 7215d9e into main Mar 18, 2026
21 checks passed
@graphite-app graphite-app bot removed the 0-merge Merge with Graphite Merge Queue label Mar 18, 2026
@graphite-app graphite-app bot deleted the feat/lower-accessor-legacy-decorators branch March 18, 2026 07:56
Boshen added a commit that referenced this pull request Mar 19, 2026
### 🚀 Features

- 7215d9e transformer: Support lowering `accessor` with legacy
decorators (#20348) (Dunqing)

### 🐛 Bug Fixes

- 3bbd0cd transformer: Emit `Object` instead of `void 0` for untyped
getter/setter `design:type` metadata (#20488) (Dunqing)
- 4ae3f3f ecmascript: Apply coercion-is-pure assumption to constructor
side-effect detection (#20420) (Dunqing)
- 11f9695 transformer: Legacy decorator on computed property key leaves
variable unassigned (#20430) (bab)
- efeba28 ecmascript: Add argument validation for NewExpression
side-effect detection (#20395) (Dunqing)

Co-authored-by: Boshen <1430279+Boshen@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-transformer Area - Transformer / Transpiler C-enhancement Category - New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

transformer: support lowering accessor with legacy decorators

2 participants