diff --git a/.eslintrc.js b/.eslintrc.js index 7363c603696ec..e4b8d27b29e13 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -11,6 +11,7 @@ module.exports = { plugins: [ 'jest', + 'no-for-of-loops', 'react', 'react-internal', ], @@ -56,6 +57,10 @@ module.exports = { // We don't care to do this 'react/jsx-wrap-multilines': [ERROR, {declaration: false, assignment: false}], + // Prevent for...of loops because they require a Symbol polyfill. + // You can disable this rule for code that isn't shipped (e.g. build scripts and tests). + 'no-for-of-loops/no-for-of-loops': ERROR, + // CUSTOM RULES // the second argument of warning/invariant should be a literal string 'react-internal/no-primitive-constructors': ERROR, diff --git a/dangerfile.js b/dangerfile.js index 61246a35f357c..2db280e0f7913 100644 --- a/dangerfile.js +++ b/dangerfile.js @@ -112,7 +112,7 @@ fetch(commitURL(parentOfOldestCommit)).then(async response => { // Show a hidden summary table for all diffs - // eslint-disable-next-line no-var + // eslint-disable-next-line no-var,no-for-of-loops/no-for-of-loops for (var name of new Set(packagesToShow)) { const thisBundleResults = results.filter(r => r.packageName === name); const changedFiles = thisBundleResults.filter( diff --git a/package.json b/package.json index 602cd80ad949a..13c6861cef333 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "eslint-plugin-babel": "^3.3.0", "eslint-plugin-flowtype": "^2.25.0", "eslint-plugin-jest": "^21.6.1", + "eslint-plugin-no-for-of-loops": "^1.0.0", "eslint-plugin-react": "^6.7.1", "eslint-plugin-react-internal": "link:./scripts/eslint-rules/", "fbjs": "^0.8.16", diff --git a/packages/react-dom/src/__tests__/ReactMultiChildReconcile-test.js b/packages/react-dom/src/__tests__/ReactMultiChildReconcile-test.js index 4b74b3087e2cf..090230be3e7a2 100644 --- a/packages/react-dom/src/__tests__/ReactMultiChildReconcile-test.js +++ b/packages/react-dom/src/__tests__/ReactMultiChildReconcile-test.js @@ -251,6 +251,7 @@ function prepareChildrenArray(childrenArray) { function prepareChildrenIterable(childrenArray) { return { '@@iterator': function*() { + // eslint-disable-next-line no-for-of-loops/no-for-of-loops for (const child of childrenArray) { yield child; } diff --git a/packages/react-native-renderer/src/__mocks__/FabricUIManager.js b/packages/react-native-renderer/src/__mocks__/FabricUIManager.js index 7bfacbd506144..9ad7d9d40662b 100644 --- a/packages/react-native-renderer/src/__mocks__/FabricUIManager.js +++ b/packages/react-native-renderer/src/__mocks__/FabricUIManager.js @@ -20,14 +20,17 @@ const RCTFabricUIManager = { let out = ''; out += ' '.repeat(indent) + info.viewName + ' ' + JSON.stringify(info.props); + // eslint-disable-next-line no-for-of-loops/no-for-of-loops for (const child of info.children) { out += '\n' + dumpSubtree(child, indent + 2); } return out; } let result = []; + // eslint-disable-next-line no-for-of-loops/no-for-of-loops for (const [rootTag, childSet] of roots) { result.push(rootTag); + // eslint-disable-next-line no-for-of-loops/no-for-of-loops for (const child of childSet) { result.push(dumpSubtree(child, 1)); } diff --git a/packages/react-native-renderer/src/__mocks__/UIManager.js b/packages/react-native-renderer/src/__mocks__/UIManager.js index 8871fe2258224..d063b3c2acc5a 100644 --- a/packages/react-native-renderer/src/__mocks__/UIManager.js +++ b/packages/react-native-renderer/src/__mocks__/UIManager.js @@ -66,6 +66,7 @@ const RCTUIManager = { let out = ''; out += ' '.repeat(indent) + info.viewName + ' ' + JSON.stringify(info.props); + // eslint-disable-next-line no-for-of-loops/no-for-of-loops for (const child of info.children) { out += '\n' + dumpSubtree(child, indent + 2); } @@ -143,6 +144,7 @@ const RCTUIManager = { indicesToInsert.push([addAtIndices[i], addChildReactTags[i]]); }); indicesToInsert.sort((a, b) => a[0] - b[0]); + // eslint-disable-next-line no-for-of-loops/no-for-of-loops for (const [i, tag] of indicesToInsert) { insertSubviewAtIndex(parentTag, tag, i); } diff --git a/packages/react-noop-renderer/src/ReactNoop.js b/packages/react-noop-renderer/src/ReactNoop.js index 643bebfb3a252..7d18c1bcf1e4e 100644 --- a/packages/react-noop-renderer/src/ReactNoop.js +++ b/packages/react-noop-renderer/src/ReactNoop.js @@ -400,6 +400,7 @@ const ReactNoop = { const n = timeout / 5 - 1; let values = []; + // eslint-disable-next-line no-for-of-loops/no-for-of-loops for (const value of flushUnitsOfWork(n)) { values.push(...value); } @@ -418,6 +419,7 @@ const ReactNoop = { flushUnitsOfWork(n: number): Array { let values = []; + // eslint-disable-next-line no-for-of-loops/no-for-of-loops for (const value of flushUnitsOfWork(n)) { values.push(...value); } @@ -427,6 +429,7 @@ const ReactNoop = { flushThrough(expected: Array): void { let actual = []; if (expected.length !== 0) { + // eslint-disable-next-line no-for-of-loops/no-for-of-loops for (const value of flushUnitsOfWork(Infinity)) { actual.push(...value); if (actual.length >= expected.length) { diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalTriangle-test.internal.js b/packages/react-reconciler/src/__tests__/ReactIncrementalTriangle-test.internal.js index ab40f3a3950af..8e8b99dd37cc5 100644 --- a/packages/react-reconciler/src/__tests__/ReactIncrementalTriangle-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactIncrementalTriangle-test.internal.js @@ -322,6 +322,7 @@ describe('ReactIncrementalTriangle', () => { function simulate(...actions) { const gen = simulateAndYield(); + // eslint-disable-next-line no-for-of-loops/no-for-of-loops for (let action of actions) { gen.next(action); } @@ -407,6 +408,7 @@ ${formatActions(actions)} function simulateMultipleRoots(...actions) { const roots = new Map(); + // eslint-disable-next-line no-for-of-loops/no-for-of-loops for (let rootID of rootIDs) { const simulator = TriangleSimulator(rootID); const generator = simulator.simulateAndYield(); diff --git a/packages/react-test-renderer/src/ReactTestRenderer.js b/packages/react-test-renderer/src/ReactTestRenderer.js index 1bf7d4d4adbcf..4f1276d413778 100644 --- a/packages/react-test-renderer/src/ReactTestRenderer.js +++ b/packages/react-test-renderer/src/ReactTestRenderer.js @@ -553,12 +553,12 @@ function findAll( } } - for (const child of root.children) { + root.children.forEach(child => { if (typeof child === 'string') { - continue; + return; } results.push(...findAll(child, predicate, options)); - } + }); return results; } diff --git a/packages/react/src/ReactElementValidator.js b/packages/react/src/ReactElementValidator.js index e227e483a1cd9..471e6d6f8b677 100644 --- a/packages/react/src/ReactElementValidator.js +++ b/packages/react/src/ReactElementValidator.js @@ -260,7 +260,9 @@ function validatePropTypes(element) { function validateFragmentProps(fragment) { currentlyValidatingElement = fragment; - for (const key of Object.keys(fragment.props)) { + const keys = Object.keys(fragment.props); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; if (!VALID_FRAGMENT_PROPS.has(key)) { warning( false, diff --git a/scripts/error-codes/invertObject.js b/scripts/error-codes/invertObject.js index 2efe7ff6eb6bd..326e61686c186 100644 --- a/scripts/error-codes/invertObject.js +++ b/scripts/error-codes/invertObject.js @@ -20,6 +20,7 @@ function invertObject(targetObj /* : ErrorMap */) /* : ErrorMap */ { const result = {}; const mapKeys = Object.keys(targetObj); + // eslint-disable-next-line no-for-of-loops/no-for-of-loops for (const originalKey of mapKeys) { const originalVal = targetObj[originalKey]; diff --git a/scripts/rollup/build.js b/scripts/rollup/build.js index 1b3c0d34bbde3..54595cca151a8 100644 --- a/scripts/rollup/build.js +++ b/scripts/rollup/build.js @@ -461,6 +461,7 @@ async function buildEverything() { // Run them serially for better console output // and to avoid any potential race conditions. + // eslint-disable-next-line no-for-of-loops/no-for-of-loops for (const bundle of Bundles.bundles) { await createBundle(bundle, UMD_DEV); await createBundle(bundle, UMD_PROD); diff --git a/yarn.lock b/yarn.lock index 708cda26ecdd4..5f1e2ce632188 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1883,6 +1883,10 @@ eslint-plugin-jest@^21.6.1: version "21.6.1" resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-21.6.1.tgz#adca015bbdb8d23b210438ff9e1cee1dd9ec35df" +eslint-plugin-no-for-of-loops@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-no-for-of-loops/-/eslint-plugin-no-for-of-loops-1.0.0.tgz#a13d91a8f1922f7fefedeab351dc0055994601f6" + "eslint-plugin-react-internal@link:./scripts/eslint-rules": version "0.0.0" uid ""