From 39c75fdcce4ae63a2320bfaac4c2369799729051 Mon Sep 17 00:00:00 2001 From: Alex Vasilev Date: Fri, 27 Jan 2023 15:58:22 +0300 Subject: [PATCH] fix(es/module): Fix handling of `this` for `systemjs` (#6857) **Related issue:** - Closes https://github.com/swc-project/swc/issues/6784. --- ...ssStaticBlock24(module=system).1.normal.js | 2 +- ...StaticBlock24(module=system).2.minified.js | 2 +- ...xportClassNameWithObjectSystem.1.normal.js | 2 +- ...ortClassNameWithObjectSystem.2.minified.js | 2 +- ...rtCallExpressionAsyncES3System.1.normal.js | 4 +- ...rtCallExpressionAsyncES5System.1.normal.js | 4 +- ...rtCallExpressionAsyncES6System.1.normal.js | 2 +- .../src/system_js.rs | 32 +++++++-- .../tests/system_js.rs | 66 +++++++++++++++++++ 9 files changed, 100 insertions(+), 16 deletions(-) diff --git a/crates/swc/tests/tsc-references/classStaticBlock24(module=system).1.normal.js b/crates/swc/tests/tsc-references/classStaticBlock24(module=system).1.normal.js index e5de907e5ab..a89655da4c2 100644 --- a/crates/swc/tests/tsc-references/classStaticBlock24(module=system).1.normal.js +++ b/crates/swc/tests/tsc-references/classStaticBlock24(module=system).1.normal.js @@ -13,7 +13,7 @@ System.register([ execute: function() { _export("C", C = function C() { "use strict"; - _class_call_check(void 0, C); + _class_call_check(this, C); }); __ = { writable: true, diff --git a/crates/swc/tests/tsc-references/classStaticBlock24(module=system).2.minified.js b/crates/swc/tests/tsc-references/classStaticBlock24(module=system).2.minified.js index 23b62e91e64..4db8af9f9f0 100644 --- a/crates/swc/tests/tsc-references/classStaticBlock24(module=system).2.minified.js +++ b/crates/swc/tests/tsc-references/classStaticBlock24(module=system).2.minified.js @@ -13,7 +13,7 @@ System.register([ execute: function() { _export("C", C = function C() { "use strict"; - _class_call_check(void 0, C); + _class_call_check(this, C); }), C.x = 1; } }; diff --git a/crates/swc/tests/tsc-references/exportClassNameWithObjectSystem.1.normal.js b/crates/swc/tests/tsc-references/exportClassNameWithObjectSystem.1.normal.js index 10d03efd003..48ac318ef84 100644 --- a/crates/swc/tests/tsc-references/exportClassNameWithObjectSystem.1.normal.js +++ b/crates/swc/tests/tsc-references/exportClassNameWithObjectSystem.1.normal.js @@ -13,7 +13,7 @@ System.register([ execute: function() { _export("Object", Object = function Object() { "use strict"; - _class_call_check(void 0, Object); + _class_call_check(this, Object); }); } }; diff --git a/crates/swc/tests/tsc-references/exportClassNameWithObjectSystem.2.minified.js b/crates/swc/tests/tsc-references/exportClassNameWithObjectSystem.2.minified.js index 3df5f984402..778e963f188 100644 --- a/crates/swc/tests/tsc-references/exportClassNameWithObjectSystem.2.minified.js +++ b/crates/swc/tests/tsc-references/exportClassNameWithObjectSystem.2.minified.js @@ -13,7 +13,7 @@ System.register([ execute: function() { _export("Object", function Object() { "use strict"; - _class_call_check(void 0, Object); + _class_call_check(this, Object); }); } }; diff --git a/crates/swc/tests/tsc-references/importCallExpressionAsyncES3System.1.normal.js b/crates/swc/tests/tsc-references/importCallExpressionAsyncES3System.1.normal.js index 0c722718f35..b0f5e79738a 100644 --- a/crates/swc/tests/tsc-references/importCallExpressionAsyncES3System.1.normal.js +++ b/crates/swc/tests/tsc-references/importCallExpressionAsyncES3System.1.normal.js @@ -91,8 +91,8 @@ System.register([ }); _export("cl2", cl2 = function cl2() { "use strict"; - _class_call_check(void 0, cl2); - (void 0).p = { + _class_call_check(this, cl2); + this.p = { m: /*#__PURE__*/ _async_to_generator(function() { var req; return _ts_generator(this, function(_state) { diff --git a/crates/swc/tests/tsc-references/importCallExpressionAsyncES5System.1.normal.js b/crates/swc/tests/tsc-references/importCallExpressionAsyncES5System.1.normal.js index 0c722718f35..b0f5e79738a 100644 --- a/crates/swc/tests/tsc-references/importCallExpressionAsyncES5System.1.normal.js +++ b/crates/swc/tests/tsc-references/importCallExpressionAsyncES5System.1.normal.js @@ -91,8 +91,8 @@ System.register([ }); _export("cl2", cl2 = function cl2() { "use strict"; - _class_call_check(void 0, cl2); - (void 0).p = { + _class_call_check(this, cl2); + this.p = { m: /*#__PURE__*/ _async_to_generator(function() { var req; return _ts_generator(this, function(_state) { diff --git a/crates/swc/tests/tsc-references/importCallExpressionAsyncES6System.1.normal.js b/crates/swc/tests/tsc-references/importCallExpressionAsyncES6System.1.normal.js index 35369fa55a9..e4ca9d2140c 100644 --- a/crates/swc/tests/tsc-references/importCallExpressionAsyncES6System.1.normal.js +++ b/crates/swc/tests/tsc-references/importCallExpressionAsyncES6System.1.normal.js @@ -42,7 +42,7 @@ System.register([ }); _export("cl2", cl2 = class cl2 { constructor(){ - (void 0).p = { + this.p = { m: /*#__PURE__*/ _async_to_generator(function*() { const req = yield import('./test') // FOUR ; diff --git a/crates/swc_ecma_transforms_module/src/system_js.rs b/crates/swc_ecma_transforms_module/src/system_js.rs index e800945034c..5ce05bb9fc4 100644 --- a/crates/swc_ecma_transforms_module/src/system_js.rs +++ b/crates/swc_ecma_transforms_module/src/system_js.rs @@ -30,7 +30,7 @@ struct SystemJs { export_values: Vec>, tla: bool, enter_async_fn: u32, - enter_fn: u32, + is_global_this: bool, root_fn_decl_idents: Vec, module_item_meta_list: Vec, import_idents: Vec, @@ -48,9 +48,9 @@ pub fn system_js(unresolved_mark: Mark, config: Config) -> impl Fold { export_map: Default::default(), export_names: vec![], export_values: vec![], + is_global_this: true, tla: false, enter_async_fn: 0, - enter_fn: 0, root_fn_decl_idents: vec![], module_item_meta_list: vec![], import_idents: vec![], @@ -69,14 +69,13 @@ pub fn system_js_with_resolver( unresolved_mark, resolver: Resolver::Real { base, resolver }, config, - + is_global_this: true, declare_var_idents: vec![], export_map: Default::default(), export_names: vec![], export_values: vec![], tla: false, enter_async_fn: 0, - enter_fn: 0, root_fn_decl_idents: vec![], module_item_meta_list: vec![], import_idents: vec![], @@ -94,6 +93,19 @@ struct ModuleItemMeta { } impl SystemJs { + fn fold_children_with_non_global_this(&mut self, n: T) -> T + where + T: FoldWith, + { + let is_global_this = self.is_global_this; + + self.is_global_this = false; + let node = n.fold_children_with(self); + self.is_global_this = is_global_this; + + node + } + fn export_call(&self, name: JsWord, span: Span, expr: Expr) -> CallExpr { CallExpr { span, @@ -568,7 +580,7 @@ impl Fold for SystemJs { Expr::Await(await_expr) } Expr::This(this_expr) => { - if !self.config.allow_top_level_this && self.enter_fn == 0 { + if !self.config.allow_top_level_this && self.is_global_this { return *undefined(DUMMY_SP); } Expr::This(this_expr) @@ -582,15 +594,21 @@ impl Fold for SystemJs { if is_async { self.enter_async_fn += 1; } - self.enter_fn += 1; let fold_fn_expr = fn_decl.fold_children_with(self); if is_async { self.enter_async_fn -= 1; } - self.enter_fn -= 1; fold_fn_expr } + fn fold_class_expr(&mut self, n: ClassExpr) -> ClassExpr { + self.fold_children_with_non_global_this(n) + } + + fn fold_function(&mut self, n: Function) -> Function { + self.fold_children_with_non_global_this(n) + } + fn fold_prop(&mut self, prop: Prop) -> Prop { match prop { Prop::Shorthand(shorthand) => Prop::KeyValue(KeyValueProp { diff --git a/crates/swc_ecma_transforms_module/tests/system_js.rs b/crates/swc_ecma_transforms_module/tests/system_js.rs index 45ab73e7e5d..237ffbbfbec 100644 --- a/crates/swc_ecma_transforms_module/tests/system_js.rs +++ b/crates/swc_ecma_transforms_module/tests/system_js.rs @@ -46,6 +46,72 @@ test!( });"# ); +test!( + syntax(), + |tester| tr( + tester, + Config { + allow_top_level_this: false + } + ), + iife, + r#" + (function(a) { + this.foo = a; + })(this); + "#, + r#"System.register([], function(_export, _context) { + "use strict"; + return { + setters: [], + execute: function() { + (function(a) { + this.foo = a; + })(void 0); + } + }; + });"# +); + +test!( + syntax(), + |tester| tr( + tester, + Config { + allow_top_level_this: false + } + ), + top_level_this_false_class, + r#" + const a = this; + class A { + constructor() { + this.a = 1; + } + test() { + this.a = 2; + } + }"#, + r#"System.register([], function(_export, _context) { + "use strict"; + var A, a; + return { + setters: [], + execute: function() { + a = void 0; + A = class A { + constructor(){ + this.a = 1; + } + test() { + this.a = 2; + } + }; + } + }; + });"# +); + test!( syntax(), |tester| tr(