fix(es/transforms): Fix bugs (#2249)

swc_ecma_transforms_compat:
 - Fix `this` in class properties. (#2228)

swc_ecma_transforms_typescript:
 - Handle `import =` correctly. (#2234)
 - Ensure that #1653 is not the case anymore. (#1653)

swc:
 - Ensure that #2232 is not the case. (#2232)
This commit is contained in:
강동윤 2021-09-15 16:46:03 +09:00 committed by GitHub
parent cab37f8166
commit 6f33c327cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 430 additions and 24 deletions

4
Cargo.lock generated
View File

@ -2769,7 +2769,7 @@ dependencies = [
[[package]]
name = "swc_ecma_transforms_compat"
version = "0.34.2"
version = "0.34.3"
dependencies = [
"arrayvec",
"fxhash",
@ -2922,7 +2922,7 @@ dependencies = [
[[package]]
name = "swc_ecma_transforms_typescript"
version = "0.40.2"
version = "0.40.3"
dependencies = [
"fxhash",
"serde",

View File

@ -6,7 +6,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_ecma_transforms_compat"
repository = "https://github.com/swc-project/swc.git"
version = "0.34.2"
version = "0.34.3"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -1,5 +1,5 @@
use std::iter;
use swc_atoms::JsWord;
use swc_atoms::{js_word, JsWord};
use swc_common::{Mark, DUMMY_SP};
use swc_ecma_ast::*;
use swc_ecma_transforms_base::helper;
@ -44,6 +44,10 @@ impl SuperCallFinder {
macro_rules! ignore_return {
($name:ident, $T:ty) => {
fn $name(&mut self, n: $T) -> $T {
if self.in_injected_define_property_call {
return n;
}
let old = self.ignore_return;
self.ignore_return = true;
let n = n.fold_children_with(self);
@ -164,6 +168,7 @@ pub(super) struct ConstructorFolder<'a> {
pub is_constructor_default: bool,
/// True when recursing into other function or class.
pub ignore_return: bool,
pub in_injected_define_property_call: bool,
}
/// `None`: `return _possibleConstructorReturn`
@ -190,6 +195,28 @@ impl Fold for ConstructorFolder<'_> {
_ => return expr,
}
// We pretend method folding mode for while folding injected `_defineProperty`
// calls.
match expr {
Expr::Call(CallExpr {
callee: ExprOrSuper::Expr(ref callee),
..
}) => match &**callee {
Expr::Ident(Ident {
sym: js_word!("_defineProperty"),
..
}) => {
let old = self.in_injected_define_property_call;
self.in_injected_define_property_call = true;
let n = expr.fold_children_with(self);
self.in_injected_define_property_call = old;
return n;
}
_ => {}
},
_ => {}
}
let expr = expr.fold_children_with(self);
match expr {
@ -395,6 +422,7 @@ pub(super) fn replace_this_in_constructor(mark: Mark, c: Constructor) -> (Constr
mark: Mark,
found: bool,
wrap_with_assertion: bool,
in_injected_define_property_call: bool,
}
impl Fold for Replacer {
@ -404,8 +432,30 @@ pub(super) fn replace_this_in_constructor(mark: Mark, c: Constructor) -> (Constr
n
}
fn fold_expr(&mut self, expr: Expr) -> Expr {
match expr {
fn fold_expr(&mut self, n: Expr) -> Expr {
// We pretend method folding mode for while folding injected `_defineProperty`
// calls.
match n {
Expr::Call(CallExpr {
callee: ExprOrSuper::Expr(ref callee),
..
}) => match &**callee {
Expr::Ident(Ident {
sym: js_word!("_defineProperty"),
..
}) => {
let old = self.in_injected_define_property_call;
self.in_injected_define_property_call = true;
let n = n.fold_children_with(self);
self.in_injected_define_property_call = old;
return n;
}
_ => {}
},
_ => {}
}
match n {
Expr::This(..) => {
self.found = true;
let this = quote_ident!(DUMMY_SP.apply_mark(self.mark), "_this");
@ -421,10 +471,18 @@ pub(super) fn replace_this_in_constructor(mark: Mark, c: Constructor) -> (Constr
Expr::Ident(this)
}
}
_ => expr.fold_children_with(self),
_ => n.fold_children_with(self),
}
}
fn fold_function(&mut self, n: Function) -> Function {
if self.in_injected_define_property_call {
return n;
}
n.fold_children_with(self)
}
fn fold_member_expr(
&mut self,
MemberExpr {
@ -454,6 +512,7 @@ pub(super) fn replace_this_in_constructor(mark: Mark, c: Constructor) -> (Constr
found: false,
mark,
wrap_with_assertion: true,
in_injected_define_property_call: false,
};
let c = c.fold_with(&mut v);

View File

@ -493,6 +493,7 @@ where
},
mark: this_mark,
ignore_return: false,
in_injected_define_property_call: false,
});
insert_this |= (mode == None && !is_always_initialized)

View File

@ -12,9 +12,9 @@ mod case;
mod hoist;
mod leap;
pub fn regenerator(global_mark: Mark) -> impl Fold {
pub fn regenerator(top_level_mark: Mark) -> impl Fold {
Regenerator {
global_mark,
global_mark: top_level_mark,
regenerator_runtime: Default::default(),
top_level_vars: Default::default(),
}

View File

@ -6539,7 +6539,7 @@ fn exec(input: PathBuf) {
let src = read_to_string(&input).unwrap();
compare_stdout(
Default::default(),
|t| classes(Some(t.comments.clone())),
|t| chain!(class_properties(), classes(Some(t.comments.clone()))),
&src,
);
}

View File

@ -1,4 +1,5 @@
use crate::es2015::regenerator;
use std::{fs::read_to_string, path::PathBuf};
use swc_common::{chain, Mark, Spanned};
use swc_ecma_ast::*;
use swc_ecma_parser::Syntax;
@ -9,7 +10,7 @@ use swc_ecma_transforms_compat::{
es2017::async_to_generator,
es2020::class_properties,
};
use swc_ecma_transforms_testing::{test, test_exec};
use swc_ecma_transforms_testing::{compare_stdout, test, test_exec};
use swc_ecma_visit::{Fold, FoldWith};
struct ParenRemover;
@ -2684,3 +2685,23 @@ test_exec!(
await res;
"
);
#[testing::fixture("tests/fixture/async-to-generator/**/exec.js")]
fn exec(input: PathBuf) {
let input = read_to_string(&input).unwrap();
compare_stdout(Default::default(), |_| async_to_generator(), &input);
}
#[testing::fixture("tests/fixture/async-to-generator/**/exec.js")]
fn exec_regenerator(input: PathBuf) {
let input = read_to_string(&input).unwrap();
compare_stdout(
Default::default(),
|_| {
let top_level_mark = Mark::fresh(Mark::root());
chain!(async_to_generator(), regenerator(top_level_mark))
},
&input,
);
}

View File

@ -1,5 +1,6 @@
#![allow(deprecated)]
use std::{fs::read_to_string, path::PathBuf};
use swc_common::chain;
use swc_ecma_parser::{EsConfig, Syntax, TsConfig};
use swc_ecma_transforms_base::resolver::resolver;
@ -10,7 +11,7 @@ use swc_ecma_transforms_compat::{
es2020::{class_properties, typescript_class_properties},
es3::reserved_words,
};
use swc_ecma_transforms_testing::{test, test_exec, Tester};
use swc_ecma_transforms_testing::{compare_stdout, test, test_exec, Tester};
use swc_ecma_visit::Fold;
fn ts() -> Syntax {
@ -5568,3 +5569,9 @@ test!(
}
"
);
#[testing::fixture("tests/fixture/classes/**/exec.js")]
fn exec(input: PathBuf) {
let src = read_to_string(&input).unwrap();
compare_stdout(Default::default(), |_| class_properties(), &src);
}

View File

@ -0,0 +1,9 @@
const foo = async () => {
try {
console.log(1)
} catch (err) {
console.log(err.message)
}
}
foo()

View File

@ -0,0 +1,22 @@
class Foo { }
class Bar extends Foo {
events = {
"abc: click": function abcClick() {
this.data = 123;
console.log(this);
}
}
setData() {
this.data = 456
}
}
const bar = new Bar();
console.log(bar.data);
console.log(bar.events)
console.log(bar.events["abc: click"]());
console.log(bar.data);
bar.setData();
console.log(bar.data);

View File

@ -6,7 +6,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_ecma_transforms_typescript"
repository = "https://github.com/swc-project/swc.git"
version = "0.40.2"
version = "0.40.3"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -1887,13 +1887,8 @@ impl VisitMut for Strip {
}
ModuleItem::ModuleDecl(ModuleDecl::TsImportEquals(import)) => {
if !import.is_export {
continue;
}
stmts.push(ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
span: DUMMY_SP,
decl: Decl::Var(VarDecl {
if !import.is_type_only {
let var = Decl::Var(VarDecl {
span: DUMMY_SP,
kind: VarDeclKind::Var,
decls: vec![VarDeclarator {
@ -1903,8 +1898,18 @@ impl VisitMut for Strip {
definite: false,
}],
declare: false,
}),
})));
});
if import.is_export {
stmts.push(ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(
ExportDecl {
span: DUMMY_SP,
decl: var,
},
)));
} else {
stmts.push(ModuleItem::Stmt(Stmt::Decl(var)));
}
}
}
ModuleItem::ModuleDecl(ModuleDecl::TsExportAssignment(export)) => {

View File

@ -0,0 +1,25 @@
export function Colors(member: Colors.KeyType): Colors {
return Colors.ValueFor(member);
}
export module Colors {
export type KeyType = keyof typeof ValueMap;
export const ValueMap = {
Red: { value: 0.0, label: 'Red' },
Blue: { value: 1.0, label: 'Blue' },
Green: { value: 2.0, label: 'Green' },
} as const;
export const Values: Colors[] = [0.0, 1.0, 2.0];
export function ValueFor(member: KeyType): Colors {
return ValueMap[member]?.value;
}
export function LabelFor(
member: KeyType
): Promise<string | undefined> {
return ValueMap[member]?.label;
}
}

View File

@ -0,0 +1,11 @@
namespace X {
export namespace Z {
export const foo = 0
}
}
namespace Y {
export namespace Z {
export const bar = 1
}
}

View File

@ -0,0 +1,18 @@
var X;
(function(X) {
var Z;
(function(Z) {
Z.foo = 0;
})(Z || (Z = {
}));
X.Z = Z;
})(X || (X = {
}));
var Y;
(function(Y) {
(function(Z) {
Z.bar = 1;
})(Z || (Z = {
}));
})(Y || (Y = {
}));

View File

@ -0,0 +1,8 @@
namespace Shapes {
export namespace Polygons {
export class Triangle { }
export class Square { }
}
}
import polygons = Shapes.Polygons;
let sq = new polygons.Square();

View File

@ -0,0 +1,17 @@
var Shapes;
(function(Shapes) {
var Polygons;
(function(Polygons) {
class Triangle {
}
Polygons.Triangle = Triangle;
class Square {
}
Polygons.Square = Square;
})(Polygons || (Polygons = {
}));
Shapes.Polygons = Polygons;
})(Shapes || (Shapes = {
}));
var polygons = Shapes.Polygons;
let sq = new polygons.Square();

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use swc_common::chain;
use swc_ecma_parser::{Syntax, TsConfig};
use swc_ecma_transforms_base::resolver::resolver;
@ -6,7 +8,7 @@ use swc_ecma_transforms_compat::{
es2020::{class_properties, nullish_coalescing, optional_chaining},
};
use swc_ecma_transforms_proposal::decorators;
use swc_ecma_transforms_testing::{test, test_exec};
use swc_ecma_transforms_testing::{test, test_exec, test_fixture};
use swc_ecma_transforms_typescript::{strip, strip::strip_with_config};
use swc_ecma_visit::Fold;
@ -460,7 +462,7 @@ to!(module_01, "module 'foo'{ }", "");
to!(declare_01, "declare var env: FOO", "");
to!(import_equals, "import A = B.C", "");
to!(import_equals, "import A = B.C", "var A = B.C;");
to!(
issue_757,
@ -4077,3 +4079,14 @@ to!(
"
);
#[testing::fixture("tests/fixture/**/input.ts")]
fn exec(input: PathBuf) {
let output = input.with_file_name("output.js");
test_fixture(
Syntax::Typescript(Default::default()),
&|_| tr(),
&input,
&output,
);
}

View File

@ -0,0 +1,7 @@
class Foo {
async sendSomeMessage(
_parent,
{ input: { toNumber, messageBody, ...all } },
{ dataSources },
) { }
}

View File

@ -0,0 +1,107 @@
import regeneratorRuntime from "regenerator-runtime";
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _asyncToGenerator(fn) {
return function() {
var self = this, args = arguments;
return new Promise(function(resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for(var i = 0; i < props.length; i++){
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _objectWithoutProperties(source, excluded) {
if (source == null) return {
};
var target = _objectWithoutPropertiesLoose(source, excluded);
var key, i;
if (Object.getOwnPropertySymbols) {
var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
for(i = 0; i < sourceSymbolKeys.length; i++){
key = sourceSymbolKeys[i];
if (excluded.indexOf(key) >= 0) continue;
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
target[key] = source[key];
}
}
return target;
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {
};
var target = {
};
var sourceKeys = Object.keys(source);
var key, i;
for(i = 0; i < sourceKeys.length; i++){
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
var Foo = /*#__PURE__*/ function() {
"use strict";
function Foo() {
_classCallCheck(this, Foo);
}
_createClass(Foo, [
{
key: "sendSomeMessage",
value: function sendSomeMessage(_parent, _param, _param1) {
return _asyncToGenerator(regeneratorRuntime.mark(function _callee() {
var toNumber, messageBody, all, dataSources;
return regeneratorRuntime.wrap(function _callee$(_ctx) {
var ref;
while(1)switch(_ctx.prev = _ctx.next){
case 0:
var ref1, ref2;
ref1 = _param, ref = ref1.input, toNumber = ref.toNumber, messageBody = ref.messageBody, ref, ref1, all = _objectWithoutProperties(_param.input, ["toNumber", "messageBody"]), ref2 = _param1, dataSources = ref2.dataSources, ref2;
case 1:
case "end":
return _ctx.stop();
}
}, _callee);
}))();
}
}
]);
return Foo;
}();

View File

@ -0,0 +1,5 @@
{
"jsc": {
"target": "es2017"
}
}

View File

@ -0,0 +1,7 @@
export const foo = async () => {
try {
console.log(1)
} catch (err) {
console.log(err.message)
}
}

View File

@ -0,0 +1,7 @@
export const foo = async ()=>{
try {
console.log(1);
} catch (err) {
console.log(err.message);
}
};

View File

@ -0,0 +1,5 @@
{
"jsc": {
"target": "es5"
}
}

View File

@ -0,0 +1,7 @@
export const foo = async () => {
try {
console.log(1)
} catch (err) {
console.log(err.message)
}
}

View File

@ -0,0 +1,45 @@
import regeneratorRuntime from "regenerator-runtime";
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _asyncToGenerator(fn) {
return function() {
var self = this, args = arguments;
return new Promise(function(resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
export var foo = _asyncToGenerator(regeneratorRuntime.mark(function _callee() {
return regeneratorRuntime.wrap(function _callee$(_ctx) {
while(1)switch(_ctx.prev = _ctx.next){
case 0:
try {
console.log(1);
} catch (err) {
console.log(err.message);
}
case 1:
case "end":
return _ctx.stop();
}
}, _callee);
}));