/** * Hold a bunch of something */ export default class Collection extends Map { baseObject: (new (...args: any[]) => V) | undefined; /** * Creates an instance of Collection */ constructor(iterable: Iterable<[string, V]> | object | null = null) { if (iterable && iterable instanceof Array) { super(iterable); } else if (iterable && iterable instanceof Object) { super(Object.entries(iterable)); } else { super(); } } /** * Map to array * ```js * [value, value, value] * ``` */ toArray(): V[] { return [...this.values()]; } /** * Map to object * ```js * { key: value, key: value, key: value } * ``` */ toObject(): { [key: string]: V } { const obj: { [key: string]: V } = {}; for (const [key, value] of this.entries()) { obj[key] = value; } return obj; } /** * Add an object * * If baseObject, add only if instance of baseObject * * If no baseObject, add * @param key The key of the object * @param value The object data * @param replace Whether to replace an existing object with the same key * @return The existing or newly created object */ add(key: string, value: V, replace: boolean = false): V | undefined | null { if (this.has(key) && !replace) { return this.get(key); } if (this.baseObject && !(value instanceof this.baseObject)) return null; this.set(key, value); return value; } /** * Return the first object to make the function evaluate true * @param func A function that takes an object and returns something * @return The first matching object, or `null` if no match */ find(func: Function): V | null { for (const item of this.values()) { if (func(item)) return item; } return null; } /** * Return an array with the results of applying the given function to each element * @param callbackfn A function that takes an object and returns something */ map(callbackfn: (value?: V, index?: number, array?: V[]) => U): U[] { const arr = []; for (const item of this.values()) { arr.push(callbackfn(item)); } return arr; } /** * Return all the objects that make the function evaluate true * @param func A function that takes an object and returns true if it matches */ filter(func: (value: V) => boolean): V[] { const arr = []; for (const item of this.values()) { if (func(item)) { arr.push(item); } } return arr; } /** * Test if at least one element passes the test implemented by the provided function. Returns true if yes, or false if not. * @param func A function that takes an object and returns true if it matches */ some(func: (value: V) => boolean) { for (const item of this.values()) { if (func(item)) { return true; } } return false; } /** * Update an object * @param key The key of the object * @param value The updated object data */ update(key: string, value: V) { return this.add(key, value, true); } /** * Remove an object * @param key The key of the object * @returns The removed object, or `null` if nothing was removed */ remove(key: string): V | null { const item = this.get(key); if (!item) { return null; } this.delete(key); return item; } /** * Get a random object from the Collection * @returns The random object or `null` if empty */ random(): V | null { if (!this.size) { return null; } return Array.from(this.values())[Math.floor(Math.random() * this.size)]; } toString() { // @ts-ignore return `[Collection<${this.baseObject.name}>]`; } }