Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(transformer/decorator): support emitting decorator metadata #9057

Conversation

Dunqing
Copy link
Member

@Dunqing Dunqing commented Feb 12, 2025

close: #9186

Implementation

The Implementation port from TypeScript

Example

Input:

class Demo {
  @LogMethod
  public foo(bar: number) {}
  @Prop
  prop: string = "hello";
}

Output:

class Demo {
  foo(bar) {}
  prop = "hello";
}
babelHelpers.decorate([
  LogMethod,
  babelHelpers.decorateParam(0, babelHelpers.decorateMetadata("design:type", Function)),
  babelHelpers.decorateParam(0, babelHelpers.decorateMetadata("design:paramtypes", [Number])),
  babelHelpers.decorateParam(0, babelHelpers.decorateMetadata("design:returntype", void 0))
], Demo.prototype, "foo", null);
babelHelpers.decorate([Prop, babelHelpers.decorateMetadata("design:type", String)], Demo.prototype, "prop", void 0);

Limitations

Compared to TypeScript

We lack a type inference ability that TypeScript has, so we cannot determine the exact type of the TyepReference refers to. See [LegacyDecoratorMetadata::serialize_type_reference_node] does.

For example:
Input:

type Foo = string;
class Cls {
  @dec
  p: Foo = ""
}

TypeScript Output:

class Cls {
  constructor() {
    this.p = "";
  }
}
__decorate([
  dec,
  __metadata("design:type", String) // Infer the type of `Foo` is `String`
], Cls.prototype, "p", void 0);

OXC Output:

var _ref;
class Cls {
    p = "";
}
babelHelpers.decorate([
  dec,
  babelHelpers.decorateMetadata("design:type", typeof (_ref = typeof Foo === "undefined" && Foo) === "function" ? _ref : Object)
],
Cls.prototype, "p", void 0);

Compared to SWC

SWC also has the above limitation, considering that SWC has been adopted in NestJS, so the limitation may not be a problem. In addition, SWC provides additional support for inferring enum members, which we currently do not have. We haven't dived into how NestJS uses it, so we don't know if it matters, thus we may leave it until we receive feedback.

@github-actions github-actions bot added the A-transformer Area - Transformer / Transpiler label Feb 12, 2025
Copy link
Member Author

Dunqing commented Feb 12, 2025


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 hot fixes, skip the queue and merge this PR next

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.

@alfaproject
Copy link

Yay, looking forward to this!

@Dunqing Dunqing changed the base branch from main to graphite-base/9057 February 18, 2025 01:27
@Dunqing Dunqing force-pushed the 02-12-feat_transformer_decorator_support_emitting_decorator_metadata branch from 2625eb3 to 7e84118 Compare February 18, 2025 01:27
@Dunqing Dunqing changed the base branch from graphite-base/9057 to 02-18-test_transformer_legacy-decorator_update_update-fixtures_for_emitdecoratormetadata February 18, 2025 01:27
@Dunqing Dunqing force-pushed the 02-12-feat_transformer_decorator_support_emitting_decorator_metadata branch from 7e84118 to ba98139 Compare February 18, 2025 01:30
Copy link

codspeed-hq bot commented Feb 18, 2025

CodSpeed Performance Report

Merging #9057 will not alter performance

Comparing 02-12-feat_transformer_decorator_support_emitting_decorator_metadata (90ba283) with main (bde4126)

Summary

✅ 33 untouched benchmarks

@Dunqing Dunqing force-pushed the 02-12-feat_transformer_decorator_support_emitting_decorator_metadata branch 3 times, most recently from 4f84925 to e58bd9b Compare February 18, 2025 03:20
@Dunqing Dunqing marked this pull request as ready for review February 18, 2025 03:22
@Dunqing Dunqing force-pushed the 02-12-feat_transformer_decorator_support_emitting_decorator_metadata branch from e58bd9b to a2aad51 Compare February 19, 2025 07:15
@Dunqing Dunqing force-pushed the 02-18-test_transformer_legacy-decorator_update_update-fixtures_for_emitdecoratormetadata branch from ff8896e to 2143049 Compare February 19, 2025 07:15
@graphite-app graphite-app bot added the 0-merge Merge with Graphite Merge Queue label Feb 19, 2025
Copy link

graphite-app bot commented Feb 19, 2025

Merge activity

close: #9186

## Implementation

The Implementation port from [TypeScript]( https://github.com/microsoft/TypeScript/blob/d85767abfd83880cea17cea70f9913e9c4496dcc/src/compiler/transformers/ts.ts#L1119-L1136)

## Example
Input:
```ts
class Demo {
  @logmethod
  public foo(bar: number) {}
  @prop
  prop: string = "hello";
}
```
Output:
```js
class Demo {
  foo(bar) {}
  prop = "hello";
}
babelHelpers.decorate([
  LogMethod,
  babelHelpers.decorateParam(0, babelHelpers.decorateMetadata("design:type", Function)),
  babelHelpers.decorateParam(0, babelHelpers.decorateMetadata("design:paramtypes", [Number])),
  babelHelpers.decorateParam(0, babelHelpers.decorateMetadata("design:returntype", void 0))
], Demo.prototype, "foo", null);
babelHelpers.decorate([Prop, babelHelpers.decorateMetadata("design:type", String)], Demo.prototype, "prop", void 0);
```

## Limitations
### Compared to TypeScript
We lack a type inference ability that TypeScript has, so we cannot determine the exact type of the TyepReference refers to. See [`LegacyDecoratorMetadata::serialize_type_reference_node`] does.

For example:
Input:
```ts
type Foo = string;
class Cls {
  @dec
  p: Foo = ""
}
```
TypeScript Output:
```js
class Cls {
  constructor() {
    this.p = "";
  }
}
__decorate([
  dec,
  __metadata("design:type", String) // Infer the type of `Foo` is `String`
], Cls.prototype, "p", void 0);
```
OXC Output:
```js
var _ref;
class Cls {
    p = "";
}
babelHelpers.decorate([
  dec,
  babelHelpers.decorateMetadata("design:type", typeof (_ref = typeof Foo === "undefined" && Foo) === "function" ? _ref : Object)
],
Cls.prototype, "p", void 0);
```
### Compared to SWC
SWC also has the above limitation, considering that SWC has been adopted in [NestJS](https://docs.nestjs.com/recipes/swc#jest--swc), so the limitation may not be a problem. In addition, SWC provides additional support for inferring enum members, which we currently do not have. We haven't dived into how NestJS uses it, so we don't know if it matters, thus we may leave it until we receive feedback.
@graphite-app graphite-app bot force-pushed the 02-18-test_transformer_legacy-decorator_update_update-fixtures_for_emitdecoratormetadata branch from 2143049 to c21f4b7 Compare February 19, 2025 14:04
@graphite-app graphite-app bot force-pushed the 02-12-feat_transformer_decorator_support_emitting_decorator_metadata branch from a2aad51 to 90ba283 Compare February 19, 2025 14:05
Base automatically changed from 02-18-test_transformer_legacy-decorator_update_update-fixtures_for_emitdecoratormetadata to main February 19, 2025 14:09
@graphite-app graphite-app bot merged commit 90ba283 into main Feb 19, 2025
27 checks passed
@graphite-app graphite-app bot deleted the 02-12-feat_transformer_decorator_support_emitting_decorator_metadata branch February 19, 2025 14:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
0-merge Merge with Graphite Merge Queue 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: emitDecoratorMetadata
2 participants