Skip to content

Commit 58204f8

Browse files
committed
[Fix] prop-types: catch infinite loop
Fixes jsx-eslint#2861
1 parent 39c79ac commit 58204f8

File tree

3 files changed

+52
-20
lines changed

3 files changed

+52
-20
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
2626
* [`no-array-index-key`]: catch `.toString` and `String()` usage ([#2813][] @RedTn)
2727
* [`function-component-definition`]: do not break on dollar signs ([#3207][] @ljharb)
2828
* [`prefer-stateless-function`]: avoid a crash inside `doctrine` ([#2596][] @ljharb)
29+
* [`prop-types`]: catch infinite loop ([#2861][] @ljharb)
2930

3031
### Changed
3132
* [readme] change [`jsx-runtime`] link from branch to sha ([#3160][] @tatsushitoji)
@@ -56,6 +57,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
5657
[#3160]: https://github.com/yannickcr/eslint-plugin-react/pull/3160
5758
[#3133]: https://github.com/yannickcr/eslint-plugin-react/pull/3133
5859
[#2921]: https://github.com/yannickcr/eslint-plugin-react/pull/2921
60+
[#2861]: https://github.com/yannickcr/eslint-plugin-react/issues/2861
5961
[#2813]: https://github.com/yannickcr/eslint-plugin-react/pull/2813
6062
[#2753]: https://github.com/yannickcr/eslint-plugin-react/pull/2753
6163
[#2614]: https://github.com/yannickcr/eslint-plugin-react/issues/2614

lib/util/propTypes.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -1187,7 +1187,11 @@ module.exports = function propTypesInstructions(context, components, utils) {
11871187
if (!component) {
11881188
return;
11891189
}
1190-
markPropTypesAsDeclared(component.node, node.parent.right || node.parent);
1190+
try {
1191+
markPropTypesAsDeclared(component.node, node.parent.right || node.parent);
1192+
} catch (e) {
1193+
if (e.constructor !== RangeError) { throw e; }
1194+
}
11911195
}
11921196
},
11931197

tests/lib/rules/prop-types.js

+45-19
Original file line numberDiff line numberDiff line change
@@ -3753,19 +3753,19 @@ ruleTester.run('prop-types', rule, {
37533753
value: string,
37543754
error: string,
37553755
}
3756-
3756+
37573757
type Form = {
37583758
fields: {
37593759
[string]: Field,
37603760
},
37613761
formError: string,
37623762
}
3763-
3763+
37643764
type Props = {
37653765
bankDetails: Form,
37663766
onBankDetailsUpdate: any => void,
37673767
}
3768-
3768+
37693769
const Provider = (props:Props) =>
37703770
<Input
37713771
label={'Account Name'}
@@ -3804,7 +3804,7 @@ ruleTester.run('prop-types', rule, {
38043804
const {bar} = this.state;
38053805
console.log(bar);
38063806
}
3807-
3807+
38083808
render() {
38093809
return null;
38103810
}
@@ -3817,10 +3817,10 @@ ruleTester.run('prop-types', rule, {
38173817
const getNameDiv = () => {
38183818
return <div>{props.name}</div>;
38193819
};
3820-
3820+
38213821
return getNameDiv();
38223822
};
3823-
3823+
38243824
DisplayName.propTypes = {
38253825
name: PropTypes.string.isRequired,
38263826
};
@@ -3832,10 +3832,10 @@ ruleTester.run('prop-types', rule, {
38323832
function renderComponent() {
38333833
return <div>{props.name}</div>
38343834
}
3835-
3835+
38363836
return renderComponent();
38373837
}
3838-
3838+
38393839
SomeComponent.propTypes = {
38403840
name: PropTypes.string
38413841
}
@@ -3845,29 +3845,29 @@ ruleTester.run('prop-types', rule, {
38453845
code: `
38463846
import React from 'react';
38473847
import { MyType } from './types';
3848-
3848+
38493849
function Component(props: Props): JSX.Element | null {
38503850
const { array } = props;
3851-
3851+
38523852
function renderFound(): JSX.Element | null {
38533853
const found = array.find(x => x.id === id); // issue here
3854-
3854+
38553855
if (!found) {
38563856
return null;
38573857
}
3858-
3858+
38593859
return (
38603860
<div>{found.id}</div>
38613861
);
38623862
}
3863-
3863+
38643864
return renderFound();
38653865
}
3866-
3866+
38673867
interface Props {
38683868
array: MyType[];
38693869
}
3870-
3870+
38713871
export default Component;
38723872
`,
38733873
features: ['types'],
@@ -3916,9 +3916,9 @@ ruleTester.run('prop-types', rule, {
39163916
code: `
39173917
import PropTypes from 'prop-types';
39183918
import React from 'react';
3919-
3919+
39203920
import { Link } from '..';
3921-
3921+
39223922
const LinkWrapper = ({ primaryLinks }) => (
39233923
<>
39243924
{primaryLinks.map((x, index) => (
@@ -3928,18 +3928,44 @@ ruleTester.run('prop-types', rule, {
39283928
))}
39293929
</>
39303930
);
3931-
3931+
39323932
LinkWrapper.propTypes = {
39333933
primaryLinks: PropTypes.arrayOf(
39343934
PropTypes.shape({
39353935
text: PropTypes.string,
39363936
})
39373937
),
39383938
};
3939-
3939+
39403940
export default LinkWrapper;
39413941
`,
39423942
features: ['fragment'],
3943+
},
3944+
{
3945+
code: `
3946+
const projectType = PropTypes.shape({
3947+
id: PropTypes.string.isRequired,
3948+
name: PropTypes.string.isRequired,
3949+
});
3950+
3951+
const nodesType = PropTypes.arrayOf(
3952+
PropTypes.shape({ project: projectType, children: nodesType }),
3953+
);
3954+
3955+
class ProjectNode extends React.Component {
3956+
render() {
3957+
return <div />;
3958+
}
3959+
}
3960+
3961+
ProjectNode.propTypes = {
3962+
project: projectType.isRequired,
3963+
nodes: nodesType,
3964+
depth: PropTypes.number.isRequired,
3965+
setActiveProject: PropTypes.func.isRequired,
3966+
activeProject: projectType,
3967+
};
3968+
`,
39433969
}
39443970
)),
39453971

0 commit comments

Comments
 (0)