import * as R from 'ramda' ; interface Type < T > extends Function { new ( ... args ) : T ; } const safeAccess = < V , T extends { [ k ] : V ; } > ( obj ) => < K extends keyof T > ( k ) : V | null => { try { return obj [ k ] ; } catch ( e ) { return null ; } } ; const mapObject = ( fn ) => ( obj ) => R . reduce ( ( acc , key ) => { acc [ key ] = fn ( obj [ key ] ) ; return acc ; } , { } , R . keys ( obj ) ) ; export const getFunctions = < T extends { } > ( obj ) : { } => R . pipe ( Object . getOwnPropertyNames , R . map ( ( k ) => [ k , k ] ) , R . fromPairs , R . filter ( R . pipe ( safeAccess ( obj ) , R . is ( Function ) ) ) , R . map ( safeAccess ( obj ) ) ) ( obj ) ; export const flipStatic = < T > ( cls ) => R . pipe ( getFunctions , mapObject ( ( f ) => ( ... rest ) => ( x ) => f ( x , ... rest ) ) ) ( cls ) ; export const flipPrototype = < T > ( cls ) => R . pipe ( getFunctions , mapObject ( ( f ) => ( ... rest ) => ( x ) => f . apply ( x , rest ) ) ) ( cls . prototype ) ; export const flipClass = < T > ( cls ) => R . merge ( flipPrototype ( cls ) , flipStatic ( cls ) ) ; export default flipClass ; export const [ DYNAMIC , FIXED_EXACT , EVEN_OPTIONAL ] = R . range ( 0 , 10 ) ; const maxArity = ( isProto = false ) => 9 - ( isProto ? 1 : 0 ) ; export const getArities = ( isProto = false ) => < T extends { [ k ] : Function ; } > ( obj ) => R . pipe ( Object . getOwnPropertyNames , R . filter ( R . pipe ( safeAccess ( obj ) , R . is ( Function ) ) ) , R . map ( R . pipe ( safeAccess ( obj ) , < F extends Function > ( f ) => [ f . name , [ R . clamp ( 0 , maxArity ( isProto ) , f . length ) , f . name ] ] ) ) , R . fromPairs ) ( obj ) ; const withLower = ( isProto = false ) => ( n , k ) => R . pipe ( R . flip ( R . range ) ( 1 + maxArity ( isProto ) ) , R . map ( ( i ) => [ `${ k }${ i + ( isProto ? 1 : 0 ) }` , [ i , k ] ] ) , R . concat ( [ [ k , [ n , k ] ] ] ) , R . fromPairs ) ( n ) ; const getUsedArities = ( isProto , addArities ) => addArities == EVEN_OPTIONAL ? R . pipe ( R . map ( R . apply ( withLower ( isProto ) ) ) , R . values , R . mergeAll ) : R . identity ; const dynamify = ( isProto , addArities , fn ) => addArities == DYNAMIC ? R . pipe ( R . nthArg ( 1 ) , R . flip ( fn ) , < F extends Function > ( f ) => ( i ) => f ( i - ( isProto ? 1 : 0 ) ) ) : fn ; export const curryStatic = < T > ( cls , addArities = EVEN_OPTIONAL ) => R . pipe ( getArities ( false ) , getUsedArities ( false , addArities ) , R . map ( R . pipe ( R . tap ( console . log . bind ( console ) ) , R . adjust ( ( k ) => ( ... args ) => cls [ k ] ( R . last ( args ) , ... R . dropLast ( 1 , args ) ) , 1 ) , R . apply ( dynamify ( false , addArities , R . curryN ) ) ) ) ) ( cls ) ; export const curryPrototype = < T > ( cls , addArities = EVEN_OPTIONAL ) => R . pipe ( getArities ( true ) , getUsedArities ( true , addArities ) , R . map ( R . apply ( dynamify ( true , addArities , R . invoker ) ) ) ) ( cls . prototype ) ; export const curryClass = < T > ( cls , addArities = EVEN_OPTIONAL ) => R . merge ( curryPrototype ( cls , addArities ) , curryStatic ( cls , addArities ) ) ; export const curryNClass = < T > ( cls ) => curryClass ( cls , DYNAMIC ) ;