UNPKG

@evolvejs/objex

Version:

Data handling module for EvolveJS

286 lines (285 loc) 9.21 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Objex = void 0; class Objex extends Map { /** * Creates a new Objex collection * @param {[K, V][]} [entries] - The pre-defined values to add to Objex */ constructor(entries) { super(entries); this.array = []; this.valueArray = []; this.keyArray = []; this._funcListeners = new Map(); } /** * Adds a new Event Listener * @param {"set" | "delete" | "clear"} name * @param {(...args: any[] => void)} listener */ on(name, listener) { this._funcListeners.set(listener, name); } /** * Removes a old Event Listener * @param {"set" | "delete" | "clear"} name * @param {(...args: any[] => void)} listener */ off(name, listener) { const value = this._funcListeners.get(listener); if (value) { if (value === name) { this._funcListeners.delete(listener); } } } /** * Emits a new event * @param {"set" | "delete" | "clear"} name * @param {(...args: any[] => void)} listener */ emit(name, ...args) { if (this._funcListeners.size !== 0) { for (const [key, value] of this._funcListeners) { if (value == name) { key(...args); } } } } /** * Get the size of the collection * @returns {Number} The size of the collection */ get size() { return super.size; } /** * Set a new entry in the Objex collection * @param {K} key - The key of the entry * @param value - The value of the entry * @returns {Objex} The Objex class instance */ set(key, value) { this.keyArray = this.valueArray = this.array = null; this.emit("set", key, value); return super.set(key, value); } /** * Get a value from the Objex collection * @param {K} key - The key to get * @returns {V | undefined} The value or `undefined` if no value found */ get(key) { return super.get(key); } /** * Checks if an entry exists */ has(key) { return super.has(key); } /** * Delete an element from the Objex * @returns {boolean} If the element was deleted */ delete(key) { this.keyArray = this.valueArray = this.array = null; this.emit("delete", key, this.get(key)); return super.delete(key); } /** * Clears the whole Objex collection */ clear() { this.keyArray = this.valueArray = this.array = null; this.emit("clear"); return super.clear(); } /** * Shuffle the whole Objex * @returns {Objex} The shuffled collection */ shuffle() { const arr = this.toArray(); for (let i = arr.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [arr[i], arr[j]] = [arr[j], arr[i]]; } this.clear(); for (const [k, v] of arr) this.set(k, v); return this; } /** * Fetch the first value(s) from the Objex * @param {number} [amount=0] - The number of values from the beginning * @returns {V | V[] | undefined} A single value or an array of values if a number was provided */ first(amount = 0) { const mapIter = this.values(); if (!amount || isNaN(amount) || amount < 0) return mapIter.next().value; amount = Math.min(amount, this.size); return Array.from({ length: amount }, () => mapIter.next().value); } /** * Fetch the last value(s) from the Objex * @param {number} [amount=0] - The number of values from the end * @returns {V | V[] | undefined} A single value or an array of values if a number was provided */ last(amount = 0) { const vArray = this.vArray(); if (!amount || isNaN(amount) || amount < 0) return vArray[vArray.length - 1]; amount = Math.min(amount, this.size); return vArray.slice(-amount); } /** * Fetch the first key(s) from the Objex * @param {number} [amount=0] - The number of keys from the beginning * @returns {K | K[] | undefined} A single key or an array of keys if a number was provided */ firstKey(amount = 0) { const keyIter = this.keys(); if (!amount || isNaN(amount) || amount < 0) return keyIter.next().value; amount = Math.min(amount, this.size); return Array.from({ length: amount }, () => keyIter.next().value); } /** * Fetch the last key(s) from the Objex * @param {number} [amount=0] - The number of keys from the end * @returns {K | K[] | undefined} A single key or an array of keys if a number was provided */ lastKey(amount = 0) { const kArray = this.kArray(); if (!amount || isNaN(amount) || amount < 0) return kArray[kArray.length - 1]; amount = Math.min(amount, this.size); return kArray.slice(-amount); } /** * Get a `[key, value]` pair array of the Objex * @returns {[K, V][]} The array of all the entries */ toArray() { if (this.array.length !== this.size) this.array = [...this.entries()]; return this.array; } /** * Get an array of all the Objex values * @returns {V[]} The array of all the values */ vArray() { if (this.valueArray.length !== this.size) this.valueArray = [...this.values()]; return this.valueArray; } /** * Get an array of all the Objex keys * @returns {K[]} The array of all the keys */ kArray() { if (this.keyArray.length !== this.size) this.keyArray = [...this.keys()]; return this.keyArray; } /** * Let's you run a function on each Objex element * @param func - The function that is to be ran on each element * @returns {T[]} The final result in an array */ map(func) { const raw = this.entries(); return Array.from({ length: this.size }, () => { const [key, value] = raw.next().value; return func(value, key, this); }); } /** * Filters the elements that passes a test * @param {Function} func - The function that needs to be satisfied * @returns {Objex} The filtered Objex collection */ filter(func) { if (!func) return this; const filtered = new this.constructor[Symbol.species](); for (let [key, value] of this) { if (func(value, key, this)) filtered.set(key, value); } return filtered; } /** * Find an element value that passes a test * @param {Function} func - The function that needs to be satisfied * @returns {V | undefined} The value or `undefined` if none found */ find(func) { for (let [key, value] of this) { if (func(value, key, this)) return value; } return undefined; } /** * Check if at least one element passes a test * @param {Function} func - The function that needs to be satisfied * @returns {boolean} If any element was found */ some(func) { for (let [key, value] of this) { if (func(value, key, this)) return true; } return false; } /** * Reduce the Objex to a single value by applying a function * @param {Function} func - The function that needs to be applied * @param {T} initialVal - Starting value for the accumulator * @returns {T} */ reduce(func, initialVal) { let acc; if (initialVal !== undefined) { acc = initialVal; for (const [k, v] of this) acc = func(acc, v, k, this); return acc; } let isFirst = true; for (let [k, v] of this) { if (isFirst) { acc = v; isFirst = false; } acc = func(acc, v, k, this); } if (isFirst) throw new TypeError("[Objex Error] Cannot reduce empty Objex."); return acc; } /** * Merge Objexes into the given objex - existing keys will NOT be overwritten * @param {...Objex} - The Objexes to be merged * @returns {Objex} - The merged Objex */ merge(...obj) { for (const objex of obj) { if (objex instanceof Map) { for (const [key, val] of objex) { if (this.has(key)) return; this.set(key, val); } } } return this; } } exports.Objex = Objex;