Skip to content

Commit

Permalink
fix(es/decorators): Fix a regression about class expressions (#8102)
Browse files Browse the repository at this point in the history
**Related issue:**

 - Closes #8095
  • Loading branch information
kdy1 authored Oct 11, 2023
1 parent 1183c32 commit cb4361f
Show file tree
Hide file tree
Showing 21 changed files with 215 additions and 19 deletions.
2 changes: 1 addition & 1 deletion crates/swc/tests/fixture/issues-2xxx/2086/output/index.ts
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 {
onChange() {}
constructor(...args){
super(...args);
_define_property._(this, "isTest", false);
}
}
};
_ts_decorate._([
state
], _class.prototype, "isTest", void 0);
Expand Down
3 changes: 2 additions & 1 deletion crates/swc/tests/fixture/issues-4xxx/4127/1/output/index.ts
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
3 changes: 2 additions & 1 deletion crates/swc/tests/fixture/issues-4xxx/4127/2/output/index.ts
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 };
3 changes: 2 additions & 1 deletion crates/swc/tests/fixture/issues-6xxx/6984/1/output/index.js
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 };
84 changes: 81 additions & 3 deletions crates/swc_ecma_transforms_proposal/src/decorators/legacy/mod.rs
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

1 comment on commit cb4361f

@github-actions
Copy link

Choose a reason for hiding this comment

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

Benchmark

Benchmark suite Current: cb4361f Previous: e1043fa Ratio
es/full/bugs-1 301273 ns/iter (± 8241) 288955 ns/iter (± 5526) 1.04
es/full/minify/libraries/antd 1516326407 ns/iter (± 14344122) 1394116231 ns/iter (± 26558988) 1.09
es/full/minify/libraries/d3 332172038 ns/iter (± 7571956) 292383982 ns/iter (± 2936402) 1.14
es/full/minify/libraries/echarts 1259703519 ns/iter (± 33591512) 1141694049 ns/iter (± 13432346) 1.10
es/full/minify/libraries/jquery 95329248 ns/iter (± 1449839) 88643929 ns/iter (± 372087) 1.08
es/full/minify/libraries/lodash 111925085 ns/iter (± 2384796) 103916758 ns/iter (± 402967) 1.08
es/full/minify/libraries/moment 56515191 ns/iter (± 424929) 52416733 ns/iter (± 327568) 1.08
es/full/minify/libraries/react 20583629 ns/iter (± 228539) 18849633 ns/iter (± 51141) 1.09
es/full/minify/libraries/terser 259154261 ns/iter (± 6019768) 232314284 ns/iter (± 2596996) 1.12
es/full/minify/libraries/three 485950656 ns/iter (± 17864303) 408384625 ns/iter (± 2630249) 1.19
es/full/minify/libraries/typescript 2825307627 ns/iter (± 120594168) 2816402782 ns/iter (± 11054970) 1.00
es/full/minify/libraries/victory 606193520 ns/iter (± 7255935) 598947446 ns/iter (± 7751231) 1.01
es/full/minify/libraries/vue 128849923 ns/iter (± 677550) 126476197 ns/iter (± 349776) 1.02
es/full/codegen/es3 34464 ns/iter (± 87) 33384 ns/iter (± 172) 1.03
es/full/codegen/es5 34463 ns/iter (± 76) 33471 ns/iter (± 82) 1.03
es/full/codegen/es2015 34484 ns/iter (± 519) 33184 ns/iter (± 117) 1.04
es/full/codegen/es2016 34450 ns/iter (± 134) 33227 ns/iter (± 100) 1.04
es/full/codegen/es2017 34470 ns/iter (± 66) 33241 ns/iter (± 107) 1.04
es/full/codegen/es2018 34466 ns/iter (± 108) 33231 ns/iter (± 101) 1.04
es/full/codegen/es2019 34376 ns/iter (± 65) 33166 ns/iter (± 87) 1.04
es/full/codegen/es2020 34381 ns/iter (± 80) 33315 ns/iter (± 96) 1.03
es/full/all/es3 177100069 ns/iter (± 870190) 176630922 ns/iter (± 1643550) 1.00
es/full/all/es5 168906962 ns/iter (± 1073118) 170591331 ns/iter (± 923941) 0.99
es/full/all/es2015 127734497 ns/iter (± 682110) 128685132 ns/iter (± 1425368) 0.99
es/full/all/es2016 127018587 ns/iter (± 985601) 129382324 ns/iter (± 1329967) 0.98
es/full/all/es2017 126647967 ns/iter (± 1225050) 128318171 ns/iter (± 1568732) 0.99
es/full/all/es2018 124431925 ns/iter (± 870413) 125086385 ns/iter (± 1896512) 0.99
es/full/all/es2019 124318345 ns/iter (± 928783) 124625454 ns/iter (± 1175732) 1.00
es/full/all/es2020 119276751 ns/iter (± 856279) 121543638 ns/iter (± 1001834) 0.98
es/full/parser 559020 ns/iter (± 5172) 567758 ns/iter (± 2293) 0.98
es/full/base/fixer 17475 ns/iter (± 86) 21468 ns/iter (± 198) 0.81
es/full/base/resolver_and_hygiene 82555 ns/iter (± 210) 86589 ns/iter (± 256) 0.95

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.