ts-data-forge
Version:
[](https://www.npmjs.com/package/ts-data-forge) [](https://www.npmjs.com/package/ts-data-forge) [ • 12.3 kB
JavaScript
import { Optional } from '../functional/optional.mjs';
import '../functional/result.mjs';
import '../number/branded-types/finite-number.mjs';
import '../number/branded-types/int.mjs';
import '../number/branded-types/int16.mjs';
import '../number/branded-types/int32.mjs';
import '../number/branded-types/non-negative-finite-number.mjs';
import '../number/branded-types/non-negative-int16.mjs';
import '../number/branded-types/non-negative-int32.mjs';
import '../number/branded-types/non-zero-finite-number.mjs';
import '../number/branded-types/non-zero-int.mjs';
import '../number/branded-types/non-zero-int16.mjs';
import '../number/branded-types/non-zero-int32.mjs';
import '../number/branded-types/non-zero-safe-int.mjs';
import '../number/branded-types/non-zero-uint16.mjs';
import '../number/branded-types/non-zero-uint32.mjs';
import '../number/branded-types/positive-finite-number.mjs';
import '../number/branded-types/positive-int.mjs';
import '../number/branded-types/positive-int16.mjs';
import '../number/branded-types/positive-int32.mjs';
import '../number/branded-types/positive-safe-int.mjs';
import '../number/branded-types/positive-uint16.mjs';
import '../number/branded-types/positive-uint32.mjs';
import '../number/branded-types/safe-int.mjs';
import '../number/branded-types/safe-uint.mjs';
import '../number/branded-types/uint.mjs';
import '../number/branded-types/uint16.mjs';
import { asUint32 } from '../number/branded-types/uint32.mjs';
import '../number/enum/int8.mjs';
import '../number/enum/uint8.mjs';
import '../number/num.mjs';
import '../number/refined-number-utils.mjs';
import { tp } from '../others/tuple.mjs';
import { unknownToString } from '../others/unknown-to-string.mjs';
/**
* Provides utility functions for IMap.
*/
var IMap;
(function (IMap) {
/**
* Creates a new IMap instance from an iterable of key-value pairs.
*
* This factory function accepts any iterable of [key, value] tuples, including arrays,
* JavaScript Maps, other IMaps, or custom iterables. The resulting IMap will contain
* all the entries from the input iterable.
*
* **Performance:** O(n) where n is the number of entries in the iterable.
*
* @template K The type of the keys. Must extend MapSetKeyType.
* @template V The type of the values.
* @param iterable An iterable of key-value pairs (e.g., Array, Map, IMap, etc.)
* @returns A new IMap instance containing all entries from the iterable.
*
* @example
* ```typescript
* // From array of tuples
* const userScores = IMap.create<string, number>([
* ["alice", 95],
* ["bob", 87],
* ["charlie", 92]
* ]);
* console.log(userScores.get("alice").unwrap()); // Output: 95
*
* // From JavaScript Map
* const jsMap = new Map([["config", { debug: true }], ["env", "production"]]);
* const config = IMap.create(jsMap);
* console.log(config.get("env").unwrap()); // Output: "production"
*
* // From another IMap (creates a copy)
* const originalMap = IMap.create<string, boolean>([["enabled", true]]);
* const copiedMap = IMap.create(originalMap);
* console.log(copiedMap.get("enabled").unwrap()); // Output: true
*
* // Empty map
* const emptyMap = IMap.create<string, number>([]);
* console.log(emptyMap.size); // Output: 0
*
* // From custom iterable
* function* generateEntries(): Generator<[string, number]> {
* for (const i of range(3)) {
* yield [`item${i}`, i * 10];
* }
* }
* const generatedMap = IMap.create(generateEntries());
* console.log(generatedMap.size); // Output: 3
* ```
*/
IMap.create = (iterable) => new IMapClass(iterable);
/**
* Checks if two IMap instances are structurally equal.
*
* Two IMaps are considered equal if they have the same size and contain exactly the same
* key-value pairs. The order of entries does not matter for equality comparison.
* Values are compared using JavaScript's `===` operator.
*
* **Performance:** O(n) where n is the size of the smaller map.
*
* @template K The type of the keys.
* @template V The type of the values.
* @param a The first IMap instance to compare.
* @param b The second IMap instance to compare.
* @returns `true` if the maps contain exactly the same key-value pairs, `false` otherwise.
*
* @example
* ```typescript
* // Basic equality comparison
* const preferences1 = IMap.create<string, boolean>([
* ["darkMode", true],
* ["notifications", false]
* ]);
* const preferences2 = IMap.create<string, boolean>([
* ["darkMode", true],
* ["notifications", false]
* ]);
* const preferences3 = IMap.create<string, boolean>([
* ["notifications", false],
* ["darkMode", true] // Order doesn't matter
* ]);
*
* console.log(IMap.equal(preferences1, preferences2)); // true
* console.log(IMap.equal(preferences1, preferences3)); // true (order doesn't matter)
*
* // Different values
* const preferences4 = IMap.create<string, boolean>([
* ["darkMode", false], // Different value
* ["notifications", false]
* ]);
* console.log(IMap.equal(preferences1, preferences4)); // false
*
* // Different keys
* const preferences5 = IMap.create<string, boolean>([
* ["darkMode", true],
* ["sounds", false] // Different key
* ]);
* console.log(IMap.equal(preferences1, preferences5)); // false
*
* // Empty maps
* const empty1 = IMap.create<string, number>([]);
* const empty2 = IMap.create<string, number>([]);
* console.log(IMap.equal(empty1, empty2)); // true
*
* // Note: For deep equality of object values, use a custom comparison
* const users1 = IMap.create<string, User>([["1", { name: "Alice" }]]);
* const users2 = IMap.create<string, User>([["1", { name: "Alice" }]]);
* console.log(IMap.equal(users1, users2)); // false (different object references)
* ```
*/
IMap.equal = (a, b) => a.size === b.size && a.every((v, k) => b.get(k) === v);
})(IMap || (IMap = {}));
/**
* Internal class implementation for IMap providing immutable map operations.
*
* This class implements the IMap interface using JavaScript's native Map as the underlying
* storage mechanism for optimal performance. All mutation operations create new instances
* rather than modifying the existing map, ensuring immutability.
*
* **Implementation Details:**
* - Uses ReadonlyMap<K, V> internally for type safety and performance
* - Implements copy-on-write semantics for efficiency
* - Provides optional debug messaging for development
*
* @template K The type of the keys. Must extend MapSetKeyType.
* @template V The type of the values.
* @implements IMap
* @implements Iterable
* @internal This class should not be used directly. Use IMap.create() instead.
*/
class IMapClass {
#map;
#showNotFoundMessage;
/**
* Constructs an IMapClass instance with the given entries.
*
* @param iterable An iterable of key-value pairs to populate the map.
* @param showNotFoundMessage Whether to log warning messages when operations
* are performed on non-existent keys. Useful for debugging.
* Defaults to false for production use.
* @internal Use IMap.create() instead of calling this constructor directly.
*/
constructor(iterable, showNotFoundMessage = false) {
this.#map = new Map(iterable);
this.#showNotFoundMessage = showNotFoundMessage;
}
/** @inheritdoc */
get size() {
return asUint32(this.#map.size);
}
/** @inheritdoc */
has(key) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
return this.#map.has(key);
}
/** @inheritdoc */
get(key) {
if (!this.has(key))
return Optional.none;
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion, @typescript-eslint/no-non-null-assertion
return Optional.some(this.#map.get(key));
}
/** @inheritdoc */
every(predicate) {
for (const [k, v] of this.entries()) {
if (!predicate(v, k))
return false;
}
return true;
}
/** @inheritdoc */
some(predicate) {
for (const [k, v] of this.entries()) {
if (predicate(v, k))
return true;
}
return false;
}
/** @inheritdoc */
delete(key) {
if (!this.has(key)) {
if (this.#showNotFoundMessage) {
const keyStr = unknownToString(key);
console.warn(`IMap.delete: key not found: ${keyStr}`);
}
return this;
}
return IMap.create(Array.from(this.#map).filter(([k]) => !Object.is(k, key)));
}
/** @inheritdoc */
set(key, value) {
if (value === this.get(key))
return this; // has no changes
if (!this.has(key)) {
return IMap.create([...this.#map, tp(key, value)]);
}
else {
return IMap.create(Array.from(this.#map, ([k, v]) => tp(k, Object.is(k, key) ? value : v)));
}
}
/** @inheritdoc */
update(key, updater) {
const curr = this.get(key);
if (Optional.isNone(curr)) {
if (this.#showNotFoundMessage) {
const keyStr = unknownToString(key);
console.warn(`IMap.update: key not found: ${keyStr}`);
}
return this;
}
return IMap.create(Array.from(this.#map, ([k, v]) => tp(k, Object.is(k, key) ? updater(curr.value) : v)));
}
/** @inheritdoc */
withMutations(actions) {
const mut_result = new Map(this.#map);
for (const action of actions) {
switch (action.type) {
case 'delete':
mut_result.delete(action.key);
break;
case 'set':
mut_result.set(action.key, action.value);
break;
case 'update': {
const { key } = action;
const curr = mut_result.get(key);
if (!mut_result.has(key) || curr === undefined) {
if (this.#showNotFoundMessage) {
const keyStr = unknownToString(key);
console.warn(`IMap.withMutations: key not found: ${keyStr}`);
}
break;
}
mut_result.set(key, action.updater(curr));
break;
}
}
}
return IMap.create(mut_result);
}
/** @inheritdoc */
map(mapFn) {
return IMap.create(this.toArray().map(([k, v]) => tp(k, mapFn(v, k))));
}
/** @inheritdoc */
mapKeys(mapFn) {
return IMap.create(this.toArray().map(([k, v]) => tp(mapFn(k), v)));
}
/** @inheritdoc */
mapEntries(mapFn) {
return IMap.create(this.toArray().map(mapFn));
}
/** @inheritdoc */
forEach(callbackfn) {
for (const [key, value] of this.#map.entries()) {
callbackfn(value, key);
}
}
/**
* @inheritdoc
*/
[Symbol.iterator]() {
return this.#map[Symbol.iterator]();
}
/** @inheritdoc */
keys() {
return this.#map.keys();
}
/** @inheritdoc */
values() {
return this.#map.values();
}
/** @inheritdoc */
entries() {
return this.#map.entries();
}
/** @inheritdoc */
toKeysArray() {
return Array.from(this.keys());
}
/** @inheritdoc */
toValuesArray() {
return Array.from(this.values());
}
/** @inheritdoc */
toEntriesArray() {
return Array.from(this.entries());
}
/** @inheritdoc */
toArray() {
return Array.from(this.entries());
}
/** @inheritdoc */
toRawMap() {
return this.#map;
}
}
export { IMap };
//# sourceMappingURL=imap.mjs.map