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       153x 235x 235x 235x 88x 88x 88x   147x   153x           38x       99x 68x   31x 31x 303x   303x 303x 303x 1x   302x   30x 30x     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;
};