fix(es): Fix bugs (#1728)

swc_ecma_transforms_compat:
 - `block_scoping`: Ensure that #1462 is fixed. (#1462)
 - `regenerator`: Inject variables at proper level. (#1718)

swc_ecam_transforms_typescript:
 - `strip`: Handle class expressions in arrow expressions correctly. (#1729)
This commit is contained in:
강동윤 2021-05-22 12:14:00 +09:00 committed by GitHub
parent d20c1d3089
commit a518c83485
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 1341 additions and 849 deletions

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.17.4"
version = "0.17.5"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -998,846 +998,3 @@ impl Visit for FunctionFinder {
self.found = true
}
}
#[cfg(test)]
mod tests {
use super::block_scoping;
use crate::{es2015, es2015::for_of::for_of, es2017::async_to_generator};
use swc_common::{chain, Mark};
use swc_ecma_parser::Syntax;
use swc_ecma_transforms_testing::{test, test_exec, Tester};
test!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
for_loop,
"for (const key in obj) {
const bar = obj[key];
let qux;
let fog;
if (Array.isArray(bar)) {
qux = bar[0];
fog = bar[1];
} else {
qux = bar;
}
baz(key, qux, fog);
}",
"for (var key in obj) {
var bar = obj[key];
var qux = void 0;
var fog = void 0;
if (Array.isArray(bar)) {
qux = bar[0];
fog = bar[1];
} else {
qux = bar;
}
baz(key, qux, fog);
}"
);
test!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
for_let_loop,
"let functions = [];
for (let i = 0; i < 10; i++) {
functions.push(function() {
console.log(i);
});
}
functions[0]();
functions[7]();",
"
var _loop = function(i) {
functions.push(function() {
console.log(i);
});
};
var functions = [];
for(var i = 0; i < 10; i++)_loop(i);
functions[0]();
functions[7]();
"
);
test_exec!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
for_let_loop_exec,
"let functions = [];
for (let i = 0; i < 10; i++) {
functions.push(function() {
return i;
});
}
expect(functions[0]()).toBe(0);
expect(functions[7]()).toBe(7);
"
);
test_exec!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
for_let_of_exec,
"let functions = [];
for (let i of [1, 3, 5, 7, 9]) {
functions.push(function() {
return i;
});
}
expect(functions[0]()).toBe(1);
expect(functions[1]()).toBe(3);
"
);
test_exec!(
::swc_ecma_parser::Syntax::default(),
|_| chain!(for_of(Default::default()), block_scoping()),
issue_609_1,
"let functions = [];
for (let i of [1, 3, 5, 7, 9]) {
functions.push(function() {
return i;
});
}
expect(functions[0]()).toBe(1);
expect(functions[1]()).toBe(3);
"
);
test!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
issue_662,
"function foo(parts) {
let match = null;
for (let i = 1; i >= 0; i--) {
for (let j = 0; j >= 0; j--) {
match = parts[i][j];
if (match) {
break;
}
}
if (match) {
break;
}
}
return match;
}
foo();",
"function foo(parts) {
var match = null;
for (var i = 1; i >= 0; i--) {
for (var j = 0; j >= 0; j--) {
match = parts[i][j];
if (match) {
break;
}
}
if (match) {
break;
}
}
return match;
}
foo();"
);
test!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
issue_686,
"module.exports = function(values) {
var vars = [];
var elem = null, name, val;
for (var i = 0; i < this.elements.length; i++) {
elem = this.elements[i];
name = elem.name;
if (!name) continue;
val = values[name];
if (val == null) val = '';
switch (elem.type) {
case 'submit':
break;
case 'radio':
case 'checkbox':
elem.checked = val.some(function(str) {
return str.toString() == elem.value;
});
break;
case 'select-multiple':
elem.fill(val);
break;
case 'textarea':
elem.innerText = val;
break;
case 'hidden':
break;
default:
if (elem.fill) {
elem.fill(val);
} else {
elem.value = val;
}
break;
}
}
return vars;
};",
"
module.exports = function(values) {
var _this = this, _loop = function(i) {
elem = _this.elements[i];
name = elem.name;
if (!name) return 'continue';
val = values[name];
if (val == null) val = '';
switch(elem.type){
case 'submit':
break;
case 'radio':
case 'checkbox':
elem.checked = val.some(function(str) {
return str.toString() == elem.value;
});
break;
case 'select-multiple':
elem.fill(val);
break;
case 'textarea':
elem.innerText = val;
break;
case 'hidden':
break;
default:
if (elem.fill) {
elem.fill(val);
} else {
elem.value = val;
}
break;
}
};
var vars = [];
var elem = null, name, val;
for(var i = 0; i < this.elements.length; i++){
var _ret = _loop(i);
if (_ret === 'continue') continue;
}
return vars;
};
"
);
test_exec!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
issue_723_1,
"function foo() {
const lod = { 0: { mig: 'bana' }};
for (let i = 0; i < 1; i++) {
const { mig } = lod[i];
return false;
(zap) => zap === mig;
}
return true;
}
expect(foo()).toBe(false);
"
);
test_exec!(
::swc_ecma_parser::Syntax::default(),
|Tester { comments, .. }| {
let mark = Mark::fresh(Mark::root());
es2015::es2015(
mark,
Some(comments.clone()),
es2015::Config {
..Default::default()
},
)
},
issue_723_2,
"function foo() {
const lod = { 0: { mig: 'bana' }};
for (let i = 0; i < 1; i++) {
const { mig } = lod[i];
return false;
(zap) => zap === mig;
}
return true;
}
expect(foo()).toBe(false);
"
);
test!(
Syntax::default(),
|Tester { comments, .. }| {
let mark = Mark::fresh(Mark::root());
es2015::es2015(
mark,
Some(comments.clone()),
es2015::Config {
..Default::default()
},
)
},
issue_1022_1,
"
for (let i = 0; i < 5; i++) {
console.log(i++, [2].every(x => x != i))
}
",
r#"
var _loop = function(i1) {
console.log(i1++, [
2
].every(function(x) {
return x != i1;
}));
i = i1, void 0;
};
for(var i = 0; i < 5; i++)_loop(i);
"#
);
test!(
Syntax::default(),
|Tester { comments, .. }| {
let mark = Mark::fresh(Mark::root());
es2015::es2015(
mark,
Some(comments.clone()),
es2015::Config {
..Default::default()
},
)
},
issue_1022_2,
"
for (let i = 0; i < 5; i++) {
console.log(i++, [2].every(x => x != i))
if (i % 2 === 0) continue
}
",
r#"
var _loop = function(i1) {
console.log(i1++, [
2
].every(function(x) {
return x != i1;
}));
if (i1 % 2 === 0) return i = i1, "continue";
i = i1, void 0;
};
for(var i = 0; i < 5; i++){
var _ret = _loop(i);
if (_ret === "continue") continue;
}
"#
);
test!(
Syntax::default(),
|Tester { comments, .. }| {
let mark = Mark::fresh(Mark::root());
es2015::es2015(
mark,
Some(comments.clone()),
es2015::Config {
..Default::default()
},
)
},
issue_1022_3,
"
for (let i = 0; i < 5; i++) {
console.log(i++, [2].every(x => x != i))
if (i % 2 === 0) break
}
",
r#"
var _loop = function(i1) {
console.log(i1++, [
2
].every(function(x) {
return x != i1;
}));
if (i1 % 2 === 0) return i = i1, "break";
i = i1, void 0;
};
for(var i = 0; i < 5; i++){
var _ret = _loop(i);
if (_ret === "break") break;
}
"#
);
test!(
Syntax::default(),
|Tester { comments, .. }| {
let mark = Mark::fresh(Mark::root());
es2015::es2015(
mark,
Some(comments.clone()),
es2015::Config {
..Default::default()
},
)
},
issue_1021_1,
"
class C {
m() {
for (let x = 0; x < 10; x++) console.log(this, y => y != x)
}
}
",
r#"
var C = function() {
"use strict";
function C() {
_classCallCheck(this, C);
}
_createClass(C, [
{
key: "m",
value: function m() {
var _this = this, _loop = function(x) {
console.log(_this, function(y) {
return y != x;
});
};
for(var x = 0; x < 10; x++)_loop(x);
}
}
]);
return C;
}();
"#
);
test!(
Syntax::default(),
|Tester { comments, .. }| {
let mark = Mark::fresh(Mark::root());
es2015::es2015(
mark,
Some(comments.clone()),
es2015::Config {
..Default::default()
},
)
},
issue_1036_1,
"
async function foo() {
await Promise.all([[1], [2], [3]].map(
async ([a]) => Promise.resolve().then(() => a * 2))
)
}
",
"
async function foo() {
await Promise.all([
[
1
],
[
2
],
[
3
]
].map(async function(param) {
var _param = _slicedToArray(param, 1), a = _param[0];
return Promise.resolve().then(function() {
return a * 2;
});
}));
}
"
);
test!(
Syntax::default(),
|Tester { comments, .. }| {
let mark = Mark::fresh(Mark::root());
chain!(
async_to_generator(),
es2015::es2015(
mark,
Some(comments.clone()),
es2015::Config {
..Default::default()
},
)
)
},
issue_1036_2,
"
async function foo() {
await Promise.all([[1], [2], [3]].map(
async ([a]) => Promise.resolve().then(() => a * 2))
)
}
",
r#"
var regeneratorRuntime = require("regenerator-runtime");
var _marked = regeneratorRuntime.mark(_foo);
function _foo() {
_foo = _asyncToGenerator(regeneratorRuntime.mark(function _callee() {
return regeneratorRuntime.wrap(function _callee$(_ctx) {
while(1)switch(_ctx.prev = _ctx.next){
case 0:
_ctx.next = 2;
return Promise.all([
[
1
],
[
2
],
[
3
]
].map(_asyncToGenerator(regeneratorRuntime.mark(function _callee1(param) {
var _param = _slicedToArray(param, 1), a = _param[0];
return regeneratorRuntime.wrap(function _callee$1(_ctx1) {
while(1)switch(_ctx1.prev = _ctx1.next){
case 0:
return _ctx1.abrupt("return", Promise.resolve().then(function() {
return a * 2;
}));
case 1:
case "end":
return _ctx1.stop();
}
}, _callee1);
}))));
case 2:
case "end":
return _ctx.stop();
}
}, _callee);
}));
return _foo.apply(this, arguments);
}
function foo() {
return _foo.apply(this, arguments);
}
"#
);
test_exec!(
Syntax::default(),
|Tester { comments, .. }| {
let mark = Mark::fresh(Mark::root());
chain!(
async_to_generator(),
es2015::es2015(
mark,
Some(comments.clone()),
es2015::Config {
..Default::default()
},
)
)
},
issue_1036_3,
"
const x = async function() {
return await Promise.all([[1], [2], [3]].map(
async ([a]) => Promise.resolve().then(() => a * 2))
)
};
return x().then(x => {
expect(x).toEqual([2, 4, 6])
})
"
);
test!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
issue_1231_1,
"
function combineOverlappingMatches(matches) {
let hasOverlaps = false
for (let i = matches.length - 1; i >= 0; i--) {
let currentMatch = matches[i]
let overlap = matches.find(match => {
return match !== currentMatch && match.itemsType === currentMatch.itemsType
})
if (overlap) {
hasOverlaps = true
matches.splice(i, 1)
}
}
if (hasOverlaps) {
combineOverlappingMatches(matches)
}
}
combineOverlappingMatches([1])
",
"
function combineOverlappingMatches(matches) {
var hasOverlaps = false;
for(var i = matches.length - 1; i >= 0; i--){
var currentMatch = matches[i];
var overlap = matches.find((match)=>{
return match !== currentMatch && match.itemsType === currentMatch.itemsType;
});
if (overlap) {
hasOverlaps = true;
matches.splice(i, 1);
}
}
if (hasOverlaps) {
combineOverlappingMatches(matches);
}
}
combineOverlappingMatches([
1
]);
"
);
test!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
issue_1415_1,
"
export function test(items) {
const infoMap = new WeakMap();
for (let i = 0; i < items.length; i += 1) {
const item = items[i];
let info;
switch (item.type) {
case 'branch1':
info = item.method1();
break;
case 'branch2':
info = item.method2();
break;
case 'branch3':
info = item.method3(
Object.fromEntries(
item.subItems.map((t) => [item.alias ?? t.name, getInfo(t)])
)
);
break;
default:
throw new Error('boom');
}
infoMap.set(item, info); // important
}
function getInfo(item) {
if (!infoMap.has(item)) {
throw new Error('no info yet');
}
return infoMap.get(item);
}
}
",
"
export function test(items) {
var infoMap = new WeakMap();
for(var i = 0; i < items.length; i += 1){
var item = items[i];
var info = void 0;
switch(item.type){
case 'branch1':
info = item.method1();
break;
case 'branch2':
info = item.method2();
break;
case 'branch3':
info = item.method3(Object.fromEntries(item.subItems.map((t)=>[
item.alias ?? t.name,
getInfo(t)
]
)));
break;
default:
throw new Error('boom');
}
infoMap.set(item, info);
}
function getInfo(item) {
if (!infoMap.has(item)) {
throw new Error('no info yet');
}
return infoMap.get(item);
}
}
"
);
test!(
::swc_ecma_parser::Syntax::default(),
|Tester { comments, .. }| {
let mark = Mark::fresh(Mark::root());
es2015::es2015(
mark,
Some(comments.clone()),
es2015::Config {
..Default::default()
},
)
},
arguments_loop,
"
function test() {
for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
console.log((() => arg)());
}
}
",
"
function test() {
var _arguments = arguments, _loop = function(i) {
var arg = _arguments[i];
console.log(function() {
return arg;
}());
};
for(var i = 0; i < arguments.length; i++)_loop(i);
}
"
);
test!(
::swc_ecma_parser::Syntax::default(),
|Tester { comments, .. }| {
let mark = Mark::fresh(Mark::root());
es2015::es2015(
mark,
Some(comments.clone()),
es2015::Config {
..Default::default()
},
)
},
arguments_loop_member,
"
function test(a) {
for (var i = 0; i < a.arguments.length; i++) {
var arg = a.arguments[i];
console.log((() => arg)());
}
}
",
"
function test(a) {
var _loop = function(i) {
var arg = a.arguments[i];
console.log(function() {
return arg;
}());
};
for(var i = 0; i < a.arguments.length; i++)_loop(i);
}
"
);
test!(
::swc_ecma_parser::Syntax::default(),
|Tester { comments, .. }| {
let mark = Mark::fresh(Mark::root());
es2015::es2015(
mark,
Some(comments.clone()),
es2015::Config {
..Default::default()
},
)
},
arguments_arrow,
"
function test() {
for (var i = 0; i < arguments.length; i++) {
console.log((() => arguments[i])());
}
}
",
"
function test() {
var _this = this, _arguments = arguments, _loop = function(i) {
console.log((function(_arguments1) {
return _arguments1[i];
}).bind(_this, _arguments)());
};
for(var i = 0; i < arguments.length; i++)_loop(i);
}
"
);
test!(
::swc_ecma_parser::Syntax::default(),
|Tester { comments, .. }| {
let mark = Mark::fresh(Mark::root());
es2015::es2015(
mark,
Some(comments.clone()),
es2015::Config {
..Default::default()
},
)
},
arguments_function,
"
function test() {
for (var i = 0; i < arguments.length; i++) {
console.log((function () { return arguments[i] })());
}
}
",
"
function test() {
var _loop = function(i) {
console.log(function() {
return arguments[i];
}());
};
for(var i = 0; i < arguments.length; i++)_loop(i);
}
"
);
}

