UNPKG

betmap

Version:
244 lines (243 loc) 8.03 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BMap = void 0; /** * Better Map() */ class BMap extends Map { constructor() { super(...arguments); this._listeners = new Map(); } /** * Custom serialization function */ toJSON() { // Convert Map to array of key-value pairs const mapArray = Array.from(this.entries()); return mapArray; } /** * Register listener */ on(event, listener) { var _a; if (!this._listeners.has(event)) { this._listeners.set(event, []); } (_a = this._listeners.get(event)) === null || _a === void 0 ? void 0 : _a.push(listener); return this; } /** * Notify subscribers */ _notify(event, entries) { const eventListeners = this._listeners.get(event); if (eventListeners != null) { eventListeners.forEach((listener) => listener(entries)); } } /** * Set key-value, return whether it's new. */ _set(key, value) { const isNewKey = !this.has(key); super.set(key, value); return isNewKey; } set(key, value) { var _a; const isNewKey = this._set(key, value); if (((_a = this._listeners) === null || _a === void 0 ? void 0 : _a.size) > 0) { this._notify(isNewKey ? 'add' : 'update', new BMap([[key, value]])); } return this; } /** * Batch add/update entries */ bSet(entries) { const newEntries = []; const updatedEntries = []; entries.forEach(([key, value]) => this._set(key, value) ? newEntries.push([key, value]) : updatedEntries.push([key, value])); if (newEntries.length > 0) { this._notify('add', new BMap(newEntries)); } if (updatedEntries.length > 0) { this._notify('update', new BMap(updatedEntries)); } return this; } /** * Batch get multiple entries from the BMap. * @param keys An array of keys to retrieve. * @returns A new BMap containing the requested entries. */ bGet(keys) { const result = new BMap(); for (const key of keys) { if (this.has(key)) { result.set(key, this.get(key)); } } return result; } /** * Delete by key. Returns deleted entry if key existed */ _delete(key) { if (this.has(key)) { const value = this.get(key); super.delete(key); return [key, value]; } return undefined; } delete(key) { const entry = this._delete(key); if (entry != null) { this._notify('delete', new BMap([[key, entry[1]]])); return true; } return false; } /** * Batch delete entries by key */ bDelete(keys) { const deletedEntries = []; const result = keys.map(key => { const entry = this._delete(key); if (entry != null) { deletedEntries.push(entry); return true; } return false; }); if (deletedEntries.length > 0) { this._notify('delete', new BMap(deletedEntries)); } return result; } clear() { const entries = new BMap(this); super.clear(); if (entries.size > 0) { this._notify('delete', entries); } } /** * Filter the map based on a predicate function. * @param predicate A function that determines whether a key-value pair should be included. * @returns A new BMap containing the filtered key-value pairs. */ filter(predicate) { const filteredEntries = []; for (const [key, value] of this.entries()) { if (predicate(key, value)) { filteredEntries.push([key, value]); } } return new BMap(filteredEntries); } /** * Returns the key-value pair of the first element in the map where predicate is true, and undefined otherwise. * @param predicate A function that returns true for the first matching key-value pair. * @returns The first matching key-value pair, or undefined if none is found. */ find(predicate) { for (const [key, value] of this.entries()) { if (predicate(key, value)) { return [key, value]; } } return undefined; } /** * Check if at least one key-value pair satisfies a condition. * @param predicate A function that returns true for a matching key-value pair. * @returns True if at least one matching key-value pair is found, false otherwise. */ some(predicate) { return this.find(predicate) !== undefined; } /** * Check if every key-value pair satisfies a condition. * @param predicate A function that returns true for a matching key-value pair. * @returns True if every key-value pair matches the condition, false otherwise. */ every(predicate) { for (const [key, value] of this.entries()) { if (!predicate(key, value)) { return false; } } return true; } /** * Map over the entries of the BMap and apply a transformation function. * @param callback A function that transforms each key/value. * @returns A new BMap with transformed entries. */ mapEntries(callback) { const newMap = new BMap(); for (const [key, value] of this.entries()) { const [transformedKey, transformedValue] = callback(key, value, this); newMap.set(transformedKey, transformedValue); } return newMap; } /** * Map over the values of the BMap and apply a transformation function. * @param callback A function that transforms each value. * @returns A new BMap with transformed values. */ mapValues(callback) { return this.mapEntries((key, value) => ([key, callback(key, value, this)])); } /** * Map over the keys of the BMap and apply a transformation function. * @param callback A function that transforms each key. * @returns A new BMap with transformed keys. */ mapKeys(callback) { return this.mapEntries((key, value) => ([callback(key, value, this), value])); } /** * Sort the entries of the BMap in place. * @param compareFunction A function that defines the sort order. * @returns The sorted BMap. */ sort(compareFunction) { const sortedEntries = Array.from(this.entries()).sort((a, b) => compareFunction({ key: a[0], value: a[1] }, { key: b[0], value: b[1] })); // Clear the current map. Using `super` instead of `this` so that we don't fire a delete event. super.clear(); // Populate the map with the sorted entries for (const [key, value] of sortedEntries) { // Using `super` instead of `this` so that we don't fire an add event. super.set(key, value); } return this; } /** * Merge two maps, resolving conflicts based on a customizable merge strategy. * @param otherMap The map to merge into the current map. * @param mergeStrategy A function that defines the merge strategy for conflicts. * @returns The merged BMap. */ merge(otherMap, mergeStrategy) { const mergedMap = new BMap(this); for (const [key, incomingValue] of otherMap.entries()) { if (mergedMap.has(key)) { const existingValue = mergedMap.get(key); const newValue = mergeStrategy(key, existingValue, incomingValue); mergedMap.set(key, newValue); } else { mergedMap.set(key, incomingValue); } } return mergedMap; } } exports.BMap = BMap;