From 76a0e35771742d3ab10222d1d9e0ef846c7a8685 Mon Sep 17 00:00:00 2001 From: Cory Deppen Date: Sat, 28 Dec 2024 19:41:26 -0500 Subject: [PATCH] [Fix] prop-types: props missing in validation when using ComponentPropsWithRef from a namespace import --- lib/util/propTypes.js | 3 +- tests/lib/rules/prop-types.js | 320 ++++++++++++++++++++++++++++++++++ 2 files changed, 322 insertions(+), 1 deletion(-) diff --git a/lib/util/propTypes.js b/lib/util/propTypes.js index 3a8cc67f93..7cec5abbdd 100644 --- a/lib/util/propTypes.js +++ b/lib/util/propTypes.js @@ -107,9 +107,10 @@ module.exports = function propTypesInstructions(context, components, utils) { const defaults = { customValidators: [] }; const configuration = Object.assign({}, defaults, context.options[0] || {}); const customValidators = configuration.customValidators; - const allowedGenericTypes = new Set(['ComponentProps', 'ComponentPropsWithoutRef', 'forwardRef', 'ForwardRefRenderFunction', 'VFC', 'VoidFunctionComponent', 'PropsWithChildren', 'SFC', 'StatelessComponent', 'FunctionComponent', 'FC']); + const allowedGenericTypes = new Set(['ComponentProps', 'ComponentPropsWithRef', 'ComponentPropsWithoutRef', 'forwardRef', 'ForwardRefRenderFunction', 'VFC', 'VoidFunctionComponent', 'PropsWithChildren', 'SFC', 'StatelessComponent', 'FunctionComponent', 'FC']); const genericTypeParamIndexWherePropsArePresent = { ComponentProps: 0, + ComponentPropsWithRef: 0, ComponentPropsWithoutRef: 0, ForwardRefRenderFunction: 1, forwardRef: 1, diff --git a/tests/lib/rules/prop-types.js b/tests/lib/rules/prop-types.js index 4a7d05ad6f..d9eb574024 100644 --- a/tests/lib/rules/prop-types.js +++ b/tests/lib/rules/prop-types.js @@ -4131,6 +4131,20 @@ ruleTester.run('prop-types', rule, { `, features: ['ts', 'no-babel'], }, + { + code: ` + import {ComponentPropsWithRef, forwardRef} from "react"; + + export const FancyButton = forwardRef>( + ({ className, children, ...props }, ref) => ( + + ), + ); + `, + features: ['ts', 'no-babel'], + }, { code: ` import {ComponentProps, forwardRef} from "react"; @@ -4167,6 +4181,28 @@ ruleTester.run('prop-types', rule, { `, features: ['ts', 'no-babel'], }, + { + code: ` + import {ComponentPropsWithRef, ElementRef, forwardRef} from "react"; + + const BaseButton = forwardRef>( + ({ children, className, ...props }, ref) => ( + + ), + ); + + export const FancyButton = forwardRef, ComponentPropsWithRef>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, { code: ` import {ComponentProps, ElementRef, forwardRef} from "react"; @@ -4233,6 +4269,50 @@ ruleTester.run('prop-types', rule, { `, features: ['ts', 'no-babel'], }, + { + code: ` + import {ComponentProps, ComponentPropsWithRef, ElementRef, forwardRef} from "react"; + + const BaseButton = forwardRef>( + ({ children, className, ...props }, ref) => ( + + ), + ); + + export const FancyButton = forwardRef, ComponentPropsWithRef>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import {ComponentProps, ComponentPropsWithRef, ElementRef, forwardRef} from "react"; + + const BaseButton = forwardRef>( + ({ children, className, ...props }, ref) => ( + + ), + ); + + export const FancyButton = forwardRef, ComponentProps>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, { code: ` import React from "react"; @@ -4251,6 +4331,20 @@ ruleTester.run('prop-types', rule, { code: ` import React from "react"; + export const FancyButton = React.forwardRef>( + ({ className, children, ...props }, ref) => ( + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import React from "react"; + export const FancyButton = React.forwardRef>( ({ className, children, ...props }, ref) => ( + ), + ); + + export const FancyButton = React.forwardRef, React.ComponentPropsWithRef>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import React from "react"; + const BaseButton = React.forwardRef>( ({ children, className, ...props }, ref) => ( + ), + ); + + export const FancyButton = React.forwardRef, React.ComponentProps>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import React from "react"; + + const BaseButton = React.forwardRef>( + ({ children, className, ...props }, ref) => ( + + ), + ); + export const FancyButton = React.forwardRef, React.ComponentPropsWithoutRef>( ({ children, className, ...props }, ref) => ( @@ -4367,6 +4527,20 @@ ruleTester.run('prop-types', rule, { code: ` import * as React from "react"; + export const FancyButton = React.forwardRef>( + ({ className, children, ...props }, ref) => ( + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import * as React from "react"; + export const FancyButton = React.forwardRef>( ({ className, children, ...props }, ref) => ( + ), + ); + + export const FancyButton = React.forwardRef, React.ComponentPropsWithRef>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import * as React from "react"; + const BaseButton = React.forwardRef>( ({ children, className, ...props }, ref) => ( + ), + ); + + export const FancyButton = React.forwardRef, React.ComponentPropsWithRef>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import * as React from "react"; + + const BaseButton = React.forwardRef>( + ({ children, className, ...props }, ref) => ( + + ), + ); + + export const FancyButton = React.forwardRef, React.ComponentProps>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, { code: ` import React, {ComponentPropsWithoutRef} from "react"; @@ -4479,6 +4719,20 @@ ruleTester.run('prop-types', rule, { `, features: ['ts', 'no-babel'], }, + { + code: ` + import React, {ComponentPropsWithRef} from "react"; + + export const FancyButton = React.forwardRef>( + ({ className, children, ...props }, ref) => ( + + ), + ); + `, + features: ['ts', 'no-babel'], + }, { code: ` import React, {ComponentProps} from "react"; @@ -4515,6 +4769,28 @@ ruleTester.run('prop-types', rule, { `, features: ['ts', 'no-babel'], }, + { + code: ` + import React, {ComponentPropsWithRef, ElementRef} from "react"; + + const BaseButton = React.forwardRef>( + ({ children, className, ...props }, ref) => ( + + ), + ); + + export const FancyButton = React.forwardRef, ComponentPropsWithRef>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, { code: ` import React, {ComponentProps, ElementRef} from "react"; @@ -4581,6 +4857,50 @@ ruleTester.run('prop-types', rule, { `, features: ['ts', 'no-babel'], }, + { + code: ` + import React, {ComponentProps, ComponentPropsWithRef, ElementRef} from "react"; + + const BaseButton = React.forwardRef>( + ({ children, className, ...props }, ref) => ( + + ), + ); + + export const FancyButton = React.forwardRef, ComponentProps>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, + { + code: ` + import React, {ComponentProps, ComponentPropsWithRef, ElementRef} from "react"; + + const BaseButton = React.forwardRef>( + ({ children, className, ...props }, ref) => ( + + ), + ); + + export const FancyButton = React.forwardRef, ComponentPropsWithRef>( + ({ children, className, ...props }, ref) => ( + + {children} + + ), + ); + `, + features: ['ts', 'no-babel'], + }, { code: ` import React, { forwardRef } from 'react';