View File

@ -60,6 +60,11 @@ impl Hoister {
impl Fold for Hoister {
noop_fold_type!();
/// Noop
fn fold_function(&mut self, n: Function) -> Function {
n
}
fn fold_expr(&mut self, e: Expr) -> Expr {
let e = e.fold_children_with(self);

View File

@ -1,5 +1,5 @@
use self::{case::CaseHandler, hoist::hoist};
use std::mem::replace;
use std::mem::take;
use swc_atoms::js_word;
use swc_common::{Mark, Spanned, DUMMY_SP};
use swc_ecma_ast::*;
@ -78,7 +78,7 @@ impl Regenerator {
span: DUMMY_SP,
kind: VarDeclKind::Var,
declare: false,
decls: replace(&mut self.top_level_vars, Default::default()),
decls: take(&mut self.top_level_vars),
}))),
);
}
@ -411,7 +411,7 @@ impl Regenerator {
buf.push(Stmt::Decl(Decl::Var(VarDecl {
span: DUMMY_SP,
kind: VarDeclKind::Var,
decls: replace(&mut self.outer_fn_vars, Default::default()),
decls: take(&mut self.outer_fn_vars),
declare: false,
})));
}

View File

@ -0,0 +1,885 @@
use swc_common::{chain, Mark};
use swc_ecma_parser::Syntax;
use swc_ecma_transforms_compat::es2015::block_scoping;
use swc_ecma_transforms_compat::{es2015, es2015::for_of::for_of, es2017::async_to_generator};
use swc_ecma_transforms_testing::{test, test_exec, Tester};
test!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
for_loop,
"for (const key in obj) {
const bar = obj[key];
let qux;
let fog;
if (Array.isArray(bar)) {
qux = bar[0];
fog = bar[1];
} else {
qux = bar;
}
baz(key, qux, fog);
}",
"for (var key in obj) {
var bar = obj[key];
var qux = void 0;
var fog = void 0;
if (Array.isArray(bar)) {
qux = bar[0];
fog = bar[1];
} else {
qux = bar;
}
baz(key, qux, fog);
}"
);
test!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
for_let_loop,
"let functions = [];
for (let i = 0; i < 10; i++) {
functions.push(function() {
console.log(i);
});
}
functions[0]();
functions[7]();",
"
var _loop = function(i) {
functions.push(function() {
console.log(i);
});
};
var functions = [];
for(var i = 0; i < 10; i++)_loop(i);
functions[0]();
functions[7]();
"
);
test_exec!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
for_let_loop_exec,
"let functions = [];
for (let i = 0; i < 10; i++) {
functions.push(function() {
return i;
});
}
expect(functions[0]()).toBe(0);
expect(functions[7]()).toBe(7);
"
);
test_exec!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
for_let_of_exec,
"let functions = [];
for (let i of [1, 3, 5, 7, 9]) {
functions.push(function() {
return i;
});
}
expect(functions[0]()).toBe(1);
expect(functions[1]()).toBe(3);
"
);
test_exec!(
::swc_ecma_parser::Syntax::default(),
|_| chain!(for_of(Default::default()), block_scoping()),
issue_609_1,
"let functions = [];
for (let i of [1, 3, 5, 7, 9]) {
functions.push(function() {
return i;
});
}
expect(functions[0]()).toBe(1);
expect(functions[1]()).toBe(3);
"
);
test!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
issue_662,
"function foo(parts) {
let match = null;
for (let i = 1; i >= 0; i--) {
for (let j = 0; j >= 0; j--) {
match = parts[i][j];
if (match) {
break;
}
}
if (match) {
break;
}
}
return match;
}
foo();",
"function foo(parts) {
var match = null;
for (var i = 1; i >= 0; i--) {
for (var j = 0; j >= 0; j--) {
match = parts[i][j];
if (match) {
break;
}
}
if (match) {
break;
}
}
return match;
}
foo();"
);
test!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
issue_686,
"module.exports = function(values) {
var vars = [];
var elem = null, name, val;
for (var i = 0; i < this.elements.length; i++) {
elem = this.elements[i];
name = elem.name;
if (!name) continue;
val = values[name];
if (val == null) val = '';
switch (elem.type) {
case 'submit':
break;
case 'radio':
case 'checkbox':
elem.checked = val.some(function(str) {
return str.toString() == elem.value;
});
break;
case 'select-multiple':
elem.fill(val);
break;
case 'textarea':
elem.innerText = val;
break;
case 'hidden':
break;
default:
if (elem.fill) {
elem.fill(val);
} else {
elem.value = val;
}
break;
}
}
return vars;
};",
"
module.exports = function(values) {
var _this = this, _loop = function(i) {
elem = _this.elements[i];
name = elem.name;
if (!name) return 'continue';
val = values[name];
if (val == null) val = '';
switch(elem.type){
case 'submit':
break;
case 'radio':
case 'checkbox':
elem.checked = val.some(function(str) {
return str.toString() == elem.value;
});
break;
case 'select-multiple':
elem.fill(val);
break;
case 'textarea':
elem.innerText = val;
break;
case 'hidden':
break;
default:
if (elem.fill) {
elem.fill(val);
} else {
elem.value = val;
}
break;
}
};
var vars = [];
var elem = null, name, val;
for(var i = 0; i < this.elements.length; i++){
var _ret = _loop(i);
if (_ret === 'continue') continue;
}
return vars;
};
"
);
test_exec!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
issue_723_1,
"function foo() {
const lod = { 0: { mig: 'bana' }};
for (let i = 0; i < 1; i++) {
const { mig } = lod[i];
return false;
(zap) => zap === mig;
}
return true;
}
expect(foo()).toBe(false);
"
);
test_exec!(
::swc_ecma_parser::Syntax::default(),
|Tester { comments, .. }| {
let mark = Mark::fresh(Mark::root());
es2015::es2015(
mark,
Some(comments.clone()),
es2015::Config {
..Default::default()
},
)
},
issue_723_2,
"function foo() {
const lod = { 0: { mig: 'bana' }};
for (let i = 0; i < 1; i++) {
const { mig } = lod[i];
return false;
(zap) => zap === mig;
}
return true;
}
expect(foo()).toBe(false);
"
);
test!(
Syntax::default(),
|Tester { comments, .. }| {
let mark = Mark::fresh(Mark::root());
es2015::es2015(
mark,
Some(comments.clone()),
es2015::Config {
..Default::default()
},
)
},
issue_1022_1,
"
for (let i = 0; i < 5; i++) {
console.log(i++, [2].every(x => x != i))
}
",
r#"
var _loop = function(i1) {
console.log(i1++, [
2
].every(function(x) {
return x != i1;
}));
i = i1, void 0;
};
for(var i = 0; i < 5; i++)_loop(i);
"#
);
test!(
Syntax::default(),
|Tester { comments, .. }| {
let mark = Mark::fresh(Mark::root());
es2015::es2015(
mark,
Some(comments.clone()),
es2015::Config {
..Default::default()
},
)
},
issue_1022_2,
"
for (let i = 0; i < 5; i++) {
console.log(i++, [2].every(x => x != i))
if (i % 2 === 0) continue
}
",
r#"
var _loop = function(i1) {
console.log(i1++, [
2
].every(function(x) {
return x != i1;
}));
if (i1 % 2 === 0) return i = i1, "continue";
i = i1, void 0;
};
for(var i = 0; i < 5; i++){
var _ret = _loop(i);
if (_ret === "continue") continue;
}
"#
);
test!(
Syntax::default(),
|Tester { comments, .. }| {
let mark = Mark::fresh(Mark::root());
es2015::es2015(
mark,
Some(comments.clone()),
es2015::Config {
..Default::default()
},
)
},
issue_1022_3,
"
for (let i = 0; i < 5; i++) {
console.log(i++, [2].every(x => x != i))
if (i % 2 === 0) break
}
",
r#"
var _loop = function(i1) {
console.log(i1++, [
2
].every(function(x) {
return x != i1;
}));
if (i1 % 2 === 0) return i = i1, "break";
i = i1, void 0;
};
for(var i = 0; i < 5; i++){
var _ret = _loop(i);
if (_ret === "break") break;
}
"#
);
test!(
Syntax::default(),
|Tester { comments, .. }| {
let mark = Mark::fresh(Mark::root());
es2015::es2015(
mark,
Some(comments.clone()),
es2015::Config {
..Default::default()
},
)
},
issue_1021_1,
"
class C {
m() {
for (let x = 0; x < 10; x++) console.log(this, y => y != x)
}
}
",
r#"
var C = function() {
"use strict";
function C() {
_classCallCheck(this, C);
}
_createClass(C, [
{
key: "m",
value: function m() {
var _this = this, _loop = function(x) {
console.log(_this, function(y) {
return y != x;
});
};
for(var x = 0; x < 10; x++)_loop(x);
}
}
]);
return C;
}();
"#
);
test!(
Syntax::default(),
|Tester { comments, .. }| {
let mark = Mark::fresh(Mark::root());
es2015::es2015(
mark,
Some(comments.clone()),
es2015::Config {
..Default::default()
},
)
},
issue_1036_1,
"
async function foo() {
await Promise.all([[1], [2], [3]].map(
async ([a]) => Promise.resolve().then(() => a * 2))
)
}
",
"
async function foo() {
await Promise.all([
[
1
],
[
2
],
[
3
]
].map(async function(param) {
var _param = _slicedToArray(param, 1), a = _param[0];
return Promise.resolve().then(function() {
return a * 2;
});
}));
}
"
);
test!(
Syntax::default(),
|Tester { comments, .. }| {
let mark = Mark::fresh(Mark::root());
chain!(
async_to_generator(),
es2015::es2015(
mark,
Some(comments.clone()),
es2015::Config {
..Default::default()
},
)
)
},
issue_1036_2,
"
async function foo() {
await Promise.all([[1], [2], [3]].map(
async ([a]) => Promise.resolve().then(() => a * 2))
)
}
",
r#"
var regeneratorRuntime = require("regenerator-runtime");
var _marked = regeneratorRuntime.mark(_foo);
function _foo() {
_foo = _asyncToGenerator(regeneratorRuntime.mark(function _callee() {
return regeneratorRuntime.wrap(function _callee$(_ctx) {
while(1)switch(_ctx.prev = _ctx.next){
case 0:
_ctx.next = 2;
return Promise.all([
[
1
],
[
2
],
[
3
]
].map(_asyncToGenerator(regeneratorRuntime.mark(function _callee1(param) {
var _param = _slicedToArray(param, 1), a = _param[0];
return regeneratorRuntime.wrap(function _callee$1(_ctx1) {
while(1)switch(_ctx1.prev = _ctx1.next){
case 0:
return _ctx1.abrupt("return", Promise.resolve().then(function() {
return a * 2;
}));
case 1:
case "end":
return _ctx1.stop();
}
}, _callee1);
}))));
case 2:
case "end":
return _ctx.stop();
}
}, _callee);
}));
return _foo.apply(this, arguments);
}
function foo() {
return _foo.apply(this, arguments);
}
"#
);
test_exec!(
Syntax::default(),
|Tester { comments, .. }| {
let mark = Mark::fresh(Mark::root());
chain!(
async_to_generator(),
es2015::es2015(
mark,
Some(comments.clone()),
es2015::Config {
..Default::default()
},
)
)
},
issue_1036_3,
"
const x = async function() {
return await Promise.all([[1], [2], [3]].map(
async ([a]) => Promise.resolve().then(() => a * 2))
)
};
return x().then(x => {
expect(x).toEqual([2, 4, 6])
})
"
);
test!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
issue_1231_1,
"
function combineOverlappingMatches(matches) {
let hasOverlaps = false
for (let i = matches.length - 1; i >= 0; i--) {
let currentMatch = matches[i]
let overlap = matches.find(match => {
return match !== currentMatch && match.itemsType === currentMatch.itemsType
})
if (overlap) {
hasOverlaps = true
matches.splice(i, 1)
}
}
if (hasOverlaps) {
combineOverlappingMatches(matches)
}
}
combineOverlappingMatches([1])
",
"
function combineOverlappingMatches(matches) {
var hasOverlaps = false;
for(var i = matches.length - 1; i >= 0; i--){
var currentMatch = matches[i];
var overlap = matches.find((match)=>{
return match !== currentMatch && match.itemsType === currentMatch.itemsType;
});
if (overlap) {
hasOverlaps = true;
matches.splice(i, 1);
}
}
if (hasOverlaps) {
combineOverlappingMatches(matches);
}
}
combineOverlappingMatches([
1
]);
"
);
test!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
issue_1415_1,
"
export function test(items) {
const infoMap = new WeakMap();
for (let i = 0; i < items.length; i += 1) {
const item = items[i];
let info;
switch (item.type) {
case 'branch1':
info = item.method1();
break;
case 'branch2':
info = item.method2();
break;
case 'branch3':
info = item.method3(
Object.fromEntries(
item.subItems.map((t) => [item.alias ?? t.name, getInfo(t)])
)
);
break;
default:
throw new Error('boom');
}
infoMap.set(item, info); // important
}
function getInfo(item) {
if (!infoMap.has(item)) {
throw new Error('no info yet');
}
return infoMap.get(item);
}
}
",
"
export function test(items) {
var infoMap = new WeakMap();
for(var i = 0; i < items.length; i += 1){
var item = items[i];
var info = void 0;
switch(item.type){
case 'branch1':
info = item.method1();
break;
case 'branch2':
info = item.method2();
break;
case 'branch3':
info = item.method3(Object.fromEntries(item.subItems.map((t)=>[
item.alias ?? t.name,
getInfo(t)
]
)));
break;
default:
throw new Error('boom');
}
infoMap.set(item, info);
}
function getInfo(item) {
if (!infoMap.has(item)) {
throw new Error('no info yet');
}
return infoMap.get(item);
}
}
"
);
test!(
::swc_ecma_parser::Syntax::default(),
|Tester { comments, .. }| {
let mark = Mark::fresh(Mark::root());
es2015::es2015(
mark,
Some(comments.clone()),
es2015::Config {
..Default::default()
},
)
},
arguments_loop,
"
function test() {
for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
console.log((() => arg)());
}
}
",
"
function test() {
var _arguments = arguments, _loop = function(i) {
var arg = _arguments[i];
console.log(function() {
return arg;
}());
};
for(var i = 0; i < arguments.length; i++)_loop(i);
}
"
);
test!(
::swc_ecma_parser::Syntax::default(),
|Tester { comments, .. }| {
let mark = Mark::fresh(Mark::root());
es2015::es2015(
mark,
Some(comments.clone()),
es2015::Config {
..Default::default()
},
)
},
arguments_loop_member,
"
function test(a) {
for (var i = 0; i < a.arguments.length; i++) {
var arg = a.arguments[i];
console.log((() => arg)());
}
}
",
"
function test(a) {
var _loop = function(i) {
var arg = a.arguments[i];
console.log(function() {
return arg;
}());
};
for(var i = 0; i < a.arguments.length; i++)_loop(i);
}
"
);
test!(
::swc_ecma_parser::Syntax::default(),
|Tester { comments, .. }| {
let mark = Mark::fresh(Mark::root());
es2015::es2015(
mark,
Some(comments.clone()),
es2015::Config {
..Default::default()
},
)
},
arguments_arrow,
"
function test() {
for (var i = 0; i < arguments.length; i++) {
console.log((() => arguments[i])());
}
}
",
"
function test() {
var _this = this, _arguments = arguments, _loop = function(i) {
console.log((function(_arguments1) {
return _arguments1[i];
}).bind(_this, _arguments)());
};
for(var i = 0; i < arguments.length; i++)_loop(i);
}
"
);
test!(
::swc_ecma_parser::Syntax::default(),
|Tester { comments, .. }| {
let mark = Mark::fresh(Mark::root());
es2015::es2015(
mark,
Some(comments.clone()),
es2015::Config {
..Default::default()
},
)
},
arguments_function,
"
function test() {
for (var i = 0; i < arguments.length; i++) {
console.log((function () { return arguments[i] })());
}
}
",
"
function test() {
var _loop = function(i) {
console.log(function() {
return arguments[i];
}());
};
for(var i = 0; i < arguments.length; i++)_loop(i);
}
"
);
test!(
::swc_ecma_parser::Syntax::default(),
|_| block_scoping(),
issue_1462_1,
"
export default function _objectSpread(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
var ownKeys = Object.keys(source);
if (typeof Object.getOwnPropertySymbols === 'function') {
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
}));
}
ownKeys.forEach(function (key) {
defineProperty(target, key, source[key]);
});
}
return target;
}
",
"
export default function _objectSpread(target) {
var _arguments = arguments, _loop = function(i) {
var source = _arguments[i] != null ? _arguments[i] : {
};
var ownKeys = Object.keys(source);
if (typeof Object.getOwnPropertySymbols === 'function') {
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) \
{
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
}));
}
ownKeys.forEach(function(key) {
defineProperty(target, key, source[key]);
});
};
for(var i = 1; i < arguments.length; i++)_loop(i);
return target;
}
"
);

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.19.1"
version = "0.19.2"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -1271,9 +1271,11 @@ impl VisitMut for Strip {
fn visit_mut_block_stmt_or_expr(&mut self, n: &mut BlockStmtOrExpr) {
match n {
BlockStmtOrExpr::Expr(expr) if expr.is_class() => {
let span = expr.span();
let ClassExpr { ident, class } = expr.take().class().unwrap();
let ident = ident.unwrap_or_else(|| private_ident!("_class"));
let (decl, extra_exprs) = self.fold_class_as_decl(ident, class);
let (decl, extra_exprs) = self.fold_class_as_decl(ident.clone(), class);
let mut stmts = vec![];
stmts.push(Stmt::Decl(decl));
stmts.extend(
@ -1282,6 +1284,10 @@ impl VisitMut for Strip {
.map(|e| e.into_stmt())
.collect::<Vec<_>>(),
);
stmts.push(Stmt::Return(ReturnStmt {
span,
arg: Some(Box::new(Expr::Ident(ident))),
}));
*n = BlockStmtOrExpr::BlockStmt(BlockStmt {
span: n.span(),
stmts,

View File

@ -59,4 +59,5 @@ export var fn = function() {
return _class;
}(MyClass);
_class.x = 5;
return _class;
};

View File

@ -58,4 +58,5 @@ export var fn = function() {
}
return _class;
}(MyClass);
return _class;
};

View File

@ -63,4 +63,5 @@ var withTeamsForUser = function(_WrappedComponent) {
return _class;
}(Component);
_class.displayName = "x";
return _class;
};

View File

@ -55,4 +55,5 @@ var withTeamsForUser = function() {
return _class;
}(Component);
_class.displayName = "x";
return _class;
};

View File

@ -58,4 +58,5 @@ export var fn = function() {
}
return _class;
}(MyClass);
return _class;
};

