All files / sportident/src/utils general.ts

100% Statements 49/49
100% Branches 14/14
100% Functions 12/12
100% Lines 42/42

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83    38x       138x 230x 230x 230x 83x 83x 83x   147x   138x           38x       88x 58x   30x 30x 298x   298x 298x 298x 1x   297x   29x 29x     38x       13x 13x   13x                 38x         153x 153x 153x 153x 153x 45x 45x 45x   153x 153x 153x 153x 216x   152x    
export type Cache<T> = {[id: string]: T};
 
export const cached = <T>(
    cache: Cache<T>,
    getThing: () => T,
): () => T => {
    const getter = (): T => {
        const getThingIdent = `${getThing.name}-${getThing.toString()}`;
        const cachedThing = cache[getThingIdent];
        if (cachedThing === undefined) {
            const newThing = getThing();
            cache[getThingIdent] = newThing;
            return newThing;
        }
        return cachedThing;
    };
    return getter;
};
 
export type Lookup = {[id: string]: string};
export type MappingWithLookup<T> = {[id: string]: T|string|Lookup};
 
export const getLookup = <T>(
    mapping: MappingWithLookup<T>,
    getLookupKey?: (value: T) => string,
): Lookup => {
    if (mapping._lookup) {
        return mapping._lookup as Lookup;
    }
    const lookup: Lookup = {};
    Object.keys(mapping)
        .filter((mappingKey) => mappingKey.substr(0, 1) !== '_')
        .forEach((mappingKey) => {
            const mappingValue = mapping[mappingKey];
            const lookupKey = getLookupKey ? getLookupKey(mappingValue as T) : (mappingValue as string);
            if (lookupKey in lookup) {
                throw new Error(`Duplicate lookup key: ${lookupKey}`);
            }
            lookup[lookupKey] = mappingKey;
        });
    mapping._lookup = lookup;
    return lookup;
};
 
export const waitFor = <T>(
    milliseconds: number,
    value?: T,
): Promise<T|undefined> => {
    const promise: Promise<T|undefined> = new Promise((resolve) => {
        setTimeout(() => resolve(value), milliseconds);
    });
    return promise;
};
 
export interface BinarySearchOptions<L, T> {
    getLength?: (list: L) => number;
    getItemAtIndex?: (list: L, index: number) => T|undefined;
    getNewRange?: (list: L, item: T, start: number, end: number) => [number, number];
}
 
export const binarySearch = <L, T>(
    list: L,
    item: T,
    options: BinarySearchOptions<L, T> = {},
): number => {
    const defaultGetLength = (list_: L): number => ((list_ as unknown) as T[]).length;
    const getLength = options.getLength || defaultGetLength;
    const defaultGetItemAtIndex = (list_: L, index: number): T => ((list_ as unknown) as T[])[index];
    const getItemAtIndex = options.getItemAtIndex || defaultGetItemAtIndex;
    const defaultGetNewRange = (list_: L, item_: T, start: number, end: number): [number, number] => {
        const mid = Math.floor((start + end) / 2);
        const midItem = getItemAtIndex(list_, mid)!;
        return (item_ <= midItem) ? [start, mid] : [mid + 1, end];
    };
    const getNewRange = options.getNewRange || defaultGetNewRange;
    let start = 0;
    let end = getLength(list);
    while (start < end) {
        [start, end] = getNewRange(list, item, start, end);
    }
    return start;
};