import omit from "lodash/omit" ; import pickBy from "lodash/pickBy" ; import trimEnd from "lodash/trimEnd" ; import * as React from "react" ; import { useHistory } from "react-router-dom" ; import { BodyMatcher , defaultMatcher , Entry , EntryRequest , EntryResponse , Multimap , MultimapMatcher , StringMatcher , StringMatcherSlice , } from "./types" ; export const entryToCurl = ( historyEntry ) : string => { const escapeQuote = ( unsafe ) => unsafe . replace ( /'/g , "\\'" ) ; const command = [ "curl" ] ; let host = "" ; const { request } = historyEntry ; command . push ( `-X${ request . method }` ) ; if ( request . headers ) { command . push ( ... Object . entries ( request . headers ) . flatMap ( ( entry ) => { const [ key , values ] = entry ; if ( key . toLowerCase ( ) === "host" ) { if ( values . length > 0 ) { host = values [ 0 ] ; } return [ ] ; } return values . map ( ( value ) => `--header '${ escapeQuote ( key ) }: ${ escapeQuote ( value ) }'` ) ; } ) ) ; } let queryString = "" ; if ( request . query_params && Object . keys ( request . query_params ) . length > 0 ) { queryString = "?" ; queryString += Object . entries ( request . query_params ) . flatMap ( ( entry ) => { const [ key , values ] = entry ; return values . map ( ( value ) => `${ key }=${ value }` ) ; } ) . join ( "&" ) ; } command . push ( `'${ escapeQuote ( host ) }${ escapeQuote ( request . path ) }${ escapeQuote ( queryString ) }'` ) ; if ( request . body ) { command . push ( `--data '${ escapeQuote ( JSON . stringify ( request . body ) ) }'` ) ; } return command . join ( " " ) ; } ; function simplifyMultimap ( multimap ) { return Object . entries ( multimap ) . reduce ( ( newMultimap , [ key , values ] ) => { if ( values . length === 0 ) { return newMultimap ; } if ( values . length === 1 ) { newMultimap [ key ] = values [ 0 ] ; return newMultimap ; } newMultimap [ key ] = [ ... values ] ; return newMultimap ; } , { } ) ; } const headersToClean = [ "Accept" , "Accept-Encoding" , "Accept-Language" , "Connection" , "Content-Length" , "Date" , "Dnt" , "If-None-Match" , "Sec-Fetch-Dest" , "Sec-Fetch-Mode" , "Sec-Fetch-Site" , "Te" , "Upgrade-Insecure-Requests" , "User-Agent" , ] ; export const cleanupRequest = ( historyEntry ) : EntryRequest => { let request = { ... historyEntry . request } ; if ( historyEntry . request . headers ) { request . headers = simplifyMultimap ( historyEntry . request . headers ) ; request . headers = omit ( request . headers , headersToClean ) ; } if ( historyEntry . request . query_params ) { request . query_params = simplifyMultimap ( historyEntry . request . query_params ) ; } request = omit ( request , "body_string" ) as EntryRequest ; request = omit ( request , "date" ) as EntryRequest ; request = omit ( request , "origin" ) as EntryRequest ; request = pickBy ( request ) as EntryRequest ; if ( typeof request . body === "object" && request . body !== null ) { request . body = bodyMatcherToPaths ( request . body ) ; } return request ; } ; export const bodyMatcherToPaths = ( bodyMatcher , currentPath = "" , result = { } ) : Record < string , unknown > => { if ( Array . isArray ( bodyMatcher ) ) { bodyMatcher . forEach ( ( item , index ) => { bodyMatcherToPaths ( item , `${ currentPath }[${ index }]` , result ) ; } ) ; return result ; } else if ( typeof bodyMatcher === "object" && bodyMatcher !== null ) { Object . entries ( bodyMatcher ) . forEach ( ( [ key , value ] ) => { bodyMatcherToPaths ( value , currentPath ? `${ currentPath }.${ key }` : `${ key }` , result ) ; } ) ; return result ; } else { result [ currentPath ] = bodyMatcher ; return result ; } } ; export const cleanupResponse = ( historyEntry ) : EntryResponse => { let response = { ... historyEntry . response } ; if ( historyEntry . response . headers ) { response . headers = simplifyMultimap ( historyEntry . response . headers ) ; response . headers = omit ( response . headers , headersToClean ) ; } response = omit ( response , "date" ) as EntryResponse ; response = pickBy ( response ) as EntryResponse ; return response ; } ; export const isStringMatcher = ( body ? ) : boolean => { if ( ! body ) { return false ; } if ( ( body as StringMatcher ) . matcher ) { return true ; } return false ; } ; export const bodyToString = ( body ? ) : string => { if ( ! body ) { return "" ; } if ( ( body as StringMatcher ) . matcher ) { return ( body as StringMatcher ) . value . trim ( ) ; } return "" ; } ; export const formatQueryParams = ( params ? ) : string => { if ( ! params ) { return "" ; } return ( "?" + Object . keys ( params ) . reduce ( ( acc , key ) => { params [ key ] . forEach ( ( v ) => { const value = v [ "value" ] || v ; const encodedValue = encodeURIComponent ( value ) ; const param = v [ "matcher" ] && v [ "matcher" ] !== defaultMatcher ? `${ key }=>(${ v [ "matcher" ] } "${ encodedValue }")` : `${ key }=${ encodedValue }` ; acc . push ( param ) ; } ) ; return acc ; } , [ ] ) . join ( "&" ) ) ; } ; export const formatHeaderValue = ( headerValue ? ) : string => { if ( ! headerValue ) { return "" ; } return headerValue . reduce ( ( acc , v ) => { const param = v . matcher !== defaultMatcher ? `${ v . matcher }: "${ v . value }"` : `${ v . value }` ; acc . push ( param ) ; return acc ; } , [ ] ) . join ( ", " ) ; } ; export const trimedPath = trimEnd ( window . basePath , "/" ) ; export type PollFunc < X , Y > = ( params : X ) => Y ; export function usePoll < K , V > ( delay , pollFunc , pollParams ) { const savedPollFunc = React . useRef < PollFunc < K , V > > ( ) ; const [ init , setInit ] = React . useState ( false ) ; const [ polling , setPolling ] = React . useState ( false ) ; React . useEffect ( ( ) => { savedPollFunc . current = pollFunc ; } , [ pollFunc ] ) ; React . useEffect ( ( ) => { function poll ( ) { if ( savedPollFunc . current ) { savedPollFunc . current ( pollParams ) ; } } if ( ! init || polling ) { poll ( ) ; } if ( polling && Boolean ( delay ) ) { const id = setInterval ( poll , delay ) ; return ( ) => clearInterval ( id ) ; } return undefined ; } , [ delay , polling , init , pollParams ] ) ; const togglePollingCb = React . useCallback ( ( ) => { setPolling ( ! polling ) ; setInit ( true ) ; } , [ polling ] ) ; const setPollingCb = React . useCallback ( ( poll ) => { setPolling ( poll ) ; setInit ( true ) ; } , [ ] ) ; return [ polling , togglePollingCb , setPollingCb ] ; } export const useQueryParams = ( ) : [ URLSearchParams , ( params : Record < string , string > , replace ? : boolean ) => void ] => { const history = useHistory ( ) ; const queryParams = new URLSearchParams ( history . location . search ) ; const setQueryParams = React . useCallback ( ( params , replace = false ) => { const newQueryParams = new URLSearchParams ( history . location . search ) ; Object . entries ( params ) . forEach ( ( [ key , value ] ) => { newQueryParams . set ( key , value ) ; } ) ; if ( replace ) { history . replace ( { search : newQueryParams . toString ( ) } ) ; } else { history . push ( { search : newQueryParams . toString ( ) } ) ; } } , [ ] ) ; return [ queryParams , setQueryParams ] ; } ; export const cleanQueryParams = < T extends { search : string ; } > ( location ) : T => { const queryParams = new URLSearchParams ( location . search ) ; const newQueryParams = new URLSearchParams ( ) ; const sessionQueryParam = queryParams . get ( "session" ) ; if ( sessionQueryParam ) { newQueryParams . set ( "session" , sessionQueryParam ) ; } return { ... location , search : newQueryParams . toString ( ) } ; } ;