View File

@ -0,0 +1,7 @@
{
"jsc": {
"parser": {
"syntax": "typescript"
}
}
}

View File

@ -0,0 +1,13 @@
async function scanUser(groups: { users: number[] }[]) {
await Promise.all(groups.map(async ({ users }) => {
for (const user of users) {
console.log('user', user)
await new Promise(resolve => setTimeout(resolve, 30))
}
}))
}
scanUser([
{ users: [1, 2, 3, 4, 5] },
{ users: [11, 12, 13, 14, 15] },
])

View File

@ -0,0 +1,136 @@
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);
});
};
}
var regeneratorRuntime = require("regenerator-runtime");
var _marked = regeneratorRuntime.mark(_scanUser);
function _scanUser() {
_scanUser = _asyncToGenerator(regeneratorRuntime.mark(function _callee(groups) {
return regeneratorRuntime.wrap(function _callee$(_ctx) {
while(1)switch(_ctx.prev = _ctx.next){
case 0:
_ctx.next = 2;
return Promise.all(groups.map(_asyncToGenerator(regeneratorRuntime.mark(function _callee1(param) {
var users = param.users;
var _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, user;
return regeneratorRuntime.wrap(function _callee$1(_ctx1) {
while(1)switch(_ctx1.prev = _ctx1.next){
case 0:
_iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
_ctx1.prev = 1;
_iterator = users[Symbol.iterator]();
case 3:
if (_iteratorNormalCompletion = (_step = _iterator.next()).done) {
_ctx1.next = 11;
break;
}
user = _step.value;
console.log('user', user);
_ctx1.next = 8;
return new Promise(function(resolve) {
return setTimeout(resolve, 30);
});
case 8:
_iteratorNormalCompletion = true;
_ctx1.next = 3;
break;
case 11:
_ctx1.next = 17;
break;
case 13:
_ctx1.prev = 13;
_ctx1.t0 = _ctx1["catch"](1);
_didIteratorError = true;
_iteratorError = _ctx1.t0;
case 17:
_ctx1.prev = 17;
_ctx1.prev = 18;
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
case 20:
_ctx1.prev = 20;
if (!_didIteratorError) {
_ctx1.next = 23;
break;
}
throw _iteratorError;
case 23:
return _ctx1.finish(20);
case 24:
return _ctx1.finish(17);
case 25:
case "end":
return _ctx1.stop();
}
}, _callee1, null, [
[
18,
,
20,
24
],
[
1,
13,
17,
25
]
]);
}))));
case 2:
case "end":
return _ctx.stop();
}
}, _callee);
}));
return _scanUser.apply(this, arguments);
}
function scanUser(groups) {
return _scanUser.apply(this, arguments);
}
scanUser([
{
users: [
1,
2,
3,
4,
5
]
},
{
users: [
11,
12,
13,
14,
15
]
},
]);

