mirror of
https://github.com/discordeno/discordeno.git
synced 2026-06-01 16:30:08 +00:00
collection rewrite
This commit is contained in:
@@ -1,239 +1,78 @@
|
||||
class Collection<K, V> extends Map<K, V> {
|
||||
private _array!: V[] | null;
|
||||
public static readonly default: typeof Collection = Collection;
|
||||
public ["constructor"]: typeof Collection;
|
||||
import { chooseRandom } from "./utils.ts";
|
||||
|
||||
public constructor(entries?: ReadonlyArray<readonly [K, V]> | null) {
|
||||
super(entries);
|
||||
|
||||
Object.defineProperty(
|
||||
this,
|
||||
"_array",
|
||||
{ value: null, writable: true, configurable: true },
|
||||
);
|
||||
|
||||
Object.defineProperty(
|
||||
this,
|
||||
"_keyArray",
|
||||
{ value: null, writable: true, configurable: true },
|
||||
);
|
||||
export default class Collection<K, V> extends Map<K, V> {
|
||||
array() {
|
||||
return [...this.values()];
|
||||
}
|
||||
|
||||
public get(key: K): V | undefined {
|
||||
return super.get(key);
|
||||
first() {
|
||||
return this.values().next().value;
|
||||
}
|
||||
|
||||
public set(key: K, value: V): this {
|
||||
this._array = null;
|
||||
return super.set(key, value);
|
||||
last() {
|
||||
return [...this.values()][this.size - 1];
|
||||
}
|
||||
|
||||
public has(key: K): boolean {
|
||||
return super.has(key);
|
||||
random() {
|
||||
return chooseRandom([...this.values()]);
|
||||
}
|
||||
|
||||
public delete(key: K): boolean {
|
||||
this._array = null;
|
||||
return super.delete(key);
|
||||
}
|
||||
|
||||
public clear(): void {
|
||||
return super.clear();
|
||||
}
|
||||
|
||||
public array(): V[] {
|
||||
if (!this._array || this._array.length !== this.size) {
|
||||
this._array = [...this.values()];
|
||||
find(callback: (value: V, key: K) => boolean) {
|
||||
for (const key of this.keys()) {
|
||||
const value = this.get(key)!;
|
||||
if (callback(value, key)) return value;
|
||||
}
|
||||
return this._array;
|
||||
// If nothing matched
|
||||
return;
|
||||
}
|
||||
|
||||
public first(): V | undefined;
|
||||
public first(amount: number): V[];
|
||||
public first(amount?: number): V | V[] | undefined {
|
||||
if (typeof amount === "undefined") return this.values().next().value;
|
||||
if (amount < 0) return this.last(amount * -1);
|
||||
amount = Math.min(this.size, amount);
|
||||
const iter = this.values();
|
||||
return Array.from({ length: amount }, (): V => iter.next().value);
|
||||
filter(callback: (value: V, key: K) => boolean) {
|
||||
const relevant = new Collection();
|
||||
this.forEach((value, key) => {
|
||||
if (callback(value, key)) relevant.set(key, value);
|
||||
});
|
||||
|
||||
return relevant;
|
||||
}
|
||||
|
||||
public last(): V | undefined;
|
||||
public last(amount: number): V[];
|
||||
public last(amount?: number): V | V[] | undefined {
|
||||
const arr = this.array();
|
||||
if (typeof amount === "undefined") return arr[arr.length - 1];
|
||||
if (amount < 0) return this.first(amount * -1);
|
||||
if (!amount) return [];
|
||||
return arr.slice(-amount);
|
||||
}
|
||||
|
||||
public random(): V;
|
||||
public random(amount: number): V[];
|
||||
public random(amount?: number): V | V[] {
|
||||
let arr = this.array();
|
||||
if (
|
||||
typeof amount === "undefined"
|
||||
) {
|
||||
return arr[Math.floor(Math.random() * arr.length)];
|
||||
}
|
||||
if (arr.length === 0 || !amount) return [];
|
||||
arr = arr.slice();
|
||||
return Array.from(
|
||||
{ length: amount },
|
||||
(): V => arr.splice(Math.floor(Math.random() * arr.length), 1)[0],
|
||||
);
|
||||
}
|
||||
|
||||
public find(
|
||||
fn: (value: V, key: K, collection: this) => boolean,
|
||||
): V | undefined;
|
||||
public find<T>(
|
||||
fn: (this: T, value: V, key: K, collection: this) => boolean,
|
||||
thisArg: T,
|
||||
): V | undefined;
|
||||
public find(
|
||||
fn: (value: V, key: K, collection: this) => boolean,
|
||||
thisArg?: unknown,
|
||||
): V | undefined {
|
||||
if (typeof thisArg !== "undefined") fn = fn.bind(thisArg);
|
||||
for (const [key, val] of this) {
|
||||
if (fn(val, key, this)) return val;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public filter(fn: (value: V, key: K, collection: this) => boolean): this;
|
||||
public filter<T>(
|
||||
fn: (this: T, value: V, key: K, collection: this) => boolean,
|
||||
thisArg: T,
|
||||
): this;
|
||||
public filter(
|
||||
fn: (value: V, key: K, collection: this) => boolean,
|
||||
thisArg?: unknown,
|
||||
): this {
|
||||
if (typeof thisArg !== "undefined") fn = fn.bind(thisArg);
|
||||
const results = new this.constructor[Symbol.species]<K, V>() as this;
|
||||
for (const [key, val] of this) {
|
||||
if (fn(val, key, this)) results.set(key, val);
|
||||
map<T>(callback: (value: V, key: K) => T) {
|
||||
const results = [];
|
||||
for (const key of this.keys()) {
|
||||
const value = this.get(key)!;
|
||||
results.push(callback(value, key));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
public map<T>(fn: (value: V, key: K, collection: this) => T): T[];
|
||||
public map<This, T>(
|
||||
fn: (this: This, value: V, key: K, collection: this) => T,
|
||||
thisArg: This,
|
||||
): T[];
|
||||
public map<T>(
|
||||
fn: (value: V, key: K, collection: this) => T,
|
||||
thisArg?: unknown,
|
||||
): T[] {
|
||||
if (typeof thisArg !== "undefined") fn = fn.bind(thisArg);
|
||||
const iter = this.entries();
|
||||
return Array.from({ length: this.size }, (): T => {
|
||||
const [key, value] = iter.next().value;
|
||||
return fn(value, key, this);
|
||||
});
|
||||
}
|
||||
|
||||
public some(fn: (value: V, key: K, collection: this) => boolean): boolean;
|
||||
public some<T>(
|
||||
fn: (this: T, value: V, key: K, collection: this) => boolean,
|
||||
thisArg: T,
|
||||
): boolean;
|
||||
public some(
|
||||
fn: (value: V, key: K, collection: this) => boolean,
|
||||
thisArg?: unknown,
|
||||
): boolean {
|
||||
if (typeof thisArg !== "undefined") fn = fn.bind(thisArg);
|
||||
for (const [key, val] of this) {
|
||||
if (fn(val, key, this)) return true;
|
||||
some(callback: (value: V, key: K) => boolean) {
|
||||
for (const key of this.keys()) {
|
||||
const value = this.get(key)!;
|
||||
if (callback(value, key)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public every(fn: (value: V, key: K, collection: this) => boolean): boolean;
|
||||
public every<T>(
|
||||
fn: (this: T, value: V, key: K, collection: this) => boolean,
|
||||
thisArg: T,
|
||||
): boolean;
|
||||
public every(
|
||||
fn: (value: V, key: K, collection: this) => boolean,
|
||||
thisArg?: unknown,
|
||||
): boolean {
|
||||
if (typeof thisArg !== "undefined") fn = fn.bind(thisArg);
|
||||
for (const [key, val] of this) {
|
||||
if (!fn(val, key, this)) return false;
|
||||
every(callback: (value: V, key: K) => boolean) {
|
||||
for (const key of this.keys()) {
|
||||
const value = this.get(key)!;
|
||||
if (!callback(value, key)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public reduce<T>(
|
||||
fn: (accumulator: T, value: V, key: K, collection: this) => T,
|
||||
reduce<T>(
|
||||
callback: (accumulator: T, value: V, key: K) => T,
|
||||
initialValue?: T,
|
||||
): T {
|
||||
let accumulator!: T;
|
||||
let accumulator: T = initialValue!;
|
||||
|
||||
if (typeof initialValue !== "undefined") {
|
||||
accumulator = initialValue;
|
||||
for (const [key, val] of this) {
|
||||
accumulator = fn(accumulator, val, key, this);
|
||||
}
|
||||
return accumulator;
|
||||
}
|
||||
let first = true;
|
||||
for (const [key, val] of this) {
|
||||
if (first) {
|
||||
accumulator = val as unknown as T;
|
||||
first = false;
|
||||
continue;
|
||||
}
|
||||
accumulator = fn(accumulator, val, key, this);
|
||||
}
|
||||
|
||||
// No items iterated.
|
||||
if (first) {
|
||||
throw new TypeError("Reduce of empty collection with no initial value");
|
||||
for (const key of this.keys()) {
|
||||
const value = this.get(key)!;
|
||||
accumulator = callback(accumulator, value, key);
|
||||
}
|
||||
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
public each(fn: (value: V, key: K, collection: this) => void): this;
|
||||
public each<T>(
|
||||
fn: (this: T, value: V, key: K, collection: this) => void,
|
||||
thisArg: T,
|
||||
): this;
|
||||
public each(
|
||||
fn: (value: V, key: K, collection: this) => void,
|
||||
thisArg?: unknown,
|
||||
): this {
|
||||
this.forEach(fn as (value: V, key: K, map: Map<K, V>) => void, thisArg);
|
||||
return this;
|
||||
}
|
||||
|
||||
public sort(
|
||||
compareFunction: (
|
||||
firstValue: V,
|
||||
secondValue: V,
|
||||
firstKey: K,
|
||||
secondKey: K,
|
||||
) => number = (x, y): number => Number(x > y) || Number(x === y) - 1,
|
||||
): this {
|
||||
const entries = [...this.entries()];
|
||||
entries.sort((a, b): number => compareFunction(a[1], b[1], a[0], b[0]));
|
||||
|
||||
// Perform clean-up
|
||||
super.clear();
|
||||
this._array = null;
|
||||
|
||||
// Set the new entries
|
||||
for (const [k, v] of entries) {
|
||||
super.set(k, v);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export default Collection;
|
||||
|
||||
@@ -13,3 +13,7 @@ export function editBotsStatus(
|
||||
) {
|
||||
sendGatewayCommand("EDIT_BOTS_STATUS", { status, game: { name, type } });
|
||||
}
|
||||
|
||||
export function chooseRandom<T>(array: T[]) {
|
||||
return array[Math.floor(Math.random() * array.length)];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user