UNPKG

@yookue/ts-multi-map

Version:

Multiple key/value map & range map for typescript

528 lines (526 loc) 13.3 kB
var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/util/MultiValueMap.ts var MultiValueMap_exports = {}; __export(MultiValueMap_exports, { MultiValueMap: () => MultiValueMap }); module.exports = __toCommonJS(MultiValueMap_exports); var MultiValueMap = class { /** * Construct a multi value map instance * * @param entries the map entries that represented as [K, V[]][] * * @example * ```ts * const map = new MultiValueMap([ * ['color', ['red', 'green', 'blue']] * ]); * ``` */ constructor(entries) { this.map = /* @__PURE__ */ new Map(); entries == null ? void 0 : entries.forEach((entry) => { const [k, vs] = entry; this.set(k, vs); }); } /** * Construct a multi value map instance * * @param entries the map entries that represented as [K, V[]][] * * @returns a multi value map instance * * @example * ```ts * const map = MultiValueMap.of([ * ['color', ['red', 'green', 'blue']] * ]); * ``` */ static of(entries) { return new MultiValueMap(entries); } /** * Returns the values of the given key * * @param key the key to retrieve * @param defaults the default values if not found * * @returns the values of the given key * * @example * ```ts * const map = MultiValueMap.of([ * ['color', ['red', 'green', 'blue']] * ]); * map.get('color'); // ['red', 'green', 'blue'] * map.get('foobar', ['foo', 'bar']); // ['foo', 'bar'] * ``` */ get(key, defaults) { return this.map.get(key) ?? defaults; } /** * Sets the values of the given key * * @param key the key to set * @param values the values to set * * @example * ```ts * map.set('color', ['red', 'green', 'blue']); * ``` */ set(key, values) { this.map.set(key, values); } /** * Push values onto the given key, the values will be appended to the given key * * @param key the key to operate * @param values the values to push * * @example * ```ts * map.push('color', ['yellow', 'black']); * ``` */ push(key, values) { const array = this.get(key) || []; array.push(...values); this.map.set(key, array); } /** * Clears the map */ clear() { this.map.clear(); } /** * Returns the keys of the map * * @returns the keys of the map */ keys() { return [...this.map.keys()]; } /** * Returns the values array of the map * * @returns the values array of the map */ values() { return [...this.map.values()]; } /** * Returns the key/values entries of the map * * @returns the key/values entries of the map */ entries() { return [...this.map.entries()]; } /** * Deletes the entry with the given key * * @param key the key to delete * * @returns whether the entry has been deleted * * @example * ```ts * map.deleteByKey('color'); * ``` */ deleteByKey(key) { return this.map.delete(key); } /** * Deletes all the entries with any of the given keys * * @param keys the keys to delete * * @returns whether any of the entries has been deleted * * @example * ```ts * map.deleteByKeys(['color', 'position']); * ``` */ deleteByKeys(keys) { if (!keys.length || this.isEmpty()) { return false; } let result = false; for (const key of keys) { if (this.deleteByKey(key)) { result = true; } } return result; } /** * Deletes the entry/entries with the given value * * @param value the value to delete * * @returns whether the entry/entries has been deleted * * @example * ```ts * map.deleteByValue('red'); * ``` */ deleteByValue(value) { if (this.isEmpty()) { return false; } let result = false; for (const [k, vs] of this.entries()) { if ((vs == null ? void 0 : vs.includes(value)) && this.map.delete(k)) { result = true; } } return result; } /** * Deletes all the entries with any of the given values * * @param values the values to delete * * @returns whether any of the entries has been deleted * * @example * ```ts * map.deleteByValues(['green', 'blue']); * ``` */ deleteByValues(values) { if (!values.length || this.isEmpty()) { return false; } let result = false; for (const value of values) { if (this.deleteByValue(value)) { result = true; } } return result; } /** * Deletes a value for the given key from the map, keeping other values * * @param key the key to operate * @param value the value to delete * * @returns whether the value has been removed * * @example * ```ts * map.deleteValueOfKey('color', 'blue'); * ``` */ deleteValueOfKey(key, value) { let array = this.get(key) || []; if (!array.includes(value)) { return false; } array = array.filter((v) => v !== value); this.map.set(key, array); return true; } /** * Processes each entry in the map * * @param callback a callback function that processes each entry * @param thisArg any instance to retrieve 'this' reference in the callback function * * @example * ```ts * map.forEach((values, key) => { * console.log(key); * }); */ forEach(callback, thisArg) { this.map.forEach((vs, k) => { callback(vs, k); }, thisArg); } /** * Processes each entry in the map with index capability * * @param callback a callback function that processes each entry * @param thisArg any instance to retrieve 'this' reference in the callback function * * @example * ```ts * map.forEachIndexing((values, key, index) => { * console.log(index); * }); */ forEachIndexing(callback, thisArg) { let index = 0; this.map.forEach((vs, k) => { callback(vs, k, index++); }, thisArg); } /** * Processes each entry in the map with breakable capability * * @param callback a callback function that processes each entry. Returning false indicates to break the map iteration * @param thisArg any instance to retrieve 'this' reference in the callback function * * @example * ```ts * map.forEachBreakable((values, key) => { * return true; * }); */ forEachBreakable(callback, thisArg) { this.map.forEach((vs, k) => { if (!callback(vs, k)) { return; } }, thisArg); } /** * Returns whether the map contains the given key * * @param key the key to check * * @returns whether the map contains the given key * * @example * ```ts * map.hasKey('color'); */ hasKey(key) { return this.map.has(key); } /** * Returns whether the map contains the given key/value pair * * @param key the key to check * @param value the value to check * * @returns whether the map contains the given key/value pair * * @example * ```ts * const map = MultiValueMap.of([ * ['color', ['red', 'green', 'blue']] * ]); * map.hasKeyValue('color', 'red'); // true * map.hasKeyValue('color', 'black'); // false */ hasKeyValue(key, value) { return this.isNotEmpty() && this.get(key, []).includes(value); } /** * Returns whether the map contains any of the given keys * * @param keys the keys to check * * @returns whether the map contains any of the given keys * * @example * ```ts * const map = MultiValueMap.of([ * ['color', ['red', 'green', 'blue']] * ]); * map.hasAnyKeys(['color', 'position']); // true */ hasAnyKeys(keys) { return this.isNotEmpty() && keys.length > 0 && keys.some((item) => this.hasKey(item)); } /** * Returns whether the map contains all the given keys * * @param keys the keys to check * * @returns whether the map contains all the given keys * * @example * ```ts * map.hasAllKeys('color', 'position'); */ hasAllKeys(keys) { return this.isNotEmpty() && keys.length > 0 && keys.every((item) => this.hasKey(item)); } /** * Returns whether any entries of the map that contains the given values * * @param values the values to check * @param exact whether matching entry values exactly * * @returns whether any entries of the map that contains the given values * * @example * ```ts * const map = MultiValueMap.of([ * ['color', ['red', 'green', 'blue']], * ['position', ['top', 'right', 'bottom', 'left']] * ]); * map.hasValue(['red', 'black'], true); // false * map.hasValue(['top', 'right'], true); // false * map.hasValue(['top', 'right'], false); // true */ hasValue(values, exact = true) { if (!values.length || this.isEmpty()) { return false; } for (const vs of this.map.values()) { const result = exact ? values.length === vs.length && values.every((item) => vs.includes(item)) : values.some((item) => vs.includes(item)); if (result) { return true; } } return false; } /** * Returns whether the map contains any of the given values * * @param values the values to check * @param exact whether matching entry values exactly * * @returns whether the map contains any of the given values * * @example * ```ts * const map = MultiValueMap.of([ * ['color', ['red', 'green', 'blue']], * ['position', ['top', 'right', 'bottom', 'left']] * ]); * map.hasAnyValues([['red', 'black'], ['green', 'blue']]); // false * map.hasAnyValues([['top', 'right'], ['top', 'right', 'bottom', 'left']]); // true */ hasAnyValues(values, exact = true) { return this.isNotEmpty() && values.length > 0 && values.some((item) => this.hasValue(item, exact)); } /** * Returns whether the map contains all the given values * * @param values the values to check * @param exact whether matching entry values exactly * * @returns whether the map contains all the given values * * @example * ```ts * map.hasAllValues(['red', 'green', 'blue'], ['top', 'right', 'bottom', 'left']); */ hasAllValues(values, exact = true) { return this.isNotEmpty() && values.length > 0 && values.every((item) => this.hasValue(item, exact)); } /** * Returns whether the map is empty * * @returns whether the map is empty */ isEmpty() { return !this.map.size; } /** * Returns whether the map is not empty * * @returns whether the map is not empty */ isNotEmpty() { return this.map.size > 0; } /** * Returns the key with the given values * * @param values the values to inspect * @param defaults the default key if nothing matches the given value * * @returns the key with the given value * * @example * ```ts * map.getKey(['foo', 'bar']); * ``` */ getKey(values, defaults) { if (this.isEmpty()) { return defaults; } for (const [k, vs] of this.entries()) { if (values.length === vs.length && values.every((item) => vs.includes(item))) { return k; } } return defaults; } /** * Response for returning the list of key/values to iterate * * @example * ```ts * for (const [key, values] of map) { * console.log(key); * } * ``` */ // @ts-ignore [Symbol.iterator]() { return this.map[Symbol.iterator](); } /** * Returns the size of map * * @returns the size of map */ get size() { return this.map.size; } /** * Returns the string representation of the map identifier ('MultiValueMap') * * @returns the string representation of the map identifier */ get [Symbol.toStringTag]() { return "MultiValueMap"; } /** * Returns the string representation of the map elements * * @returns the string representation of the map elements * * @example * ```ts * const map = MultiValueMap.of([ * ['color', ['red', 'green', 'blue']], * ['position', ['top', 'right', 'bottom', 'left']] * ]); * console.log(map.toString()); // 'color:[red,green,blue];position:[top,right,bottom,left]' */ toString() { return [...this].map((entry) => { const [k, vs] = entry.length <= 1 ? [[], entry[0]] : [entry.slice(0, -1), entry[entry.length - 1]]; return `${k}:[${vs.join()}]`; }).join(";"); } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { MultiValueMap });