View File

@ -0,0 +1,8 @@
{
"jsc": {
"parser": {
"syntax": "typescript"
},
"target": "es2016"
}
}

View File

@ -0,0 +1,13 @@
async function scanUser(groups: { users: number[] }[]) {
await Promise.all(groups.map(async ({ users }) => {
for (const user of users) {
console.log('user', user)
await new Promise(resolve => setTimeout(resolve, 30))
}
}))
}
scanUser([
{ users: [1, 2, 3, 4, 5] },
{ users: [11, 12, 13, 14, 15] },
])

View File

@ -0,0 +1,64 @@
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 _scanUser() {
_scanUser = _asyncToGenerator(function*(groups) {
yield Promise.all(groups.map(_asyncToGenerator(function*({ users }) {
for (const user of users){
console.log('user', user);
yield new Promise((resolve)=>setTimeout(resolve, 30)
);
}
})));
});
return _scanUser.apply(this, arguments);
}
function scanUser(groups) {
return _scanUser.apply(this, arguments);
}
scanUser([
{
users: [
1,
2,
3,
4,
5
]
},
{
users: [
11,
12,
13,
14,
15
]
},
]);

View File

@ -0,0 +1,14 @@
function createConstructor(callback) {
let klass
return (...args) => {
if (klass === undefined) {
klass = callback()
}
return new klass(...args)
}
}
const constructor = createConstructor(() => class {
})
console.log(constructor())

