Skip to content

feat(es/proposal): add decorators 2023-11 support#11686

Merged
kdy1 merged 6 commits intomainfrom
kdy1/decorators-2023-11-babel-parity
Mar 16, 2026
Merged

feat(es/proposal): add decorators 2023-11 support#11686
kdy1 merged 6 commits intomainfrom
kdy1/decorators-2023-11-babel-parity

Conversation

@kdy1
Copy link
Member

@kdy1 kdy1 commented Mar 16, 2026

Summary

  • Add full decoratorVersion: "2023-11" support in SWC with Babel parity.
  • Align transform output/ABI with Babel applyDecs2311 behavior.
  • Keep default behavior and pre-existing decorator versions unchanged.

What changed

  • Public API:
    • Add "2023-11" to decoratorVersion in packages/types/index.ts.
    • Wire DecoratorVersion::V202311 in crates/swc/src/config/mod.rs.
  • Proposal transform:
    • Add decorator_2023_11 pass and export it from proposal transforms.
    • Extend decorator_impl.rs with 2023-11 specific descriptor encoding and helper call path.
    • Implement applyDecs2311 argument ordering and optional args behavior (classDecsHaveThis, instanceBrand, parentClass).
    • Preserve 2022-03 behavior/output path.
  • Helpers:
    • Add _apply_decs_2311 helper in transforms base and helpers package.
    • Register/export helper in helper registries and package exports.
  • Test harness:
    • Remove 2023-11 todo!() pass gap.
    • Make decorators plugin options parser tolerant to additional option keys.
    • Reflect Babel assumptions in class-properties/static-block transform path.
    • Include exec.ts fixtures.
    • For input.ts, resolve expected file as output.ts first, fallback to output.js.
  • Fixtures:
    • Import Babel 2023-11* decorators fixtures (including assumptions fixtures and options files).

Validation

  • git submodule update --init --recursive
  • UPDATE=1 cargo test -p swc_ecma_transforms_proposal
  • cargo test -p swc_ecma_transforms_proposal
  • UPDATE=1 cargo test -p swc_ecma_transforms_proposal --test decorators fixture_tests -- --ignored
  • cargo test -p swc_ecma_transforms_proposal --test decorators fixture_tests -- --ignored
  • cargo test -p swc_ecma_transforms_base
  • ⚠️ cargo test -p swc fails in source_map tests due missing external node module sourcemap-validator in this environment.
  • ⚠️ cargo fmt --all / cargo clippy --all --all-targets -- -D warnings blocked by unrelated pre-existing syntax error in crates/swc_es_parser/tests/bench_parser_inputs.rs.
  • ⚠️ decorators exec ignored tests require mocha; unavailable in this environment.

@changeset-bot
Copy link

changeset-bot bot commented Mar 16, 2026

🦋 Changeset detected

Latest commit: 886afdf

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@socket-security
Copy link

socket-security bot commented Mar 16, 2026

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn Critical
Critical CVE: npm cipher-base is missing type checks, leading to hash rewind and passing on crafted data

CVE: GHSA-cpq7-6gpm-g9rc cipher-base is missing type checks, leading to hash rewind and passing on crafted data (CRITICAL)

Affected versions: < 1.0.5

Patched version: 1.0.5

From: ?npm/cipher-base@1.0.4

ℹ Read more on: This package | This alert | What is a critical CVE?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Remove or replace dependencies that include known critical CVEs. Consumers can use dependency overrides or npm audit fix --force to remove vulnerable dependencies.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/cipher-base@1.0.4. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn High
Obfuscated code: npm buffer is 96.0% likely obfuscated

Confidence: 0.96

Location: Package overview

From: ?npm/buffer@4.9.2

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/buffer@4.9.2. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

@github-actions
Copy link
Contributor

github-actions bot commented Mar 16, 2026

Binary Sizes

File Size
swc.linux-x64-gnu.node 28M (28834504 bytes)

Commit: 4d2cb38

