@samitouri / QOS-React-2 / commits / 467b1034ce

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 ""