Skip to content

fix(transpiler): treat emitDecoratorMetadata as implying legacy decorators - #27527

Merged
Jarred-Sumner merged 1 commit into
mainfrom
claude/fix-emitDecoratorMetadata-implies-legacy-decorators
Feb 28, 2026
Merged

Jarred-Sumner merged 1 commit into
mainfrom
claude/fix-emitDecoratorMetadata-implies-legacy-decorators

Conversation

@robobun

@robobun robobun commented Feb 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • When emitDecoratorMetadata: true is set in tsconfig.json without experimentalDecorators: true, Bun now correctly uses legacy decorator semantics instead of TC39 standard decorator lowering
  • emitDecoratorMetadata only makes sense with TypeScript's legacy decorator system (reflect-metadata), so its presence implies the user expects legacy decorator behavior
  • This fixes a regression from ce715b5 where NestJS, TypeORM, Angular, and other legacy-decorator frameworks would crash with descriptor.value undefined

Closes #27526

Test plan

  • Added regression test test/regression/issue/27526.test.ts with two cases:
    • Legacy decorators work when emitDecoratorMetadata: true but experimentalDecorators is absent
    • TC39 standard decorators still work when neither option is set
  • Verified test fails with system Bun (USE_SYSTEM_BUN=1) and passes with debug build (bun bd test)

🤖 Generated with Claude Code

@robobun

robobun commented Feb 27, 2026 •

Copy link
Copy Markdown
Collaborator Author
Updated 1:58 AM PT - Feb 28th, 2026

❌ Your commit 00553cda has 2 failures in Build #38305 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 27527

That installs a local version of the PR into your bun-27527 executable, so you can run:

bun-27527 --bun

@coderabbitai

coderabbitai Bot commented Feb 27, 2026 •

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 4a5c20b and 00553cd.

📒 Files selected for processing (3)
  • src/bundler/ParseTask.zig
  • src/transpiler.zig
  • test/regression/issue/27526.test.ts

Walkthrough

Adjusts decorator-selection logic so legacy/experimental decorator semantics are used when TypeScript's emitDecoratorMetadata is enabled; adds explanatory comments and adds regression tests covering both emitDecoratorMetadata and no-decorator-flag scenarios.

Changes

Cohort / File(s) Summary
Core Decorator Logic
src/bundler/ParseTask.zig, src/transpiler.zig
Changed standard-decorators condition from (!loader.isTypeScript() or !experimental_decorators) to (!loader.isTypeScript() or !(experimental_decorators or emit_decorator_metadata)). Added comments clarifying that emitDecoratorMetadata implies legacy/experimental decorators and that TC39 standard decorators use a different metadata mechanism.
Regression Tests
test/regression/issue/27526.test.ts
Added two tests: one asserting legacy decorator semantics when emitDecoratorMetadata: true, and one asserting TC39 standard decorators when neither emitDecoratorMetadata nor experimentalDecorators is set; both validate observable output and exit status.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: treating emitDecoratorMetadata as implying legacy decorators in the transpiler.
Description check ✅ Passed The description covers what the PR does and includes a test plan, but lacks explicit documentation of how code changes were verified beyond test execution.
Linked Issues check ✅ Passed The PR addresses all coding requirements from issue #27526: fixes decorator handling regression, ensures emitDecoratorMetadata implies legacy decorators, preserves TC39 standard decorator behavior, and includes regression tests.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the decorator handling regression: two implementation files modified for consistent decorator logic and one test file added to verify the fix.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

…ators

When `emitDecoratorMetadata: true` is set in tsconfig.json without
`experimentalDecorators: true`, Bun now correctly uses legacy decorator
semantics instead of TC39 standard decorator lowering.

`emitDecoratorMetadata` is a TypeScript feature that only makes sense
with the legacy decorator system (reflect-metadata). TC39 standard
decorators have their own metadata mechanism. This fixes a regression
introduced in ce715b5 where frameworks like NestJS, TypeORM, and
Angular would crash with `descriptor.value` undefined when their
tsconfig did not explicitly set `experimentalDecorators: true`.

Closes #27526

