Repository: swc-project/swc (rust)

Issue:
addInitializer missing on class field decorators
### Describe the bug

```ts
function bar(_, ctx) {
  console.log("should not be undefined", ctx.addInitializer);
}
class Foo {
  @bar baz = 1
}


new Foo()
```

outputs undefined

### Input code

```typescript
function bar(_, ctx) {
  console.log("should not be undefined", ctx.addInitializer);
}
class Foo {
  @bar baz = 1
}


new Foo()
```


### Config

```json
{
  "jsc": {
    "parser": { "syntax": "typescript", "decorators": true },
    "transform": { "decoratorVersion": "2022-03" }
  }
}
```


### Playground link (or link to the minimal reproduction)

https://play.swc.rs/?version=1.3.100&code=H4sIAAAAAAAAAyWNwQrCMBAF7%2FsVj55SkILnIngS%2FApJk60uhF1oEiwV%2F920nmeYmauGIqaY%2FOIeJ4Sy9vgQEEyzJR6SPV2XX1ZThFrBxKgaeRbl2B3%2B4GO8qxTxSTZe%2Fo2RvhSSzxk3syN4bYd22XDBuUEi5fcOXU8%2FkPoNpIUAAAA%3D&config=H4sIAAAAAAAAAz2MwQqEMAxE7%2F2KkLOCdG%2F7Id5LjeDCtmWShRXpvxsRvL1h5s0RiPijmd90OHpoCSq4MrHuxdLfmW1vohlbMx6IF8kVySrUO8NPqA%2B3bUhF14rvffAMZ4FutVxXcYpxnF5M3ZUeejgB%2BD%2B8W4QAAAA%3D

### SWC Info output

_No response_

### Expected behavior

addInitializer should be defined on class property decorators as well as .

The same code works on babel and tsc. I thought it was an issue there since the proposal readme says addInitializer does not exist, but apparently the readme is outdated against the actual spec.

### Actual behavior

_No response_

### Version

1.3.104

### Additional context


