mirror of
https://github.com/discordeno/discordeno.git
synced 2026-06-04 09:50:07 +00:00
149 lines
3.7 KiB
TypeScript
149 lines
3.7 KiB
TypeScript
import { Bot } from '../bot.js'
|
|
|
|
export class Collection<K, V> extends Map<K, V> {
|
|
maxSize: number | undefined
|
|
sweeper: CollectionSweeper<K, V> & { intervalId?: number } | undefined
|
|
|
|
constructor (entries?: (ReadonlyArray<readonly [K, V]> | null) | Map<K, V>, options?: CollectionOptions<K, V>) {
|
|
super(entries ?? [])
|
|
|
|
this.maxSize = options?.maxSize
|
|
|
|
if ((options?.sweeper) == null) return
|
|
|
|
this.startSweeper(options.sweeper)
|
|
}
|
|
|
|
startSweeper (options: CollectionSweeper<K, V>): number {
|
|
if (this.sweeper?.intervalId) clearInterval(this.sweeper.intervalId)
|
|
|
|
this.sweeper = options
|
|
this.sweeper.intervalId = setInterval(() => {
|
|
this.forEach((value, key) => {
|
|
if (!this.sweeper?.filter(value, key, options.bot)) return
|
|
|
|
this.delete(key)
|
|
return key
|
|
})
|
|
}, options.interval)
|
|
|
|
return this.sweeper.intervalId!
|
|
}
|
|
|
|
stopSweeper (): void {
|
|
return clearInterval(this.sweeper?.intervalId)
|
|
}
|
|
|
|
changeSweeperInterval (newInterval: number) {
|
|
if (this.sweeper == null) return
|
|
|
|
this.startSweeper({ filter: this.sweeper.filter, interval: newInterval })
|
|
}
|
|
|
|
changeSweeperFilter (newFilter: (value: V, key: K, bot: Bot) => boolean) {
|
|
if (this.sweeper == null) return
|
|
|
|
this.startSweeper({ filter: newFilter, interval: this.sweeper.interval })
|
|
}
|
|
|
|
set (key: K, value: V) {
|
|
// When this collection is maxSized make sure we can add first
|
|
if ((this.maxSize || this.maxSize === 0) && this.size >= this.maxSize) {
|
|
return this
|
|
}
|
|
|
|
return super.set(key, value)
|
|
}
|
|
|
|
forceSet (key: K, value: V) {
|
|
return super.set(key, value)
|
|
}
|
|
|
|
array () {
|
|
return [...this.values()]
|
|
}
|
|
|
|
/** Retrieve the value of the first element in this collection */
|
|
first (): V | undefined {
|
|
return this.values().next().value
|
|
}
|
|
|
|
last (): V | undefined {
|
|
return [...this.values()][this.size - 1]
|
|
}
|
|
|
|
random (): V | undefined {
|
|
const array = [...this.values()]
|
|
return array[Math.floor(Math.random() * array.length)]
|
|
}
|
|
|
|
find (callback: (value: V, key: K) => boolean) {
|
|
for (const key of this.keys()) {
|
|
const value = this.get(key)!
|
|
if (callback(value, key)) return value
|
|
}
|
|
// If nothing matched
|
|
}
|
|
|
|
filter (callback: (value: V, key: K) => boolean) {
|
|
const relevant = new Collection<K, V>()
|
|
this.forEach((value, key) => {
|
|
if (callback(value, key)) relevant.set(key, value)
|
|
})
|
|
|
|
return relevant
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
reduce<T>(callback: (accumulator: T, value: V, key: K) => T, initialValue?: T): T {
|
|
let accumulator: T = initialValue!
|
|
|
|
for (const key of this.keys()) {
|
|
const value = this.get(key)!
|
|
accumulator = callback(accumulator, value, key)
|
|
}
|
|
|
|
return accumulator
|
|
}
|
|
}
|
|
|
|
export interface CollectionOptions<K, V> {
|
|
sweeper?: CollectionSweeper<K, V>
|
|
maxSize?: number
|
|
}
|
|
|
|
export interface CollectionSweeper<K, V> {
|
|
/** The filter to determine whether an element should be deleted or not */
|
|
filter: (value: V, key: K, ...args: any[]) => boolean
|
|
/** The interval in which the sweeper should run */
|
|
interval: number
|
|
/** The bot object itself */
|
|
bot?: Bot
|
|
}
|