Disable for...of by default, rewrite cases where it matters (#12198)
* Add no-for-of lint rule * Ignore legit use cases of for..of * Rewrite for..of in source code
Dan Abramov committed
Feb 9, 2018 at 16:11 UTC
467b1034ce8af6807e11deb9dfeca4d4e922ed82
13 files changed
+30
-5
.eslintrc.js
+5
@@ -11,6 +11,7 @@ module.exports = {
11
12
plugins: [
13
'jest',
14
+ 'no-for-of-loops',
15
'react',
16
'react-internal',
17
],
@@ -56,6 +57,10 @@ module.exports = {
57
// We don't care to do this
58
'react/jsx-wrap-multilines': [ERROR, {declaration: false, assignment: false}],
59
60
+ // Prevent for...of loops because they require a Symbol polyfill.
61
+ // You can disable this rule for code that isn't shipped (e.g. build scripts and tests).
62
+ 'no-for-of-loops/no-for-of-loops': ERROR,
63
+
64
// CUSTOM RULES
65
// the second argument of warning/invariant should be a literal string
66
'react-internal/no-primitive-constructors': ERROR,
dangerfile.js
+1
-1
@@ -112,7 +112,7 @@ fetch(commitURL(parentOfOldestCommit)).then(async response => {
112
113
// Show a hidden summary table for all diffs
114
115
- // eslint-disable-next-line no-var
115
+ // eslint-disable-next-line no-var,no-for-of-loops/no-for-of-loops
116
for (var name of new Set(packagesToShow)) {
117
const thisBundleResults = results.filter(r => r.packageName === name);
118
const changedFiles = thisBundleResults.filter(
package.json
+1
@@ -56,6 +56,7 @@
56
"eslint-plugin-babel": "^3.3.0",
57
"eslint-plugin-flowtype": "^2.25.0",
58
"eslint-plugin-jest": "^21.6.1",
59
+ "eslint-plugin-no-for-of-loops": "^1.0.0",
60
"eslint-plugin-react": "^6.7.1",
61
"eslint-plugin-react-internal": "link:./scripts/eslint-rules/",
62
"fbjs": "^0.8.16",
packages/react-dom/src/__tests__/ReactMultiChildReconcile-test.js
+1
@@ -251,6 +251,7 @@ function prepareChildrenArray(childrenArray) {
251
function prepareChildrenIterable(childrenArray) {
252
return {
253
'@@iterator': function*() {
254
+ // eslint-disable-next-line no-for-of-loops/no-for-of-loops
255
for (const child of childrenArray) {
256
yield child;
257
}
packages/react-native-renderer/src/__mocks__/FabricUIManager.js
+3
@@ -20,14 +20,17 @@ const RCTFabricUIManager = {
20
let out = '';
21
out +=
22
' '.repeat(indent) + info.viewName + ' ' + JSON.stringify(info.props);
23
+ // eslint-disable-next-line no-for-of-loops/no-for-of-loops
24
for (const child of info.children) {
25
out += '\n' + dumpSubtree(child, indent + 2);
26
}
27
return out;
28
}
29
let result = [];
30
+ // eslint-disable-next-line no-for-of-loops/no-for-of-loops
31
for (const [rootTag, childSet] of roots) {
32
result.push(rootTag);
33
+ // eslint-disable-next-line no-for-of-loops/no-for-of-loops
34
for (const child of childSet) {
35
result.push(dumpSubtree(child, 1));
36
}
packages/react-native-renderer/src/__mocks__/UIManager.js
+2
@@ -66,6 +66,7 @@ const RCTUIManager = {
66
let out = '';
67
out +=
68
' '.repeat(indent) + info.viewName + ' ' + JSON.stringify(info.props);
69
+ // eslint-disable-next-line no-for-of-loops/no-for-of-loops
70
for (const child of info.children) {
71
out += '\n' + dumpSubtree(child, indent + 2);
72
}
@@ -143,6 +144,7 @@ const RCTUIManager = {
144
indicesToInsert.push([addAtIndices[i], addChildReactTags[i]]);
145
});
146
indicesToInsert.sort((a, b) => a[0] - b[0]);
147
+ // eslint-disable-next-line no-for-of-loops/no-for-of-loops
148
for (const [i, tag] of indicesToInsert) {
149
insertSubviewAtIndex(parentTag, tag, i);
150
}
packages/react-noop-renderer/src/ReactNoop.js
+3
@@ -400,6 +400,7 @@ const ReactNoop = {
400
const n = timeout / 5 - 1;
401
402
let values = [];
403
+ // eslint-disable-next-line no-for-of-loops/no-for-of-loops
404
for (const value of flushUnitsOfWork(n)) {
405
values.push(...value);
406
}
@@ -418,6 +419,7 @@ const ReactNoop = {
419
420
flushUnitsOfWork(n: number): Array<mixed> {
421
let values = [];
422
+ // eslint-disable-next-line no-for-of-loops/no-for-of-loops
423
for (const value of flushUnitsOfWork(n)) {
424
values.push(...value);
425
}
@@ -427,6 +429,7 @@ const ReactNoop = {
429
flushThrough(expected: Array<mixed>): void {
430
let actual = [];
431
if (expected.length !== 0) {
432
+ // eslint-disable-next-line no-for-of-loops/no-for-of-loops
433
for (const value of flushUnitsOfWork(Infinity)) {
434
actual.push(...value);
435
if (actual.length >= expected.length) {
packages/react-reconciler/src/__tests__/ReactIncrementalTriangle-test.internal.js
+2
@@ -322,6 +322,7 @@ describe('ReactIncrementalTriangle', () => {
322
323
function simulate(...actions) {
324
const gen = simulateAndYield();
325
+ // eslint-disable-next-line no-for-of-loops/no-for-of-loops
326
for (let action of actions) {
327
gen.next(action);
328
}
@@ -407,6 +408,7 @@ ${formatActions(actions)}
408
409
function simulateMultipleRoots(...actions) {
410
const roots = new Map();
411
+ // eslint-disable-next-line no-for-of-loops/no-for-of-loops
412
for (let rootID of rootIDs) {
413
const simulator = TriangleSimulator(rootID);
414
const generator = simulator.simulateAndYield();
packages/react-test-renderer/src/ReactTestRenderer.js
+3
-3
@@ -553,12 +553,12 @@ function findAll(
553
}
554
}
555
556
- for (const child of root.children) {
556
+ root.children.forEach(child => {
557
if (typeof child === 'string') {
558
- continue;
558
+ return;
559
}
560
results.push(...findAll(child, predicate, options));
561
- }
561
+ });
562
563
return results;
564
}
packages/react/src/ReactElementValidator.js
+3
-1
@@ -260,7 +260,9 @@ function validatePropTypes(element) {
260
function validateFragmentProps(fragment) {
261
currentlyValidatingElement = fragment;
262
263
- for (const key of Object.keys(fragment.props)) {
263
+ const keys = Object.keys(fragment.props);
264
+ for (let i = 0; i < keys.length; i++) {
265
+ const key = keys[i];
266
if (!VALID_FRAGMENT_PROPS.has(key)) {
267
warning(
268
false,
scripts/error-codes/invertObject.js
+1
@@ -20,6 +20,7 @@ function invertObject(targetObj /* : ErrorMap */) /* : ErrorMap */ {
20
const result = {};
21
const mapKeys = Object.keys(targetObj);
22
23
+ // eslint-disable-next-line no-for-of-loops/no-for-of-loops
24
for (const originalKey of mapKeys) {
25
const originalVal = targetObj[originalKey];
26
scripts/rollup/build.js
+1
@@ -461,6 +461,7 @@ async function buildEverything() {
461
462
// Run them serially for better console output
463
// and to avoid any potential race conditions.
464
+ // eslint-disable-next-line no-for-of-loops/no-for-of-loops
465
for (const bundle of Bundles.bundles) {
466
await createBundle(bundle, UMD_DEV);
467
await createBundle(bundle, UMD_PROD);
yarn.lock
+4
@@ -1883,6 +1883,10 @@ eslint-plugin-jest@^21.6.1:
1883
version "21.6.1"
1884
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-21.6.1.tgz#adca015bbdb8d23b210438ff9e1cee1dd9ec35df"
1885
1886
+eslint-plugin-no-for-of-loops@^1.0.0:
1887
+ version "1.0.0"
1888
+ resolved "https://registry.yarnpkg.com/eslint-plugin-no-for-of-loops/-/eslint-plugin-no-for-of-loops-1.0.0.tgz#a13d91a8f1922f7fefedeab351dc0055994601f6"
1889
+
1890
"eslint-plugin-react-internal@link:./scripts/eslint-rules":
1891
version "0.0.0"
1892
uid ""