import * as _ from 'lodash' ; import * as PropTypes from 'prop-types' ; import leven from './leven' ; type ObjectOf < T > = Record < string , T > ; const typeOf = ( x ) => Object . prototype . toString . call ( x ) ; /**
 * Ensure a prop is a valid DOM node.
 */ export const domNode = ( props , propName ) => { if ( props [ propName ] === undefined ) return undefined ; if ( props [ propName ] === null ) return null ; if ( props [ propName ] instanceof Element ) return undefined ; return new Error ( `Invalid prop "${ propName }" supplied, expected a DOM node.` ) ; } ; param suggestions export const suggest = ( suggestions ) => { if ( ! Array . isArray ( suggestions ) ) { throw new Error ( 'Invalid argument supplied to suggest, expected an instance of array.' ) ; } const findBestSuggestions = _ . memoize ( ( str ) => { const propValueWords = str . split ( ' ' ) ; return _ . take ( _ . sortBy ( _ . map ( suggestions , ( suggestion ) => { const suggestionWords = suggestion . split ( ' ' ) ; const propValueScore = _ . sum ( _ . map ( _ . map ( propValueWords , x => _ . map ( suggestionWords , y => leven ( x , y ) ) ) , _ . min ) ) ; const suggestionScore = _ . sum ( _ . map ( _ . map ( suggestionWords , x => _ . map ( propValueWords , y => leven ( x , y ) ) ) , _ . min ) ) ; return { suggestion , score : propValueScore + suggestionScore } ; } ) , [ 'score' , 'suggestion' ] ) , 3 ) ; } ) ; const suggestionsLookup = suggestions . reduce ( ( acc , key ) => { acc [ key . split ( ' ' ) . sort ( ) . join ( ' ' ) ] = true ; return acc ; } , { } ) ; return ( props , propName , componentName ) => { const propValue = props [ propName ] ; if ( ! propValue || suggestionsLookup [ propValue ] ) return undefined ; const propValueSorted = propValue . split ( ' ' ) . sort ( ) . join ( ' ' ) ; if ( suggestionsLookup [ propValueSorted ] ) return undefined ; const bestMatches = findBestSuggestions ( propValue ) ; if ( bestMatches . some ( x => x . score === 0 ) ) return undefined ; return new Error ( [ `Invalid prop \`${ propName }\` of value \`${ propValue }\` supplied to \`${ componentName }\`.` , `\n\nInstead of \`${ propValue }\`, did you mean:` , bestMatches . map ( x => `\n  - ${ x . suggestion }` ) . join ( '' ) , '\n' , ] . join ( '' ) ) ; } ; } ; /**
 * The prop cannot be used.
 * Similar to `deprecate` but with different error message.
 */ export const never = ( props , propName , componentName ) => { if ( _ . isNil ( props [ propName ] ) || props [ propName ] === false ) return undefined ; return new Error ( `Prop \`${ propName }\` in \`${ componentName }\` cannot be used.` ) ; } ; param disallowedProps export const disallow = ( disallowedProps ) => ( props , propName , componentName ) => { if ( ! Array . isArray ( disallowedProps ) ) { throw new Error ( [ 'Invalid argument supplied to disallow, expected an instance of array.' , ` See \`${ propName }\` prop in \`${ componentName }\`.` , ] . join ( '' ) ) ; } if ( _ . isNil ( props [ propName ] ) || props [ propName ] === false ) return undefined ; const disallowed = disallowedProps . reduce ( ( acc , disallowedProp ) => { if ( ! _ . isNil ( props [ disallowedProp ] ) && props [ disallowedProp ] !== false ) { return [ ... acc , disallowedProp ] ; } return acc ; } , [ ] ) ; if ( disallowed . length > 0 ) { return new Error ( [ `Prop \`${ propName }\` in \`${ componentName }\` conflicts with props: \`${ disallowed . join ( '`, `' ) }\`.` , 'They cannot be defined together, choose one or the other.' , ] . join ( ' ' ) ) ; } return undefined ; } ; param validators export const every = ( validators ) => ( props , propName , componentName , ... args ) => { if ( ! Array . isArray ( validators ) ) { throw new Error ( [ 'Invalid argument supplied to every, expected an instance of array.' , `See \`${ propName }\` prop in \`${ componentName }\`.` , ] . join ( ' ' ) ) ; } return _ . first ( _ . compact ( _ . map ( validators , validator => { if ( typeof validator !== 'function' ) { throw new Error ( `every() argument "validators" should contain functions, found: ${ typeOf ( validator ) }.` ) ; } return validator ( props , propName , componentName , ... args ) ; } ) ) ) ; } ; param validators export const some = ( validators ) => ( props , propName , componentName , ... args ) => { if ( ! Array . isArray ( validators ) ) { throw new Error ( [ 'Invalid argument supplied to some, expected an instance of array.' , `See \`${ propName }\` prop in \`${ componentName }\`.` , ] . join ( ' ' ) ) ; } const errors = _ . compact ( _ . map ( validators , validator => { if ( ! _ . isFunction ( validator ) ) { throw new Error ( `some() argument "validators" should contain functions, found: ${ typeOf ( validator ) }.` ) ; } return validator ( props , propName , componentName , ... args ) ; } ) ) ; if ( errors . length === validators . length ) { const error = new Error ( 'One of these validators must pass:' ) ; error . message += `\n${ _ . map ( errors , err => `- ${ err . message }` ) . join ( '\n' ) }` ; return error ; } return undefined ; } ; param propsShape param validator export const givenProps = ( propsShape , validator ) => ( props , propName , componentName , ... args ) => { if ( ! _ . isPlainObject ( propsShape ) ) { throw new Error ( [ 'Invalid argument supplied to givenProps, expected an object.' , `See \`${ propName }\` prop in \`${ componentName }\`.` , ] . join ( ' ' ) ) ; } if ( typeof validator !== 'function' ) { throw new Error ( [ 'Invalid argument supplied to givenProps, expected a function.' , `See \`${ propName }\` prop in \`${ componentName }\`.` , ] . join ( ' ' ) ) ; } const shouldValidate = _ . keys ( propsShape ) . every ( ( key ) => { const val = propsShape [ key ] ; return typeof val === 'function' ? ! val ( props , key , componentName , ... args ) : val === props [ propName ] ; } ) ; if ( ! shouldValidate ) return undefined ; const error = validator ( props , propName , componentName , ... args ) ; if ( error ) { const prettyProps = `{ ${ _ . keys ( _ . pick ( props , _ . keys ( propsShape ) ) ) . map ( key => { const val = props [ key ] ; let renderedValue = val ; if ( typeof val === 'string' ) renderedValue = `"${ val }"` ; else if ( Array . isArray ( val ) ) renderedValue = `[${ val . join ( ', ' ) }]` ; else if ( _ . isObject ( val ) ) renderedValue = '{...}' ; return `${ key }: ${ renderedValue }` ; } ) . join ( ', ' ) } }` ; error . message = `Given props ${ prettyProps }: ${ error . message }` ; return error ; } } ; param requiredProps export const demand = ( requiredProps ) => ( props , propName , componentName ) => { if ( ! Array . isArray ( requiredProps ) ) { throw new Error ( [ 'Invalid `requiredProps` argument supplied to require, expected an instance of array.' , ` See \`${ propName }\` prop in \`${ componentName }\`.` , ] . join ( '' ) ) ; } if ( props [ propName ] === undefined ) return undefined ; const missingRequired = requiredProps . filter ( requiredProp => props [ requiredProp ] === undefined ) ; if ( missingRequired . length > 0 ) { return new Error ( `\`${ propName }\` prop in \`${ componentName }\` requires props: \`${ missingRequired . join ( '`, `' ) }\`.` ) ; } return undefined ; } ; param possible export const multipleProp = ( possible ) => ( props , propName , componentName ) => { if ( ! Array . isArray ( possible ) ) { throw new Error ( [ 'Invalid argument supplied to some, expected an instance of array.' , `See \`${ propName }\` prop in \`${ componentName }\`.` , ] . join ( ' ' ) ) ; } const propValue = props [ propName ] ; if ( _ . isNil ( propValue ) || propValue === false ) return undefined ; const values = propValue . replace ( 'large screen' , 'large-screen' ) . replace ( / vertically/g , '-vertically' ) . split ( ' ' ) . map ( val => _ . trim ( val ) . replace ( '-' , ' ' ) ) ; const invalid = _ . difference ( values , possible ) ; if ( invalid . length > 0 ) { return new Error ( `\`${ propName }\` prop in \`${ componentName }\` has invalid values: \`${ invalid . join ( '`, `' ) }\`.` ) ; } return undefined ; } ; /**
 * Ensure a component can render as a node passed as a prop value in place of children.
 */ export const nodeContent = every ( [ disallow ( [ 'children' ] ) , PropTypes . node ] ) ; export const wrapperShorthand = PropTypes . oneOfType ( [ PropTypes . node , PropTypes . object , PropTypes . arrayOf ( PropTypes . oneOfType ( [ PropTypes . node , PropTypes . object ] ) ) , ] ) ; /**
 * A shorthand prop which can be used together with `children`.
 */ export const shorthandAllowingChildren = PropTypes . oneOfType ( [ PropTypes . node , PropTypes . object , PropTypes . func , ] ) ; /**
 * Item shorthand is a description of a component that can be a literal,
 * a props object, an element or a render function.
 */ export const itemShorthand = every ( [ disallow ( [ 'children' ] ) , shorthandAllowingChildren ] ) ; export const itemShorthandWithKindProp = ( kindPropValues ) => { return every ( [ disallow ( [ 'children' ] ) , PropTypes . oneOfType ( [ PropTypes . node , PropTypes . shape ( { kind : PropTypes . oneOf ( kindPropValues ) , } ) , PropTypes . func , ] ) , ] ) ; } ; export const itemShorthandWithoutJSX = every ( [ disallow ( [ 'children' ] ) , PropTypes . oneOfType ( [ PropTypes . func , PropTypes . number , PropTypes . object , PropTypes . string , PropTypes . oneOf ( [ false ] ) , ] ) , ] ) ; /**
 * Collection shorthand ensures a prop is an array of item shorthand.
 */ export const collectionShorthand = every ( [ disallow ( [ 'children' ] ) , PropTypes . arrayOf ( itemShorthand ) ] ) ; export const collectionShorthandWithKindProp = ( kindPropValues ) => { return every ( [ disallow ( [ 'children' ] ) , PropTypes . arrayOf ( itemShorthandWithKindProp ( kindPropValues ) ) , ] ) ; } ; param help param validator export const deprecate = ( help , validator ? ) => ( props , propName , componentName , ... args ) => { if ( typeof help !== 'string' ) { throw new Error ( [ 'Invalid `help` argument supplied to deprecate, expected a string.' , `See \`${ propName }\` prop in \`${ componentName }\`.` , ] . join ( ' ' ) ) ; } if ( props [ propName ] === undefined ) return undefined ; const error = new Error ( `The \`${ propName }\` prop in \`${ componentName }\` is deprecated.` ) ; if ( help ) error . message += ` ${ help }` ; if ( validator ) { if ( typeof validator === 'function' ) { const validationError = validator ( props , propName , componentName , ... args ) ; if ( validationError ) { error . message = `${ error . message } ${ validationError . message }` ; } } else { throw new Error ( [ 'Invalid argument supplied to deprecate, expected a function.' , `See \`${ propName }\` prop in \`${ componentName }\`.` , ] . join ( ' ' ) ) ; } } return error ; } ; export const accessibility = PropTypes . func ; export const size = PropTypes . oneOf < 'smallest' | 'smaller' | 'small' | 'medium' | 'large' | 'larger' | 'largest' > ( [ 'smallest' , 'smaller' , 'small' , 'medium' , 'large' , 'larger' , 'largest' ] ) ; export const align = PropTypes . oneOf < 'start' | 'end' | 'center' | 'justify' > ( [ 'start' , 'end' , 'center' , 'justify' , ] ) ; export const animation = PropTypes . oneOfType ( [ PropTypes . shape ( { name : PropTypes . string . isRequired , delay : PropTypes . string , direction : PropTypes . string , duration : PropTypes . string , fillMode : PropTypes . string , iterationCount : PropTypes . string , playState : PropTypes . string , timingFunction : PropTypes . string , } ) as any , PropTypes . string , ] ) ; export const design = PropTypes . shape ( { position : PropTypes . string , display : PropTypes . string , top : PropTypes . string , right : PropTypes . string , bottom : PropTypes . string , left : PropTypes . string , padding : PropTypes . string , paddingTop : PropTypes . string , paddingRight : PropTypes . string , paddingBottom : PropTypes . string , paddingLeft : PropTypes . string , margin : PropTypes . string , marginTop : PropTypes . string , marginRight : PropTypes . string , marginBottom : PropTypes . string , marginLeft : PropTypes . string , width : PropTypes . string , height : PropTypes . string , minWidth : PropTypes . string , maxWidth : PropTypes . string , minHeight : PropTypes . string , maxHeight : PropTypes . string , } ) ; /** A checker that matches the React.Ref type. */ export const ref = PropTypes . oneOfType ( [ PropTypes . func , PropTypes . object as PropTypes . Validator < { current : any ; } > , ] ) ;