@kdy1 kdy1 force-pushed the kdy1/decorators-2023-11-babel-parity branch from a8be077 to 8472435 Compare March 16, 2026 05:04
@codspeed-hq
Copy link

codspeed-hq bot commented Mar 16, 2026

Merging this PR will not alter performance

✅ 219 untouched benchmarks


Comparing kdy1/decorators-2023-11-babel-parity (886afdf) with main (1be052e)

Open in CodSpeed

@kdy1 kdy1 marked this pull request as ready for review March 16, 2026 12:44
@kdy1 kdy1 requested review from a team as code owners March 16, 2026 12:44
Copilot AI review requested due to automatic review settings March 16, 2026 12:44
kodiakhq[bot]
kodiakhq bot previously approved these changes Mar 16, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds decoratorVersion: "2023-11" support to SWC with Babel applyDecs2311 parity, including the transform pass, helper registration, test fixtures, and bug fixes to existing 2022-03 decorator output.

Changes:

  • Wire DecoratorVersion::V202311 transform pass and _apply_decs_2311 helper
  • Import Babel 2023-11 decorator test fixtures and fix existing 2022-03 output issues
  • Fix ClassNameTdzFolder to use to_id() comparison and skip static-private helper class refs

Reviewed changes

Copilot reviewed 295 out of 578 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
crates/swc/src/config/mod.rs Wire V202311 decorator pass instead of todo!()
crates/swc_ecma_transforms_proposal/src/lib.rs Export decorator_2023_11 module
crates/swc_ecma_transforms_proposal/src/decorator_2023_11.rs New pass delegating to decorator_impl
crates/swc_ecma_transforms_proposal/Cargo.toml Add dev-dependencies for tests
crates/swc_ecma_transforms_base/src/helpers/mod.rs Register apply_decs_2311 helper
crates/swc_ecma_transforms_base/src/helpers/_class_name_tdz_error.js Change Error to ReferenceError
crates/swc_ecma_compat_es2022/src/class_properties/class_name_tdz.rs Fix id comparison and skip static-private helper args
tests/decorators/2023-11-*/** New test fixtures
tests/decorators/2022-03-*/**/output.js Updated existing test outputs

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +50 to +57
if matches!(
&**sym,
"_class_static_private_field_destructure"
| "_class_static_private_field_spec_set"
| "_class_static_private_field_update"
| "_class_static_private_method_get"
| "_class_static_private_field_spec_get"
)
@claude

