From 703b340d39c3efb69f4a0d375ab6e5a2f9a4acd9 Mon Sep 17 00:00:00 2001 From: magic-akari Date: Thu, 23 Feb 2023 09:37:06 +0800 Subject: [PATCH] fix(es/decorator): Preserve evaluation order (#6972) **Related issue:** - Closes https://github.com/swc-project/swc/issues/6951. --- crates/swc/tests/exec.rs | 24 +++++++++++++++++ .../issues-3xxx/3686/1/output/index.ts | 5 +--- .../fixture/issues-6xxx/6951/1/input/.swcrc | 24 +++++++++++++++++ .../fixture/issues-6xxx/6951/1/input/index.ts | 9 +++++++ .../issues-6xxx/6951/1/output/index.ts | 15 +++++++++++ .../fixture/issues-6xxx/6951/2/input/.swcrc | 24 +++++++++++++++++ .../fixture/issues-6xxx/6951/2/input/index.ts | 9 +++++++ .../issues-6xxx/6951/2/output/index.ts | 13 ++++++++++ .../fixture/issues-6xxx/6951/3/input/.swcrc | 25 ++++++++++++++++++ .../fixture/issues-6xxx/6951/3/input/index.ts | 9 +++++++ .../issues-6xxx/6951/3/output/index.ts | 15 +++++++++++ .../fixture/issues-6xxx/6951/4/input/.swcrc | 25 ++++++++++++++++++ .../fixture/issues-6xxx/6951/4/input/index.ts | 9 +++++++ .../issues-6xxx/6951/4/output/index.ts | 16 ++++++++++++ .../legacy-metadata/issues/3979/output.ts | 3 +-- .../legacy-only/issues/1913/1/output.ts | 7 +++-- .../legacy-only/issues/1913/2/output.ts | 7 +++-- .../legacy-only/issues/591/1/output.ts | 8 ++---- .../legacy-only/issues/591/2/output.ts | 8 ++---- .../legacy-only/issues/879/1/output.ts | 5 +--- .../tests/simplify_dce.rs | 4 +-- .../src/decorators/legacy/mod.rs | 26 +------------------ .../src/decorators/mod.rs | 5 +--- .../src/strip.rs | 2 +- 24 files changed, 234 insertions(+), 63 deletions(-) create mode 100644 crates/swc/tests/fixture/issues-6xxx/6951/1/input/.swcrc create mode 100644 crates/swc/tests/fixture/issues-6xxx/6951/1/input/index.ts create mode 100644 crates/swc/tests/fixture/issues-6xxx/6951/1/output/index.ts create mode 100644 crates/swc/tests/fixture/issues-6xxx/6951/2/input/.swcrc create mode 100644 crates/swc/tests/fixture/issues-6xxx/6951/2/input/index.ts create mode 100644 crates/swc/tests/fixture/issues-6xxx/6951/2/output/index.ts create mode 100644 crates/swc/tests/fixture/issues-6xxx/6951/3/input/.swcrc create mode 100644 crates/swc/tests/fixture/issues-6xxx/6951/3/input/index.ts create mode 100644 crates/swc/tests/fixture/issues-6xxx/6951/3/output/index.ts create mode 100644 crates/swc/tests/fixture/issues-6xxx/6951/4/input/.swcrc create mode 100644 crates/swc/tests/fixture/issues-6xxx/6951/4/input/index.ts create mode 100644 crates/swc/tests/fixture/issues-6xxx/6951/4/output/index.ts diff --git a/crates/swc/tests/exec.rs b/crates/swc/tests/exec.rs index 8cb8b0eb5fa7..2deeeeb0b3ee 100644 --- a/crates/swc/tests/exec.rs +++ b/crates/swc/tests/exec.rs @@ -113,6 +113,29 @@ fn init_helpers() -> Arc { } fn create_matrix(entry: &Path) -> Vec { + // use_define_for_class_fields: false + // force to use [[Set]] instead of [[Define]] + // EsVersion should be lower than EsVersion::Es2022 + let force_set_class_field = entry + .parent() + .map(|parent| parent.join(".swcrc")) + .and_then(|path| fs::read_to_string(path).ok()) + .and_then(|content| { + jsonc_parser::parse_to_serde_value( + &content, + &jsonc_parser::ParseOptions { + allow_comments: true, + allow_trailing_commas: true, + allow_loose_object_property_names: false, + }, + ) + .ok()? + }) + .and_then(|content| serde_json::from_value::(content).ok()) + .and_then(|config| config.jsc.transform.into_inner()) + .map(|c| c.use_define_for_class_fields == false.into()) + .unwrap_or(false); + [ EsVersion::Es2022, EsVersion::Es2021, @@ -125,6 +148,7 @@ fn create_matrix(entry: &Path) -> Vec { EsVersion::Es5, ] .into_iter() + .filter(|e| !force_set_class_field || e < &EsVersion::Es2022) .matrix(|| { let default_es = Syntax::Es(EsConfig { ..Default::default() diff --git a/crates/swc/tests/fixture/issues-3xxx/3686/1/output/index.ts b/crates/swc/tests/fixture/issues-3xxx/3686/1/output/index.ts index 25a9dd7e1aeb..6f18979d860e 100644 --- a/crates/swc/tests/fixture/issues-3xxx/3686/1/output/index.ts +++ b/crates/swc/tests/fixture/issues-3xxx/3686/1/output/index.ts @@ -10,10 +10,7 @@ const _tsDecorate = require("@swc/helpers/lib/_ts_decorate.js").default; const CD = ()=>{}; const PD = ()=>{}; let ServiceError = class ServiceError1 extends Error { - constructor(...args){ - super(...args); - this.code = ServiceError.Code.badResponse; - } + code = ServiceError.Code.badResponse; name = "ServiceError.BadResponse"; }; _tsDecorate([ diff --git a/crates/swc/tests/fixture/issues-6xxx/6951/1/input/.swcrc b/crates/swc/tests/fixture/issues-6xxx/6951/1/input/.swcrc new file mode 100644 index 000000000000..dd0192930e90 --- /dev/null +++ b/crates/swc/tests/fixture/issues-6xxx/6951/1/input/.swcrc @@ -0,0 +1,24 @@ +{ + "jsc": { + "parser": { + "syntax": "typescript", + "tsx": false, + "decorators": true + }, + "target": "es5", + "loose": false, + "minify": { + "compress": false, + "mangle": false + }, + "transform": { + "legacyDecorator": true, + "decoratorMetadata": true + } + }, + "module": { + "type": "es6" + }, + "minify": false, + "isModule": true +} \ No newline at end of file diff --git a/crates/swc/tests/fixture/issues-6xxx/6951/1/input/index.ts b/crates/swc/tests/fixture/issues-6xxx/6951/1/input/index.ts new file mode 100644 index 000000000000..b9963a16ed27 --- /dev/null +++ b/crates/swc/tests/fixture/issues-6xxx/6951/1/input/index.ts @@ -0,0 +1,9 @@ +class A { + @observable a = true; + + b = false; + + @foo static c = 1; + + constructor() {} +} diff --git a/crates/swc/tests/fixture/issues-6xxx/6951/1/output/index.ts b/crates/swc/tests/fixture/issues-6xxx/6951/1/output/index.ts new file mode 100644 index 000000000000..734109078ce7 --- /dev/null +++ b/crates/swc/tests/fixture/issues-6xxx/6951/1/output/index.ts @@ -0,0 +1,15 @@ +import _class_call_check from "@swc/helpers/src/_class_call_check.mjs"; +import _ts_decorate from "@swc/helpers/src/_ts_decorate.mjs"; +var A = function A() { + "use strict"; + _class_call_check(this, A); + this.a = true; + this.b = false; +}; +A.c = 1; +_ts_decorate([ + observable +], A.prototype, "a", void 0); +_ts_decorate([ + foo +], A, "c", void 0); diff --git a/crates/swc/tests/fixture/issues-6xxx/6951/2/input/.swcrc b/crates/swc/tests/fixture/issues-6xxx/6951/2/input/.swcrc new file mode 100644 index 000000000000..81201c6d4d37 --- /dev/null +++ b/crates/swc/tests/fixture/issues-6xxx/6951/2/input/.swcrc @@ -0,0 +1,24 @@ +{ + "jsc": { + "parser": { + "syntax": "typescript", + "tsx": false, + "decorators": true + }, + "target": "es2022", + "loose": false, + "minify": { + "compress": false, + "mangle": false + }, + "transform": { + "legacyDecorator": true, + "decoratorMetadata": true + } + }, + "module": { + "type": "es6" + }, + "minify": false, + "isModule": true +} \ No newline at end of file diff --git a/crates/swc/tests/fixture/issues-6xxx/6951/2/input/index.ts b/crates/swc/tests/fixture/issues-6xxx/6951/2/input/index.ts new file mode 100644 index 000000000000..b9963a16ed27 --- /dev/null +++ b/crates/swc/tests/fixture/issues-6xxx/6951/2/input/index.ts @@ -0,0 +1,9 @@ +class A { + @observable a = true; + + b = false; + + @foo static c = 1; + + constructor() {} +} diff --git a/crates/swc/tests/fixture/issues-6xxx/6951/2/output/index.ts b/crates/swc/tests/fixture/issues-6xxx/6951/2/output/index.ts new file mode 100644 index 000000000000..f1e79df1d08f --- /dev/null +++ b/crates/swc/tests/fixture/issues-6xxx/6951/2/output/index.ts @@ -0,0 +1,13 @@ +import _ts_decorate from "@swc/helpers/src/_ts_decorate.mjs"; +class A { + a = true; + b = false; + static c = 1; + constructor(){} +} +_ts_decorate([ + observable +], A.prototype, "a", void 0); +_ts_decorate([ + foo +], A, "c", void 0); diff --git a/crates/swc/tests/fixture/issues-6xxx/6951/3/input/.swcrc b/crates/swc/tests/fixture/issues-6xxx/6951/3/input/.swcrc new file mode 100644 index 000000000000..7a6270cc108c --- /dev/null +++ b/crates/swc/tests/fixture/issues-6xxx/6951/3/input/.swcrc @@ -0,0 +1,25 @@ +{ + "jsc": { + "parser": { + "syntax": "typescript", + "tsx": false, + "decorators": true + }, + "target": "es2015", + "loose": false, + "minify": { + "compress": false, + "mangle": false + }, + "transform": { + "legacyDecorator": true, + "decoratorMetadata": true, + "useDefineForClassFields": true + } + }, + "module": { + "type": "es6" + }, + "minify": false, + "isModule": true +} \ No newline at end of file diff --git a/crates/swc/tests/fixture/issues-6xxx/6951/3/input/index.ts b/crates/swc/tests/fixture/issues-6xxx/6951/3/input/index.ts new file mode 100644 index 000000000000..b9963a16ed27 --- /dev/null +++ b/crates/swc/tests/fixture/issues-6xxx/6951/3/input/index.ts @@ -0,0 +1,9 @@ +class A { + @observable a = true; + + b = false; + + @foo static c = 1; + + constructor() {} +} diff --git a/crates/swc/tests/fixture/issues-6xxx/6951/3/output/index.ts b/crates/swc/tests/fixture/issues-6xxx/6951/3/output/index.ts new file mode 100644 index 000000000000..a498294045a5 --- /dev/null +++ b/crates/swc/tests/fixture/issues-6xxx/6951/3/output/index.ts @@ -0,0 +1,15 @@ +import _define_property from "@swc/helpers/src/_define_property.mjs"; +import _ts_decorate from "@swc/helpers/src/_ts_decorate.mjs"; +class A { + constructor(){ + _define_property(this, "a", true); + _define_property(this, "b", false); + } +} +_define_property(A, "c", 1); +_ts_decorate([ + observable +], A.prototype, "a", void 0); +_ts_decorate([ + foo +], A, "c", void 0); diff --git a/crates/swc/tests/fixture/issues-6xxx/6951/4/input/.swcrc b/crates/swc/tests/fixture/issues-6xxx/6951/4/input/.swcrc new file mode 100644 index 000000000000..02b4aeba424e --- /dev/null +++ b/crates/swc/tests/fixture/issues-6xxx/6951/4/input/.swcrc @@ -0,0 +1,25 @@ +{ + "jsc": { + "parser": { + "syntax": "typescript", + "tsx": false, + "decorators": true + }, + "target": "es5", + "loose": false, + "minify": { + "compress": false, + "mangle": false + }, + "transform": { + "legacyDecorator": true, + "decoratorMetadata": true, + "useDefineForClassFields": true + } + }, + "module": { + "type": "es6" + }, + "minify": false, + "isModule": true +} \ No newline at end of file diff --git a/crates/swc/tests/fixture/issues-6xxx/6951/4/input/index.ts b/crates/swc/tests/fixture/issues-6xxx/6951/4/input/index.ts new file mode 100644 index 000000000000..b9963a16ed27 --- /dev/null +++ b/crates/swc/tests/fixture/issues-6xxx/6951/4/input/index.ts @@ -0,0 +1,9 @@ +class A { + @observable a = true; + + b = false; + + @foo static c = 1; + + constructor() {} +} diff --git a/crates/swc/tests/fixture/issues-6xxx/6951/4/output/index.ts b/crates/swc/tests/fixture/issues-6xxx/6951/4/output/index.ts new file mode 100644 index 000000000000..36ffec360e3b --- /dev/null +++ b/crates/swc/tests/fixture/issues-6xxx/6951/4/output/index.ts @@ -0,0 +1,16 @@ +import _class_call_check from "@swc/helpers/src/_class_call_check.mjs"; +import _define_property from "@swc/helpers/src/_define_property.mjs"; +import _ts_decorate from "@swc/helpers/src/_ts_decorate.mjs"; +var A = function A() { + "use strict"; + _class_call_check(this, A); + _define_property(this, "a", true); + _define_property(this, "b", false); +}; +_define_property(A, "c", 1); +_ts_decorate([ + observable +], A.prototype, "a", void 0); +_ts_decorate([ + foo +], A, "c", void 0); diff --git a/crates/swc_ecma_transforms/tests/fixture/legacy-metadata/issues/3979/output.ts b/crates/swc_ecma_transforms/tests/fixture/legacy-metadata/issues/3979/output.ts index 870f525a2284..9701797896ad 100644 --- a/crates/swc_ecma_transforms/tests/fixture/legacy-metadata/issues/3979/output.ts +++ b/crates/swc_ecma_transforms/tests/fixture/legacy-metadata/issues/3979/output.ts @@ -1,8 +1,7 @@ class A { - x; + x = 1; constructor(); constructor(){ - this.x = 1; console.log(123); } } diff --git a/crates/swc_ecma_transforms/tests/fixture/legacy-only/issues/1913/1/output.ts b/crates/swc_ecma_transforms/tests/fixture/legacy-only/issues/1913/1/output.ts index 93515d0f4a96..d12280ef05e2 100644 --- a/crates/swc_ecma_transforms/tests/fixture/legacy-only/issues/1913/1/output.ts +++ b/crates/swc_ecma_transforms/tests/fixture/legacy-only/issues/1913/1/output.ts @@ -1,11 +1,10 @@ class Store { constructor(){ - this.doSomething = ()=>{ - console.log("run"); - }; this.doSomething(); } - doSomething; + doSomething = ()=>{ + console.log("run"); + }; } __decorate([ action diff --git a/crates/swc_ecma_transforms/tests/fixture/legacy-only/issues/1913/2/output.ts b/crates/swc_ecma_transforms/tests/fixture/legacy-only/issues/1913/2/output.ts index f7904daa25ab..c61438efe04c 100644 --- a/crates/swc_ecma_transforms/tests/fixture/legacy-only/issues/1913/2/output.ts +++ b/crates/swc_ecma_transforms/tests/fixture/legacy-only/issues/1913/2/output.ts @@ -1,12 +1,11 @@ class Store extends BaseStore { constructor(){ super(); - this.doSomething = ()=>{ - console.log("run"); - }; this.doSomething(); } - doSomething; + doSomething = ()=>{ + console.log("run"); + }; } __decorate([ action diff --git a/crates/swc_ecma_transforms/tests/fixture/legacy-only/issues/591/1/output.ts b/crates/swc_ecma_transforms/tests/fixture/legacy-only/issues/591/1/output.ts index c423718db9ee..82c475b5e0ce 100644 --- a/crates/swc_ecma_transforms/tests/fixture/legacy-only/issues/591/1/output.ts +++ b/crates/swc_ecma_transforms/tests/fixture/legacy-only/issues/591/1/output.ts @@ -1,10 +1,6 @@ export class Example { - constructor(){ - this.bar = "1"; - this.baz = "2"; - } - bar; - baz; + bar = "1"; + baz = "2"; } __decorate([ foo() diff --git a/crates/swc_ecma_transforms/tests/fixture/legacy-only/issues/591/2/output.ts b/crates/swc_ecma_transforms/tests/fixture/legacy-only/issues/591/2/output.ts index fb8f70e34714..f79ba5f183cf 100644 --- a/crates/swc_ecma_transforms/tests/fixture/legacy-only/issues/591/2/output.ts +++ b/crates/swc_ecma_transforms/tests/fixture/legacy-only/issues/591/2/output.ts @@ -1,10 +1,6 @@ class Example { - constructor(){ - this.bar = "1"; - this.baz = "2"; - } - bar; - baz; + bar = "1"; + baz = "2"; } __decorate([ foo() diff --git a/crates/swc_ecma_transforms/tests/fixture/legacy-only/issues/879/1/output.ts b/crates/swc_ecma_transforms/tests/fixture/legacy-only/issues/879/1/output.ts index 6552552fd2ac..8b61351b7028 100644 --- a/crates/swc_ecma_transforms/tests/fixture/legacy-only/issues/879/1/output.ts +++ b/crates/swc_ecma_transforms/tests/fixture/legacy-only/issues/879/1/output.ts @@ -1,8 +1,5 @@ export default class X { - constructor(){ - this.prop = ""; - } - prop: string; + prop: string = ""; } __decorate([ networked diff --git a/crates/swc_ecma_transforms_optimization/tests/simplify_dce.rs b/crates/swc_ecma_transforms_optimization/tests/simplify_dce.rs index bcccc835aa65..ca1e58a41b74 100644 --- a/crates/swc_ecma_transforms_optimization/tests/simplify_dce.rs +++ b/crates/swc_ecma_transforms_optimization/tests/simplify_dce.rs @@ -466,9 +466,7 @@ test!( " export default class X { - constructor(){ - this.anything = 0; - } + anything = 0; x() { const localVar = aFunctionSomewhere(); return localVar; diff --git a/crates/swc_ecma_transforms_proposal/src/decorators/legacy/mod.rs b/crates/swc_ecma_transforms_proposal/src/decorators/legacy/mod.rs index b02153fe7535..0a0366b334e9 100644 --- a/crates/swc_ecma_transforms_proposal/src/decorators/legacy/mod.rs +++ b/crates/swc_ecma_transforms_proposal/src/decorators/legacy/mod.rs @@ -20,10 +20,9 @@ enum EnumKind { Num, } -pub(super) fn new(metadata: bool, use_define_for_class_fields: bool) -> TscDecorator { +pub(super) fn new(metadata: bool) -> TscDecorator { TscDecorator { metadata, - use_define_for_class_fields, enums: Default::default(), vars: Default::default(), appended_exprs: Default::default(), @@ -36,7 +35,6 @@ pub(super) fn new(metadata: bool, use_define_for_class_fields: bool) -> TscDecor pub(super) struct TscDecorator { metadata: bool, - use_define_for_class_fields: bool, enums: AHashMap, @@ -352,28 +350,6 @@ impl VisitMut for TscDecorator { key.as_arg(), undefined(DUMMY_SP).as_arg(), ); - - if !self.use_define_for_class_fields && !c.is_static { - if let Some(init) = c.value.take() { - self.constructor_exprs - .push(Box::new(Expr::Assign(AssignExpr { - span: c.span, - op: op!("="), - left: PatOrExpr::Expr(Box::new(Expr::Member(MemberExpr { - span: DUMMY_SP, - obj: Box::new(Expr::This(ThisExpr { span: DUMMY_SP })), - prop: match &c.key { - PropName::Ident(i) => MemberProp::Ident(i.clone()), - _ => MemberProp::Computed(ComputedPropName { - span: DUMMY_SP, - expr: Box::new(prop_name_to_expr_value(c.key.clone())), - }), - }, - }))), - right: init, - }))); - } - } } } } diff --git a/crates/swc_ecma_transforms_proposal/src/decorators/mod.rs b/crates/swc_ecma_transforms_proposal/src/decorators/mod.rs index 171b449dcf34..e858ebd95875 100644 --- a/crates/swc_ecma_transforms_proposal/src/decorators/mod.rs +++ b/crates/swc_ecma_transforms_proposal/src/decorators/mod.rs @@ -57,10 +57,7 @@ mod legacy; /// ``` pub fn decorators(c: Config) -> impl Fold { if c.legacy { - Either::Left(as_folder(self::legacy::new( - c.emit_metadata, - c.use_define_for_class_fields, - ))) + Either::Left(as_folder(self::legacy::new(c.emit_metadata))) } else { if c.emit_metadata { unimplemented!("emitting decorator metadata while using new proposal") diff --git a/crates/swc_ecma_transforms_typescript/src/strip.rs b/crates/swc_ecma_transforms_typescript/src/strip.rs index 21aaddacb48f..4b0131f528ee 100644 --- a/crates/swc_ecma_transforms_typescript/src/strip.rs +++ b/crates/swc_ecma_transforms_typescript/src/strip.rs @@ -65,7 +65,7 @@ pub struct Config { /// When running `tsc` with configuration `"target": "", /// "useDefineForClassFields": true`, TS class fields are transformed to /// `Object.defineProperty()` statements. You must additionally apply the - /// `swc_ecmascript::transforms::compat::es2022::class_properties()` pass to + /// [swc_ecma_transforms_compat::es2022::class_properties()] pass to /// get this backward-compatible output. #[serde(default)] pub use_define_for_class_fields: bool,