Skip to content

Commit

Permalink
[Fix] jsx-max-depth: Prevent getting stuck in circular references
Browse files Browse the repository at this point in the history
Fixes #2880.
  • Loading branch information
AriPerkkio authored and ljharb committed Mar 30, 2021
1 parent 106ccf4 commit 7ce9106
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 5 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel

## Unreleased

### Fixed
* [`jsx-max-depth`]: Prevent getting stuck in circular references ([#2957][] @AriPerkkio)

### Changed
* Fix CHANGELOG.md ([#2950][] @JounQin)

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

## [7.23.1] - 2021.03.23
Expand Down
22 changes: 17 additions & 5 deletions lib/rules/jsx-max-depth.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
'use strict';

const has = require('has');
const includes = require('array-includes');
const variableUtil = require('../util/variable');
const jsxUtil = require('../util/jsx');
const docsUrl = require('../util/docsUrl');
Expand Down Expand Up @@ -83,8 +84,8 @@ module.exports = {
});
}

function findJSXElementOrFragment(variables, name) {
function find(refs) {
function findJSXElementOrFragment(variables, name, previousReferences) {
function find(refs, prevRefs) {
let i = refs.length;

while (--i >= 0) {
Expand All @@ -94,15 +95,26 @@ module.exports = {
return (jsxUtil.isJSX(writeExpr)
&& writeExpr)
|| ((writeExpr && writeExpr.type === 'Identifier')
&& findJSXElementOrFragment(variables, writeExpr.name));
&& findJSXElementOrFragment(variables, writeExpr.name, prevRefs));
}
}

return null;
}

const variable = variableUtil.getVariable(variables, name);
return variable && variable.references && find(variable.references);
if (variable && variable.references) {
const containDuplicates = previousReferences.some((ref) => includes(variable.references, ref));

// Prevent getting stuck in circular references
if (containDuplicates) {
return false;
}

return find(variable.references, previousReferences.concat(variable.references));
}

return false;
}

function checkDescendant(baseDepth, children) {
Expand Down Expand Up @@ -141,7 +153,7 @@ module.exports = {
}

const variables = variableUtil.variablesInScope(context);
const element = findJSXElementOrFragment(variables, node.expression.name);
const element = findJSXElementOrFragment(variables, node.expression.name, []);

if (element) {
const baseDepth = getDepth(node);
Expand Down
27 changes: 27 additions & 0 deletions tests/lib/rules/jsx-max-depth.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,33 @@ ruleTester.run('jsx-max-depth', rule, {
' return <div>{A}</div>;',
'}'
].join('\n')
}, {
// Validates circular references don't get rule stuck
code: `
function Component() {
let first = "";
const second = first;
first = second;
return <div id={first} />;
};
`
},
{
// Validates circular references are checked at multiple levels
code: `
function Component() {
let first = "";
let second = "";
let third = "";
let fourth = "";
const fifth = first;
first = second;
second = third;
third = fourth;
fourth = fifth;
return <div id={first} />;
};
`
}],

invalid: [{
Expand Down

0 comments on commit 7ce9106

Please sign in to comment.