Skip to content

Commit 8309daf

Browse files
AriPerkkioljharb
authored andcommitted
[Fix] jsx-max-depth: Prevent getting stuck in circular references
Fixes #2880.
1 parent 106ccf4 commit 8309daf

File tree

3 files changed

+49
-5
lines changed

3 files changed

+49
-5
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
55

66
## Unreleased
77

8+
### Fixed
9+
* [`jsx-max-depth`]: Prevent getting stuck in circular references ([#2957][] @AriPerkkio)
10+
811
### Changed
912
* Fix CHANGELOG.md ([#2950][] @JounQin)
1013

14+
[#2957]: https://github.com/yannickcr/eslint-plugin-react/pull/2957
1115
[#2950]: https://github.com/yannickcr/eslint-plugin-react/pull/2950
1216

1317
## [7.23.1] - 2021.03.23

lib/rules/jsx-max-depth.js

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
'use strict';
77

88
const has = require('has');
9+
const includes = require('array-includes');
910
const variableUtil = require('../util/variable');
1011
const jsxUtil = require('../util/jsx');
1112
const docsUrl = require('../util/docsUrl');
1213

14+
1315
// ------------------------------------------------------------------------------
1416
// Rule Definition
1517
// ------------------------------------------------------------------------------
@@ -83,8 +85,8 @@ module.exports = {
8385
});
8486
}
8587

86-
function findJSXElementOrFragment(variables, name) {
87-
function find(refs) {
88+
function findJSXElementOrFragment(variables, name, previousReferences) {
89+
function find(refs, prevRefs) {
8890
let i = refs.length;
8991

9092
while (--i >= 0) {
@@ -94,15 +96,26 @@ module.exports = {
9496
return (jsxUtil.isJSX(writeExpr)
9597
&& writeExpr)
9698
|| ((writeExpr && writeExpr.type === 'Identifier')
97-
&& findJSXElementOrFragment(variables, writeExpr.name));
99+
&& findJSXElementOrFragment(variables, writeExpr.name, prevRefs));
98100
}
99101
}
100102

101103
return null;
102104
}
103105

104106
const variable = variableUtil.getVariable(variables, name);
105-
return variable && variable.references && find(variable.references);
107+
if (variable && variable.references) {
108+
const containDuplicates = previousReferences.some((ref) => includes(variable.references, ref));
109+
110+
// Prevent getting stuck in circular references
111+
if (containDuplicates) {
112+
return false;
113+
}
114+
115+
return find(variable.references, previousReferences.concat(variable.references));
116+
}
117+
118+
return false;
106119
}
107120

108121
function checkDescendant(baseDepth, children) {
@@ -141,7 +154,7 @@ module.exports = {
141154
}
142155

143156
const variables = variableUtil.variablesInScope(context);
144-
const element = findJSXElementOrFragment(variables, node.expression.name);
157+
const element = findJSXElementOrFragment(variables, node.expression.name, []);
145158

146159
if (element) {
147160
const baseDepth = getDepth(node);

tests/lib/rules/jsx-max-depth.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,33 @@ ruleTester.run('jsx-max-depth', rule, {
114114
' return <div>{A}</div>;',
115115
'}'
116116
].join('\n')
117+
}, {
118+
// Validates circular references don't get rule stuck
119+
code: `
120+
function Component() {
121+
let first = "";
122+
const second = first;
123+
first = second;
124+
return <div id={first} />;
125+
};
126+
`
127+
},
128+
{
129+
// Validates circular references are checked at multiple levels
130+
code: `
131+
function Component() {
132+
let first = "";
133+
let second = "";
134+
let third = "";
135+
let fourth = "";
136+
const fifth = first;
137+
first = second;
138+
second = third;
139+
third = fourth;
140+
fourth = fifth;
141+
return <div id={first} />;
142+
};
143+
`
117144
}],
118145

119146
invalid: [{

0 commit comments

Comments
 (0)