This comment has been minimized.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 21810dfe37

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +2963 to +2967
if self.is_unresolved_ident(id) {
self.implicit_globals.insert(id.sym.clone());
assign.left = AssignTarget::Simple(SimpleAssignTarget::Member(
self.global_this_member_expr(id.sym.clone(), id.span),
));

Choose a reason for hiding this comment

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

P1 Badge Avoid rewriting unresolved assignments to globalThis

This branch changes runtime semantics for real user code when decoratorVersion: "2023-11" is enabled: any unresolved assignment like foo = 1 is rewritten to globalThis.foo = 1, so ESM/strict code that should throw ReferenceError now silently mutates globals. Because visit_mut_expr runs over normal program expressions (not just test harness wrappers), this introduces behavior that diverges from JavaScript semantics and Babel output in production transforms.

Useful? React with 👍 / 👎.

@kdy1 kdy1 changed the title feat(proposal): add decorators 2023-11 support with Babel parity feat(es/proposal): add decorators 2023-11 support Mar 16, 2026
@kdy1 kdy1 merged commit e96eb6a into main Mar 16, 2026
22 checks passed
@kdy1 kdy1 deleted the kdy1/decorators-2023-11-babel-parity branch March 16, 2026 15:12
@github-actions github-actions bot added this to the Planned milestone Mar 16, 2026
@claude
Copy link
Contributor

claude bot commented Mar 16, 2026

Code Review: feat(es/proposal) — Decorators 2023-11 Support

Impressive piece of work bringing full 2023-11 decorator parity with Babel. The approach of extending the existing decorator_impl.rs with version-gated paths is reasonable and keeps the codebase unified. Below are the findings, grouped by severity.


High Priority

1. is_unresolved_ident uses hard-coded context IDs 0 | 1 (decorator_impl.rs)

fn is_unresolved_ident(&self, ident: &Ident) -> bool {
    matches!(ident.ctxt.as_u32(), 0 | 1)
}

This is fragile — SyntaxContext values depend on how marks are allocated and could differ between runs or after refactors. The pass should store the actual unresolved_mark (or the SyntaxContext derived from it) and compare against that. False positives here would silently rewrite user code.

2. Implicit globals rewrite to globalThis.x runs unconditionally (decorator_impl.rs visit_mut_expr)
The rewrite of unresolved identifier assignments to globalThis.x = ... (and corresponding reads) appears to be for sloppy-mode compatibility with Babel fixtures. If this is only needed for test compatibility, it should not be in the production transform path — it changes semantics for all users. Consider gating this behind a test-only flag or removing it entirely if the Babel fixtures can be adjusted.


Medium Priority

3. prop.value.clone() where .take() would suffice (decorator_impl.rs, proto init injection)

if let Some(value) = prop.value.clone() {

The value is immediately overwritten on the next line, so the clone creates a wasted allocation. Using .take() would be more efficient and idiomatic.

4. Hard-coded helper name list in class_name_tdz.rs
The skip list of static-private helper names (_class_static_private_field_destructure, etc.) is matched by string. If helper names change or new ones are added, this list silently becomes stale. Consider a more structural approach (e.g., a helper attribute/tag) for robustness, or at minimum add a comment noting this coupling.

5. #[serde(deny_unknown_fields)] removed from BabelTestOptions (decorators.rs)
The original had deny_unknown_fields, but the new version silently ignores unknown option keys. While this was likely intentional for forward-compatibility with newer Babel options, it reduces test strictness — a typo in an option name would be silently swallowed rather than failing the test.

6. Duplicate utility code in _apply_decs_2311.js
The helper includes its own toPrimitive, toPropertyKey, checkInRHS, and setFunctionName implementations. If these exist as separate SWC helpers already, this is duplicated code that ships to users. This matches Babel's self-contained approach, so it may be intentional, but worth confirming.


Low Priority

7. visit_mut_class_members is ~540 lines long
This function handles every member kind (method, field, accessor, static, private) in one monolithic block. Extracting helpers per member kind would improve readability and testability.

8. collect::<Vec<_>>().into_iter() pattern

self.state.static_non_field_lhs.drain(..)
    .chain(...)
    .collect::<Vec<_>>()
    .into_iter()

The collect + into_iter creates a needless temporary allocation. The chain can be iterated directly.

9. static_block_mark declared but unused in test harness (decorators.rs)
Dead code — likely a leftover from development.

10. #[allow(unused)] at top of test file
This blanket suppression could mask real unused-code warnings. Consider narrowing it to specific items.

11. Obscure JS expression in _apply_decs_2311.js line 352

if ((kind & 8) == isStatic && !kindOnly == isField) {

!kindOnly == isField relies on loose-equality coercion between booleans and numbers. It works correctly but is hard to audit. Something like (kindOnly === 0) === !!isField would be clearer.


Positives

  • Clean public API surface via decorator_2023_11.rs — minimal, well-structured entry point.
  • The _apply_decs_2311.js helper is generally well-written: correct reverse-order application, proper addInitializer guarding, correct Symbol.metadata fallback, and no prototype pollution vectors (Object.create(null) for lookups).
  • Good test coverage with extensive Babel fixture imports covering accessors, classes, methods, fields, ordering, and assumptions.
  • The class_name_tdz.rs fix from sym comparison to to_id() comparison is correct and important — prevents false matches across scopes.
  • Config wiring (config/mod.rs) is clean — replaces todo!() with the actual implementation.

Summary

The implementation is solid overall with good Babel parity. The two high-priority items (is_unresolved_ident magic numbers and the unconditional globalThis rewrite) should be addressed before merge as they affect correctness for production users. The medium-priority items are worth addressing but not blockers.

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants