ts-data-forge
Version:
[](https://www.npmjs.com/package/ts-data-forge) [](https://www.npmjs.com/package/ts-data-forge) [ • 16.7 kB
JavaScript
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 { unknownToString } from '../others/unknown-to-string.mjs';
// No imports from functional needed anymore
/**
* Provides utility functions for ISet.
*/
var ISet;
(function (ISet) {
/**
* Creates a new ISet instance from an iterable of elements.
*
* This factory function accepts any iterable of elements, including arrays,
* JavaScript Sets, other ISets, or custom iterables. Duplicate elements in the
* input iterable will be automatically deduplicated in the resulting set.
*
* **Performance:** O(n) where n is the number of elements in the iterable.
*
* @template K The type of the elements. Must extend MapSetKeyType.
* @param iterable An iterable of elements (e.g., Array, Set, ISet, etc.)
* @returns A new ISet instance containing all unique elements from the iterable.
*
* @example
* ```typescript
* // From array (duplicates automatically removed)
* const uniqueIds = ISet.create([1, 2, 3, 2, 1]); // Contains: 1, 2, 3
* console.log(uniqueIds.size); // Output: 3
*
* // From JavaScript Set
* const jsSet = new Set(["red", "green", "blue"]);
* const colors = ISet.create(jsSet);
* console.log(colors.has("red")); // Output: true
*
* // From another ISet (creates a copy)
* const originalTags = ISet.create(["typescript", "immutable"]);
* const copiedTags = ISet.create(originalTags);
* console.log(copiedTags.size); // Output: 2
*
* // Empty set
* const emptyPermissions = ISet.create<string>([]);
* console.log(emptyPermissions.isEmpty); // Output: true
*
* // Fluent operations
* const processedNumbers = ISet.create([1, 2, 3, 4, 5])
* .filter(x => x % 2 === 0) // Keep even numbers: 2, 4
* .add(6) // Add 6: 2, 4, 6
* .delete(2); // Remove 2: 4, 6
* console.log(processedNumbers.toArray().toSorted()); // Output: [4, 6]
*
* // From generator function
* function* generatePrimes(): Generator<number> {
* yield 2; yield 3; yield 5; yield 7;
* }
* const primes = ISet.create(generatePrimes());
* console.log(primes.size); // Output: 4
* ```
*/
ISet.create = (iterable) => new ISetClass(iterable);
/**
* Checks if two ISet instances are structurally equal.
*
* Two ISets are considered equal if they have the same size and contain exactly the same
* elements. The order of elements does not matter for equality comparison since sets are
* unordered collections. Elements are compared using JavaScript's `===` operator.
*
* **Performance:** O(n) where n is the size of the smaller set.
*
* @template K The type of the elements.
* @param a The first ISet instance to compare.
* @param b The second ISet instance to compare.
* @returns `true` if the sets contain exactly the same elements, `false` otherwise.
*
* @example
* ```typescript
* // Basic equality comparison
* const permissions1 = ISet.create(["read", "write", "execute"]);
* const permissions2 = ISet.create(["execute", "read", "write"]); // Order doesn't matter
* const permissions3 = ISet.create(["read", "write"]);
*
* console.log(ISet.equal(permissions1, permissions2)); // true
* console.log(ISet.equal(permissions1, permissions3)); // false (different sizes)
*
* // With different element types
* const numbers1 = ISet.create([1, 2, 3]);
* const numbers2 = ISet.create([3, 1, 2]);
* const numbers3 = ISet.create([1, 2, 4]); // Different element
*
* console.log(ISet.equal(numbers1, numbers2)); // true
* console.log(ISet.equal(numbers1, numbers3)); // false
*
* // Empty sets
* const empty1 = ISet.create<string>([]);
* const empty2 = ISet.create<string>([]);
* console.log(ISet.equal(empty1, empty2)); // true
*
* // Single element sets
* const single1 = ISet.create(["unique"]);
* const single2 = ISet.create(["unique"]);
* const single3 = ISet.create(["different"]);
*
* console.log(ISet.equal(single1, single2)); // true
* console.log(ISet.equal(single1, single3)); // false
* ```
*/
ISet.equal = (a, b) => a.size === b.size && a.every((e) => b.has(e));
/**
* Computes the difference between two ISet instances, identifying added and deleted elements.
*
* This function performs a set difference operation to determine what elements were added
* and what elements were deleted when transitioning from the old set to the new set.
* This is useful for change detection, state management, and synchronization scenarios.
*
* **Performance:** O(n + m) where n and m are the sizes of the old and new sets respectively.
*
* @template K The type of the elements.
* @param oldSet The original set representing the previous state.
* @param newSet The new set representing the current state.
* @returns An object with `added` and `deleted` properties, each containing an ISet
* of elements that were added or removed respectively.
*
* @example
* ```typescript
* // User permission changes
* const oldPermissions = ISet.create(["read", "write", "delete"]);
* const newPermissions = ISet.create(["read", "write", "execute", "admin"]);
*
* const permissionDiff = ISet.diff(oldPermissions, newPermissions);
*
* console.log("Permissions removed:", permissionDiff.deleted.toArray());
* // Output: ["delete"]
*
* console.log("Permissions added:", permissionDiff.added.toArray());
* // Output: ["execute", "admin"]
*
* // No changes
* const unchanged1 = ISet.create(["a", "b", "c"]);
* const unchanged2 = ISet.create(["a", "b", "c"]);
* const noDiff = ISet.diff(unchanged1, unchanged2);
*
* console.log(noDiff.added.isEmpty); // true
* console.log(noDiff.deleted.isEmpty); // true
*
* // Complete replacement
* const oldTags = ISet.create(["javascript", "react"]);
* const newTags = ISet.create(["typescript", "vue"]);
* const tagDiff = ISet.diff(oldTags, newTags);
*
* console.log(tagDiff.deleted.toArray()); // ["javascript", "react"]
* console.log(tagDiff.added.toArray()); // ["typescript", "vue"]
* ```
*/
ISet.diff = (oldSet, newSet) => ({
deleted: oldSet.subtract(newSet),
added: newSet.subtract(oldSet),
});
/**
* Computes the intersection of two ISet instances.
*
* Returns a new set containing only the elements that are present in both input sets.
* This operation is commutative: `intersection(a, b) === intersection(b, a)`.
*
* **Performance:** O(min(n, m)) where n and m are the sizes of the input sets.
*
* @template K The type of the elements.
* @param a The first set.
* @param b The second set.
* @returns A new ISet instance containing elements common to both sets.
*
* @example
* ```typescript
* // Finding common permissions between user and role
* const userPermissions = ISet.create(["read", "write", "delete", "admin"]);
* const rolePermissions = ISet.create(["read", "write", "execute"]);
*
* const commonPermissions = ISet.intersection(userPermissions, rolePermissions);
* console.log(commonPermissions.toArray()); // ["read", "write"]
*
* // No common elements
* const setA = ISet.create([1, 2, 3]);
* const setB = ISet.create([4, 5, 6]);
* const noCommon = ISet.intersection(setA, setB);
* console.log(noCommon.isEmpty); // true
*
* // Complete overlap
* const identical1 = ISet.create(["a", "b", "c"]);
* const identical2 = ISet.create(["a", "b", "c"]);
* const completeOverlap = ISet.intersection(identical1, identical2);
* console.log(ISet.equal(completeOverlap, identical1)); // true
*
* // Intersection with empty set
* const nonEmpty = ISet.create([1, 2, 3]);
* const empty = ISet.create<number>([]);
* const withEmpty = ISet.intersection(nonEmpty, empty);
* console.log(withEmpty.isEmpty); // true
* ```
*/
ISet.intersection = (a, b) => a.intersect(b);
/**
* Computes the union of two ISet instances.
*
* Returns a new set containing all elements that are present in either input set.
* Duplicate elements are automatically handled since sets only contain unique values.
* This operation is commutative: `union(a, b) === union(b, a)`.
*
* **Performance:** O(n + m) where n and m are the sizes of the input sets.
*
* @template K1 The type of elements in the first set.
* @template K2 The type of elements in the second set.
* @param a The first set.
* @param b The second set.
* @returns A new ISet instance containing all elements from both sets.
*
* @example
* ```typescript
* // Combining permissions from multiple sources
* const userPermissions = ISet.create(["read", "write"]);
* const rolePermissions = ISet.create(["write", "execute", "admin"]);
*
* const allPermissions = ISet.union(userPermissions, rolePermissions);
* console.log(allPermissions.toArray().toSorted());
* // Output: ["admin", "execute", "read", "write"]
*
* // Union with different types (type widening)
* const numbers = ISet.create([1, 2, 3]);
* const strings = ISet.create(["a", "b"]);
* const mixed = ISet.union(numbers, strings); // ISet<number | string>
* console.log(mixed.size); // 5
*
* // Union with empty set
* const nonEmpty = ISet.create(["item1", "item2"]);
* const empty = ISet.create<string>([]);
* const withEmpty = ISet.union(nonEmpty, empty);
* console.log(ISet.equal(withEmpty, nonEmpty)); // true
*
* // Overlapping sets
* const featuresA = ISet.create(["feature1", "feature2", "feature3"]);
* const featuresB = ISet.create(["feature2", "feature3", "feature4"]);
* const allFeatures = ISet.union(featuresA, featuresB);
* console.log(allFeatures.size); // 4 (duplicates removed)
* ```
*/
ISet.union = (a, b) => a.union(b);
})(ISet || (ISet = {}));
/**
* Internal class implementation for ISet providing immutable set operations.
*
* This class implements the ISet interface using JavaScript's native Set as the underlying
* storage mechanism for optimal performance. All mutation operations create new instances
* rather than modifying the existing set, ensuring immutability.
*
* **Implementation Details:**
* - Uses ReadonlySet<K> 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 elements. Must extend MapSetKeyType.
* @implements ISet
* @implements Iterable
* @internal This class should not be used directly. Use ISet.create() instead.
*/
class ISetClass {
#set;
#showNotFoundMessage;
/**
* Constructs an ISetClass instance with the given elements.
*
* @param iterable An iterable of elements to populate the set.
* @param showNotFoundMessage Whether to log warning messages when operations
* are performed on non-existent elements. Useful for debugging.
* Defaults to false for production use.
* @internal Use ISet.create() instead of calling this constructor directly.
*/
constructor(iterable, showNotFoundMessage = false) {
this.#set = new Set(iterable);
this.#showNotFoundMessage = showNotFoundMessage;
}
/** @inheritdoc */
get size() {
return asUint32(this.#set.size);
}
/** @inheritdoc */
get isEmpty() {
return this.size === 0;
}
/** @inheritdoc */
has(key) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
return this.#set.has(key);
}
/** @inheritdoc */
every(predicate) {
for (const key of this.values()) {
if (!predicate(key))
return false;
}
return true;
}
/** @inheritdoc */
some(predicate) {
for (const key of this.values()) {
if (predicate(key))
return true;
}
return false;
}
/** @inheritdoc */
add(key) {
if (this.has(key))
return this;
return ISet.create([...this.#set, key]);
}
/** @inheritdoc */
delete(key) {
if (!this.has(key)) {
if (this.#showNotFoundMessage) {
const keyStr = unknownToString(key);
console.warn(`ISet.delete: key not found: ${keyStr}`);
}
return this;
}
return ISet.create(Array.from(this.#set).filter((k) => !Object.is(k, key)));
}
/** @inheritdoc */
withMutations(actions) {
const mut_result = new Set(this.#set);
for (const action of actions) {
switch (action.type) {
case 'delete':
mut_result.delete(action.key);
break;
case 'add':
mut_result.add(action.key);
break;
}
}
return ISet.create(mut_result);
}
/** @inheritdoc */
map(mapFn) {
return ISet.create(this.toArray().map(mapFn));
}
/** @inheritdoc */
filter(predicate) {
return ISet.create(this.toArray().filter(predicate));
}
/** @inheritdoc */
filterNot(predicate) {
return ISet.create(this.toArray().filter((e) => !predicate(e)));
}
/** @inheritdoc */
forEach(callbackfn) {
for (const v of this.#set.values()) {
callbackfn(v);
}
}
/** @inheritdoc */
isSubsetOf(set) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
return this.every((k) => set.has(k));
}
/** @inheritdoc */
isSupersetOf(set) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
return set.every((k) => this.has(k));
}
/** @inheritdoc */
subtract(set) {
return ISet.create(this.toArray().filter((k) => !set.has(k)));
}
/** @inheritdoc */
intersect(set) {
return ISet.create(this.toArray().filter((k) => set.has(k)));
}
/** @inheritdoc */
union(set) {
return ISet.create([...this, ...set]);
}
/**
* @inheritdoc
*/
[Symbol.iterator]() {
return this.#set[Symbol.iterator]();
}
/** @inheritdoc */
keys() {
return this.#set.keys();
}
/** @inheritdoc */
values() {
return this.#set.values();
}
/** @inheritdoc */
entries() {
return this.#set.entries();
}
/** @inheritdoc */
toArray() {
return Array.from(this.values());
}
/** @inheritdoc */
toRawSet() {
return this.#set;
}
}
export { ISet };
//# sourceMappingURL=iset.mjs.map