mirror of
https://github.com/swc-project/swc.git
synced 2024-11-23 00:32:15 +03:00
feat(es/compat): Support iterator protocol on loose mode (#6034)
This commit is contained in:
parent
6749e6948e
commit
80da0981bd
@ -291,7 +291,8 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> {
|
||||
loose: self.loose
|
||||
},
|
||||
for_of: compat::es2015::for_of::Config {
|
||||
assume_array: self.loose
|
||||
assume_array: false,
|
||||
loose: self.loose
|
||||
},
|
||||
spread: compat::es2015::spread::Config { loose: self.loose },
|
||||
destructuring: compat::es2015::destructuring::Config {
|
||||
|
64
crates/swc/tests/exec/issues-6xxx/6028/1/.swcrc
Normal file
64
crates/swc/tests/exec/issues-6xxx/6028/1/.swcrc
Normal file
@ -0,0 +1,64 @@
|
||||
{
|
||||
"jsc": {
|
||||
"parser": {
|
||||
"syntax": "ecmascript",
|
||||
"jsx": false
|
||||
},
|
||||
"target": "es5",
|
||||
"loose": true,
|
||||
"minify": {
|
||||
"compress": {
|
||||
"arguments": false,
|
||||
"arrows": true,
|
||||
"booleans": true,
|
||||
"booleans_as_integers": false,
|
||||
"collapse_vars": true,
|
||||
"comparisons": true,
|
||||
"computed_props": true,
|
||||
"conditionals": true,
|
||||
"dead_code": true,
|
||||
"directives": false,
|
||||
"drop_console": false,
|
||||
"drop_debugger": true,
|
||||
"evaluate": true,
|
||||
"expression": false,
|
||||
"hoist_funs": false,
|
||||
"hoist_props": true,
|
||||
"hoist_vars": false,
|
||||
"if_return": true,
|
||||
"join_vars": true,
|
||||
"keep_classnames": false,
|
||||
"keep_fargs": true,
|
||||
"keep_fnames": false,
|
||||
"keep_infinity": false,
|
||||
"loops": true,
|
||||
"negate_iife": true,
|
||||
"properties": true,
|
||||
"reduce_funcs": false,
|
||||
"reduce_vars": false,
|
||||
"side_effects": true,
|
||||
"switches": true,
|
||||
"typeofs": true,
|
||||
"unsafe": false,
|
||||
"unsafe_arrows": false,
|
||||
"unsafe_comps": false,
|
||||
"unsafe_Function": false,
|
||||
"unsafe_math": false,
|
||||
"unsafe_symbols": false,
|
||||
"unsafe_methods": false,
|
||||
"unsafe_proto": false,
|
||||
"unsafe_regexp": false,
|
||||
"unsafe_undefined": false,
|
||||
"unused": true,
|
||||
"const_to_let": true,
|
||||
"pristine_globals": true
|
||||
},
|
||||
"mangle": false
|
||||
}
|
||||
},
|
||||
"module": {
|
||||
"type": "commonjs"
|
||||
},
|
||||
"minify": false,
|
||||
"isModule": false
|
||||
}
|
4
crates/swc/tests/exec/issues-6xxx/6028/1/exec.js
Normal file
4
crates/swc/tests/exec/issues-6xxx/6028/1/exec.js
Normal file
@ -0,0 +1,4 @@
|
||||
const m = new Map([[1, 2]])
|
||||
for (const k of m.keys()) {
|
||||
console.log(k)
|
||||
}
|
@ -1 +1 @@
|
||||
export function test(list){var cur=list.findIndex(function(p){return 1==p});~cur||(cur=list.findIndex(function(p){return 0!==p}));for(var _i=0;_i<list.length;_i++)cur+=list[_i].value;return cur}
|
||||
import _create_for_of_iterator_helper_loose from"@swc/helpers/src/_create_for_of_iterator_helper_loose.mjs";export function test(list){var cur=list.findIndex(function(p){return 1==p});~cur||(cur=list.findIndex(function(p){return 0!==p}));for(var _step,_iterator=_create_for_of_iterator_helper_loose(list);!(_step=_iterator()).done;)cur+=_step.value.value;return cur}
|
||||
|
11
crates/swc/tests/fixture/issues-6xxx/6028/input/.swcrc
Normal file
11
crates/swc/tests/fixture/issues-6xxx/6028/input/.swcrc
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"jsc": {
|
||||
"parser": {
|
||||
"syntax": "ecmascript",
|
||||
"jsx": false
|
||||
},
|
||||
"target": "es5",
|
||||
"loose": true
|
||||
},
|
||||
"isModule": false
|
||||
}
|
4
crates/swc/tests/fixture/issues-6xxx/6028/input/input.js
Normal file
4
crates/swc/tests/fixture/issues-6xxx/6028/input/input.js
Normal file
@ -0,0 +1,4 @@
|
||||
const m = new Map([[1, 2]])
|
||||
for (const k of m.keys()) {
|
||||
console.log(k)
|
||||
}
|
11
crates/swc/tests/fixture/issues-6xxx/6028/output/input.js
Normal file
11
crates/swc/tests/fixture/issues-6xxx/6028/output/input.js
Normal file
@ -0,0 +1,11 @@
|
||||
import _create_for_of_iterator_helper_loose from "@swc/helpers/src/_create_for_of_iterator_helper_loose.mjs";
|
||||
var m = new Map([
|
||||
[
|
||||
1,
|
||||
2
|
||||
]
|
||||
]);
|
||||
for(var _iterator = _create_for_of_iterator_helper_loose(m.keys()), _step; !(_step = _iterator()).done;){
|
||||
var k = _step.value;
|
||||
console.log(k);
|
||||
}
|
@ -246,6 +246,7 @@ where
|
||||
pass,
|
||||
ForOf,
|
||||
es2015::for_of(es2015::for_of::Config {
|
||||
loose,
|
||||
assume_array: loose || assumptions.iterable_is_array
|
||||
}),
|
||||
true
|
||||
|
@ -0,0 +1,19 @@
|
||||
|
||||
function _createForOfIteratorHelperLoose(o, allowArrayLike) {
|
||||
var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
|
||||
if (it) return (it = it.call(o)).next.bind(it);
|
||||
// Fallback for engines without symbol support
|
||||
if (
|
||||
Array.isArray(o) ||
|
||||
(it = unsupportedIterableToArray(o)) ||
|
||||
(allowArrayLike && o && typeof o.length === "number")
|
||||
) {
|
||||
if (it) o = it;
|
||||
var i = 0;
|
||||
return function () {
|
||||
if (i >= o.length) return { done: true };
|
||||
return { done: false, value: o[i++] };
|
||||
}
|
||||
}
|
||||
throw new TypeError("Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
||||
}
|
@ -356,6 +356,8 @@ define_helpers!(Helpers {
|
||||
possible_constructor_return
|
||||
),
|
||||
|
||||
create_for_of_iterator_helper_loose: (unsupported_iterable_to_array),
|
||||
|
||||
ts_decorate: (),
|
||||
ts_generator: (),
|
||||
ts_metadata: (),
|
||||
|
@ -4,7 +4,10 @@ use serde::Deserialize;
|
||||
use swc_atoms::js_word;
|
||||
use swc_common::{util::take::Take, Mark, Spanned, DUMMY_SP};
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_transforms_base::perf::{ParExplode, Parallel};
|
||||
use swc_ecma_transforms_base::{
|
||||
helper,
|
||||
perf::{ParExplode, Parallel},
|
||||
};
|
||||
use swc_ecma_transforms_macros::parallel;
|
||||
use swc_ecma_utils::{
|
||||
alias_if_required, member_expr, prepend_stmt, private_ident, quote_ident, ExprFactory,
|
||||
@ -57,6 +60,7 @@ pub fn for_of(c: Config) -> impl Fold + VisitMut {
|
||||
#[derive(Debug, Clone, Copy, Default, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Config {
|
||||
pub loose: bool,
|
||||
pub assume_array: bool,
|
||||
}
|
||||
|
||||
@ -84,7 +88,7 @@ impl ForOf {
|
||||
..
|
||||
}: ForOfStmt,
|
||||
) -> Stmt {
|
||||
if right.is_array() || self.c.assume_array {
|
||||
if right.is_array() || (self.c.assume_array && !self.c.loose) {
|
||||
// Convert to normal for loop if rhs is array
|
||||
//
|
||||
// babel's output:
|
||||
@ -199,6 +203,124 @@ impl ForOf {
|
||||
};
|
||||
}
|
||||
|
||||
// Loose mode
|
||||
if self.c.loose {
|
||||
let iterator = private_ident!("_iterator");
|
||||
let step = private_ident!("_step");
|
||||
|
||||
let decls = vec![
|
||||
VarDeclarator {
|
||||
span: DUMMY_SP,
|
||||
name: iterator.clone().into(),
|
||||
init: Some(Box::new(Expr::Call(CallExpr {
|
||||
span: DUMMY_SP,
|
||||
callee: helper!(
|
||||
create_for_of_iterator_helper_loose,
|
||||
"createForOfIteratorHelperLoose"
|
||||
),
|
||||
args: vec![right.as_arg()],
|
||||
type_args: Default::default(),
|
||||
}))),
|
||||
definite: Default::default(),
|
||||
},
|
||||
VarDeclarator {
|
||||
span: DUMMY_SP,
|
||||
name: step.clone().into(),
|
||||
init: None,
|
||||
definite: Default::default(),
|
||||
},
|
||||
];
|
||||
|
||||
let mut body = match *body {
|
||||
Stmt::Block(b) => b,
|
||||
_ => BlockStmt {
|
||||
span: DUMMY_SP,
|
||||
stmts: vec![*body],
|
||||
},
|
||||
};
|
||||
|
||||
match left {
|
||||
VarDeclOrPat::VarDecl(var) => {
|
||||
assert_eq!(
|
||||
var.decls.len(),
|
||||
1,
|
||||
"Variable declarator of for of loop cannot contain multiple entries"
|
||||
);
|
||||
prepend_stmt(
|
||||
&mut body.stmts,
|
||||
VarDecl {
|
||||
span: DUMMY_SP,
|
||||
kind: var.kind,
|
||||
declare: false,
|
||||
decls: vec![VarDeclarator {
|
||||
span: DUMMY_SP,
|
||||
name: var.decls.into_iter().next().unwrap().name,
|
||||
init: Some(step.clone().make_member(quote_ident!("value")).into()),
|
||||
definite: false,
|
||||
}],
|
||||
}
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
|
||||
VarDeclOrPat::Pat(pat) => prepend_stmt(
|
||||
&mut body.stmts,
|
||||
AssignExpr {
|
||||
span: DUMMY_SP,
|
||||
left: pat.into(),
|
||||
op: op!("="),
|
||||
right: step.clone().make_member(quote_ident!("value")).into(),
|
||||
}
|
||||
.into_stmt(),
|
||||
),
|
||||
}
|
||||
|
||||
// !(_step = _iterator()).done;
|
||||
let test = Box::new(Expr::Unary(UnaryExpr {
|
||||
span: DUMMY_SP,
|
||||
op: op!("!"),
|
||||
arg: AssignExpr {
|
||||
span: DUMMY_SP,
|
||||
op: op!("="),
|
||||
left: step.into(),
|
||||
right: CallExpr {
|
||||
span: DUMMY_SP,
|
||||
callee: iterator.as_callee(),
|
||||
args: vec![],
|
||||
type_args: Default::default(),
|
||||
}
|
||||
.into(),
|
||||
}
|
||||
.make_member(quote_ident!("done"))
|
||||
.into(),
|
||||
}));
|
||||
|
||||
let stmt = Stmt::For(ForStmt {
|
||||
span,
|
||||
init: Some(
|
||||
VarDecl {
|
||||
span: DUMMY_SP,
|
||||
kind: VarDeclKind::Var,
|
||||
declare: false,
|
||||
decls,
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
test: Some(test),
|
||||
update: None,
|
||||
body: Box::new(Stmt::Block(body)),
|
||||
});
|
||||
return match label {
|
||||
Some(label) => LabeledStmt {
|
||||
span,
|
||||
label,
|
||||
body: Box::new(stmt),
|
||||
}
|
||||
.into(),
|
||||
_ => stmt,
|
||||
};
|
||||
}
|
||||
|
||||
let var_span = left.span().apply_mark(Mark::fresh(Mark::root()));
|
||||
|
||||
let mut body = match *body {
|
||||
|
@ -293,7 +293,10 @@ try {
|
||||
// for_of_as_array_for_of
|
||||
test!(
|
||||
syntax(),
|
||||
|_| for_of(Config { assume_array: true }),
|
||||
|_| for_of(Config {
|
||||
assume_array: true,
|
||||
..Default::default()
|
||||
}),
|
||||
for_of_as_array_for_of,
|
||||
r#"
|
||||
let elm;
|
||||
@ -317,7 +320,10 @@ for(let _i = 0; _i < array.length; _i++){
|
||||
// for_of_as_array_for_of_array_pattern
|
||||
test!(
|
||||
syntax(),
|
||||
|_| for_of(Config { assume_array: true }),
|
||||
|_| for_of(Config {
|
||||
assume_array: true,
|
||||
..Default::default()
|
||||
}),
|
||||
for_of_as_array_for_of_array_pattern,
|
||||
r#"
|
||||
let elm;
|
||||
@ -340,7 +346,10 @@ for(let _i = 0; _i < array.length; _i++){
|
||||
// regression_redeclare_array_8913
|
||||
test!(
|
||||
syntax(),
|
||||
|_| for_of(Config { assume_array: true }),
|
||||
|_| for_of(Config {
|
||||
assume_array: true,
|
||||
..Default::default()
|
||||
}),
|
||||
regression_redeclare_array_8913,
|
||||
r#"
|
||||
function f(...t) {
|
||||
@ -364,7 +373,10 @@ function f(...t) {
|
||||
// for_of_as_array_for_of_declaration_array_pattern
|
||||
test!(
|
||||
syntax(),
|
||||
|_| for_of(Config { assume_array: true }),
|
||||
|_| for_of(Config {
|
||||
assume_array: true,
|
||||
..Default::default()
|
||||
}),
|
||||
for_of_as_array_for_of_declaration_array_pattern,
|
||||
r#"
|
||||
for (const [elm] of array) {
|
||||
@ -383,7 +395,10 @@ for(let _i = 0; _i < array.length; _i++){
|
||||
// for_of_as_array_for_of_expression
|
||||
test!(
|
||||
syntax(),
|
||||
|_| for_of(Config { assume_array: true }),
|
||||
|_| for_of(Config {
|
||||
assume_array: true,
|
||||
..Default::default()
|
||||
}),
|
||||
for_of_as_array_for_of_expression,
|
||||
r#"
|
||||
let i;
|
||||
@ -404,7 +419,10 @@ for(let _i = 0; _i < items.length; _i++){
|
||||
// for_of_as_array_for_of_declaration
|
||||
test!(
|
||||
syntax(),
|
||||
|_| for_of(Config { assume_array: true }),
|
||||
|_| for_of(Config {
|
||||
assume_array: true,
|
||||
..Default::default()
|
||||
}),
|
||||
for_of_as_array_for_of_declaration,
|
||||
r#"
|
||||
for (const elm of array) {
|
||||
@ -445,7 +463,10 @@ expect(results).toEqual([1, 2, 3]);
|
||||
// for_of_as_array_for_of_static_declaration
|
||||
test!(
|
||||
syntax(),
|
||||
|_| for_of(Config { assume_array: true }),
|
||||
|_| for_of(Config {
|
||||
assume_array: true,
|
||||
..Default::default()
|
||||
}),
|
||||
for_of_as_array_for_of_static_declaration,
|
||||
r#"
|
||||
const array = [];
|
||||
@ -469,7 +490,10 @@ for(let _i = 0; _i < array.length; _i++){
|
||||
// for_of_as_array_for_of_static
|
||||
test!(
|
||||
syntax(),
|
||||
|_| for_of(Config { assume_array: true }),
|
||||
|_| for_of(Config {
|
||||
assume_array: true,
|
||||
..Default::default()
|
||||
}),
|
||||
for_of_as_array_for_of_static,
|
||||
r#"
|
||||
const array = [];
|
||||
@ -495,7 +519,10 @@ for (let _i = 0; _i < array.length; _i++) {
|
||||
// for_of_as_array_for_of_import_es2015
|
||||
test!(
|
||||
syntax(),
|
||||
|_| for_of(Config { assume_array: true }),
|
||||
|_| for_of(Config {
|
||||
assume_array: true,
|
||||
..Default::default()
|
||||
}),
|
||||
for_of_as_array_for_of_import_es2015,
|
||||
r#"
|
||||
import { array } from "foo";
|
||||
@ -560,7 +587,10 @@ try {
|
||||
// regression_if_label_3858
|
||||
test!(
|
||||
syntax(),
|
||||
|_| for_of(Config { assume_array: true }),
|
||||
|_| for_of(Config {
|
||||
assume_array: true,
|
||||
..Default::default()
|
||||
}),
|
||||
regression_if_label_3858,
|
||||
r#"
|
||||
if ( true )
|
||||
@ -591,6 +621,7 @@ fn fixture(input: PathBuf) {
|
||||
resolver(Mark::new(), top_level_mark, false),
|
||||
for_of(Config {
|
||||
assume_array: false,
|
||||
..Default::default()
|
||||
})
|
||||
)
|
||||
},
|
||||
|
@ -63,7 +63,10 @@ fn esm_to_amd(input: PathBuf) {
|
||||
test!(
|
||||
syntax(),
|
||||
|t| chain!(
|
||||
for_of(for_of::Config { assume_array: true }),
|
||||
for_of(for_of::Config {
|
||||
assume_array: true,
|
||||
..Default::default()
|
||||
}),
|
||||
tr(Default::default(), false, t.comments.clone())
|
||||
),
|
||||
for_of_as_array_for_of_import_amd,
|
||||
|
@ -65,7 +65,10 @@ fn esm_to_cjs(input: PathBuf) {
|
||||
test!(
|
||||
syntax(),
|
||||
|tester| chain!(
|
||||
for_of(for_of::Config { assume_array: true }),
|
||||
for_of(for_of::Config {
|
||||
assume_array: true,
|
||||
..Default::default()
|
||||
}),
|
||||
tr(Default::default(), false, tester.comments.clone())
|
||||
),
|
||||
for_of_as_array_for_of_import_commonjs,
|
||||
|
@ -0,0 +1,20 @@
|
||||
import unsupportedIterableToArray from "./_unsupported_iterable_to_array.mjs";
|
||||
|
||||
export default function _createForOfIteratorHelperLoose(o, allowArrayLike) {
|
||||
var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
|
||||
if (it) return (it = it.call(o)).next.bind(it);
|
||||
// Fallback for engines without symbol support
|
||||
if (
|
||||
Array.isArray(o) ||
|
||||
(it = unsupportedIterableToArray(o)) ||
|
||||
(allowArrayLike && o && typeof o.length === "number")
|
||||
) {
|
||||
if (it) o = it;
|
||||
var i = 0;
|
||||
return function () {
|
||||
if (i >= o.length) return { done: true };
|
||||
return { done: false, value: o[i++] };
|
||||
}
|
||||
}
|
||||
throw new TypeError("Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
||||
}
|
Loading…
Reference in New Issue
Block a user