@evolvejs/objex
Version:
Data handling module for EvolveJS
286 lines (285 loc) • 9.21 kB
JavaScript
"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;