Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(require-default-props): add option to ignore functional components #2532

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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