import { parse as urllibParse } from "url" ; import { defaults , noop , flatten } from "./lodash" ; import { CallbackFunction } from "../types" ; import Debug from "./debug" ; import TLSProfiles from "../constants/TLSProfiles" ; export param { Buffer } a param { Buffer } b returns { boolean } export function bufferEqual ( a , b ) { if ( typeof a . equals === "function" ) { return a . equals ( b ) ; } if ( a . length !== b . length ) { return false ; } for ( let i = 0 ; i < a . length ; ++ i ) { if ( a [ i ] !== b [ i ] ) { return false ; } } return true ; } param { * } value param { string } encoding return { * } example private export function convertBufferToString ( value , encoding ? ) { if ( value instanceof Buffer ) { return value . toString ( encoding ) ; } if ( Array . isArray ( value ) ) { const length = value . length ; const res = Array ( length ) ; for ( let i = 0 ; i < length ; ++ i ) { res [ i ] = value [ i ] instanceof Buffer && encoding === "utf8" ? value [ i ] . toString ( ) : convertBufferToString ( value [ i ] , encoding ) ; } return res ; } return value ; } param { Array } arr return { Array } example private export function wrapMultiResult ( arr ) { if ( ! arr ) { return null ; } const result = [ ] ; const length = arr . length ; for ( let i = 0 ; i < length ; ++ i ) { const item = arr [ i ] ; if ( item instanceof Error ) { result . push ( [ item ] ) ; } else { result . push ( [ null , item ] ) ; } } return result ; } param { string } value return { boolean } example private export function isInt ( value ) { const x = parseFloat ( value ) ; return ! isNaN ( value ) && ( x | 0 ) === x ; } param { array } array return { object } example export function packObject ( array ) { const result = { } ; const length = array . length ; for ( let i = 1 ; i < length ; i += 2 ) { result [ array [ i - 1 ] ] = array [ i ] ; } return result ; } param { function } callback param { number } timeout return { function } export function timeout ( callback , timeout ) { let timer ; const run = function ( ) { if ( timer ) { clearTimeout ( timer ) ; timer = null ; callback . apply ( this , arguments ) ; } } ; timer = setTimeout ( run , timeout , new Error ( "timeout" ) ) ; return run ; } param { object } obj return { array } example export function convertObjectToArray < T > ( obj ) { const result = [ ] ; const keys = Object . keys ( obj ) ; for ( let i = 0 , l = keys . length ; i < l ; i ++ ) { result . push ( keys [ i ] , obj [ keys [ i ] ] ) ; } return result ; } param { Map } map return { array } example export function convertMapToArray < K , V > ( map ) { const result = [ ] ; let pos = 0 ; map . forEach ( function ( value , key ) { result [ pos ] = key ; result [ pos + 1 ] = value ; pos += 2 ; } ) ; return result ; } param { * } arg return { string } export function toArg ( arg ) { if ( arg === null || typeof arg === "undefined" ) { return "" ; } return String ( arg ) ; } param { Error } error param { string } friendlyStack param { string } filterPath export function optimizeErrorStack ( error , friendlyStack , filterPath ) { const stacks = friendlyStack . split ( "\n" ) ; let lines = "" ; let i ; for ( i = 1 ; i < stacks . length ; ++ i ) { if ( stacks [ i ] . indexOf ( filterPath ) === - 1 ) { break ; } } for ( let j = i ; j < stacks . length ; ++ j ) { lines += "\n" + stacks [ j ] ; } const pos = error . stack . indexOf ( "\n" ) ; error . stack = error . stack . slice ( 0 , pos ) + lines ; return error ; } param { string } url return { Object } export function parseURL ( url ) { if ( isInt ( url ) ) { return { port : url } ; } let parsed = urllibParse ( url , true , true ) ; if ( ! parsed . slashes && url [ 0 ] !== "/" ) { url = "//" + url ; parsed = urllibParse ( url , true , true ) ; } const options = parsed . query || { } ; const allowUsernameInURI = options . allowUsernameInURI && options . allowUsernameInURI !== "false" ; delete options . allowUsernameInURI ; const result = { } ; if ( parsed . auth ) { const index = parsed . auth . indexOf ( ":" ) ; if ( allowUsernameInURI ) { result . username = index === - 1 ? parsed . auth : parsed . auth . slice ( 0 , index ) ; } result . password = index === - 1 ? "" : parsed . auth . slice ( index + 1 ) ; } if ( parsed . pathname ) { if ( parsed . protocol === "redis:" || parsed . protocol === "rediss:" ) { if ( parsed . pathname . length > 1 ) { result . db = parsed . pathname . slice ( 1 ) ; } } else { result . path = parsed . pathname ; } } if ( parsed . host ) { result . host = parsed . hostname ; } if ( parsed . port ) { result . port = parsed . port ; } defaults ( result , options ) ; return result ; } interface ITLSOptions { port : number ; host : string ; [ key ] : any ; } param { Object } options return { Object } export function resolveTLSProfile ( options ) { let tls = options ?. tls ; if ( typeof tls === "string" ) tls = { profile : tls } ; const profile = TLSProfiles [ tls ?. profile ] ; if ( profile ) { tls = Object . assign ( { } , profile , tls ) ; delete tls . profile ; options = Object . assign ( { } , options , { tls } ) ; } return options ; } export template T param { T [ ] } array param { number } from returns { T } export function sample < T > ( array , from = 0 ) { const length = array . length ; if ( from >= length ) { return ; } return array [ from + Math . floor ( Math . random ( ) * ( length - from ) ) ] ; } export template T param { T [ ] } array returns { T [ ] } export function shuffle < T > ( array ) { let counter = array . length ; while ( counter > 0 ) { const index = Math . floor ( Math . random ( ) * counter ) ; counter -- ; [ array [ counter ] , array [ index ] ] = [ array [ index ] , array [ counter ] ] ; } return array ; } /**
 * Error message for connection being disconnected
 */ export const CONNECTION_CLOSED_ERROR_MSG = "Connection is closed." ; export function zipMap < K , V > ( keys , values ) { const map = new Map < K , V > ( ) ; keys . forEach ( ( key , index ) => { map . set ( key , values [ index ] ) ; } ) ; return map ; } export { Debug , defaults , noop , flatten } ;