View File

@ -0,0 +1,78 @@
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) {
for(var i = 0, arr2 = new Array(arr.length); i < arr.length; i++){
arr2[i] = arr[i];
}
return arr2;
}
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function isNativeReflectConstruct() {
if (typeof Reflect === "undefined" || !Reflect.construct) return false;
if (Reflect.construct.sham) return false;
if (typeof Proxy === "function") return true;
try {
Date.prototype.toString.call(Reflect.construct(Date, [], function() {
}));
return true;
} catch (e) {
return false;
}
}
function _construct(Parent, args, Class) {
if (isNativeReflectConstruct()) {
_construct = Reflect.construct;
} else {
_construct = function _construct(Parent, args, Class) {
var a = [
null
];
a.push.apply(a, args);
var Constructor = Function.bind.apply(Parent, a);
var instance = new Constructor();
if (Class) _setPrototypeOf(instance, Class.prototype);
return instance;
};
}
return _construct.apply(null, arguments);
}
function _iterableToArray(iter) {
if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance");
}
function _setPrototypeOf(o, p) {
_setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
}
function createConstructor(callback) {
var klass;
return function() {
for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
args[_key] = arguments[_key];
}
if (klass === undefined) {
klass = callback();
}
return _construct(klass, _toConsumableArray(args));
};
}
var constructor = createConstructor(function() {
var _class = function _class() {
"use strict";
_classCallCheck(this, _class);
};
return _class;
});
console.log(constructor());

