import { scriptTag , linkTag , doc , retryIdentifier , ScriptElementCtor , LinkElementCtor , ImageElementCtor , ElementCtor } from './constants' ; export const identity = function < T > ( x ) : T { return x ; } ; export const noop = ( ) => { } ; export const hasOwn = Object . prototype . hasOwnProperty ; template T template R param { ( this : T , ... callbackArgs : any [ ] ) => R } func param { T } thisArg param { * } args returns { R } export const safeCall = function < T , R > ( func , thisArg , args ) : R { if ( typeof func !== 'function' ) { return null as any ; } return func . call ( thisArg , args ) ; } ; param { string } current param { string } oldStr param { string } newStr returns export const stringReplace = function ( current , oldStr , newStr ) { const idx = current . indexOf ( oldStr ) ; if ( idx === - 1 ) { return current ; } return current . substring ( 0 , idx ) + newStr + current . substring ( idx + oldStr . length ) ; } ; /**
 * remove duplicates from an array of strings
 */ export const unique = function ( array ) { const map = { } as any ; array . forEach ( item => { map [ item ] = true ; } ) ; return Object . keys ( map ) ; } ; param { string } str returns export const toSlug = function ( str ) { return str . replace ( /([a-z])([A-Z])/g , ( _ , $1 , $2 ) => `${ $1 }-${ $2 . toLowerCase ( ) }` ) ; } ; template T param { ArrayLike < T > } arrayLike returns { T [ ] } export const arrayFrom = function < T > ( arrayLike ) : T [ ] { return [ ] . slice . call ( arrayLike ) ; } ; param { any } obj returns export const collectPropertyNames = function ( obj ) { const getProto = Object . getPrototypeOf ? Object . getPrototypeOf : function ( x ) { return x . __proto__ ; } ; let keys = Object . keys ( obj ) ; while ( getProto ( obj ) ) { keys = keys . concat ( Object . keys ( getProto ( obj ) ) ) ; obj = getProto ( obj ) ; } return keys . filter ( key => key !== 'constructor' ) ; } ; example param { any } proto param { string } key returns export const isFunctionProperty = function ( proto , key ) { try { return typeof proto [ key ] === 'function' ; } catch ( e ) { return false ; } } ; returns export const supportDocumentWrite = ( ) => { return ! /Edge|MSIE|rv:/i . test ( navigator . userAgent ) ; } ; param { HTMLScriptElement } $script param { string } newSrc export const loadNextScript = function ( $script , newSrc , onload = noop , isAsync = false ) { const isAsyncScript = isAsync || $script . defer || $script . async ; if ( doc . readyState === 'loading' && supportDocumentWrite ( ) && ! isAsyncScript ) { const retryId = randomString ( ) ; const newHtml = $script . outerHTML . replace ( /data-retry-id="[^"]+"/ , '' ) . replace ( /src=(?:"[^"]+"|.+)([ >])/ , `${ retryIdentifier }=${ retryId } src="${ newSrc }"$1` ) ; doc . write ( newHtml ) ; const newScript = doc . querySelector ( `script[${ retryIdentifier }="${ retryId }"]` ) as HTMLScriptElement ; if ( newScript ) { newScript . onload = onload ; } return ; } const $newScript = doc . createElement ( scriptTag ) ; Object . keys ( ScriptElementCtor . prototype ) . forEach ( function ( key ) { if ( key !== 'src' && ( $script as any ) [ key ] && typeof ( $script as any ) [ key ] !== 'object' ) { try { ; ( $newScript as any ) [ key ] = ( $script as any ) [ key ] ; } catch ( _ ) { } } } ) ; $newScript . src = newSrc ; $newScript . onload = $script . onload ; $newScript . onerror = $script . onerror ; $newScript . setAttribute ( retryIdentifier , randomString ( ) ) ; const originalNonce = $script . getAttribute ( 'nonce' ) ; if ( originalNonce ) { $newScript . setAttribute ( 'nonce' , originalNonce ) ; } doc . getElementsByTagName ( 'head' ) [ 0 ] . appendChild ( $newScript ) ; } ; param { CSSStyleSheet } styleSheet returns export const getCssRules = function ( styleSheet ) { try { return styleSheet . rules ; } catch ( _ ) { try { return styleSheet . cssRules ; } catch ( _ ) { return null ; } } } ; param { CSSStyleSheet } styleSheet returns export const supportRules = function ( styleSheet ) { const rules = getCssRules ( styleSheet ) ; return ! ! rules ; } ; param { HTMLLinkElement } $link param { string } newHref export const loadNextLink = function ( $link , newHref , onload ? ) { const $newLink = doc . createElement ( linkTag ) ; Object . keys ( LinkElementCtor . prototype ) . forEach ( function ( key ) { if ( key !== 'href' && ( $link as any ) [ key ] && typeof ( $link as any ) [ key ] !== 'object' ) { try { ; ( $newLink as any ) [ key ] = ( $link as any ) [ key ] ; } catch ( _ ) { } } } ) ; $newLink . href = newHref ; $newLink . onload = onload || $link . onload ; $newLink . onerror = $link . onerror ; $newLink . setAttribute ( retryIdentifier , randomString ( ) ) ; doc . getElementsByTagName ( 'head' ) [ 0 ] . appendChild ( $newLink ) ; } ; export const hashTarget = function ( element ) { if ( ! element ) { return 'null' ; } if ( ! ( element instanceof ElementCtor ) ) { return 'not_supported' ; } const nodeName = element . nodeName ; const src = ( element as any ) . src ; const href = ( element as any ) . href ; const dataRetryId = element . getAttribute ( retryIdentifier ) ; return [ nodeName , src , href , dataRetryId ] . join ( ';' ) ; } ; export const randomString = ( ) => Math . random ( ) . toString ( 36 ) . slice ( 2 ) ; param target export const getTargetUrl = function ( target ) { if ( target instanceof ScriptElementCtor || target instanceof ImageElementCtor ) { return target . src ; } if ( target instanceof LinkElementCtor ) { return target . href ; } return '' ; } ;