import { isValidElement , Children , ReactNode } from 'react' ; import { isEmpty , isFunction , has , get } from 'lodash' ; import { Requireable } from 'prop-types' ; import components from '#config/components' ; export interface CheckChildrenTypes { ( props , propName , componentName , location , propFullName ) : Error | null ; } const checkChildrenTypes = ( props , propName , componentName ) => { let error = null ; const children = props [ propName ] ; const cpName = componentName . replace ( 'CL' , '' ) ; if ( ( ( isEmpty ( children ) && typeof children !== 'function' ) || ( typeof children === 'function' && ! children ) ) && props [ 'isRequired' ] ) { error = new Error ( `The prop '${ propName }' is marked as required in '${ cpName }', but its value is '${ children }'.` ) ; } Children . map ( children , ( c ) : any => { if ( error ) return error ; const type = c . type ; const itemTypes = get ( components , `${ cpName }.permittedChildren` ) ; const errorMsg = `Invalid prop '${ propName }' supplied to ${ cpName }. Only components ${ itemTypes . join ( ', ' ) } are allowed.` ; if ( isFunction ( type ) && has ( type , 'displayName' ) ) { const displayName = get ( type , 'displayName' ) ; const childComponentName = type . name ; if ( displayName && displayName === `${ childComponentName }` ) { if ( ! itemTypes . includes ( childComponentName ) ) { error = new Error ( errorMsg ) ; } } } if ( ! isValidElement ( c ) ) { error = new Error ( errorMsg ) ; } } ) ; return error ; } ; const childrenTypes = checkChildrenTypes ; childrenTypes [ 'isRequired' ] = ( props , propName , componentName , location , propFullName ) : Error | null | Element [ ] => checkChildrenTypes ( { ... props , isRequired : true } , propName , componentName , location , propFullName ) ; export default childrenTypes as Requireable < ReactNode > ;