Skip to content

Commit 7ce9106

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

File tree

3 files changed

+48
-5
lines changed

3 files changed

+48
-5
lines changed

CHANGELOG.md

+4
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

+17-5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
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');
@@ -83,8 +84,8 @@ module.exports = {
8384
});
8485
}
8586

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

9091
while (--i >= 0) {
@@ -94,15 +95,26 @@ module.exports = {
9495
return (jsxUtil.isJSX(writeExpr)
9596
&& writeExpr)
9697
|| ((writeExpr && writeExpr.type === 'Identifier')
97-
&& findJSXElementOrFragment(variables, writeExpr.name));
98+
&& findJSXElementOrFragment(variables, writeExpr.name, prevRefs));
9899
}
99100
}
100101

101102
return null;
102103
}
103104

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

108120
function checkDescendant(baseDepth, children) {
@@ -141,7 +153,7 @@ module.exports = {
141153
}
142154

143155
const variables = variableUtil.variablesInScope(context);
144-
const element = findJSXElementOrFragment(variables, node.expression.name);
156+
const element = findJSXElementOrFragment(variables, node.expression.name, []);
145157

146158
if (element) {
147159
const baseDepth = getDepth(node);

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

+27
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)