import type { Merger , DefuFn , Defu } from './types' ; function isObject ( val ) { return val !== null && typeof val === 'object' ; } function _defu < T > ( baseObj , defaults , namespace = '.' , merger ? ) { if ( ! isObject ( defaults ) ) { return _defu ( baseObj , { } , namespace , merger ) ; } const obj = Object . assign ( { } , defaults ) ; for ( const key in baseObj ) { if ( key === '__proto__' || key === 'constructor' ) { continue ; } const val = baseObj [ key ] ; if ( val === null || val === undefined ) { continue ; } if ( merger && merger ( obj , key , val , namespace ) ) { continue ; } if ( Array . isArray ( val ) && Array . isArray ( obj [ key ] ) ) { obj [ key ] = obj [ key ] . concat ( val ) ; } else if ( isObject ( val ) && isObject ( obj [ key ] ) ) { obj [ key ] = _defu ( val , obj [ key ] , ( namespace ? `${ namespace }.` : '' ) + key . toString ( ) , merger ) ; } else { obj [ key ] = val ; } } return obj ; } function extend ( merger ? ) { return ( ... args ) => args . reduce ( ( p , c ) => _defu ( p , c , '' , merger ) , { } as any ) ; } const defu = extend ( ) as Defu ; defu . fn = extend ( ( obj , key , currentValue , _namespace ) => { if ( typeof obj [ key ] !== 'undefined' && typeof currentValue === 'function' ) { obj [ key ] = currentValue ( obj [ key ] ) ; return true ; } } ) ; defu . arrayFn = extend ( ( obj , key , currentValue , _namespace ) => { if ( Array . isArray ( obj [ key ] ) && typeof currentValue === 'function' ) { obj [ key ] = currentValue ( obj [ key ] ) ; return true ; } } ) ; defu . extend = extend ; export default defu ;