Repository: swc-project/swc (rust)

Issue:
Error Convert New.target in Constructor Function
### Describe the bug

When object extends null, in the _inherits function, Object can't create new.target.prototype, there will be a typeError if running the converted code by swc by node, 
```bash
TypeError: Cannot read properties of undefined (reading 'constructor')
```

### Input code

```typescript
class MyObject extends null {
  constructor() {
    return Object.create(new.target.prototype);
  }
}
var obj = new MyObject();
```


### Config

```json
{
  "jsc": {
    "parser": {
      "syntax": "ecmascript",
      "jsx": false,
      "dynamicImport": false,
      "privateMethod": false,
      "functionBind": false,
      "exportDefaultFrom": false,
      "exportNamespaceFrom": false,
      "decorators": false,
      "decoratorsBeforeExport": false,
      "topLevelAwait": false,
      "importMeta": false
    },
    "transform": null,
    "target": "es5",
    "loose": false,
    "externalHelpers": false
  }
}
```


### Playground link

https://play.swc.rs/?version=1.2.107&code=H4sIAAAAAAAAAz2NwQnDMBAE%2Fwb3sE%2FpowZMSgipQb4cASNO5rRKYkJ6t4MhsK9hhpWSW8N1u82LCqFvqt0brJeCzzgAUq3Ru7B6iCcCXNndcEZJXDM1mL4Ssz%2BUafXKym3VOP2C7zgce2ZHnRdccJj%2FyxCnHamxM%2F%2BEAAAA&config=H4sIAAAAAAAAA0WMTQrEIAxG75K1286id5hDBCctFv9IUhgR714tlu7C915ehUMsrBUyshCPS0pU%2FMMKZAOKZZcVTNf6tKEXagYUeScdiiyd%2BZSEJjUQXHRbGSWbQmYSeRHG3T9m66GQfucYKmjJdAc%2F0N7G%2FHPynaLySe0Cj9ke9LUAAAA%3D

### Expected behavior

Here is converted by babel, it can be run normally by node.
```js
"use strict";

function _instanceof(left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { return !!right[Symbol.hasInstance](left); } else { return left instanceof right; } }

function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }

function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }

function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }

function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }

function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); }

function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }

function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }

function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }

var MyObject = /*#__PURE__*/function (_ref) {
  _inherits(MyObject, _ref);

  var _super = _createSuper(MyObject);

  function MyObject() {
    var _this;

    _classCallCheck(this, MyObject);

    return _possibleConstructorReturn(_this, Object.create(new.target.prototype));
  }

  return MyObject;
}(null);

var obj = new MyObject();
```


### Version

1.2.107

### Additional context

I run swc use cmd as follows
```bash
npx swc --config-file=.swcrc poc.js -o poc.js
```
The environment is ubuntu 20.04 amd64.

Pull request description:
fix(ecma/transform/compat): apply `new.target` before `classes`
<!-- Thanks for submitting a pull request! Please provide enough information so that others can review your pull request. -->

**Description:**
A proper fix is impossible, since the only other way to get `new.target` is by `this.constructor`, however in this situation any access to `this` would throw an error. The following code would also generate wrong output
```js
class A {
  constructor() {
    Object.setPrototypeOf(this, null)
    console.log(new.target)
  }
}
```
But consider original issue, apply `new.target` transform later would generate correct result because after class transformation, access `this` in normal function would not throw. If `new.target` is applied first, `this` would be transpiled to `_this` in `classes` which would be `undefined`. The result is **technically incorrect**, but there's no better way. Babel behaves the same, and so does in current swc's `preset-env`
**Related issue (if exists):**
fixes #2682, incompletely

Patch:
diff --git a/crates/swc_ecma_transforms_compat/src/es2015/mod.rs b/crates/swc_ecma_transforms_compat/src/es2015/mod.rs
index a1cac75fbf..399bfe424d 100644
--- a/crates/swc_ecma_transforms_compat/src/es2015/mod.rs
+++ b/crates/swc_ecma_transforms_compat/src/es2015/mod.rs
@@ -50,8 +50,8 @@ where
     chain!(
         block_scoped_functions(),
         template_literal(c.template_literal),
-        new_target(),
         classes(comments),
+        new_target(),
         spread(c.spread),
         // https://github.com/Microsoft/TypeScript/issues/5441
         Optional::new(object_super(), !c.typescript),
@@ -388,4 +388,22 @@ return new B(20).print()"
         }());
         "
     );
