Fix false positive lint error with large number of branches (#24287)
* Switched RulesOfHooks.js to use BigInt. Added test and updated .eslintrc.js to use es2020. * Added BigInt as readonly global in eslintrc.cjs.js and eslintrc.cjs2015.js * Added comment to RulesOfHooks.js that gets rid of BigInt eslint error * Got rid of changes in .eslintrc.js and yarn.lock * Move global down Co-authored-by: stephen cyron <stephen.cyron@fdmgroup.com> Co-authored-by: dan <dan.abramov@gmail.com>
Stephen Cyron committed
Apr 7, 2022 at 19:22 UTC
1f7a901d7b2fc073e29a1887553b1bd18080da1b
4 files changed
+81
-9
packages/eslint-plugin-react-hooks/__tests__/ESLintRulesOfHooks-test.js
+69
@@ -325,6 +325,75 @@ const tests = {
325
useHook();
326
}
327
`,
328
+ `
329
+ // Valid because the neither the conditions before or after the hook affect the hook call
330
+ // Failed prior to implementing BigInt because pathsFromStartToEnd and allPathsFromStartToEnd were too big and had rounding errors
331
+ const useSomeHook = () => {};
332
+
333
+ const SomeName = () => {
334
+ const filler = FILLER ?? FILLER ?? FILLER;
335
+ const filler2 = FILLER ?? FILLER ?? FILLER;
336
+ const filler3 = FILLER ?? FILLER ?? FILLER;
337
+ const filler4 = FILLER ?? FILLER ?? FILLER;
338
+ const filler5 = FILLER ?? FILLER ?? FILLER;
339
+ const filler6 = FILLER ?? FILLER ?? FILLER;
340
+ const filler7 = FILLER ?? FILLER ?? FILLER;
341
+ const filler8 = FILLER ?? FILLER ?? FILLER;
342
+
343
+ useSomeHook();
344
+
345
+ if (anyConditionCanEvenBeFalse) {
346
+ return null;
347
+ }
348
+
349
+ return (
350
+ <React.Fragment>
351
+ {FILLER ? FILLER : FILLER}
352
+ {FILLER ? FILLER : FILLER}
353
+ {FILLER ? FILLER : FILLER}
354
+ {FILLER ? FILLER : FILLER}
355
+ {FILLER ? FILLER : FILLER}
356
+ {FILLER ? FILLER : FILLER}
357
+ {FILLER ? FILLER : FILLER}
358
+ {FILLER ? FILLER : FILLER}
359
+ {FILLER ? FILLER : FILLER}
360
+ {FILLER ? FILLER : FILLER}
361
+ {FILLER ? FILLER : FILLER}
362
+ {FILLER ? FILLER : FILLER}
363
+ {FILLER ? FILLER : FILLER}
364
+ {FILLER ? FILLER : FILLER}
365
+ {FILLER ? FILLER : FILLER}
366
+ {FILLER ? FILLER : FILLER}
367
+ {FILLER ? FILLER : FILLER}
368
+ {FILLER ? FILLER : FILLER}
369
+ {FILLER ? FILLER : FILLER}
370
+ {FILLER ? FILLER : FILLER}
371
+ {FILLER ? FILLER : FILLER}
372
+ {FILLER ? FILLER : FILLER}
373
+ {FILLER ? FILLER : FILLER}
374
+ {FILLER ? FILLER : FILLER}
375
+ {FILLER ? FILLER : FILLER}
376
+ {FILLER ? FILLER : FILLER}
377
+ {FILLER ? FILLER : FILLER}
378
+ {FILLER ? FILLER : FILLER}
379
+ {FILLER ? FILLER : FILLER}
380
+ {FILLER ? FILLER : FILLER}
381
+ {FILLER ? FILLER : FILLER}
382
+ {FILLER ? FILLER : FILLER}
383
+ {FILLER ? FILLER : FILLER}
384
+ {FILLER ? FILLER : FILLER}
385
+ {FILLER ? FILLER : FILLER}
386
+ {FILLER ? FILLER : FILLER}
387
+ {FILLER ? FILLER : FILLER}
388
+ {FILLER ? FILLER : FILLER}
389
+ {FILLER ? FILLER : FILLER}
390
+ {FILLER ? FILLER : FILLER}
391
+ {FILLER ? FILLER : FILLER}
392
+ {FILLER ? FILLER : FILLER}
393
+ </React.Fragment>
394
+ );
395
+ };
396
+ `,
397
`
398
// Valid because the neither the condition nor the loop affect the hook call.
399
function App(props) {
packages/eslint-plugin-react-hooks/src/RulesOfHooks.js
+10
-9
@@ -5,6 +5,7 @@
5
* LICENSE file in the root directory of this source tree.
6
*/
7
8
+/* global BigInt */
9
/* eslint-disable no-for-of-loops/no-for-of-loops */
10
11
'use strict';
@@ -175,7 +176,7 @@ export default {
176
cyclic.add(cyclicSegment);
177
}
178
178
- return 0;
179
+ return BigInt('0');
180
}
181
182
// add the current segment to pathList
@@ -187,11 +188,11 @@ export default {
188
}
189
190
if (codePath.thrownSegments.includes(segment)) {
190
- paths = 0;
191
+ paths = BigInt('0');
192
} else if (segment.prevSegments.length === 0) {
192
- paths = 1;
193
+ paths = BigInt('1');
194
} else {
194
- paths = 0;
195
+ paths = BigInt('0');
196
for (const prevSegment of segment.prevSegments) {
197
paths += countPathsFromStart(prevSegment, pathList);
198
}
@@ -199,7 +200,7 @@ export default {
200
201
// If our segment is reachable then there should be at least one path
202
// to it from the start of our code path.
202
- if (segment.reachable && paths === 0) {
203
+ if (segment.reachable && paths === BigInt('0')) {
204
cache.delete(segment.id);
205
} else {
206
cache.set(segment.id, paths);
@@ -246,7 +247,7 @@ export default {
247
cyclic.add(cyclicSegment);
248
}
249
249
- return 0;
250
+ return BigInt('0');
251
}
252
253
// add the current segment to pathList
@@ -258,11 +259,11 @@ export default {
259
}
260
261
if (codePath.thrownSegments.includes(segment)) {
261
- paths = 0;
262
+ paths = BigInt('0');
263
} else if (segment.nextSegments.length === 0) {
263
- paths = 1;
264
+ paths = BigInt('1');
265
} else {
265
- paths = 0;
266
+ paths = BigInt('0');
267
for (const nextSegment of segment.nextSegments) {
268
paths += countPathsToEnd(nextSegment, pathList);
269
}
scripts/rollup/validate/eslintrc.cjs.js
+1
@@ -7,6 +7,7 @@ module.exports = {
7
},
8
globals: {
9
// ES 6
10
+ BigInt: 'readonly',
11
Map: 'readonly',
12
Set: 'readonly',
13
Proxy: 'readonly',
scripts/rollup/validate/eslintrc.cjs2015.js
+1
@@ -7,6 +7,7 @@ module.exports = {
7
},
8
globals: {
9
// ES 6
10
+ BigInt: 'readonly',
11
Map: 'readonly',
12
Set: 'readonly',
13
Proxy: 'readonly',