![image](https://github.com/swc-project/swc/assets/2303841/4a39be4a-0b20-4e1e-9861-60b436e71da3)

https://github.com/microsoft/TypeScript/issues/57096

Pull request:
fix(es/helpers): Add `addInitializer` to field decorators
**Description:**

At some point the spec text of ES decorators was changed to also have addInitializer for field decorators. This is already used e.g. in mobx. This simple change removes the special case that was present for field decorators and seems to fix the issue for me.

This change is backwards compatible since it only affects code that was broken before.

**Related issue:**

 - Closes #8525

Patch:
diff --git a/crates/swc_ecma_transforms_base/src/helpers/_apply_decs_2203_r.js b/crates/swc_ecma_transforms_base/src/helpers/_apply_decs_2203_r.js
index 718c02a068..2693c372ad 100644
--- a/crates/swc_ecma_transforms_base/src/helpers/_apply_decs_2203_r.js
+++ b/crates/swc_ecma_transforms_base/src/helpers/_apply_decs_2203_r.js
@@ -67,12 +67,10 @@ function applyDecs2203RFactory() {
 
         var decoratorFinishedRef = { v: false };
 
-        if (kind !== 0 /* FIELD */) {
-            ctx.addInitializer = createAddInitializerMethod(
-                initializers,
-                decoratorFinishedRef
-            );
-        }
+        ctx.addInitializer = createAddInitializerMethod(
+            initializers,
+            decoratorFinishedRef
+        );
 
         var get, set;
         if (kind === 0 /* FIELD */) {
@@ -376,17 +374,13 @@ function applyDecs2203RFactory() {
                 base = Class;
                 kind = kind - 5 /* STATIC */;
                 // initialize staticInitializers when we see a non-field static member
-                if (kind !== 0 /* FIELD */) {
-                    staticInitializers = staticInitializers || [];
-                    initializers = staticInitializers;
-                }
+                staticInitializers = staticInitializers || [];
+                initializers = staticInitializers;
             } else {
                 base = Class.prototype;
                 // initialize protoInitializers when we see a non-field member
-                if (kind !== 0 /* FIELD */) {
-                    protoInitializers = protoInitializers || [];
-                    initializers = protoInitializers;
-                }
+                protoInitializers = protoInitializers || [];
+                initializers = protoInitializers;
             }
 
             if (kind !== 0 /* FIELD */ && !isPrivate) {
diff --git a/packages/helpers/esm/_apply_decs_2203_r.js b/packages/helpers/esm/_apply_decs_2203_r.js
index 6ac65fd3b0..ed6427d095 100644
--- a/packages/helpers/esm/_apply_decs_2203_r.js
+++ b/packages/helpers/esm/_apply_decs_2203_r.js
@@ -51,9 +51,7 @@ export function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentCla
 
         var decoratorFinishedRef = { v: false };
 
-        if (kind !== 0 /* FIELD */) {
-            ctx.addInitializer = createAddInitializerMethod(initializers, decoratorFinishedRef);
-        }
+        ctx.addInitializer = createAddInitializerMethod(initializers, decoratorFinishedRef);
 
         var get, set;
         if (kind === 0 /* FIELD */) {
@@ -306,17 +304,13 @@ export function _apply_decs_2203_r(targetClass, memberDecs, classDecs, parentCla
                 base = Class;
                 kind = kind - 5 /* STATIC */;
                 // initialize staticInitializers when we see a non-field static member
-                if (kind !== 0 /* FIELD */) {
-                    staticInitializers = staticInitializers || [];
-                    initializers = staticInitializers;
-                }
+                staticInitializers = staticInitializers || [];
+                initializers = staticInitializers;
             } else {
                 base = Class.prototype;
                 // initialize protoInitializers when we see a non-field member
-                if (kind !== 0 /* FIELD */) {
-                    protoInitializers = protoInitializers || [];
-                    initializers = protoInitializers;
-                }
+                protoInitializers = protoInitializers || [];
+                initializers = protoInitializers;
             }
 
             if (kind !== 0 /* FIELD */ && !isPrivate) {


Test patch:
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/private/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/private/exec.js
index a2f8421a7a..fc42602b5b 100644
--- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/private/exec.js
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/private/exec.js
@@ -25,7 +25,7 @@ expect(aContext.name).toBe('#a');
 expect(aContext.kind).toBe('field');
 expect(aContext.static).toBe(false);
 expect(aContext.private).toBe(true);
-expect(typeof aContext.addInitializer).toBe('undefined');
+expect(typeof aContext.addInitializer).toBe('function');
 
 expect(bContext.access.get.call(foo)).toBe(124);
 bContext.access.set.call(foo, 123);
@@ -34,4 +34,4 @@ expect(bContext.name).toBe('#b');
 expect(bContext.kind).toBe('field');
 expect(bContext.static).toBe(false);
 expect(bContext.private).toBe(true);
-expect(typeof aContext.addInitializer).toBe('undefined');
+expect(typeof aContext.addInitializer).toBe('function');
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/public/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/public/exec.js
index 70883de504..6e0eaa079f 100644
--- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/public/exec.js
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/public/exec.js
@@ -34,7 +34,7 @@ expect(aContext.name).toBe('a');
 expect(aContext.kind).toBe('field');
 expect(aContext.static).toBe(false);
 expect(aContext.private).toBe(false);
-expect(typeof aContext.addInitializer).toBe('undefined');
+expect(typeof aContext.addInitializer).toBe('function');
 expect(foo.hasOwnProperty('a')).toBe(true);
 expect(Foo.prototype.hasOwnProperty('a')).toBe(false);
 
@@ -45,7 +45,7 @@ expect(bContext.name).toBe('b');
 expect(bContext.kind).toBe('field');
 expect(bContext.static).toBe(false);
 expect(bContext.private).toBe(false);
-expect(typeof bContext.addInitializer).toBe('undefined');
+expect(typeof bContext.addInitializer).toBe('function');
 expect(foo.hasOwnProperty('b')).toBe(true);
 expect(Foo.prototype.hasOwnProperty('b')).toBe(false);
 
@@ -56,6 +56,6 @@ expect(cContext.name).toBe('c');
 expect(cContext.kind).toBe('field');
 expect(cContext.static).toBe(false);
 expect(cContext.private).toBe(false);
-expect(typeof cContext.addInitializer).toBe('undefined');
+expect(typeof cContext.addInitializer).toBe('function');
 expect(foo.hasOwnProperty('c')).toBe(true);
 expect(Foo.prototype.hasOwnProperty('c')).toBe(false);
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/static-private/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/static-private/exec.js
index 586dc93511..e58d71d4ac 100644
--- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/static-private/exec.js
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/static-private/exec.js
@@ -23,7 +23,7 @@ expect(aContext.name).toBe('#a');
 expect(aContext.kind).toBe('field');
 expect(aContext.static).toBe(true);
 expect(aContext.private).toBe(true);
-expect(typeof aContext.addInitializer).toBe('undefined');
+expect(typeof aContext.addInitializer).toBe('function');
 
 expect(bContext.access.get.call(Foo)).toBe(124);
 bContext.access.set.call(Foo, 123);
@@ -32,4 +32,4 @@ expect(bContext.name).toBe('#b');
 expect(bContext.kind).toBe('field');
 expect(bContext.static).toBe(true);
 expect(bContext.private).toBe(true);
-expect(typeof aContext.addInitializer).toBe('undefined');
+expect(typeof aContext.addInitializer).toBe('function');
diff --git a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/static-public/exec.js b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/static-public/exec.js
index 534fb5d049..4ca3b1bd12 100644
--- a/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/static-public/exec.js
+++ b/crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-fields--to-es2015/static-public/exec.js
@@ -32,7 +32,7 @@ expect(aContext.name).toBe('a');
 expect(aContext.kind).toBe('field');
 expect(aContext.static).toBe(true);
 expect(aContext.private).toBe(false);
-expect(typeof aContext.addInitializer).toBe('undefined');
+expect(typeof aContext.addInitializer).toBe('function');
 expect(Foo.hasOwnProperty('a')).toBe(true);
 
 expect(Foo.b).toBe(124);
@@ -42,7 +42,7 @@ expect(bContext.name).toBe('b');
 expect(bContext.kind).toBe('field');
 expect(bContext.static).toBe(true);
 expect(bContext.private).toBe(false);
-expect(typeof bContext.addInitializer).toBe('undefined');
+expect(typeof bContext.addInitializer).toBe('function');
 expect(Foo.hasOwnProperty('b')).toBe(true);
 
 expect(Foo.c).toBe(457);
@@ -52,5 +52,5 @@ expect(cContext.name).toBe('c');
 expect(cContext.kind).toBe('field');
 expect(cContext.static).toBe(true);
 expect(cContext.private).toBe(false);
-expect(typeof cContext.addInitializer).toBe('undefined');
+expect(typeof cContext.addInitializer).toBe('function');
 expect(Foo.hasOwnProperty('c')).toBe(true);