2021-10-03 09:03:56 +02:00
import { EventEmitter } from "events" ;
2021-11-07 09:17:19 +01:00
import { Dispatch , SetStateAction , useEffect , useState } from "react" ;
2021-10-03 09:03:56 +02:00
export type Unpromisify < T > = T extends Promise < infer R > ? R : T ;
export type Unarray < T > = T extends Array < infer R > ? R : T ;
export type Tab = Unarray < Unpromisify < ReturnType < typeof browser.tabs.query > >> ;
2021-11-09 17:47:42 +01:00
export type Request = {
cookieStoreId? : string ;
documentUrl? : string ; // RL of the document in which the resource will be loaded. For example, if the web page at "https://example.com" contains an image or an iframe, then the documentUrl for the image or iframe will be "https://example.com". For a top-level document, documentUrl is undefined.
frameId : number ;
incognito? : boolean ;
method : string ;
originUrl : string ;
parentFrameId : number ;
proxyInfo ? : {
host : string ;
port : number ;
type : string ;
username : string ;
proxyDNS : boolean ;
failoverTimeout : number ;
} ;
requestHeaders ? : { name : string ; value? : string ; binaryValue? : number [ ] } [ ] ;
requestId : string ;
tabId : number ;
thirdParty? : boolean ;
timeStamp : number ;
type : string ;
url : string ; // the target of the request;
urlClassification ? : { firstParty : string [ ] ; thirdParty : string [ ] } ;
} ;
2021-10-03 09:03:56 +02:00
export function getshorthost ( host : string ) {
2021-11-24 22:03:03 +01:00
const parts = host
2021-11-07 15:45:26 +01:00
. replace ( /^.*:\/\// , "" )
. replace ( /\/.*$/ , "" )
2021-11-24 22:03:03 +01:00
. split ( "." ) ;
2021-11-24 23:58:12 +01:00
let lookback = parts . at ( - 2 ) . length > 3 ? - 2 : - 3 ;
if ( parts . at ( - 2 ) == "doubleclick" ) {
lookback = - 4 ; // to distinguish between google ads and stats
}
return parts . slice ( lookback ) . join ( "." ) ;
2021-10-03 09:03:56 +02:00
}
2021-11-07 09:17:19 +01:00
export function useEmitter (
e : EventEmitter
) : [ number , Dispatch < SetStateAction < number > > ] {
2021-10-03 09:03:56 +02:00
const [ counter , setCounter ] = useState < number > ( 0 ) ;
useEffect ( ( ) = > {
const callback = ( ) = > {
setCounter ( ( counter ) = > counter + 1 ) ;
} ;
e . on ( "change" , callback ) ;
return ( ) = > {
e . removeListener ( "change" , callback ) ;
} ;
} , [ ] ) ;
2021-11-07 09:17:19 +01:00
return [ counter , setCounter ] ;
2021-10-03 09:03:56 +02:00
}
export function parseCookie ( cookie : string ) : Record < string , string > {
return cookie
. split ( ";" )
. map ( ( l ) = > l . split ( "=" ) )
. reduce (
( acc , [ key , value ] ) = > ( {
. . . acc ,
[ key ] : value ,
} ) ,
{ }
) ;
}
2021-11-06 21:48:25 +01:00
export async function getTabByID ( id : number ) {
const tabs = await browser . tabs . query ( { currentWindow : true } ) ;
return tabs . find ( ( tab ) = > tab . id == id ) ;
}
2021-11-07 10:09:41 +01:00
2021-11-22 13:28:31 +01:00
export function parseToObject ( str : unknown ) : Record < string | symbol , unknown > {
let result : Record < string | symbol , unknown > ;
let original_string : string ;
2021-11-07 10:09:41 +01:00
if ( typeof str === "string" ) {
2021-11-22 13:28:31 +01:00
original_string = str ;
result = JSON . parse ( str ) ;
2021-11-07 10:09:41 +01:00
} else if ( typeof str == "object" ) {
2021-11-22 13:28:31 +01:00
result = str as Record < string | symbol , unknown > ;
original_string =
( result [ Symbol . for ( "originalString" ) ] as string ) || JSON . stringify ( str ) ;
2021-11-07 10:09:41 +01:00
}
2021-11-22 13:28:31 +01:00
result [ Symbol . for ( "originalString" ) ] = original_string ;
return result ;
2021-11-07 10:09:41 +01:00
}
export function isJSONObject (
str : unknown
) : str is Record < string , unknown > | string | number {
try {
return JSON . stringify ( parseToObject ( str ) ) [ 0 ] == "{" ;
} catch ( e ) {
return false ;
}
}
export function isURL ( str : unknown ) : str is string {
try {
return ! ! ( typeof str === "string" && new URL ( str ) ) ;
} catch ( e ) {
return false ;
}
}
export function hyphenate ( str : string ) : string {
return str . replace ( /[_\[A-Z]/g , ` ${ String . fromCharCode ( 173 ) } $ & ` ) ;
}
2021-11-07 13:57:24 +01:00
2021-11-09 17:47:42 +01:00
export function unique < T > ( array : T [ ] ) : Array < T > {
return Array . from ( new Set < T > ( array ) ) ;
2021-11-07 17:18:17 +01:00
}
export function allSubhosts ( host : string ) {
const parts = host . split ( "." ) ;
const result = [ ] ;
for ( let i = 0 ; i < parts . length - 2 ; i ++ ) {
result . push ( parts . slice ( i ) . join ( "." ) ) ;
}
return result ;
}
2021-11-07 17:44:22 +01:00
export function reduceConcat < T > ( a : T [ ] , b : T [ ] ) : T [ ] {
return a . concat ( b ) ;
}
2021-11-07 19:03:00 +01:00
export function getDate() {
const d = new Date ( ) ;
return ` ${ d . getFullYear ( ) } - ${ ( d . getMonth ( ) + 1 )
. toString ( )
. padStart ( 2 , "0" ) } - $ { d . getDate ( ) . toString ( ) . padStart ( 2 , "0" ) } ` ;
}
2021-11-11 11:10:52 +01:00
export function toBase64 ( file : File ) : Promise < string > {
return new Promise ( ( resolve ) = > {
const FR = new FileReader ( ) ;
FR . addEventListener ( "load" , ( e ) = > {
resolve ( e . target . result as string ) ;
} ) ;
FR . readAsDataURL ( file ) ;
} ) ;
}
2021-11-21 18:19:58 +01:00
export function makeThrottle ( interval : number ) {
let last_emit = 0 ;
function emit ( callback : ( ) = > void ) {
if ( Date . now ( ) - last_emit > interval ) {
callback ( ) ;
last_emit = Date . now ( ) ;
return true ;
} else {
return false ;
}
}
return function ( callback : ( ) = > void ) {
if ( ! emit ( callback ) ) {
setTimeout ( ( ) = > emit ( callback ) , interval ) ;
}
} ;
}
2021-11-22 12:03:55 +01:00
export function isSameURL ( url1 : string , url2 : string ) : boolean {
if ( url1 === url2 ) {
return true ;
}
url1 = url1 . replace ( /^https?:\/\// , "" ) . replace ( /\/$/ , "" ) ;
url2 = url2 . replace ( /^https?:\/\// , "" ) . replace ( /\/$/ , "" ) ;
return url1 === url2 ;
}
2021-11-22 15:08:29 +01:00
export function isBase64 ( s : string ) : boolean {
try {
atob ( s ) ;
return true ;
} catch ( e ) { }
return false ;
}
export function isBase64JSON ( s : unknown ) : s is string {
return typeof s === "string" && isBase64 ( s ) && isJSONObject ( atob ( s ) ) ;
}
2021-11-22 17:54:15 +01:00
export function flattenObject (
obj : Record < string , unknown >
) : [ string , string ] [ ] {
const ret : [ string , string ] [ ] = [ ] ;
for ( const [ key , value ] of Object . entries ( obj ) ) {
const value = obj [ key ] ;
if ( value === null ) {
ret . push ( [ key , "null" ] ) ;
continue ;
}
if ( typeof value === "object" ) {
const flattened = flattenObject ( value as Record < string , unknown > ) ;
for ( const [ subkey , subvalue ] of flattened ) {
ret . push ( [ ` ${ key } . ${ subkey } ` , subvalue ] ) ;
}
} else {
ret . push ( [ key , value . toString ( ) ] ) ;
}
}
return ret ;
}
export function flattenObjectEntries (
entries : [ string , unknown ] [ ]
) : [ string , string ] [ ] {
return flattenObject ( Object . fromEntries ( entries ) ) ;
}
2021-11-22 18:56:36 +01:00
export function maskString (
str : string ,
max_fraction_remaining : number ,
max_chars_total : number
) : string {
const amount_of_chars_to_cut =
str . length - Math . min ( str . length * max_fraction_remaining , max_chars_total ) ;
if ( amount_of_chars_to_cut == 0 ) {
return str ;
}
return (
str . slice ( 0 , str . length / 2 - amount_of_chars_to_cut / 2 ) +
"(...)" +
str . slice ( str . length / 2 + amount_of_chars_to_cut / 2 )
) ;
}