Skip to content

Commit 95045a3

Browse files
committed
[Fix] jsx-max-depth: Prevent getting stuck in circular references
1 parent 823824b commit 95045a3

File tree

2 files changed

+47
-5
lines changed

2 files changed

+47
-5
lines changed

lib/rules/jsx-max-depth.js

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ const variableUtil = require('../util/variable');
1010
const jsxUtil = require('../util/jsx');
1111
const docsUrl = require('../util/docsUrl');
1212

13+
function includes(array, item) {
14+
return !!array.some((i) => i === item);
15+
}
16+
1317
// ------------------------------------------------------------------------------
1418
// Rule Definition
1519
// ------------------------------------------------------------------------------
@@ -83,8 +87,8 @@ module.exports = {
8387
});
8488
}
8589

86-
function findJSXElementOrFragment(variables, name) {
87-
function find(refs) {
90+
function findJSXElementOrFragment(variables, name, previousReferences) {
91+
function find(refs, prevRefs) {
8892
let i = refs.length;
8993

9094
while (--i >= 0) {
@@ -94,15 +98,26 @@ module.exports = {
9498
return (jsxUtil.isJSX(writeExpr)
9599
&& writeExpr)
96100
|| ((writeExpr && writeExpr.type === 'Identifier')
97-
&& findJSXElementOrFragment(variables, writeExpr.name));
101+
&& findJSXElementOrFragment(variables, writeExpr.name, prevRefs));
98102
}
99103
}
100104

101105
return null;
102106
}
103107

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

108123
function checkDescendant(baseDepth, children) {
@@ -141,7 +156,7 @@ module.exports = {
141156
}
142157

143158
const variables = variableUtil.variablesInScope(context);
144-
const element = findJSXElementOrFragment(variables, node.expression.name);
159+
const element = findJSXElementOrFragment(variables, node.expression.name, []);
145160

146161
if (element) {
147162
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)