View File

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

View File

@ -0,0 +1,14 @@
function createConstructor(callback) {
let klass
return (...args) => {
if (klass === undefined) {
klass = callback()
}
return new klass(...args)
}
}
const constructor = createConstructor(() => class {
})
console.log(constructor())

View File

@ -0,0 +1,13 @@
function createConstructor(callback) {
let klass;
return (...args)=>{
if (klass === undefined) {
klass = callback();
}
return new klass(...args);
};
}
const constructor = createConstructor(()=>class {
}
);
console.log(constructor());

View File

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

View File

@ -0,0 +1,14 @@
function createConstructor(callback) {
let klass
return (...args) => {
if (klass === undefined) {
klass = callback()
}
return new klass(...args)
}
}
const constructor = createConstructor(() => class {
})
console.log(constructor())

View File

@ -0,0 +1,13 @@
function createConstructor(callback) {
let klass;
return (...args)=>{
if (klass === undefined) {
klass = callback();
}
return new klass(...args);
};
}
const constructor = createConstructor(()=>class {
}
);
console.log(constructor());

View File

@ -0,0 +1,8 @@
{
"jsc": {
"parser": {
"syntax": "typescript"
},
"target": "es2020"
}
}

View File

@ -0,0 +1,14 @@
function createConstructor(callback) {
let klass
return (...args) => {
if (klass === undefined) {
klass = callback()
}
return new klass(...args)
}
}
const constructor = createConstructor(() => class {
})
console.log(constructor())

View File

@ -0,0 +1,15 @@
function createConstructor(callback) {
let klass;
return (...args)=>{
if (klass === undefined) {
klass = callback();
}
return new klass(...args);
};
}
const constructor = createConstructor(()=>{
class _class {
}
return _class;
});
console.log(constructor());