Extract for-of iterator handling to a helper (#11262)

* Extract for-of iterator handling to a helper

Dis greatly recudes the code size when for-of is used multiple times across the
codebase. Also, makes it easier to read what's happening in a compiled loop.

* Unify spec and loose code

* Legacy implementation fallback

* Update tmp var name

* Updates from review and after rebase
This commit is contained in:
Nicolò Ribaudo 2020-03-17 00:45:34 +01:00 committed by GitHub
parent a11855e586
commit 59976680df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 624 additions and 576 deletions

View File

@ -1036,6 +1036,61 @@ helpers.nonIterableRest = helper("7.0.0-beta.0")`
} }
`; `;
helpers.createForOfIteratorHelper = helper("7.9.0")`
// s: start (create the iterator)
// n: next
// e: error (called whenever something throws)
// f: finish (always called at the end)
export default function _createForOfIteratorHelper(o) {
if (typeof Symbol === "undefined" || o[Symbol.iterator] == null)
throw new TypeError("Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
var it, normalCompletion = true, didErr = false, err;
return {
s() {
it = o[Symbol.iterator]();
},
n() {
var step = it.next();
normalCompletion = step.done;
return step;
},
e(e) {
didErr = true;
err = e;
},
f() {
try {
if (!normalCompletion && it.return != null) it.return();
} finally {
if (didErr) throw err;
}
}
};
}
`;
helpers.createForOfIteratorHelperLoose = helper("7.9.0")`
export default function _createForOfIteratorHelperLoose(o) {
var i = 0;
if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) {
if (Array.isArray(o))
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.");
}
i = o[Symbol.iterator]();
return i.next.bind(i);
}
`;
helpers.skipFirstGeneratorNext = helper("7.0.0-beta.0")` helpers.skipFirstGeneratorNext = helper("7.0.0-beta.0")`
export default function _skipFirstGeneratorNext(fn) { export default function _skipFirstGeneratorNext(fn) {
return function () { return function () {

View File

@ -4,6 +4,7 @@
"syntax-jsx", "syntax-jsx",
"transform-react-jsx", "transform-react-jsx",
"transform-block-scoped-functions", "transform-block-scoped-functions",
"transform-for-of" "transform-for-of",
["external-helpers", { "helperVersion": "7.100.0" }]
] ]
} }

View File

@ -10,12 +10,11 @@ var _loop = function (i) {
}); });
}; };
var _iteratorNormalCompletion = true; var _iterator = babelHelpers.createForOfIteratorHelper(nums),
var _didIteratorError = false; _step;
var _iteratorError = undefined;
try { try {
for (var _iterator = nums[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { for (_iterator.s(); !(_step = _iterator.n()).done;) {
var i = _step.value; var i = _step.value;
var x; var x;
var f; var f;
@ -23,16 +22,7 @@ try {
_loop(i); _loop(i);
} }
} catch (err) { } catch (err) {
_didIteratorError = true; _iterator.e(err);
_iteratorError = err;
} finally { } finally {
try { _iterator.f();
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
} }

View File

@ -1,6 +1,8 @@
import { declare } from "@babel/helper-plugin-utils"; import { declare } from "@babel/helper-plugin-utils";
import { template, types as t } from "@babel/core"; import { template, types as t } from "@babel/core";
import transformWithoutHelper from "./no-helper-implementation";
export default declare((api, options) => { export default declare((api, options) => {
api.assertVersion(7); api.assertVersion(7);
@ -79,56 +81,37 @@ export default declare((api, options) => {
}; };
} }
const pushComputedProps = loose
? pushComputedPropsLoose
: pushComputedPropsSpec;
const buildForOfArray = template(` const buildForOfArray = template(`
for (var KEY = 0, NAME = ARR; KEY < NAME.length; KEY++) BODY; for (var KEY = 0, NAME = ARR; KEY < NAME.length; KEY++) BODY;
`); `);
const buildForOfLoose = template(` const buildForOfLoose = template.statements(`
for (var LOOP_OBJECT = OBJECT, for (var ITERATOR_HELPER = CREATE_ITERATOR_HELPER(OBJECT), STEP_KEY;
IS_ARRAY = Array.isArray(LOOP_OBJECT), !(STEP_KEY = ITERATOR_HELPER()).done;) BODY;
INDEX = 0, `);
LOOP_OBJECT = IS_ARRAY ? LOOP_OBJECT : LOOP_OBJECT[Symbol.iterator]();;) {
INTERMEDIATE; const buildForOf = template.statements(`
if (IS_ARRAY) { var ITERATOR_HELPER = CREATE_ITERATOR_HELPER(OBJECT), STEP_KEY;
if (INDEX >= LOOP_OBJECT.length) break; try {
ID = LOOP_OBJECT[INDEX++]; for (ITERATOR_HELPER.s(); !(STEP_KEY = ITERATOR_HELPER.n()).done;) BODY;
} else { } catch (err) {
INDEX = LOOP_OBJECT.next(); ITERATOR_HELPER.e(err);
if (INDEX.done) break; } finally {
ID = INDEX.value; ITERATOR_HELPER.f();
}
} }
`); `);
const buildForOf = template(` const builder = loose
var ITERATOR_COMPLETION = true; ? {
var ITERATOR_HAD_ERROR_KEY = false; build: buildForOfLoose,
var ITERATOR_ERROR_KEY = undefined; helper: "createForOfIteratorHelperLoose",
try { getContainer: nodes => nodes,
for (
var ITERATOR_KEY = OBJECT[Symbol.iterator](), STEP_KEY;
!(ITERATOR_COMPLETION = (STEP_KEY = ITERATOR_KEY.next()).done);
ITERATOR_COMPLETION = true
) {}
} catch (err) {
ITERATOR_HAD_ERROR_KEY = true;
ITERATOR_ERROR_KEY = err;
} finally {
try {
if (!ITERATOR_COMPLETION && ITERATOR_KEY.return != null) {
ITERATOR_KEY.return();
}
} finally {
if (ITERATOR_HAD_ERROR_KEY) {
throw ITERATOR_ERROR_KEY;
}
} }
} : {
`); build: buildForOf,
helper: "createForOfIteratorHelper",
getContainer: nodes => nodes[1].block.body,
};
function _ForOfStatementArray(path) { function _ForOfStatementArray(path) {
const { node, scope } = path; const { node, scope } = path;
@ -136,7 +119,7 @@ export default declare((api, options) => {
const right = scope.generateUidIdentifierBasedOnNode(node.right, "arr"); const right = scope.generateUidIdentifierBasedOnNode(node.right, "arr");
const iterationKey = scope.generateUidIdentifier("i"); const iterationKey = scope.generateUidIdentifier("i");
let loop = buildForOfArray({ const loop = buildForOfArray({
BODY: node.body, BODY: node.body,
KEY: iterationKey, KEY: iterationKey,
NAME: right, NAME: right,
@ -164,19 +147,7 @@ export default declare((api, options) => {
); );
} }
if (path.parentPath.isLabeledStatement()) { return loop;
loop = t.labeledStatement(path.parentPath.node.label, loop);
}
return [loop];
}
function replaceWithArray(path) {
if (path.parentPath.isLabeledStatement()) {
path.parentPath.replaceWithMultiple(_ForOfStatementArray(path));
} else {
path.replaceWithMultiple(_ForOfStatementArray(path));
}
} }
return { return {
@ -189,156 +160,64 @@ export default declare((api, options) => {
right.isGenericType("Array") || right.isGenericType("Array") ||
t.isArrayTypeAnnotation(right.getTypeAnnotation()) t.isArrayTypeAnnotation(right.getTypeAnnotation())
) { ) {
replaceWithArray(path); path.replaceWith(_ForOfStatementArray(path));
return; return;
} }
const { node } = path; if (!state.availableHelper(builder.helper)) {
const build = pushComputedProps(path, state); // Babel <7.9.0 doesn't support this helper
const declar = build.declar; transformWithoutHelper(loose, path, state);
const loop = build.loop; return;
const block = loop.body; }
const { node, parent, scope } = path;
const left = node.left;
let declar;
const stepKey = scope.generateUid("step");
const stepValue = t.memberExpression(
t.identifier(stepKey),
t.identifier("value"),
);
if (t.isVariableDeclaration(left)) {
// for (let i of test)
declar = t.variableDeclaration(left.kind, [
t.variableDeclarator(left.declarations[0].id, stepValue),
]);
} else {
// for (i of test), for ({ i } of test)
declar = t.expressionStatement(
t.assignmentExpression("=", left, stepValue),
);
}
// ensure that it's a block so we can take all its statements // ensure that it's a block so we can take all its statements
path.ensureBlock(); path.ensureBlock();
// add the value declaration to the new loop body node.body.body.unshift(declar);
if (declar) {
block.body.push(declar);
}
// push the rest of the original loop body onto our new body const nodes = builder.build({
block.body = block.body.concat(node.body.body); CREATE_ITERATOR_HELPER: state.addHelper(builder.helper),
ITERATOR_HELPER: scope.generateUidIdentifier("iterator"),
STEP_KEY: t.identifier(stepKey),
OBJECT: node.right,
BODY: node.body,
});
const container = builder.getContainer(nodes);
t.inherits(loop, node); t.inherits(container[0], node);
t.inherits(loop.body, node.body); t.inherits(container[0].body, node.body);
if (build.replaceParent) { if (t.isLabeledStatement(parent)) {
path.parentPath.replaceWithMultiple(build.node); container[0] = t.labeledStatement(parent.label, container[0]);
path.parentPath.replaceWithMultiple(nodes);
path.remove(); path.remove();
} else { } else {
path.replaceWithMultiple(build.node); path.replaceWithMultiple(nodes);
} }
}, },
}, },
}; };
function pushComputedPropsLoose(path, file) {
const { node, scope, parent } = path;
const { left } = node;
let declar, id, intermediate;
if (
t.isIdentifier(left) ||
t.isPattern(left) ||
t.isMemberExpression(left)
) {
// for (i of test), for ({ i } of test)
id = left;
intermediate = null;
} else if (t.isVariableDeclaration(left)) {
// for (let i of test)
id = scope.generateUidIdentifier("ref");
declar = t.variableDeclaration(left.kind, [
t.variableDeclarator(left.declarations[0].id, t.identifier(id.name)),
]);
intermediate = t.variableDeclaration("var", [
t.variableDeclarator(t.identifier(id.name)),
]);
} else {
throw file.buildCodeFrameError(
left,
`Unknown node type ${left.type} in ForStatement`,
);
}
const iteratorKey = scope.generateUidIdentifier("iterator");
const isArrayKey = scope.generateUidIdentifier("isArray");
const loop = buildForOfLoose({
LOOP_OBJECT: iteratorKey,
IS_ARRAY: isArrayKey,
OBJECT: node.right,
INDEX: scope.generateUidIdentifier("i"),
ID: id,
INTERMEDIATE: intermediate,
});
//
const isLabeledParent = t.isLabeledStatement(parent);
let labeled;
if (isLabeledParent) {
labeled = t.labeledStatement(parent.label, loop);
}
return {
replaceParent: isLabeledParent,
declar: declar,
node: labeled || loop,
loop: loop,
};
}
function pushComputedPropsSpec(path, file) {
const { node, scope, parent } = path;
const left = node.left;
let declar;
const stepKey = scope.generateUid("step");
const stepValue = t.memberExpression(
t.identifier(stepKey),
t.identifier("value"),
);
if (
t.isIdentifier(left) ||
t.isPattern(left) ||
t.isMemberExpression(left)
) {
// for (i of test), for ({ i } of test)
declar = t.expressionStatement(
t.assignmentExpression("=", left, stepValue),
);
} else if (t.isVariableDeclaration(left)) {
// for (let i of test)
declar = t.variableDeclaration(left.kind, [
t.variableDeclarator(left.declarations[0].id, stepValue),
]);
} else {
throw file.buildCodeFrameError(
left,
`Unknown node type ${left.type} in ForStatement`,
);
}
const template = buildForOf({
ITERATOR_HAD_ERROR_KEY: scope.generateUidIdentifier("didIteratorError"),
ITERATOR_COMPLETION: scope.generateUidIdentifier(
"iteratorNormalCompletion",
),
ITERATOR_ERROR_KEY: scope.generateUidIdentifier("iteratorError"),
ITERATOR_KEY: scope.generateUidIdentifier("iterator"),
STEP_KEY: t.identifier(stepKey),
OBJECT: node.right,
});
const isLabeledParent = t.isLabeledStatement(parent);
const tryBody = template[3].block.body;
const loop = tryBody[0];
if (isLabeledParent) {
tryBody[0] = t.labeledStatement(parent.label, loop);
}
//
return {
replaceParent: isLabeledParent,
declar: declar,
loop: loop,
node: template,
};
}
}); });

View File

@ -0,0 +1,192 @@
import { template, types as t } from "@babel/core";
// This is the legacy implementation, which inlines all the code.
// It must be kept for compatibility reasons.
// TODO (Babel 8): Remove this code.
export default function transformWithoutHelper(loose, path, state) {
const pushComputedProps = loose
? pushComputedPropsLoose
: pushComputedPropsSpec;
const { node } = path;
const build = pushComputedProps(path, state);
const declar = build.declar;
const loop = build.loop;
const block = loop.body;
// ensure that it's a block so we can take all its statements
path.ensureBlock();
// add the value declaration to the new loop body
if (declar) {
block.body.push(declar);
}
// push the rest of the original loop body onto our new body
block.body = block.body.concat(node.body.body);
t.inherits(loop, node);
t.inherits(loop.body, node.body);
if (build.replaceParent) {
path.parentPath.replaceWithMultiple(build.node);
path.remove();
} else {
path.replaceWithMultiple(build.node);
}
}
const buildForOfLoose = template(`
for (var LOOP_OBJECT = OBJECT,
IS_ARRAY = Array.isArray(LOOP_OBJECT),
INDEX = 0,
LOOP_OBJECT = IS_ARRAY ? LOOP_OBJECT : LOOP_OBJECT[Symbol.iterator]();;) {
INTERMEDIATE;
if (IS_ARRAY) {
if (INDEX >= LOOP_OBJECT.length) break;
ID = LOOP_OBJECT[INDEX++];
} else {
INDEX = LOOP_OBJECT.next();
if (INDEX.done) break;
ID = INDEX.value;
}
}
`);
const buildForOf = template(`
var ITERATOR_COMPLETION = true;
var ITERATOR_HAD_ERROR_KEY = false;
var ITERATOR_ERROR_KEY = undefined;
try {
for (
var ITERATOR_KEY = OBJECT[Symbol.iterator](), STEP_KEY;
!(ITERATOR_COMPLETION = (STEP_KEY = ITERATOR_KEY.next()).done);
ITERATOR_COMPLETION = true
) {}
} catch (err) {
ITERATOR_HAD_ERROR_KEY = true;
ITERATOR_ERROR_KEY = err;
} finally {
try {
if (!ITERATOR_COMPLETION && ITERATOR_KEY.return != null) {
ITERATOR_KEY.return();
}
} finally {
if (ITERATOR_HAD_ERROR_KEY) {
throw ITERATOR_ERROR_KEY;
}
}
}
`);
function pushComputedPropsLoose(path, file) {
const { node, scope, parent } = path;
const { left } = node;
let declar, id, intermediate;
if (t.isIdentifier(left) || t.isPattern(left) || t.isMemberExpression(left)) {
// for (i of test), for ({ i } of test)
id = left;
intermediate = null;
} else if (t.isVariableDeclaration(left)) {
// for (let i of test)
id = scope.generateUidIdentifier("ref");
declar = t.variableDeclaration(left.kind, [
t.variableDeclarator(left.declarations[0].id, t.identifier(id.name)),
]);
intermediate = t.variableDeclaration("var", [
t.variableDeclarator(t.identifier(id.name)),
]);
} else {
throw file.buildCodeFrameError(
left,
`Unknown node type ${left.type} in ForStatement`,
);
}
const iteratorKey = scope.generateUidIdentifier("iterator");
const isArrayKey = scope.generateUidIdentifier("isArray");
const loop = buildForOfLoose({
LOOP_OBJECT: iteratorKey,
IS_ARRAY: isArrayKey,
OBJECT: node.right,
INDEX: scope.generateUidIdentifier("i"),
ID: id,
INTERMEDIATE: intermediate,
});
//
const isLabeledParent = t.isLabeledStatement(parent);
let labeled;
if (isLabeledParent) {
labeled = t.labeledStatement(parent.label, loop);
}
return {
replaceParent: isLabeledParent,
declar: declar,
node: labeled || loop,
loop: loop,
};
}
function pushComputedPropsSpec(path, file) {
const { node, scope, parent } = path;
const left = node.left;
let declar;
const stepKey = scope.generateUid("step");
const stepValue = t.memberExpression(
t.identifier(stepKey),
t.identifier("value"),
);
if (t.isIdentifier(left) || t.isPattern(left) || t.isMemberExpression(left)) {
// for (i of test), for ({ i } of test)
declar = t.expressionStatement(
t.assignmentExpression("=", left, stepValue),
);
} else if (t.isVariableDeclaration(left)) {
// for (let i of test)
declar = t.variableDeclaration(left.kind, [
t.variableDeclarator(left.declarations[0].id, stepValue),
]);
} else {
throw file.buildCodeFrameError(
left,
`Unknown node type ${left.type} in ForStatement`,
);
}
const template = buildForOf({
ITERATOR_HAD_ERROR_KEY: scope.generateUidIdentifier("didIteratorError"),
ITERATOR_COMPLETION: scope.generateUidIdentifier(
"iteratorNormalCompletion",
),
ITERATOR_ERROR_KEY: scope.generateUidIdentifier("iteratorError"),
ITERATOR_KEY: scope.generateUidIdentifier("iterator"),
STEP_KEY: t.identifier(stepKey),
OBJECT: node.right,
});
const isLabeledParent = t.isLabeledStatement(parent);
const tryBody = template[3].block.body;
const loop = tryBody[0];
if (isLabeledParent) {
tryBody[0] = t.labeledStatement(parent.label, loop);
}
//
return {
replaceParent: isLabeledParent,
declar: declar,
loop: loop,
node: template,
};
}

View File

@ -0,0 +1,9 @@
let arr = (() => [1, 2, 3])(); // Disable inference
let res = [];
for (const x of arr) {
if (x === 2) break;
res.push(x);
}
expect(res).toEqual([1]);

View File

@ -0,0 +1,9 @@
let arr = (() => [1, 2, 3])(); // Disable inference
let res = [];
for (const x of arr) {
if (x === 2) continue;
res.push(x);
}
expect(res).toEqual([1, 3]);

View File

@ -0,0 +1,6 @@
let arr = (() => [1, 2, 3])(); // Disable inference
let res = [];
for (const x of arr) res.push(x);
expect(res).toEqual([1, 2, 3]);

View File

@ -0,0 +1,12 @@
function* f() {
yield 1; yield 2; yield 3;
}
let res = [];
for (const x of f()) {
if (x === 2) break;
res.push(x);
}
expect(res).toEqual([1]);

View File

@ -0,0 +1,12 @@
function* f() {
yield 1; yield 2; yield 3;
}
let res = [];
for (const x of f()) {
if (x === 2) continue;
res.push(x);
}
expect(res).toEqual([1, 3]);

View File

@ -0,0 +1,9 @@
function* f() {
yield 1; yield 2; yield 3;
}
let res = [];
for (const x of f()) res.push(x);
expect(res).toEqual([1, 2, 3]);

View File

@ -0,0 +1,6 @@
{
"plugins": [
["transform-for-of", { "loose": true }],
["external-helpers", { "helperVersion": "7.100.0" }]
]
}

View File

@ -1,10 +1,3 @@
for (var _iterator = arr, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { for (var _iterator = babelHelpers.createForOfIteratorHelperLoose(arr), _step; !(_step = _iterator()).done;) {
if (_isArray) { i = _step.value;
if (_i >= _iterator.length) break;
i = _iterator[_i++];
} else {
_i = _iterator.next();
if (_i.done) break;
i = _i.value;
}
} }

View File

@ -1,16 +1,5 @@
for (var _iterator = foo, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { for (var _iterator = babelHelpers.createForOfIteratorHelperLoose(foo), _step; !(_step = _iterator()).done;) {
var _ref; var i = _step.value;
if (_isArray) {
if (_i >= _iterator.length) break;
_ref = _iterator[_i++];
} else {
_i = _iterator.next();
if (_i.done) break;
_ref = _i.value;
}
var i = _ref;
switch (i) { switch (i) {
case 1: case 1:

View File

@ -1,14 +1,3 @@
for (var _iterator = arr, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { for (var _iterator = babelHelpers.createForOfIteratorHelperLoose(arr), _step; !(_step = _iterator()).done;) {
var _ref; let i = _step.value;
if (_isArray) {
if (_i >= _iterator.length) break;
_ref = _iterator[_i++];
} else {
_i = _iterator.next();
if (_i.done) break;
_ref = _i.value;
}
let i = _ref;
} }

View File

@ -1,10 +1,3 @@
for (var _iterator = arr, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { for (var _iterator = babelHelpers.createForOfIteratorHelperLoose(arr), _step; !(_step = _iterator()).done;) {
if (_isArray) { obj.prop = _step.value;
if (_i >= _iterator.length) break;
obj.prop = _iterator[_i++];
} else {
_i = _iterator.next();
if (_i.done) break;
obj.prop = _i.value;
}
} }

View File

@ -1,29 +1,7 @@
for (var _iterator = arr, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { for (var _iterator = babelHelpers.createForOfIteratorHelperLoose(arr), _step; !(_step = _iterator()).done;) {
var _ref; var i = _step.value;
if (_isArray) {
if (_i >= _iterator.length) break;
_ref = _iterator[_i++];
} else {
_i = _iterator.next();
if (_i.done) break;
_ref = _i.value;
}
var i = _ref;
} }
for (var _iterator2 = numbers, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { for (var _iterator2 = babelHelpers.createForOfIteratorHelperLoose(numbers), _step2; !(_step2 = _iterator2()).done;) {
var _ref2; var i = _step2.value;
if (_isArray2) {
if (_i2 >= _iterator2.length) break;
_ref2 = _iterator2[_i2++];
} else {
_i2 = _iterator2.next();
if (_i2.done) break;
_ref2 = _i2.value;
}
var i = _ref2;
} }

View File

@ -1,30 +1,8 @@
b: for (var _iterator = d(), _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { b: for (var _iterator = babelHelpers.createForOfIteratorHelperLoose(d()), _step; !(_step = _iterator()).done;) {
var _ref; let c = _step.value;
if (_isArray) { for (var _iterator2 = babelHelpers.createForOfIteratorHelperLoose(f()), _step2; !(_step2 = _iterator2()).done;) {
if (_i >= _iterator.length) break; let e = _step2.value;
_ref = _iterator[_i++];
} else {
_i = _iterator.next();
if (_i.done) break;
_ref = _i.value;
}
let c = _ref;
for (var _iterator2 = f(), _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) {
var _ref2;
if (_isArray2) {
if (_i2 >= _iterator2.length) break;
_ref2 = _iterator2[_i2++];
} else {
_i2 = _iterator2.next();
if (_i2.done) break;
_ref2 = _i2.value;
}
let e = _ref2;
continue b; continue b;
} }
} }

View File

@ -1,3 +1,6 @@
{ {
"plugins": [["transform-for-of", { "loose": true }]] "plugins": [
["transform-for-of", { "loose": true }],
["external-helpers", { "helperVersion": "7.100.0" }]
]
} }

View File

@ -1,14 +1,3 @@
for (var _iterator = arr, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { for (var _iterator = babelHelpers.createForOfIteratorHelperLoose(arr), _step; !(_step = _iterator()).done;) {
var _ref; var i = _step.value;
if (_isArray) {
if (_i >= _iterator.length) break;
_ref = _iterator[_i++];
} else {
_i = _iterator.next();
if (_i.done) break;
_ref = _i.value;
}
var i = _ref;
} }

View File

@ -1,3 +1,7 @@
{ {
"plugins": ["transform-for-of", "transform-flow-strip-types"] "plugins": [
"transform-for-of",
"transform-flow-strip-types",
["external-helpers", { "helperVersion": "7.100.0" }]
]
} }

View File

@ -3,26 +3,16 @@ for (var _i = 0, _arr = b; _i < _arr.length; _i++) {
} }
function a(b) { function a(b) {
var _iteratorNormalCompletion = true; var _iterator = babelHelpers.createForOfIteratorHelper(b),
var _didIteratorError = false; _step;
var _iteratorError = undefined;
try { try {
for (var _iterator = b[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { for (_iterator.s(); !(_step = _iterator.n()).done;) {
const y = _step.value; const y = _step.value;
} }
} catch (err) { } catch (err) {
_didIteratorError = true; _iterator.e(err);
_iteratorError = err;
} finally { } finally {
try { _iterator.f();
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
} }
} }

View File

@ -1,5 +1,3 @@
if (true) { if (true) loop: for (var _i = 0, _arr = []; _i < _arr.length; _i++) {
loop: for (var _i = 0, _arr = []; _i < _arr.length; _i++) { let ch = _arr[_i];
let ch = _arr[_i];
}
} }

View File

@ -1,24 +1,14 @@
var _iteratorNormalCompletion = true; var _iterator = babelHelpers.createForOfIteratorHelper(b),
var _didIteratorError = false; _step;
var _iteratorError = undefined;
try { try {
myLabel: //woops myLabel: //woops
for (var _iterator = b[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { for (_iterator.s(); !(_step = _iterator.n()).done;) {
let a = _step.value; let a = _step.value;
continue myLabel; continue myLabel;
} }
} catch (err) { } catch (err) {
_didIteratorError = true; _iterator.e(err);
_iteratorError = err;
} finally { } finally {
try { _iterator.f();
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
} }

View File

@ -1,3 +1,6 @@
{ {
"plugins": ["transform-for-of"] "plugins": [
"transform-for-of",
["external-helpers", { "helperVersion": "7.100.0" }]
]
} }

View File

@ -0,0 +1,9 @@
let arr = (() => [1, 2, 3])(); // Disable inference
let res = [];
for (const x of arr) {
if (x === 2) break;
res.push(x);
}
expect(res).toEqual([1]);

View File

@ -0,0 +1,9 @@
let arr = (() => [1, 2, 3])(); // Disable inference
let res = [];
for (const x of arr) {
if (x === 2) continue;
res.push(x);
}
expect(res).toEqual([1, 3]);

View File

@ -0,0 +1,6 @@
let arr = (() => [1, 2, 3])(); // Disable inference
let res = [];
for (const x of arr) res.push(x);
expect(res).toEqual([1, 2, 3]);

View File

@ -0,0 +1,12 @@
function* f() {
yield 1; yield 2; yield 3;
}
let res = [];
for (const x of f()) {
if (x === 2) break;
res.push(x);
}
expect(res).toEqual([1]);

View File

@ -0,0 +1,12 @@
function* f() {
yield 1; yield 2; yield 3;
}
let res = [];
for (const x of f()) {
if (x === 2) continue;
res.push(x);
}
expect(res).toEqual([1, 3]);

View File

@ -0,0 +1,9 @@
function* f() {
yield 1; yield 2; yield 3;
}
let res = [];
for (const x of f()) res.push(x);
expect(res).toEqual([1, 2, 3]);

View File

@ -0,0 +1,6 @@
{
"plugins": [
["transform-for-of", { "loose": false }],
["external-helpers", { "helperVersion": "7.100.0" }]
]
}

View File

@ -0,0 +1,35 @@
let done = false, value = 0;
// jest.fn isn't available in exec tests
function fn(impl = () => {}) {
function f() {
f.calls++;
return impl();
}
f.calls = 0;
return f;
}
const iterator = {
next: fn(() => ({ done, value })),
throw: fn(),
return: fn(() => { throw {} }),
};
const obj = {
[Symbol.iterator]: fn(() => iterator),
};
const err = new Error();
expect(() => {
for (const x of obj) {
value++;
if (value == 2) throw err;
}
}).toThrow(err);
expect(obj[Symbol.iterator].calls).toBe(1);
expect(iterator.next.calls).toBe(2);
expect(iterator.throw.calls).toBe(0);
expect(iterator.return.calls).toBe(1);

View File

@ -1,22 +1,12 @@
var _iteratorNormalCompletion = true; var _iterator = babelHelpers.createForOfIteratorHelper(arr),
var _didIteratorError = false; _step;
var _iteratorError = undefined;
try { try {
for (var _iterator = arr[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { for (_iterator.s(); !(_step = _iterator.n()).done;) {
i = _step.value; i = _step.value;
} }
} catch (err) { } catch (err) {
_didIteratorError = true; _iterator.e(err);
_iteratorError = err;
} finally { } finally {
try { _iterator.f();
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
} }

View File

@ -1,9 +1,8 @@
var _iteratorNormalCompletion = true; var _iterator = babelHelpers.createForOfIteratorHelper(foo),
var _didIteratorError = false; _step;
var _iteratorError = undefined;
try { try {
for (var _iterator = foo[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { for (_iterator.s(); !(_step = _iterator.n()).done;) {
var i = _step.value; var i = _step.value;
switch (i) { switch (i) {
@ -12,16 +11,7 @@ try {
} }
} }
} catch (err) { } catch (err) {
_didIteratorError = true; _iterator.e(err);
_iteratorError = err;
} finally { } finally {
try { _iterator.f();
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
} }

View File

@ -1,22 +1,12 @@
var _iteratorNormalCompletion = true; var _iterator = babelHelpers.createForOfIteratorHelper(arr),
var _didIteratorError = false; _step;
var _iteratorError = undefined;
try { try {
for (var _iterator = arr[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { for (_iterator.s(); !(_step = _iterator.n()).done;) {
let i = _step.value; let i = _step.value;
} }
} catch (err) { } catch (err) {
_didIteratorError = true; _iterator.e(err);
_iteratorError = err;
} finally { } finally {
try { _iterator.f();
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
} }

View File

@ -1,22 +1,12 @@
var _iteratorNormalCompletion = true; var _iterator = babelHelpers.createForOfIteratorHelper(arr),
var _didIteratorError = false; _step;
var _iteratorError = undefined;
try { try {
for (var _iterator = arr[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { for (_iterator.s(); !(_step = _iterator.n()).done;) {
obj.prop = _step.value; obj.prop = _step.value;
} }
} catch (err) { } catch (err) {
_didIteratorError = true; _iterator.e(err);
_iteratorError = err;
} finally { } finally {
try { _iterator.f();
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
} }

View File

@ -1,45 +1,25 @@
var _iteratorNormalCompletion = true; var _iterator = babelHelpers.createForOfIteratorHelper(arr),
var _didIteratorError = false; _step;
var _iteratorError = undefined;
try { try {
for (var _iterator = arr[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { for (_iterator.s(); !(_step = _iterator.n()).done;) {
var i = _step.value; var i = _step.value;
} }
} catch (err) { } catch (err) {
_didIteratorError = true; _iterator.e(err);
_iteratorError = err;
} finally { } finally {
try { _iterator.f();
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
} }
var _iteratorNormalCompletion2 = true; var _iterator2 = babelHelpers.createForOfIteratorHelper(numbers),
var _didIteratorError2 = false; _step2;
var _iteratorError2 = undefined;
try { try {
for (var _iterator2 = numbers[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var i = _step2.value; var i = _step2.value;
} }
} catch (err) { } catch (err) {
_didIteratorError2 = true; _iterator2.e(err);
_iteratorError2 = err;
} finally { } finally {
try { _iterator2.f();
if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
} }

View File

@ -1,45 +1,26 @@
var _iteratorNormalCompletion = true; var _iterator = babelHelpers.createForOfIteratorHelper(d()),
var _didIteratorError = false; _step;
var _iteratorError = undefined;
try { try {
b: for (var _iterator = d()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { b: for (_iterator.s(); !(_step = _iterator.n()).done;) {
let c = _step.value; let c = _step.value;
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false; var _iterator2 = babelHelpers.createForOfIteratorHelper(f()),
var _iteratorError2 = undefined; _step2;
try { try {
for (var _iterator2 = f()[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
let e = _step2.value; let e = _step2.value;
continue b; continue b;
} }
} catch (err) { } catch (err) {
_didIteratorError2 = true; _iterator2.e(err);
_iteratorError2 = err;
} finally { } finally {
try { _iterator2.f();
if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
} }
} }
} catch (err) { } catch (err) {
_didIteratorError = true; _iterator.e(err);
_iteratorError = err;
} finally { } finally {
try { _iterator.f();
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
} }

View File

@ -1,3 +1,6 @@
{ {
"plugins": ["transform-for-of"] "plugins": [
"transform-for-of",
["external-helpers", { "helperVersion": "7.100.0" }]
]
} }

View File

@ -1,22 +1,12 @@
var _iteratorNormalCompletion = true; var _iterator = babelHelpers.createForOfIteratorHelper(arr),
var _didIteratorError = false; _step;
var _iteratorError = undefined;
try { try {
for (var _iterator = arr[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { for (_iterator.s(); !(_step = _iterator.n()).done;) {
var i = _step.value; var i = _step.value;
} }
} catch (err) { } catch (err) {
_didIteratorError = true; _iterator.e(err);
_iteratorError = err;
} finally { } finally {
try { _iterator.f();
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
} }

View File

@ -1,7 +1,7 @@
{ {
"plugins": [ "plugins": [
"proposal-class-properties", "proposal-class-properties",
"external-helpers", ["external-helpers", { "helperVersion": "7.100.0" }],
"syntax-typescript", "syntax-typescript",
"syntax-flow", "syntax-flow",
"transform-parameters", "transform-parameters",

View File

@ -153,28 +153,18 @@ function forOf() {
rest[_key16] = arguments[_key16]; rest[_key16] = arguments[_key16];
} }
var _iteratorNormalCompletion = true; var _iterator = babelHelpers.createForOfIteratorHelper(this),
var _didIteratorError = false; _step;
var _iteratorError = undefined;
try { try {
for (var _iterator = this[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { for (_iterator.s(); !(_step = _iterator.n()).done;) {
rest[0] = _step.value; rest[0] = _step.value;
; ;
} }
} catch (err) { } catch (err) {
_didIteratorError = true; _iterator.e(err);
_iteratorError = err;
} finally { } finally {
try { _iterator.f();
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
} }
} }

View File

@ -1,7 +1,3 @@
function _createSuper(Derived) { return function () { var Super = babelHelpers.getPrototypeOf(Derived), result; if (_isNativeReflectConstruct()) { var NewTarget = babelHelpers.getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return babelHelpers.possibleConstructorReturn(this, result); }; }
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 broken(x) { function broken(x) {
if (true) { if (true) {
var Foo = /*#__PURE__*/function (_Bar) { var Foo = /*#__PURE__*/function (_Bar) {
@ -9,7 +5,7 @@ function broken(x) {
babelHelpers.inherits(Foo, _Bar); babelHelpers.inherits(Foo, _Bar);
var _super = _createSuper(Foo); var _super = babelHelpers.createSuper(Foo);
function Foo() { function Foo() {
babelHelpers.classCallCheck(this, Foo); babelHelpers.classCallCheck(this, Foo);

View File

@ -1,3 +1,6 @@
{ {
"plugins": ["transform-for-of", ["transform-runtime", { "corejs": 2 }]] "plugins": [
"transform-for-of",
["transform-runtime", { "corejs": 2, "version": "7.100.0" }]
]
} }

View File

@ -1,24 +1,14 @@
var _getIterator = require("@babel/runtime-corejs2/core-js/get-iterator"); var _createForOfIteratorHelper = require("@babel/runtime-corejs2/helpers/createForOfIteratorHelper");
var _iteratorNormalCompletion = true; var _iterator = _createForOfIteratorHelper(arr),
var _didIteratorError = false; _step;
var _iteratorError = undefined;
try { try {
for (var _iterator = _getIterator(arr), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { for (_iterator.s(); !(_step = _iterator.n()).done;) {
var i = _step.value; var i = _step.value;
} }
} catch (err) { } catch (err) {
_didIteratorError = true; _iterator.e(err);
_iteratorError = err;
} finally { } finally {
try { _iterator.f();
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
} }

View File

@ -1,3 +1,6 @@
{ {
"plugins": ["transform-for-of", ["transform-runtime", { "corejs": 3 }]] "plugins": [
"transform-for-of",
["transform-runtime", { "corejs": 3, "version": "7.100.0" }]
]
} }

View File

@ -1,24 +1,14 @@
var _getIterator = require("@babel/runtime-corejs3/core-js/get-iterator"); var _createForOfIteratorHelper = require("@babel/runtime-corejs3/helpers/createForOfIteratorHelper");
var _iteratorNormalCompletion = true; var _iterator = _createForOfIteratorHelper(arr),
var _didIteratorError = false; _step;
var _iteratorError = undefined;
try { try {
for (var _iterator = _getIterator(arr), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { for (_iterator.s(); !(_step = _iterator.n()).done;) {
var i = _step.value; var i = _step.value;
} }
} catch (err) { } catch (err) {
_didIteratorError = true; _iterator.e(err);
_iteratorError = err;
} finally { } finally {
try { _iterator.f();
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
} }

View File

@ -1,3 +1,6 @@
{ {
"plugins": ["transform-for-of", "transform-runtime"] "plugins": [
"transform-for-of",
["transform-runtime", { "version": "7.100.0" }]
]
} }

View File

@ -1,22 +1,14 @@
var _iteratorNormalCompletion = true; var _createForOfIteratorHelper = require("@babel/runtime/helpers/createForOfIteratorHelper");
var _didIteratorError = false;
var _iteratorError = undefined; var _iterator = _createForOfIteratorHelper(arr),
_step;
try { try {
for (var _iterator = arr[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { for (_iterator.s(); !(_step = _iterator.n()).done;) {
var i = _step.value; var i = _step.value;
} }
} catch (err) { } catch (err) {
_didIteratorError = true; _iterator.e(err);
_iteratorError = err;
} finally { } finally {
try { _iterator.f();
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
} }

View File

@ -6,10 +6,11 @@ function _iterableToArrayLimit(arr, i) { if ((typeof Symbol === "undefined" || !
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
function _createForOfIteratorHelper(o) { if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); var it, normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e) { didErr = true; err = _e; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
// https://github.com/babel/babel/issues/7557 // https://github.com/babel/babel/issues/7557
var _iteratorNormalCompletion = true; var _iterator = _createForOfIteratorHelper(c),
var _didIteratorError = false; _step;
var _iteratorError = undefined;
try { try {
var _loop = function _loop() { var _loop = function _loop() {
@ -23,20 +24,11 @@ try {
}); });
}; };
for (var _iterator = c[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { for (_iterator.s(); !(_step = _iterator.n()).done;) {
_loop(); _loop();
} }
} catch (err) { } catch (err) {
_didIteratorError = true; _iterator.e(err);
_iteratorError = err;
} finally { } finally {
try { _iterator.f();
if (!_iteratorNormalCompletion && _iterator["return"] != null) {
_iterator["return"]();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
} }