Skip to content

fix: keep object methods, accessors and computed keys in decorator metadata - #498

Open
ashley-hunter wants to merge 1 commit into
voidzero-dev:mainfrom
ashley-hunter:fix/decorator-object-members
Open

ashley-hunter wants to merge 1 commit into
voidzero-dev:mainfrom
ashley-hunter:fix/decorator-object-members

Conversation

@ashley-hunter

Copy link
Copy Markdown
Collaborator

Object literals in decorator metadata lost any member that is not a plain key: value pair. This is on 0.0.39 and main:

  • { attach() {} } compiled to the invalid {attach:() {}}.
  • get, set, async and * were lost.
  • Computed keys were silently dropped.

No error was reported. The cause is convert_object_expression in output/oxc_converter.rs, which every re-emitted field goes through: providers, viewProviders, animations, NgModule and @Injectable metadata, and setClassMetadata.

  • Such objects are now kept as written with TypeScript types stripped, as ngtsc does. Type stripping previously failed for objects because codegen drops the parentheses the unwrap relied on.
  • An arrow returning such an object, () => ({ a() {} }), now keeps the parentheses around its body.
  • Methods and accessors on a decorator's own options object, such as @Injectable({ useFactory() {} }) or @ViewChild('x', { get read() {} }), were read as values and emitted as invalid code. Like ngtsc's reflectObjectLiteral, they are now ignored.

When a component's resources are inlined, its metadata object in setClassMetadata is rebuilt from the plain properties only, matching ngtsc's transformDecoratorResources.

One remaining difference: ngc rejects @Input({ transform(v) {} }) with NG1010. oxc now ignores the method rather than reporting the error.

Tests

  • Integration tests cover member kinds across decorators and fields, arrow bodies, ignored option members (including signal input/model/output/viewChild options), BigInt keys, and a component that combines accessors with templateUrl. Expected output is taken from ngc 22.
  • 30 comparison fixtures check the output against ngtsc. 29 of them fail on 0.0.39.
  • A unit test covers type stripping for object fallbacks.

Compiling 2,678 decorated files from real-world Angular repos gives byte-identical output to main in both AOT and JIT mode, with no measurable change in compile time.

…tadata

Object literals in decorator metadata lost any member that is not a plain
`key: value` pair. `{ attach() {} }` compiled to the invalid `{attach:() {}}`,
`get`/`set`/`async`/`*` were dropped, and computed keys disappeared, with no
error. Such objects are now kept as written, with TypeScript types stripped,
as ngtsc does. Type stripping also failed for objects because codegen drops
the redundant parentheses the unwrap relied on, and an arrow returning such an
object now keeps the parentheses around its body.

When a component's resources are inlined, its metadata object in
`setClassMetadata` is rebuilt from the plain properties only, matching ngtsc's
`transformDecoratorResources`.

Methods and accessors on a decorator's own options object, such as
`@Injectable({ useFactory() {} })` or `@ViewChild('x', { get read() {} })`,
were read as `key: value` pairs and emitted as invalid code. Like ngtsc's
`reflectObjectLiteral`, they are now ignored.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant