Skip to content

Commit

Permalink
[New] require-default-props: add option to ignore functional compon…
Browse files Browse the repository at this point in the history
…ents
  • Loading branch information
RedTn authored and ljharb committed Dec 24, 2019
1 parent 0d7019b commit 4f3cd90
Show file tree
Hide file tree
Showing 4 changed files with 400 additions and 5 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -11,6 +11,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
* [`prop-types`][]: Support Flow Type spread ([#2446][] @moroine)
* [`jsx-props-no-spreading`][]: add `explicitSpread` option to allow explicit spread of props ([#2449][] @pawelnvk)
* [`jsx-no-target-blank`][]: warn on `target={'_blank'}` expressions ([#2451][] @timkraut)
* [`require-default-props`]: add option to ignore functional components ([#2532][] @RedTn)

### Fixed
* [`sort-prop-types`][], [`jsx-sort-default-props`][]: disable broken autofix ([#2505][] @webOS101)
Expand All @@ -34,6 +35,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
* [Docs] [`no-unused-prop-types`][]: clean up prose ([#2273][] @coryhouse)
* [Docs] [`jsx-no-bind`][]: add section about React Hooks ([#2443][] @kdex)

[#2532]: https://github.com/yannickcr/eslint-plugin-react/pull/2532
[#2505]: https://github.com/yannickcr/eslint-plugin-react/pull/2505
[#2504]: https://github.com/yannickcr/eslint-plugin-react/pull/2504
[#2500]: https://github.com/yannickcr/eslint-plugin-react/pull/2500
Expand Down
64 changes: 63 additions & 1 deletion docs/rules/require-default-props.md
Expand Up @@ -188,12 +188,13 @@ NotAComponent.propTypes = {

```js
...
"react/require-default-props": [<enabled>, { forbidDefaultForRequired: <boolean> }]
"react/require-default-props": [<enabled>, { forbidDefaultForRequired: <boolean>, ignoreFunctionalComponents: <boolean> }]
...
```

* `enabled`: for enabling the rule. 0=off, 1=warn, 2=error. Defaults to 0.
* `forbidDefaultForRequired`: optional boolean to forbid prop default for a required prop. Defaults to false.
* `ignoreFunctionalComponents`: optional boolean to ignore this rule for functional components. Defaults to false.

### `forbidDefaultForRequired`

Expand Down Expand Up @@ -269,6 +270,67 @@ MyStatelessComponent.propTypes = {
};
```

### `ignoreFunctionalComponents`

When set to `true`, ignores this rule for all functional components.

The following patterns are warnings:

```jsx
class Greeting extends React.Component {
render() {
return (
<h1>Hello, {this.props.foo} {this.props.bar}</h1>
);
}

static propTypes = {
foo: PropTypes.string,
bar: PropTypes.string.isRequired
};

static defaultProps = {
foo: "foo",
bar: "bar"
};
}
```

The following patterns are **not** warnings:

```jsx
function MyStatelessComponent({ foo, bar }) {
return <div>{foo}{bar}</div>;
}

MyStatelessComponent.propTypes = {
foo: PropTypes.string,
bar: PropTypes.string
};
```

```jsx
const MyStatelessComponent = ({ foo, bar }) => {
return <div>{foo}{bar}</div>;
}

MyStatelessComponent.propTypes = {
foo: PropTypes.string,
bar: PropTypes.string
};
```

```jsx
const MyStatelessComponent = function({ foo, bar }) {
return <div>{foo}{bar}</div>;
}

MyStatelessComponent.propTypes = {
foo: PropTypes.string,
bar: PropTypes.string
};
```

## When Not To Use It

If you don't care about using `defaultsProps` for your component's props that are not required, you can disable this rule.
Expand Down
15 changes: 12 additions & 3 deletions lib/rules/require-default-props.js
Expand Up @@ -7,7 +7,7 @@

const Components = require('../util/Components');
const docsUrl = require('../util/docsUrl');

const astUtil = require('../util/ast');

// ------------------------------------------------------------------------------
// Rule Definition
Expand All @@ -26,6 +26,9 @@ module.exports = {
properties: {
forbidDefaultForRequired: {
type: 'boolean'
},
ignoreFunctionalComponents: {
type: 'boolean'
}
},
additionalProperties: false
Expand All @@ -35,7 +38,7 @@ module.exports = {
create: Components.detect((context, components) => {
const configuration = context.options[0] || {};
const forbidDefaultForRequired = configuration.forbidDefaultForRequired || false;

const ignoreFunctionalComponents = configuration.ignoreFunctionalComponents || false;

/**
* Reports all propTypes passed in that don't have a defaultProps counterpart.
Expand Down Expand Up @@ -83,7 +86,13 @@ module.exports = {
'Program:exit'() {
const list = components.list();

Object.keys(list).filter(component => list[component].declaredPropTypes).forEach((component) => {
Object.keys(list).filter((component) => {
if (ignoreFunctionalComponents &&
(astUtil.isFunction(list[component].node) || astUtil.isFunctionLikeExpression(list[component].node))) {
return false;
}
return list[component].declaredPropTypes;
}).forEach((component) => {
reportPropTypesWithoutDefault(
list[component].declaredPropTypes,
list[component].defaultProps || {}
Expand Down

0 comments on commit 4f3cd90

Please sign in to comment.