Skip to content

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

Merged
Brooooooklyn merged 1 commit into
voidzero-dev:mainfrom
ashley-hunter:fix/decorator-object-members
Oct 2, 2026
Merged

Brooooooklyn merged 1 commit into
voidzero-dev:mainfrom
ashley-hunter:fix/decorator-object-members

Conversation

@ashley-hunter

@ashley-hunter ashley-hunter commented Sep 24, 2026 •

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.

@Input options are evaluated rather than reflected, so ngc rejects @Input({ transform(v) {} }) with NG1010; oxc reports the same 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.
@Brooooooklyn
Brooooooklyn force-pushed the fix/decorator-object-members branch from 6b7827e to 3b88a9c Compare October 2, 2026 04:37
@Brooooooklyn

Copy link
Copy Markdown
Member

Rebased onto main (conflict in directive/property_decorators.rs, where #495 had folded the three signal alias loops into options_alias — moved the new is_metadata_property check into that helper).

One test needed an update: test_methods_and_accessors_on_decorator_options_are_ignored used @Input({ transform(v: string) { return v; } }), which now reports the NG1010-style error from #494 (@Input decorator argument must resolve to a string or an object literal) — matching ngc, since @Input options are evaluated rather than reflected. Replaced it with a plain alias in the ignore test and added test_input_options_method_transform_is_an_error asserting the error. PR body updated accordingly.

All cargo test -p oxc_angular_compiler tests pass and pnpm compare --fixtures is green on the new object-members fixtures.

@Brooooooklyn
Brooooooklyn merged commit b49a521 into voidzero-dev:main Oct 2, 2026
10 checks passed
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.

2 participants