UNPKG

deep-equality-data-structures

Version:

Javascript data structures (e.g., Map, Set) that support deep object equality

172 lines (171 loc) 5.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DeepMap = void 0; const errors_1 = require("./errors"); const normalizer_1 = require("./normalizer"); /** * A Map implementation that supports deep equality for object keys. */ class DeepMap extends Map { // NOTE: This is actually a thin wrapper. We're not using super other than to drive the (typed) API contract. /** * @param entries optional list of key-value pairs to initialize the map * @param options configuration options */ constructor(entries, options = {}) { super(); this.options = options; this.normalizer = new normalizer_1.Normalizer(options); const transformedEntries = entries ? entries.map(([key, val]) => [this.normalizeKey(key), { key, val }]) : null; this.map = new Map(transformedEntries); } /** * Getter for number of kev-value pairs in the map. * @inheritdoc */ get size() { return this.map.size; } /** * Returns true if the given key is present in the map. * @inheritdoc */ has(key) { return this.map.has(this.normalizeKey(key)); } /** * @inheritdoc */ set(key, val) { this.map.set(this.normalizeKey(key), { key, val }); return this; } /** * @inheritdoc */ get(key) { var _a; return (_a = this.map.get(this.normalizeKey(key))) === null || _a === void 0 ? void 0 : _a.val; } /** * @inheritdoc */ delete(key) { return this.map.delete(this.normalizeKey(key)); } /** * Clear all key-value pairs from the map. * @inheritdoc */ clear() { this.map.clear(); } /** * @inheritdoc */ forEach(callbackfn) { this.map.forEach((pair, _key, _internalMap) => { callbackfn(pair.val, pair.key, this); }); } /** * @yields the next key-value pair in the map * @inheritdoc */ *[Symbol.iterator]() { for (const [_hashStr, pair] of this.map[Symbol.iterator]()) { yield [pair.key, pair.val]; } } /** * @yields the next key-value pair in the map * @inheritdoc */ *entries() { for (const entry of this[Symbol.iterator]()) { yield entry; } } /** * @inheritdoc */ *keys() { for (const [key, _val] of this[Symbol.iterator]()) { yield key; } } /** * @inheritdoc */ *values() { for (const [_key, val] of this[Symbol.iterator]()) { yield val; } } /** * @param other the map to compare against * @returns true if the entries of `other` are the same as this map */ equals(other) { this.validateUsingSameOptionsAs(other); return this.size === other.size && this.contains(other); } /** * @param other the map to compare against * @returns true if the entries of `other` are all contained in this map */ contains(other) { this.validateUsingSameOptionsAs(other); return [...other.entries()].every(([key, val]) => this.keyValuePairIsPresentIn(key, val, this)); } /** * @param other the map to compare against * @returns a new map whose keys are the union of keys between `this` and `other` maps. * * NOTE: If both maps prescribe the same key, the key-value pair from `this` will be retained. */ union(other) { this.validateUsingSameOptionsAs(other); return new DeepMap([...other.entries(), ...this.entries()], this.options); } /** * @param other the map to compare against * @returns a new map containing all key-value pairs in `this` that are also present in `other`. */ intersection(other) { this.validateUsingSameOptionsAs(other); const intersectingPairs = [...this.entries()].filter(([key, val]) => this.keyValuePairIsPresentIn(key, val, other)); return new DeepMap(intersectingPairs, this.options); } /** * @param other the map to compare against * @returns a new map containing all key-value pairs in `this` that are not present in `other`. */ difference(other) { this.validateUsingSameOptionsAs(other); const differencePairs = [...this.entries()].filter(([key, val]) => !this.keyValuePairIsPresentIn(key, val, other)); return new DeepMap(differencePairs, this.options); } // PRIVATE/PROTECTED METHODS FOLLOW... normalizeKey(input) { return this.normalizer.normalizeKey(input); } normalizeValue(input) { return this.normalizer.normalizeValue(input); } validateUsingSameOptionsAs(other) { if (this.normalizer.getOptionsChecksum() !== other['normalizer'].getOptionsChecksum()) { throw new errors_1.DeepEqualityDataStructuresError('Structures must use same options for Comparable interface operations'); } } /** * @returns true if the key is present in the provided map w/ the specified value */ keyValuePairIsPresentIn(key, val, mapToCheck) { const checkVal = mapToCheck.get(key); return checkVal !== undefined && this.normalizeValue(checkVal) === this.normalizeValue(val); } } exports.DeepMap = DeepMap;