Skip to content

Commit

Permalink
[New] prefer-read-only-props, prop-types, component detection: al…
Browse files Browse the repository at this point in the history
…low components to be async functions
  • Loading branch information
pnodet authored and ljharb committed Nov 15, 2023
1 parent 9ff9ef9 commit 3fb79e1
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 13 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -10,6 +10,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
* [`no-invalid-html-attribute`]: add support for `apple-touch-startup-image` `rel` attributes in `link` tags ([#3638][] @thomashockaday)
* [`no-unknown-property`]: add requireDataLowercase option ([#3645][] @HermanBilous)
* [`no-unknown-property`]: add `displaystyle` on `<math>` ([#3652][] @lounsbrough)
* [`prefer-read-only-props`], [`prop-types`], component detection: allow components to be async functions ([#3654][] @pnodet)

### Fixed
* [`jsx-no-leaked-render`]: preserve RHS parens for multiline jsx elements while fixing ([#3623][] @akulsr0)
Expand All @@ -22,6 +23,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
* [Refactor] [`function-component-definition`]: exit early if no type params ([#3634][] @HenryBrown0)
* [Refactor] [`jsx-props-no-multi-spaces`]: extract type parameters to var ([#3634][] @HenryBrown0)

[#3654]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3654
[#3652]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3652
[#3645]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3645
[#3638]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3638
Expand Down
9 changes: 2 additions & 7 deletions lib/util/Components.js
Expand Up @@ -855,7 +855,7 @@ function componentRule(rule, context) {
},

FunctionExpression(node) {
if (node.async) {
if (node.async && node.generator) {
components.add(node, 0);
return;
}
Expand All @@ -868,7 +868,7 @@ function componentRule(rule, context) {
},

FunctionDeclaration(node) {
if (node.async) {
if (node.async && node.generator) {
components.add(node, 0);
return;
}
Expand All @@ -881,11 +881,6 @@ function componentRule(rule, context) {
},

ArrowFunctionExpression(node) {
if (node.async) {
components.add(node, 0);
return;
}

const component = utils.getStatelessComponent(node);
if (!component) {
return;
Expand Down
42 changes: 42 additions & 0 deletions tests/lib/rules/prefer-read-only-props.js
Expand Up @@ -218,6 +218,19 @@ ruleTester.run('prefer-read-only-props', rule, {
`,
features: ['ts', 'no-babel-old'],
},
{
code: `
import React from "react";
type Props = {
readonly name: string[];
}
const MyComponent: React.FC<Props> = async ({ name }) => {
return <div>{name}</div>;
};
export default MyComponent;
`,
features: ['ts', 'no-babel-old'],
},
{
code: `
import React from "react";
Expand Down Expand Up @@ -500,6 +513,35 @@ ruleTester.run('prefer-read-only-props', rule, {
},
],
},
{
code: `
import React from "react";
type Props = {
name: string[];
}
const MyComponent: React.FC<Props> = async ({ name }) => {
return <div>{name}</div>;
};
export default MyComponent;
`,
output: `
import React from "react";
type Props = {
readonly name: string[];
}
const MyComponent: React.FC<Props> = async ({ name }) => {
return <div>{name}</div>;
};
export default MyComponent;
`,
features: ['ts', 'no-babel-old'],
errors: [
{
messageId: 'readOnlyProp',
data: { name: 'name' },
},
],
},
{
code: `
type Props = {
Expand Down
15 changes: 9 additions & 6 deletions tests/lib/rules/prop-types.js
Expand Up @@ -1571,25 +1571,28 @@ ruleTester.run('prop-types', rule, {
options: [{ skipUndeclared: false }],
},
{
// Async functions can't be components.
// Async generator functions can't be components.
code: `
var Hello = async function(props) {
var Hello = async function* (props) {
yield null;
return <div>Hello {props.name}</div>;
}
`,
},
{
// Async functions can't be components.
// Async generator functions can't be components.
code: `
async function Hello(props) {
async function* Hello(props) {
yield null;
return <div>Hello {props.name}</div>;
}
`,
},
{
// Async functions can't be components.
// Async generator functions can't be components.
code: `
var Hello = async (props) => {
var Hello = async function* (props) {
yield null;
return <div>Hello {props.name}</div>;
}
`,
Expand Down

0 comments on commit 3fb79e1

Please sign in to comment.