+
+    test_exec!(
+        ::swc_ecma_parser::Syntax::default(),
+        |t| es2015(
+            Mark::fresh(Mark::root()),
+            Some(t.comments.clone()),
+            Default::default()
+        ),
+        issue_2682,
+        "class MyObject extends null {
+            constructor() {
+              return Object.create(new.target.prototype);
+            }
+          }
+        var obj = new MyObject();
+        expect(obj.constructor).toBe(MyObject);
+        "
+    );
 }


Test patch:
diff --git a/crates/swc/tests/fixture/new-target/output/class-extends-error.ts b/crates/swc/tests/fixture/new-target/output/class-extends-error.ts
index bf624ea071..5a99378f6a 100644
--- a/crates/swc/tests/fixture/new-target/output/class-extends-error.ts
+++ b/crates/swc/tests/fixture/new-target/output/class-extends-error.ts
@@ -56,6 +56,13 @@ function _inherits(subClass, superClass) {
     });
     if (superClass) _setPrototypeOf(subClass, superClass);
 }
+function _instanceof(left, right) {
+    if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
+        return right[Symbol.hasInstance](left);
+    } else {
+        return left instanceof right;
+    }
+}
 function _isNativeFunction(fn) {
     return Function.toString.call(fn).indexOf("[native code]") !== -1;
 }
@@ -126,7 +133,7 @@ function _createSuper(Derived) {
         return _possibleConstructorReturn(this, result);
     };
 }
