Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(es/decorators): Fix a regression about class expressions #8102

Merged
merged 17 commits into from
Oct 11, 2023
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export default class t{#t;constructor(t){this.#t=t}#e(){setTimeout(()=>{this.#t.textContent="TESTED"},1e3)}run(){this.#e()}}
var t;t=class{#t;constructor(t){this.#t=t}#e(){setTimeout(()=>{this.#t.textContent="TESTED"},1e3)}run(){this.#e()}};export{t as default};
5 changes: 3 additions & 2 deletions crates/swc/tests/fixture/issues-4xxx/4063/1/output/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ define([
function state() {}
class Controller {
}
class _class extends Controller {
var _class;
_class = class _$class extends Controller {
Copy link
Member Author

Choose a reason for hiding this comment

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

Minifier will be able to merge these, so I think this change is fine.

onChange() {}
constructor(...args){
super(...args);
_define_property._(this, "isTest", false);
}
}
};
_ts_decorate._([
state
], _class.prototype, "isTest", void 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ const _ts_decorate = require("@swc/helpers/_/_ts_decorate");
function test(constructor) {
console.log(constructor);
}
let _class = class _class {
var _class;
_class = class _$class {
};
_class = _ts_decorate._([
test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { _ as _ts_decorate } from "@swc/helpers/_/_ts_decorate";
function test(constructor) {
console.log(constructor);
}
let _class = class _class {
var _class;
_class = class _$class {
};
_class = _ts_decorate([
test
Expand Down
5 changes: 3 additions & 2 deletions crates/swc/tests/fixture/issues-5xxx/5626/output/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ import { _ as _ts_metadata } from "@swc/helpers/_/_ts_metadata";
function Prop() {
return function() {};
}
var Example = function Example() {
var Example;
Example = function Example() {
"use strict";
_class_call_check(this, Example);
_define_property(this, "prop", void 0);
};
export { Example as default };
_ts_decorate([
Prop(),
_ts_metadata("design:type", typeof BigInt === "undefined" ? Object : BigInt)
], Example.prototype, "prop", void 0);
export { Example as default };
Copy link
Member Author

Choose a reason for hiding this comment

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

This is a bugfix

Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { _ as _create_super } from "@swc/helpers/_/_create_super";
import { _ as _ts_decorate } from "@swc/helpers/_/_ts_decorate";
import React from "react";
import { withRouter } from "react-router-dom";
var App = /*#__PURE__*/ function(_React_Component) {
var App;
App = /*#__PURE__*/ function(_React_Component) {
"use strict";
_inherits(App, _React_Component);
var _super = _create_super(App);
Expand Down
20 changes: 20 additions & 0 deletions crates/swc/tests/fixture/issues-8xxx/8095/es2020/input/.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": false,
"decorators": true
},
"target": "es2020",
"loose": false,
"minify": {
"compress": false,
"mangle": false
}
},
"module": {
"type": "es6"
},
"minify": false,
"isModule": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const foo = class { @foo foo(v) { return v } }
10 changes: 10 additions & 0 deletions crates/swc/tests/fixture/issues-8xxx/8095/es2020/output/1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { _ as _ts_decorate } from "@swc/helpers/_/_ts_decorate";
var _class;
const foo = _class = class _$class {
foo(v) {
return v;
}
};
_ts_decorate([
foo
], _class.prototype, "foo", null);
20 changes: 20 additions & 0 deletions crates/swc/tests/fixture/issues-8xxx/8095/es2022/input/.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": false,
"decorators": true
},
"target": "es2022",
"loose": false,
"minify": {
"compress": false,
"mangle": false
}
},
"module": {
"type": "es6"
},
"minify": false,
"isModule": true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const foo = class { @foo foo(v) { return v } }
10 changes: 10 additions & 0 deletions crates/swc/tests/fixture/issues-8xxx/8095/es2022/output/1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { _ as _ts_decorate } from "@swc/helpers/_/_ts_decorate";
var _class;
const foo = _class = class _$class {
foo(v) {
return v;
}
};
_ts_decorate([
foo
], _class.prototype, "foo", null);
20 changes: 20 additions & 0 deletions crates/swc/tests/fixture/issues-8xxx/8095/es5/input/.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": false,
"decorators": true
},
"target": "es5",
"loose": false,
"minify": {
"compress": false,
"mangle": false
}
},
"module": {
"type": "es6"
},
"minify": false,
"isModule": true
}
1 change: 1 addition & 0 deletions crates/swc/tests/fixture/issues-8xxx/8095/es5/input/1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const foo = class { @foo foo(v) { return v } }
22 changes: 22 additions & 0 deletions crates/swc/tests/fixture/issues-8xxx/8095/es5/output/1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { _ as _class_call_check } from "@swc/helpers/_/_class_call_check";
import { _ as _create_class } from "@swc/helpers/_/_create_class";
import { _ as _ts_decorate } from "@swc/helpers/_/_ts_decorate";
var _class;
var foo = _class = /*#__PURE__*/ function() {
"use strict";
function _$class() {
_class_call_check(this, _$class);
}
_create_class(_$class, [
{
key: "foo",
value: function foo(v) {
return v;
}
}
]);
return _$class;
}();
_ts_decorate([
foo
], _class.prototype, "foo", null);
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
let A = class A {
var A;
A = class A {
};
A = _ts_decorate([
dec
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export default class A {
var A;
A = class A {
foo() {}
}
};
_ts_decorate([
dec
], A.prototype, "foo", null);
Expand All @@ -10,3 +11,4 @@ class B {
_ts_decorate([
dec
], B.prototype, "foo", null);
export { A as default };
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export default class X {
var X;
X = class X {
prop: string = "";
}
};
_ts_decorate([
networked
], X.prototype, "prop", void 0);
export { X as default };
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
function myDecorator(decoratee) {}
let _class = class _class {
var _class;
_class = class _$class {
};
_class = _ts_decorate([
myDecorator
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export default class _class {
var _class;
_class = class _$class {
bar() {}
}
};
_ts_decorate([
foo
], _class.prototype, "bar", null);
export { _class as default };
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub(super) fn new(metadata: bool) -> TscDecorator {
class_name: Default::default(),
constructor_exprs: Default::default(),
exports: Default::default(),
assign_class_expr_to: Default::default(),
}
}

Expand All @@ -49,6 +50,8 @@ pub(super) struct TscDecorator {
constructor_exprs: Vec<Box<Expr>>,

exports: Vec<ExportSpecifier>,

assign_class_expr_to: Option<Ident>,
}

impl TscDecorator {
Expand Down Expand Up @@ -291,14 +294,49 @@ impl VisitMut for TscDecorator {
self.class_name = old;
}

fn visit_mut_expr(&mut self, e: &mut Expr) {
e.visit_mut_children_with(self);

if let Some(var_name) = self.assign_class_expr_to.take() {
*e = Expr::Assign(AssignExpr {
span: DUMMY_SP,
op: op!("="),
left: var_name.into(),
right: Box::new(e.take()),
});
}
}

fn visit_mut_class_expr(&mut self, n: &mut ClassExpr) {
let old = self.class_name.take();

if contains_decorator(n) && n.ident.is_none() {
n.ident = Some(private_ident!("_class"));
}
let ident = private_ident!("_$class");

let var_name = private_ident!("_class");

self.vars.push(VarDeclarator {
span: DUMMY_SP,
name: Pat::Ident(var_name.clone().into()),
init: None,
definite: Default::default(),
});

self.class_name = Some(var_name.clone());
n.ident = Some(ident);

n.visit_mut_children_with(self);

self.class_name = old;

self.assign_class_expr_to = Some(var_name);

return;
}
if let Some(ident) = &n.ident {
self.class_name = Some(ident.clone());
if self.class_name.is_none() {
self.class_name = Some(ident.clone());
}
}

n.visit_mut_children_with(self);
Expand Down Expand Up @@ -405,6 +443,46 @@ impl VisitMut for TscDecorator {

fn visit_mut_module_item(&mut self, module_item: &mut ModuleItem) {
match module_item {
ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultDecl(ExportDefaultDecl {
decl: DefaultDecl::Class(c),
..
})) => {
c.visit_mut_with(self);

if self.assign_class_expr_to.is_none() {
if let Some(var_name) = c.ident.clone() {
self.vars.push(VarDeclarator {
span: DUMMY_SP,
name: Pat::Ident(var_name.clone().into()),
init: None,
definite: Default::default(),
});

self.assign_class_expr_to = Some(var_name);
}
}

if let Some(var_name) = self.assign_class_expr_to.take() {
*module_item = ModuleItem::Stmt(
Expr::Assign(AssignExpr {
span: DUMMY_SP,
op: op!("="),
left: var_name.clone().into(),
right: Box::new(Expr::Class(c.take())),
})
.into_stmt(),
);

self.exports
.push(ExportSpecifier::Named(ExportNamedSpecifier {
span: DUMMY_SP,
orig: ModuleExportName::Ident(var_name),
exported: Some(ModuleExportName::Ident(quote_ident!("default"))),
is_type_only: Default::default(),
}));
}
}

ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(n)) => {
let export_decl_span = n.span;

Expand Down