Co-Authored-By: Claude <noreply@anthropic.com>
@robobun
robobun force-pushed the claude/fix-emitDecoratorMetadata-implies-legacy-decorators branch from 4a5c20b to 00553cd Compare February 28, 2026 09:14

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — straightforward one-line condition fix applied consistently in both code paths, with a good regression test.

Extended reasoning...

Overview

This PR fixes a regression where emitDecoratorMetadata: true in tsconfig.json (without experimentalDecorators: true) caused Bun to use TC39 standard decorator lowering instead of legacy decorators. The fix adds emit_decorator_metadata to the condition that determines whether to use standard vs. legacy decorators, applied identically in src/bundler/ParseTask.zig and src/transpiler.zig. A regression test validates both legacy and standard decorator paths.

Security risks

None. This is a transpiler semantics fix that only affects how decorators are lowered — no auth, crypto, permissions, or external I/O changes.

Level of scrutiny

This is production-critical transpiler code, but the change is minimal and mechanical: a single boolean condition extended with an or clause, applied identically in two locations. The logic is sound — emitDecoratorMetadata is a TypeScript-only feature tied to reflect-metadata and legacy decorators; TC39 standard decorators have their own metadata mechanism. The change correctly treats emitDecoratorMetadata as implying legacy decorator intent.

Other factors

  • The regression test covers both the fixed case (legacy decorators with emitDecoratorMetadata) and the unaffected case (TC39 standard decorators when neither flag is set).
  • CodeRabbit found no issues. No bugs were found by the bug hunting system.
  • No outstanding reviewer comments or prior reviews to address.
  • The PR is well-scoped and self-contained.

@Jarred-Sumner
Jarred-Sumner merged commit af0c90d into main Feb 28, 2026
62 of 64 checks passed
@Jarred-Sumner
Jarred-Sumner deleted the claude/fix-emitDecoratorMetadata-implies-legacy-decorators branch February 28, 2026 10:39
structwafel pushed a commit to structwafel/bun that referenced this pull request Apr 25, 2026
…ators (oven-sh#27527)

## Summary

- When `emitDecoratorMetadata: true` is set in tsconfig.json without
`experimentalDecorators: true`, Bun now correctly uses legacy decorator
semantics instead of TC39 standard decorator lowering
- `emitDecoratorMetadata` only makes sense with TypeScript's legacy
decorator system (`reflect-metadata`), so its presence implies the user
expects legacy decorator behavior
- This fixes a regression from ce715b5 where NestJS, TypeORM,
Angular, and other legacy-decorator frameworks would crash with
`descriptor.value` undefined

Closes oven-sh#27526

## Test plan

- [x] Added regression test `test/regression/issue/27526.test.ts` with
two cases:
- Legacy decorators work when `emitDecoratorMetadata: true` but
`experimentalDecorators` is absent
  - TC39 standard decorators still work when neither option is set
- [x] Verified test fails with system Bun (`USE_SYSTEM_BUN=1`) and
passes with debug build (`bun bd test`)


🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
xhjkl pushed a commit to xhjkl/bun that referenced this pull request May 14, 2026
…ators (oven-sh#27527)

## Summary

- When `emitDecoratorMetadata: true` is set in tsconfig.json without
`experimentalDecorators: true`, Bun now correctly uses legacy decorator
semantics instead of TC39 standard decorator lowering
- `emitDecoratorMetadata` only makes sense with TypeScript's legacy
decorator system (`reflect-metadata`), so its presence implies the user
expects legacy decorator behavior
- This fixes a regression from ce715b5 where NestJS, TypeORM,
Angular, and other legacy-decorator frameworks would crash with
`descriptor.value` undefined

Closes oven-sh#27526

## Test plan

- [x] Added regression test `test/regression/issue/27526.test.ts` with
two cases:
- Legacy decorators work when `emitDecoratorMetadata: true` but
`experimentalDecorators` is absent
  - TC39 standard decorators still work when neither option is set
- [x] Verified test fails with system Bun (`USE_SYSTEM_BUN=1`) and
passes with debug build (`bun bd test`)


🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Regression: NestJS controllers crash on bun 1.3.10 with bun --watch src/main.ts (descriptor.value undefined)

2 participants