diff --git a/src/util/Collection.js b/src/util/Collection.js index 79cfc0110..7eb66a905 100644 --- a/src/util/Collection.js +++ b/src/util/Collection.js @@ -98,7 +98,7 @@ class Collection extends Map { * Obtains the last value(s) in this collection. This relies on {@link Collection#array}, and thus the caching * mechanism applies here as well. * @param {number} [amount] Amount of values to obtain from the end - * @returns {*|Array<*>} A single value if no amount is provided or an array of values, starting from the end if + * @returns {*|Array<*>} A single value if no amount is provided or an array of values, starting from the start if * amount is negative */ last(amount) { @@ -113,7 +113,7 @@ class Collection extends Map { * Obtains the last key(s) in this collection. This relies on {@link Collection#keyArray}, and thus the caching * mechanism applies here as well. * @param {number} [amount] Amount of keys to obtain from the end - * @returns {*|Array<*>} A single key if no amount is provided or an array of keys, starting from the end if + * @returns {*|Array<*>} A single key if no amount is provided or an array of keys, starting from the start if * amount is negative */ lastKey(amount) { @@ -125,7 +125,7 @@ class Collection extends Map { } /** - * Obtains random value(s) from this collection. This relies on {@link Collection#array}, and thus the caching + * Obtains unique random value(s) from this collection. This relies on {@link Collection#array}, and thus the caching * mechanism applies here as well. * @param {number} [amount] Amount of values to obtain randomly * @returns {*|Array<*>} A single value if no amount is provided or an array of values @@ -141,7 +141,7 @@ class Collection extends Map { } /** - * Obtains random key(s) from this collection. This relies on {@link Collection#keyArray}, and thus the caching + * Obtains unique random key(s) from this collection. This relies on {@link Collection#keyArray}, and thus the caching * mechanism applies here as well. * @param {number} [amount] Amount of keys to obtain randomly * @returns {*|Array<*>} A single key if no amount is provided or an array @@ -157,106 +157,41 @@ class Collection extends Map { } /** - * Searches for all items where their specified property's value is identical to the given value - * (`item[prop] === value`). - * @param {string} prop The property to test against - * @param {*} value The expected value - * @returns {Array} - * @example - * collection.findAll('username', 'Bob'); - */ - findAll(prop, value) { - if (typeof prop !== 'string') throw new TypeError('Key must be a string.'); - if (typeof value === 'undefined') throw new Error('Value must be specified.'); - const results = []; - for (const item of this.values()) { - if (item[prop] === value) results.push(item); - } - return results; - } - - /** - * Searches for a single item where its specified property's value is identical to the given value - * (`item[prop] === value`), or the given function returns a truthy value. In the latter case, this is identical to + * Searches for a single item where the given function returns a truthy value. This behaves like * [Array.find()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find). * All collections used in Discord.js are mapped using their `id` property, and if you want to find by id you * should use the `get` method. See * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get) for details. - * @param {string|Function} propOrFn The property to test against, or the function to test with - * @param {*} [value] The expected value - only applicable and required if using a property for the first argument + * @param {Function} fn The function to test with (should return boolean) + * @param {*} [thisArg] Value to use as `this` when executing function * @returns {*} - * @example - * collection.find('username', 'Bob'); - * @example - * collection.find(val => val.username === 'Bob'); + * @example collection.find(user => user.username === 'Bob'); */ - find(propOrFn, value) { - if (typeof propOrFn === 'string') { - if (typeof value === 'undefined') throw new Error('Value must be specified.'); - for (const item of this.values()) { - if (item[propOrFn] === value) return item; - } - return undefined; - } else if (typeof propOrFn === 'function') { - for (const [key, val] of this) { - if (propOrFn(val, key, this)) return val; - } - return undefined; - } else { - throw new Error('First argument must be a property string or a function.'); + find(fn, thisArg) { + if (typeof thisArg !== 'undefined') fn = fn.bind(thisArg); + for (const [key, val] of this) { + if (fn(val, key, this)) return val; } + return undefined; } /* eslint-disable max-len */ /** - * Searches for the key of a single item where its specified property's value is identical to the given value - * (`item[prop] === value`), or the given function returns a truthy value. In the latter case, this is identical to - * [Array.findIndex()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex). - * @param {string|Function} propOrFn The property to test against, or the function to test with - * @param {*} [value] The expected value - only applicable and required if using a property for the first argument + * Searches for the key of a single item where the given function returns a truthy value. This behaves like + * [Array.findIndex()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex), + * but returns the key rather than the positional index. + * @param {Function} fn The function to test with (should return boolean) + * @param {*} [thisArg] Value to use as `this` when executing function * @returns {*} - * @example - * collection.findKey('username', 'Bob'); - * @example - * collection.findKey(val => val.username === 'Bob'); + * @example collection.findKey(user => user.username === 'Bob'); */ /* eslint-enable max-len */ - findKey(propOrFn, value) { - if (typeof propOrFn === 'string') { - if (typeof value === 'undefined') throw new Error('Value must be specified.'); - for (const [key, val] of this) { - if (val[propOrFn] === value) return key; - } - return undefined; - } else if (typeof propOrFn === 'function') { - for (const [key, val] of this) { - if (propOrFn(val, key, this)) return key; - } - return undefined; - } else { - throw new Error('First argument must be a property string or a function.'); + findKey(fn, thisArg) { + if (typeof thisArg !== 'undefined') fn = fn.bind(thisArg); + for (const [key, val] of this) { + if (fn(val, key, this)) return key; } - } - - /** - * Searches for the existence of a single item where its specified property's value is identical to the given value - * (`item[prop] === value`), or the given function returns a truthy value. - * Do not use this to check for an item by its ID. Instead, use `collection.has(id)`. See - * [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has) for details. - * @param {string|Function} propOrFn The property to test against, or the function to test with - * @param {*} [value] The expected value - only applicable and required if using a property for the first argument - * @returns {boolean} - * @example - * if (collection.exists('username', 'Bob')) { - * console.log('user here!'); - * } - * @example - * if (collection.exists(user => user.username === 'Bob')) { - * console.log('user here!'); - * } - */ - exists(propOrFn, value) { - return Boolean(this.find(propOrFn, value)); + return undefined; } /** @@ -266,7 +201,7 @@ class Collection extends Map { * @returns {number} The number of removed entries */ sweep(fn, thisArg) { - if (thisArg) fn = fn.bind(thisArg); + if (typeof thisArg !== 'undefined') fn = fn.bind(thisArg); const previousSize = this.size; for (const [key, val] of this) { if (fn(val, key, this)) this.delete(key); @@ -278,12 +213,13 @@ class Collection extends Map { * Identical to * [Array.filter()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), * but returns a Collection instead of an Array. - * @param {Function} fn Function used to test (should return a boolean) - * @param {Object} [thisArg] Value to use as `this` when executing function + * @param {Function} fn The function to test with (should return boolean) + * @param {*} [thisArg] Value to use as `this` when executing function * @returns {Collection} + * @example collection.filter(user => user.username === 'Bob'); */ filter(fn, thisArg) { - if (thisArg) fn = fn.bind(thisArg); + if (typeof thisArg !== 'undefined') fn = fn.bind(thisArg); const results = new Collection(); for (const [key, val] of this) { if (fn(val, key, this)) results.set(key, val); @@ -292,30 +228,36 @@ class Collection extends Map { } /** - * Identical to - * [Array.filter()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter). + * Partitions the collection into two collections where the first collection + * contains the items that passed and the second contains the items that failed. * @param {Function} fn Function used to test (should return a boolean) - * @param {Object} [thisArg] Value to use as `this` when executing function - * @returns {Array} + * @param {*} [thisArg] Value to use as `this` when executing function + * @returns {Collection[]} + * @example const [big, small] = collection.partition(guild => guild.memberCount > 250); */ - filterArray(fn, thisArg) { - if (thisArg) fn = fn.bind(thisArg); - const results = []; + partition(fn, thisArg) { + if (typeof thisArg !== 'undefined') fn = fn.bind(thisArg); + const results = [new Collection(), new Collection()]; for (const [key, val] of this) { - if (fn(val, key, this)) results.push(val); + if (fn(val, key, this)) { + results[0].set(key, val); + } else { + results[1].set(key, val); + } } return results; } /** - * Identical to + * Maps each item to another value. Identical in behavior to * [Array.map()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map). * @param {Function} fn Function that produces an element of the new array, taking three arguments * @param {*} [thisArg] Value to use as `this` when executing function * @returns {Array} + * @example collection.map(user => user.tag); */ map(fn, thisArg) { - if (thisArg) fn = fn.bind(thisArg); + if (typeof thisArg !== 'undefined') fn = fn.bind(thisArg); const arr = new Array(this.size); let i = 0; for (const [key, val] of this) arr[i++] = fn(val, key, this); @@ -323,14 +265,15 @@ class Collection extends Map { } /** - * Identical to + * Checks if there exists an item that passes a test. Identical in behavior to * [Array.some()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some). * @param {Function} fn Function used to test (should return a boolean) - * @param {Object} [thisArg] Value to use as `this` when executing function + * @param {*} [thisArg] Value to use as `this` when executing function * @returns {boolean} + * @example collection.some(user => user.discriminator === '0000'); */ some(fn, thisArg) { - if (thisArg) fn = fn.bind(thisArg); + if (typeof thisArg !== 'undefined') fn = fn.bind(thisArg); for (const [key, val] of this) { if (fn(val, key, this)) return true; } @@ -338,14 +281,15 @@ class Collection extends Map { } /** - * Identical to + * Checks if all items passes a test. Identical in behavior to * [Array.every()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every). * @param {Function} fn Function used to test (should return a boolean) - * @param {Object} [thisArg] Value to use as `this` when executing function + * @param {*} [thisArg] Value to use as `this` when executing function * @returns {boolean} + * @example collection.every(user => !user.bot); */ every(fn, thisArg) { - if (thisArg) fn = fn.bind(thisArg); + if (typeof thisArg !== 'undefined') fn = fn.bind(thisArg); for (const [key, val] of this) { if (!fn(val, key, this)) return false; } @@ -353,12 +297,13 @@ class Collection extends Map { } /** - * Identical to + * Applies a function to produce a single value. Identical in behavior to * [Array.reduce()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce). * @param {Function} fn Function used to reduce, taking four arguments; `accumulator`, `currentValue`, `currentKey`, * and `collection` * @param {*} [initialValue] Starting value for the accumulator * @returns {*} + * @example collection.reduce((acc, guild) => acc + guild.memberCount, 0); */ reduce(fn, initialValue) { let accumulator; @@ -456,6 +401,7 @@ class Collection extends Map { * If omitted, the collection is sorted according to each character's Unicode code point value, * according to the string conversion of each element. * @returns {Collection} + * @example collection.sort((userA, userB) => userA.createdTimestamp - userB.createdTimestamp); */ sort(compareFunction = (x, y) => +(x > y) || +(x === y) - 1) { return new Collection([...this.entries()].sort((a, b) => compareFunction(a[1], b[1], a[0], b[0])));