import { mapObject , isObject , isUndefined } from '@kirei/shared' ; import { isFunction } from '@vue/shared' ; import { warn } from '../warn' ; import type { Props , PropsData , NormalizedProps , NormalizedProp , PropInstance , PropConstructor } from '../types' ; param props returns private export function normalizeProps < T = Props > ( props ) { for ( const key of Object . keys ( props ) ) { const prop = props [ key ] ; let normal = prop as NormalizedProp ; if ( isObject < PropInstance > ( prop ) && ! Array . isArray ( prop ) ) { normal . type = prop . type as PropConstructor [ ] ; normal . default = prop . default ; normal . validator = prop . validator ?? null ; normal . required = ! ! prop . required ; } else { normal = props [ key ] = { type : prop as PropConstructor [ ] , validator : null , required : false , } as NormalizedProp ; } if ( normal . type ) { if ( ! Array . isArray ( normal . type ) ) { normal . type = [ normal . type ] ; } if ( ! normal . type ?. every ( isFunction ) ) { throw new TypeError ( `Type invalid in prop '${ key }'!` ) ; } const [ first ] = normal . type ; normal . cast = first === Boolean || first === Number ; } else { normal . cast = false ; } } return props as NormalizedProps < T > ; } param props returns private export function propDefaults < T extends NormalizedProps > ( props ) { return mapObject < T , string , PropsData < T > > ( ( key , prop ) => { const { type , default : def } = prop ; if ( isObject ( def ) ) { warn ( `Prop defaults requires Objects to be returned by a factory function to avoid cross referencing across elements.` ) ; } let value ; if ( ! isUndefined ( def ) ) { value = isFunction ( def ) ? def ( ) : def ; try { validateProp ( prop , key , value ) ; } catch ( ex ) { throw new TypeError ( `Default prop value invalid for prop "${ key }", type "${ typeof value }" unexpected.` ) ; } } else if ( type != null && type [ 0 ] === Boolean ) { value = false ; } return [ key , value as string ] ; } , props ) ; } param props param key param value returns private export function validateProp < T extends NormalizedProp , V = T extends NormalizedProp < infer I > ? I : any > ( prop , key , value ) { const { type , required , validator , cast } = prop ; if ( type != null ) { if ( value != null && ! type . some ( t => Object . getPrototypeOf ( value ) == t . prototype ) ) { throw new Error ( `Type error in prop '${ key }'.` ) ; } } if ( required && isUndefined ( value ) ) { throw new Error ( `Value required in prop '${ key }'.` ) ; } if ( validator && ! validator ( value ) ) { throw new Error ( `Validation error in prop '${ key }'.` ) ; } if ( cast ) { switch ( type [ 0 ] ) { case Boolean : const str = String ( value ) ; if ( value == null || str === 'false' ) { return false as V ; } else if ( str === '' || str === 'true' ) { return true ; } break ; case Number : let n = Number ( value ) ; if ( ! isNaN ( n ) ) { return n ; } } } return value ; }