UNPKG

event-reduce-js

Version:

javascript implementation of the event-reduce algorithm https://pubkey.github.io/event-reduce/

173 lines (146 loc) 4.44 kB
import type { MongoQuery, DeepReadonlyObject } from './types/index.js'; export function lastOfArray<T>(ar: T[]): T { return ar[ar.length - 1]; } /** * @link https://stackoverflow.com/a/5915122 */ export function randomOfArray<T>(items: T[]): T { return items[Math.floor(Math.random() * items.length)]; } export function shuffleArray<T>(arr: T[]): T[] { return arr.slice().sort(() => (Math.random() - 0.5)); } /** * normalizes sort-field * in: '-age' * out: 'age' */ export function normalizeSortField(field: string): string { if (field.startsWith('-')) { return field.substr(1); } else { return field; } } export function getSortFieldsOfQuery(query: MongoQuery): string[] { if (!query.sort) { // if no sort-order is set, use the primary key return ['_id']; } return query.sort.map(maybeArray => { if (Array.isArray(maybeArray)) { return maybeArray[0].map((field: any) => normalizeSortField(field)); } else { return normalizeSortField(maybeArray); } }); } /** * @link https://stackoverflow.com/a/1431113 */ export function replaceCharAt(str: string, index: number, replacement: string) { return str.substr(0, index) + replacement + str.substr(index + replacement.length); } export function mapToObject<K, V>(map: Map<K, V>): { [k: string]: V } { const ret: any = {}; map.forEach( (value: V, key: K) => { ret[key as any] = value; } ); return ret; } export function objectToMap<K, V>(object: { [k: string]: V }): Map<K, V> { const ret = new Map(); Object.entries(object).forEach(([k, v]) => { ret.set(k, v); }); return ret; } export function cloneMap<K, V>(map: Map<K, V>): Map<K, V> { const ret: any = new Map(); map.forEach( (value: V, key: K) => { ret[key as any] = value; } ); return ret; } /** * does a flat copy on the objects, * is about 3 times faster then using deepClone * @link https://jsperf.com/object-rest-spread-vs-clone/2 */ export function flatClone<T>(obj: T | DeepReadonlyObject<T>): T { return Object.assign({}, obj) as any; } export function ensureNotFalsy<T>(obj: T | false | undefined | null): T { if (!obj) { throw new Error('ensureNotFalsy() is falsy'); } return obj; } export function mergeSets<T>(sets: Set<T>[]): Set<T> { let ret: Set<T> = new Set(); sets.forEach(set => { ret = new Set([...ret, ...set]); }); return ret; } /** * @link https://stackoverflow.com/a/12830454/3443137 */ export function roundToTwoDecimals(num: number): number { return parseFloat(num.toFixed(2)); } export function isObject(value: null) { const type = typeof value; return value !== null && (type === 'object' || type === 'function'); } export function getProperty(object: any, path: string | string[], value?: any) { if (Array.isArray(path)) { path = path.join('.'); } if (!isObject(object as any) || typeof path !== 'string') { return value === undefined ? object : value; } const pathArray = path.split('.'); if (pathArray.length === 0) { return value; } for (let index = 0; index < pathArray.length; index++) { const key = pathArray[index]; if (isStringIndex(object as any, key as any)) { object = index === pathArray.length - 1 ? undefined : null; } else { object = (object as any)[key]; } if (object === undefined || object === null) { // `object` is either `undefined` or `null` so we want to stop the loop, and // if this is not the last bit of the path, and // if it didn't return `undefined` // it would return `null` if `object` is `null` // but we want `get({foo: null}, 'foo.bar')` to equal `undefined`, or the supplied value, not `null` if (index !== pathArray.length - 1) { return value; } break; } } return object === undefined ? value : object; } function isStringIndex(object: any[], key: string) { if (typeof key !== 'number' && Array.isArray(object)) { const index = Number.parseInt(key, 10); return Number.isInteger(index) && object[index] === object[key as any]; } return false; }