-var CustomError = /*#__PURE__*/ function(Error) {
+var CustomError = /*#__PURE__*/ function _target(Error) {
     "use strict";
     _inherits(CustomError, Error);
     var _super = _createSuper(CustomError);
@@ -134,7 +141,7 @@ var CustomError = /*#__PURE__*/ function(Error) {
         _classCallCheck(this, CustomError);
         var _this;
         _this = _super.call(this, message); // 'Error' breaks prototype chain here
-        Object.setPrototypeOf(_assertThisInitialized(_this), _this.constructor.prototype); // restore prototype chain
+        Object.setPrototypeOf(_assertThisInitialized(_this), (_instanceof(this, CustomError) ? this.constructor : void 0).prototype); // restore prototype chain
         return _this;
     }
     return CustomError;
diff --git a/crates/swc/tests/tsc-references/newTarget.es5_es5.1.normal.js b/crates/swc/tests/tsc-references/newTarget.es5_es5.1.normal.js
index 9024bab7f7..1fc3182193 100644
--- a/crates/swc/tests/tsc-references/newTarget.es5_es5.1.normal.js
+++ b/crates/swc/tests/tsc-references/newTarget.es5_es5.1.normal.js
@@ -78,13 +78,13 @@ function _createSuper(Derived) {
 }
 var A = function A() {
     "use strict";
+    var _newtarget = _instanceof(this, A) ? this.constructor : void 0;
     _classCallCheck(this, A);
-    var _newtarget = this.constructor;
     // @target: es5
     this.d = function _target() {
-        return this.constructor;
+        return _instanceof(this, _target) ? this.constructor : void 0;
     };
-    var a = this.constructor;
+    var a = _instanceof(this, A) ? this.constructor : void 0;
     var b = function() {
         return _newtarget;
     };
@@ -92,16 +92,15 @@ var A = function A() {
 A.c = function _target() {
     return _instanceof(this, _target) ? this.constructor : void 0;
 };
-var B = /*#__PURE__*/ function(A) {
+var B = /*#__PURE__*/ function _target(A) {
     "use strict";
     _inherits(B, A);
     var _super = _createSuper(B);
     function B() {
+        var _newtarget = _instanceof(this, B) ? this.constructor : void 0;
         _classCallCheck(this, B);
-        var _this;
-        var _newtarget = _this.constructor;
-        _this = _super.call(this);
-        var e = _this.constructor;
+        var _this = _super.call(this);
+        var e = _instanceof(this, B) ? this.constructor : void 0;
         var f = function() {
             return _newtarget;
         };
diff --git a/crates/swc/tests/tsc-references/newTarget.es5_es5.2.minified.js b/crates/swc/tests/tsc-references/newTarget.es5_es5.2.minified.js
index 0ed17502c0..baf5888d17 100644
--- a/crates/swc/tests/tsc-references/newTarget.es5_es5.2.minified.js
+++ b/crates/swc/tests/tsc-references/newTarget.es5_es5.2.minified.js
@@ -16,9 +16,9 @@ function _setPrototypeOf(o, p) {
 }
 var A = function() {
     "use strict";
-    _classCallCheck(this, A), this.constructor, this.d = function() {
-        return this.constructor;
-    }, this.constructor;
+    _instanceof(this, A) && this.constructor, _classCallCheck(this, A), this.d = function _target() {
+        return _instanceof(this, _target) ? this.constructor : void 0;
+    }, _instanceof(this, A) && this.constructor;
 };
 A.c = function _target() {
     return _instanceof(this, _target) ? this.constructor : void 0;
@@ -56,8 +56,9 @@ var B = function(A1) {
         })(self);
     });
     function B() {
-        var _this;
-        return _classCallCheck(this, B), _this.constructor, (_this = _super.call(this)).constructor, _this;
+        _instanceof(this, B) && this.constructor, _classCallCheck(this, B);
+        var _this = _super.call(this);
+        return _instanceof(this, B) && this.constructor, _this;
     }
     return B;
 }(A);
diff --git a/crates/swc/tests/tsc-references/newTarget.es6_es5.1.normal.js b/crates/swc/tests/tsc-references/newTarget.es6_es5.1.normal.js
index 354142ea0c..1b7053e68c 100644
--- a/crates/swc/tests/tsc-references/newTarget.es6_es5.1.normal.js
+++ b/crates/swc/tests/tsc-references/newTarget.es6_es5.1.normal.js
@@ -78,13 +78,13 @@ function _createSuper(Derived) {
 }
 var A = function A() {
     "use strict";
+    var _newtarget = _instanceof(this, A) ? this.constructor : void 0;
     _classCallCheck(this, A);
-    var _newtarget = this.constructor;
     // @target: es6
     this.d = function _target() {
-        return this.constructor;
+        return _instanceof(this, _target) ? this.constructor : void 0;
     };
-    var a = this.constructor;
+    var a = _instanceof(this, A) ? this.constructor : void 0;
     var b = function() {
         return _newtarget;
     };
@@ -92,16 +92,15 @@ var A = function A() {
 A.c = function _target() {
     return _instanceof(this, _target) ? this.constructor : void 0;
 };
-var B = /*#__PURE__*/ function(A) {
+var B = /*#__PURE__*/ function _target(A) {
     "use strict";
     _inherits(B, A);
     var _super = _createSuper(B);
     function B() {
+        var _newtarget = _instanceof(this, B) ? this.constructor : void 0;
         _classCallCheck(this, B);
-        var _this;
-        var _newtarget = _this.constructor;
-        _this = _super.call(this);
-        var e = _this.constructor;
+        var _this = _super.call(this);
+        var e = _instanceof(this, B) ? this.constructor : void 0;
         var f = function() {
             return _newtarget;
         };
diff --git a/crates/swc/tests/tsc-references/newTarget.es6_es5.2.minified.js b/crates/swc/tests/tsc-references/newTarget.es6_es5.2.minified.js
index 0ed17502c0..baf5888d17 100644
--- a/crates/swc/tests/tsc-references/newTarget.es6_es5.2.minified.js
+++ b/crates/swc/tests/tsc-references/newTarget.es6_es5.2.minified.js
@@ -16,9 +16,9 @@ function _setPrototypeOf(o, p) {
 }
 var A = function() {
     "use strict";
-    _classCallCheck(this, A), this.constructor, this.d = function() {
-        return this.constructor;
-    }, this.constructor;
+    _instanceof(this, A) && this.constructor, _classCallCheck(this, A), this.d = function _target() {
+        return _instanceof(this, _target) ? this.constructor : void 0;
+    }, _instanceof(this, A) && this.constructor;
 };
 A.c = function _target() {
     return _instanceof(this, _target) ? this.constructor : void 0;
@@ -56,8 +56,9 @@ var B = function(A1) {
         })(self);
     });
     function B() {
-        var _this;
-        return _classCallCheck(this, B), _this.constructor, (_this = _super.call(this)).constructor, _this;
+        _instanceof(this, B) && this.constructor, _classCallCheck(this, B);
+        var _this = _super.call(this);
+        return _instanceof(this, B) && this.constructor, _this;
     }
     return B;
 }(A);