import { IWrapContext , IDeferred } from './types' ; const uniqId = Math . random ( ) . toString ( 36 ) . slice ( 2 , 8 ) ; let globalIndex = 0 ; export function getId ( ) { globalIndex += 1 ; return `mm-${ uniqId }-${ globalIndex }` ; } export function noop ( ) { } export function walkTree < T > ( tree , callback , key = 'c' ) { const walk = ( item , parent ? ) : void => callback ( item , ( ) => { item [ key ] ?. forEach ( ( child ) => { walk ( child , item ) ; } ) ; } , parent ) ; walk ( tree ) ; } export function arrayFrom < T > ( arrayLike ) { if ( Array . from ) return Array . from ( arrayLike ) ; const array = [ ] ; for ( let i = 0 ; i < arrayLike . length ; i += 1 ) { array . push ( arrayLike [ i ] ) ; } return array ; } export function flatMap < T , U > ( arrayLike , callback ) { if ( ( arrayLike as Array < T > ) . flatMap ) return ( arrayLike as Array < T > ) . flatMap ( callback ) ; const array = [ ] ; for ( let i = 0 ; i < arrayLike . length ; i += 1 ) { const result = callback ( arrayLike [ i ] , i , arrayLike ) ; if ( Array . isArray ( result ) ) array . push ( ... result ) ; else array . push ( result ) ; } return array ; } export function addClass ( className , ... rest ) { const classList = ( className || '' ) . split ( ' ' ) . filter ( Boolean ) ; rest . forEach ( ( item ) => { if ( item && classList . indexOf ( item ) < 0 ) classList . push ( item ) ; } ) ; return classList . join ( ' ' ) ; } export function childSelector < T extends Element > ( filter ? ) { if ( typeof filter === 'string' ) { const tagName = filter ; filter = ( el ) : boolean => el . tagName === tagName ; } const filterFn = filter ; return function selector ( ) : T [ ] { let nodes = arrayFrom ( ( this as HTMLElement ) . childNodes as NodeListOf < T > ) ; if ( filterFn ) nodes = nodes . filter ( ( node ) => filterFn ( node ) ) ; return nodes ; } ; } export function wrapFunction < T extends ( ... args : any [ ] ) => any > ( fn , { before , after , } ) { return function wrapped ( ... args ) { const ctx = { args , thisObj : this , } ; try { if ( before ) before ( ctx ) ; } catch { } ctx . result = fn . apply ( ctx . thisObj , ctx . args ) ; try { if ( after ) after ( ctx ) ; } catch { } return ctx . result ; } as T ; } export function defer < T > ( ) { const obj = { } ; obj . promise = new Promise < T > ( ( resolve , reject ) => { obj . resolve = resolve ; obj . reject = reject ; } ) ; return obj as IDeferred < T > ; } export function memoize < T extends ( ... args : any [ ] ) => any > ( fn ) { const cache = { } ; return function memoized ( ... args ) : T { const key = `${ args [ 0 ] }` ; let data = cache [ key ] ; if ( ! data ) { data = { value : fn ( ... args ) , } ; cache [ key ] = data ; } return data . value ; } as T ; }