@ls-stack/utils 3.62.0 → 3.65.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/arrayUtils.cjs +5 -0
- package/dist/arrayUtils.d.cts +2 -1
- package/dist/arrayUtils.d.ts +2 -1
- package/dist/arrayUtils.js +3 -1
- package/dist/{chunk-2LO5FYP5.js → chunk-MI4UE2PQ.js} +1 -1
- package/dist/{chunk-GVIDV772.js → chunk-WFQJUJTC.js} +4 -0
- package/dist/{chunk-SGRS4OEE.js → chunk-ZXIKIA5B.js} +1 -1
- package/dist/concurrentCalls.js +4 -4
- package/dist/filterObjectOrArrayKeys.js +2 -2
- package/dist/keyedMap.cjs +224 -0
- package/dist/keyedMap.d.cts +75 -0
- package/dist/keyedMap.d.ts +75 -0
- package/dist/keyedMap.js +145 -0
- package/dist/keyedSet.cjs +205 -0
- package/dist/keyedSet.d.cts +76 -0
- package/dist/keyedSet.d.ts +76 -0
- package/dist/keyedSet.js +126 -0
- package/dist/objUtils.js +2 -2
- package/dist/serializeXML.js +1 -1
- package/dist/testUtils.js +3 -3
- package/package.json +9 -1
package/dist/arrayUtils.cjs
CHANGED
|
@@ -31,6 +31,7 @@ __export(arrayUtils_exports, {
|
|
|
31
31
|
hasDuplicates: () => hasDuplicates,
|
|
32
32
|
intersperse: () => intersperse,
|
|
33
33
|
isInArray: () => isInArray,
|
|
34
|
+
isInArrayWithoutNarrowing: () => isInArrayWithoutNarrowing,
|
|
34
35
|
looseIsInArray: () => looseIsInArray,
|
|
35
36
|
rejectArrayUndefinedValues: () => rejectArrayUndefinedValues,
|
|
36
37
|
rejectDuplicates: () => rejectDuplicates,
|
|
@@ -106,6 +107,9 @@ function isInArray(value, oneOf) {
|
|
|
106
107
|
}
|
|
107
108
|
return false;
|
|
108
109
|
}
|
|
110
|
+
function isInArrayWithoutNarrowing(value, oneOf) {
|
|
111
|
+
return oneOf.includes(value);
|
|
112
|
+
}
|
|
109
113
|
function looseIsInArray(value, array) {
|
|
110
114
|
return array.includes(value);
|
|
111
115
|
}
|
|
@@ -215,6 +219,7 @@ function repeat(value, count, separator) {
|
|
|
215
219
|
hasDuplicates,
|
|
216
220
|
intersperse,
|
|
217
221
|
isInArray,
|
|
222
|
+
isInArrayWithoutNarrowing,
|
|
218
223
|
looseIsInArray,
|
|
219
224
|
rejectArrayUndefinedValues,
|
|
220
225
|
rejectDuplicates,
|
package/dist/arrayUtils.d.cts
CHANGED
|
@@ -76,6 +76,7 @@ declare function arrayWithPrevAndIndex<T>(array: T[]): {
|
|
|
76
76
|
index: number;
|
|
77
77
|
}[];
|
|
78
78
|
declare function isInArray<T, const U extends T>(value: T, oneOf: readonly U[]): value is U;
|
|
79
|
+
declare function isInArrayWithoutNarrowing<T, const U extends T>(value: T, oneOf: readonly U[]): boolean;
|
|
79
80
|
declare function looseIsInArray(value: unknown, array: readonly unknown[]): boolean;
|
|
80
81
|
declare function findAfterIndex<T>(array: T[], index: number, predicate: (item: T) => boolean): T | undefined;
|
|
81
82
|
declare function findBeforeIndex<T>(array: T[], index: number, predicate: (item: T) => boolean): T | undefined;
|
|
@@ -167,4 +168,4 @@ declare function intersperse<T, I>(array: T[], separator: I): (T | I)[];
|
|
|
167
168
|
*/
|
|
168
169
|
declare function repeat<T>(value: T, count: number, separator?: T): T[];
|
|
169
170
|
|
|
170
|
-
export { type FilterAndMapReturn, type SortByProps, type SortByValueFn, arrayOps, arrayWithPrev, arrayWithPrevAndIndex, filterAndMap, findAfterIndex, findAndMap, findBeforeIndex, getAscIndexOrder, hasDuplicates, intersperse, isInArray, looseIsInArray, rejectArrayUndefinedValues, rejectDuplicates, repeat, sortBy, truncateArray };
|
|
171
|
+
export { type FilterAndMapReturn, type SortByProps, type SortByValueFn, arrayOps, arrayWithPrev, arrayWithPrevAndIndex, filterAndMap, findAfterIndex, findAndMap, findBeforeIndex, getAscIndexOrder, hasDuplicates, intersperse, isInArray, isInArrayWithoutNarrowing, looseIsInArray, rejectArrayUndefinedValues, rejectDuplicates, repeat, sortBy, truncateArray };
|
package/dist/arrayUtils.d.ts
CHANGED
|
@@ -76,6 +76,7 @@ declare function arrayWithPrevAndIndex<T>(array: T[]): {
|
|
|
76
76
|
index: number;
|
|
77
77
|
}[];
|
|
78
78
|
declare function isInArray<T, const U extends T>(value: T, oneOf: readonly U[]): value is U;
|
|
79
|
+
declare function isInArrayWithoutNarrowing<T, const U extends T>(value: T, oneOf: readonly U[]): boolean;
|
|
79
80
|
declare function looseIsInArray(value: unknown, array: readonly unknown[]): boolean;
|
|
80
81
|
declare function findAfterIndex<T>(array: T[], index: number, predicate: (item: T) => boolean): T | undefined;
|
|
81
82
|
declare function findBeforeIndex<T>(array: T[], index: number, predicate: (item: T) => boolean): T | undefined;
|
|
@@ -167,4 +168,4 @@ declare function intersperse<T, I>(array: T[], separator: I): (T | I)[];
|
|
|
167
168
|
*/
|
|
168
169
|
declare function repeat<T>(value: T, count: number, separator?: T): T[];
|
|
169
170
|
|
|
170
|
-
export { type FilterAndMapReturn, type SortByProps, type SortByValueFn, arrayOps, arrayWithPrev, arrayWithPrevAndIndex, filterAndMap, findAfterIndex, findAndMap, findBeforeIndex, getAscIndexOrder, hasDuplicates, intersperse, isInArray, looseIsInArray, rejectArrayUndefinedValues, rejectDuplicates, repeat, sortBy, truncateArray };
|
|
171
|
+
export { type FilterAndMapReturn, type SortByProps, type SortByValueFn, arrayOps, arrayWithPrev, arrayWithPrevAndIndex, filterAndMap, findAfterIndex, findAndMap, findBeforeIndex, getAscIndexOrder, hasDuplicates, intersperse, isInArray, isInArrayWithoutNarrowing, looseIsInArray, rejectArrayUndefinedValues, rejectDuplicates, repeat, sortBy, truncateArray };
|
package/dist/arrayUtils.js
CHANGED
|
@@ -10,13 +10,14 @@ import {
|
|
|
10
10
|
hasDuplicates,
|
|
11
11
|
intersperse,
|
|
12
12
|
isInArray,
|
|
13
|
+
isInArrayWithoutNarrowing,
|
|
13
14
|
looseIsInArray,
|
|
14
15
|
rejectArrayUndefinedValues,
|
|
15
16
|
rejectDuplicates,
|
|
16
17
|
repeat,
|
|
17
18
|
sortBy,
|
|
18
19
|
truncateArray
|
|
19
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-WFQJUJTC.js";
|
|
20
21
|
import "./chunk-C2SVCIWE.js";
|
|
21
22
|
import "./chunk-JF2MDHOJ.js";
|
|
22
23
|
export {
|
|
@@ -31,6 +32,7 @@ export {
|
|
|
31
32
|
hasDuplicates,
|
|
32
33
|
intersperse,
|
|
33
34
|
isInArray,
|
|
35
|
+
isInArrayWithoutNarrowing,
|
|
34
36
|
looseIsInArray,
|
|
35
37
|
rejectArrayUndefinedValues,
|
|
36
38
|
rejectDuplicates,
|
|
@@ -60,6 +60,9 @@ function isInArray(value, oneOf) {
|
|
|
60
60
|
}
|
|
61
61
|
return false;
|
|
62
62
|
}
|
|
63
|
+
function isInArrayWithoutNarrowing(value, oneOf) {
|
|
64
|
+
return oneOf.includes(value);
|
|
65
|
+
}
|
|
63
66
|
function looseIsInArray(value, array) {
|
|
64
67
|
return array.includes(value);
|
|
65
68
|
}
|
|
@@ -164,6 +167,7 @@ export {
|
|
|
164
167
|
arrayWithPrev,
|
|
165
168
|
arrayWithPrevAndIndex,
|
|
166
169
|
isInArray,
|
|
170
|
+
isInArrayWithoutNarrowing,
|
|
167
171
|
looseIsInArray,
|
|
168
172
|
findAfterIndex,
|
|
169
173
|
findBeforeIndex,
|
package/dist/concurrentCalls.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
truncateString
|
|
3
3
|
} from "./chunk-BM4PYVOX.js";
|
|
4
|
-
import {
|
|
5
|
-
safeJsonStringify
|
|
6
|
-
} from "./chunk-VAAMRG4K.js";
|
|
7
4
|
import {
|
|
8
5
|
sleep
|
|
9
6
|
} from "./chunk-5DZT3Z5Z.js";
|
|
7
|
+
import {
|
|
8
|
+
safeJsonStringify
|
|
9
|
+
} from "./chunk-VAAMRG4K.js";
|
|
10
10
|
import {
|
|
11
11
|
truncateArray
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-WFQJUJTC.js";
|
|
13
13
|
import {
|
|
14
14
|
invariant
|
|
15
15
|
} from "./chunk-C2SVCIWE.js";
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/keyedMap.ts
|
|
21
|
+
var keyedMap_exports = {};
|
|
22
|
+
__export(keyedMap_exports, {
|
|
23
|
+
CompositeKeyMap: () => CompositeKeyMap,
|
|
24
|
+
KeyedMap: () => KeyedMap
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(keyedMap_exports);
|
|
27
|
+
|
|
28
|
+
// src/typeGuards.ts
|
|
29
|
+
function isObject(value) {
|
|
30
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// src/assertions.ts
|
|
34
|
+
var isObject2 = isObject;
|
|
35
|
+
|
|
36
|
+
// src/getCompositeKey.ts
|
|
37
|
+
function getCompositeKey(input, maxSortingDepth = 3) {
|
|
38
|
+
if (typeof input === "string") return `"${input}`;
|
|
39
|
+
if (!input || typeof input !== "object") return `$${input}`;
|
|
40
|
+
return stringifyCompact(input, maxSortingDepth, 0, /* @__PURE__ */ new WeakSet());
|
|
41
|
+
}
|
|
42
|
+
function stringifyCompact(input, maxSortingDepth, depth, refs) {
|
|
43
|
+
const isJsObj = input && typeof input === "object";
|
|
44
|
+
if (isJsObj) {
|
|
45
|
+
if (refs.has(input)) {
|
|
46
|
+
throw new Error("Circular reference detected");
|
|
47
|
+
}
|
|
48
|
+
refs.add(input);
|
|
49
|
+
}
|
|
50
|
+
let result;
|
|
51
|
+
if (Array.isArray(input)) {
|
|
52
|
+
result = "[";
|
|
53
|
+
for (const v of input) {
|
|
54
|
+
if (result.length > 1) result += ",";
|
|
55
|
+
result += stringifyCompact(v, maxSortingDepth, depth + 1, refs);
|
|
56
|
+
}
|
|
57
|
+
result += "]";
|
|
58
|
+
} else if (isObject2(input)) {
|
|
59
|
+
let entries = Object.entries(input);
|
|
60
|
+
if (entries.length === 0) {
|
|
61
|
+
result = "{}";
|
|
62
|
+
} else {
|
|
63
|
+
if (depth < maxSortingDepth) {
|
|
64
|
+
entries = entries.sort(
|
|
65
|
+
([a], [b]) => a < b ? -1 : a > b ? 1 : 0
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
result = "{";
|
|
69
|
+
for (const [k, v] of entries) {
|
|
70
|
+
if (v === void 0) continue;
|
|
71
|
+
if (result.length > 1) result += ",";
|
|
72
|
+
result += `${k}:${stringifyCompact(v, maxSortingDepth, depth + 1, refs)}`;
|
|
73
|
+
}
|
|
74
|
+
result += "}";
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
result = JSON.stringify(input);
|
|
78
|
+
}
|
|
79
|
+
if (isJsObj) {
|
|
80
|
+
refs.delete(input);
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// src/keyedMap.ts
|
|
86
|
+
var KeyedMap = class {
|
|
87
|
+
map;
|
|
88
|
+
getKey;
|
|
89
|
+
/**
|
|
90
|
+
* @param getKey - Function to compute an internal key from the external key
|
|
91
|
+
* @param entries - Optional initial entries to add to the map
|
|
92
|
+
*/
|
|
93
|
+
constructor(getKey, entries) {
|
|
94
|
+
this.getKey = getKey;
|
|
95
|
+
this.map = /* @__PURE__ */ new Map();
|
|
96
|
+
if (entries) {
|
|
97
|
+
for (const [key, value] of entries) {
|
|
98
|
+
this.set(key, value);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/** The number of entries in the map */
|
|
103
|
+
get size() {
|
|
104
|
+
return this.map.size;
|
|
105
|
+
}
|
|
106
|
+
/** Sets a value for the given key. If the key exists, replaces both key and value. */
|
|
107
|
+
set(key, value) {
|
|
108
|
+
const internalKey = this.getKey(key);
|
|
109
|
+
this.map.set(internalKey, { key, value });
|
|
110
|
+
return this;
|
|
111
|
+
}
|
|
112
|
+
/** Sets multiple entries at once. */
|
|
113
|
+
setMultiple(entries) {
|
|
114
|
+
for (const [key, value] of entries) {
|
|
115
|
+
this.set(key, value);
|
|
116
|
+
}
|
|
117
|
+
return this;
|
|
118
|
+
}
|
|
119
|
+
/** Gets the value for the given key, or undefined if not found. */
|
|
120
|
+
get(key) {
|
|
121
|
+
const internalKey = this.getKey(key);
|
|
122
|
+
return this.map.get(internalKey)?.value;
|
|
123
|
+
}
|
|
124
|
+
/** Checks if the map contains the given key. */
|
|
125
|
+
has(key) {
|
|
126
|
+
const internalKey = this.getKey(key);
|
|
127
|
+
return this.map.has(internalKey);
|
|
128
|
+
}
|
|
129
|
+
/** Removes the entry for the given key. Returns true if the entry was removed. */
|
|
130
|
+
delete(key) {
|
|
131
|
+
const internalKey = this.getKey(key);
|
|
132
|
+
return this.map.delete(internalKey);
|
|
133
|
+
}
|
|
134
|
+
/** Removes multiple entries. Returns the number of entries removed. */
|
|
135
|
+
deleteMultiple(keys) {
|
|
136
|
+
let count = 0;
|
|
137
|
+
for (const key of keys) {
|
|
138
|
+
if (this.delete(key)) {
|
|
139
|
+
count++;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return count;
|
|
143
|
+
}
|
|
144
|
+
/** Removes all entries from the map. */
|
|
145
|
+
clear() {
|
|
146
|
+
this.map.clear();
|
|
147
|
+
}
|
|
148
|
+
/** Executes a callback for each entry in the map. */
|
|
149
|
+
forEach(callback, thisArg) {
|
|
150
|
+
for (const { key, value } of this.map.values()) {
|
|
151
|
+
callback.call(thisArg, value, key, this);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/** Finds the first entry matching the predicate. */
|
|
155
|
+
find(predicate) {
|
|
156
|
+
for (const { key, value } of this.map.values()) {
|
|
157
|
+
if (predicate(value, key)) {
|
|
158
|
+
return { key, value };
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return void 0;
|
|
162
|
+
}
|
|
163
|
+
/** Gets the value for the given key, or throws if not found. */
|
|
164
|
+
getOrThrow(key) {
|
|
165
|
+
const value = this.get(key);
|
|
166
|
+
if (value === void 0 && !this.has(key)) {
|
|
167
|
+
throw new Error(`Key not found in KeyedMap`);
|
|
168
|
+
}
|
|
169
|
+
return value;
|
|
170
|
+
}
|
|
171
|
+
/** Gets the value for the given key, or inserts and returns the fallback value. */
|
|
172
|
+
getOrInsert(key, fallback) {
|
|
173
|
+
if (!this.has(key)) {
|
|
174
|
+
this.set(key, fallback());
|
|
175
|
+
}
|
|
176
|
+
return this.getOrThrow(key);
|
|
177
|
+
}
|
|
178
|
+
/** Returns values that match the predicate. */
|
|
179
|
+
toFilteredValues(predicate) {
|
|
180
|
+
const values = [];
|
|
181
|
+
for (const { key, value } of this.map.values()) {
|
|
182
|
+
if (predicate(value, key)) {
|
|
183
|
+
values.push(value);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return values;
|
|
187
|
+
}
|
|
188
|
+
/** Returns all values as an array. */
|
|
189
|
+
toValues() {
|
|
190
|
+
return [...this.values()];
|
|
191
|
+
}
|
|
192
|
+
/** Returns all keys as an array. */
|
|
193
|
+
toKeys() {
|
|
194
|
+
return [...this.keys()];
|
|
195
|
+
}
|
|
196
|
+
*keys() {
|
|
197
|
+
for (const { key } of this.map.values()) {
|
|
198
|
+
yield key;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
*values() {
|
|
202
|
+
for (const { value } of this.map.values()) {
|
|
203
|
+
yield value;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
*entries() {
|
|
207
|
+
for (const { key, value } of this.map.values()) {
|
|
208
|
+
yield [key, value];
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
[Symbol.iterator]() {
|
|
212
|
+
return this.entries();
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
var CompositeKeyMap = class extends KeyedMap {
|
|
216
|
+
constructor(entries) {
|
|
217
|
+
super(getCompositeKey, entries);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
221
|
+
0 && (module.exports = {
|
|
222
|
+
CompositeKeyMap,
|
|
223
|
+
KeyedMap
|
|
224
|
+
});
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A Map implementation that uses a custom key function to determine key equality.
|
|
3
|
+
* Keys with the same computed internal key are considered equal.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* const map = new KeyedMap<{ x: number; y: number }, string, string>(
|
|
7
|
+
* (key) => `${key.x},${key.y}`,
|
|
8
|
+
* );
|
|
9
|
+
* map.set({ x: 1, y: 2 }, 'point A');
|
|
10
|
+
* map.get({ x: 1, y: 2 }); // 'point A' (different object, same computed key)
|
|
11
|
+
*
|
|
12
|
+
* @template K - The type of the external key
|
|
13
|
+
* @template V - The type of the value
|
|
14
|
+
* @template InternalKey - The type of the internal key used for comparison
|
|
15
|
+
*/
|
|
16
|
+
declare class KeyedMap<K, V, InternalKey = string> {
|
|
17
|
+
private map;
|
|
18
|
+
private getKey;
|
|
19
|
+
/**
|
|
20
|
+
* @param getKey - Function to compute an internal key from the external key
|
|
21
|
+
* @param entries - Optional initial entries to add to the map
|
|
22
|
+
*/
|
|
23
|
+
constructor(getKey: (key: K) => InternalKey, entries?: Iterable<[K, V]>);
|
|
24
|
+
/** The number of entries in the map */
|
|
25
|
+
get size(): number;
|
|
26
|
+
/** Sets a value for the given key. If the key exists, replaces both key and value. */
|
|
27
|
+
set(key: K, value: V): this;
|
|
28
|
+
/** Sets multiple entries at once. */
|
|
29
|
+
setMultiple(entries: Iterable<[K, V]>): this;
|
|
30
|
+
/** Gets the value for the given key, or undefined if not found. */
|
|
31
|
+
get(key: K): V | undefined;
|
|
32
|
+
/** Checks if the map contains the given key. */
|
|
33
|
+
has(key: K): boolean;
|
|
34
|
+
/** Removes the entry for the given key. Returns true if the entry was removed. */
|
|
35
|
+
delete(key: K): boolean;
|
|
36
|
+
/** Removes multiple entries. Returns the number of entries removed. */
|
|
37
|
+
deleteMultiple(keys: Iterable<K>): number;
|
|
38
|
+
/** Removes all entries from the map. */
|
|
39
|
+
clear(): void;
|
|
40
|
+
/** Executes a callback for each entry in the map. */
|
|
41
|
+
forEach(callback: (value: V, key: K, map: KeyedMap<K, V, InternalKey>) => void, thisArg?: unknown): void;
|
|
42
|
+
/** Finds the first entry matching the predicate. */
|
|
43
|
+
find(predicate: (value: V, key: K) => boolean): {
|
|
44
|
+
key: K;
|
|
45
|
+
value: V;
|
|
46
|
+
} | undefined;
|
|
47
|
+
/** Gets the value for the given key, or throws if not found. */
|
|
48
|
+
getOrThrow(key: K): V;
|
|
49
|
+
/** Gets the value for the given key, or inserts and returns the fallback value. */
|
|
50
|
+
getOrInsert(key: K, fallback: () => V): V;
|
|
51
|
+
/** Returns values that match the predicate. */
|
|
52
|
+
toFilteredValues(predicate: (value: V, key: K) => boolean): V[];
|
|
53
|
+
/** Returns all values as an array. */
|
|
54
|
+
toValues(): V[];
|
|
55
|
+
/** Returns all keys as an array. */
|
|
56
|
+
toKeys(): K[];
|
|
57
|
+
keys(): IterableIterator<K>;
|
|
58
|
+
values(): IterableIterator<V>;
|
|
59
|
+
entries(): IterableIterator<[K, V]>;
|
|
60
|
+
[Symbol.iterator](): IterableIterator<[K, V]>;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* A Map that compares keys by value instead of reference.
|
|
64
|
+
* Uses `getCompositeKey` to generate a stable string key for any value.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* const map = new CompositeKeyMap<{ x: number; y: number }, string>();
|
|
68
|
+
* map.set({ x: 1, y: 2 }, 'point A');
|
|
69
|
+
* map.get({ x: 1, y: 2 }); // 'point A' (different object, same value)
|
|
70
|
+
*/
|
|
71
|
+
declare class CompositeKeyMap<K, V> extends KeyedMap<K, V, string> {
|
|
72
|
+
constructor(entries?: Iterable<[K, V]>);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export { CompositeKeyMap, KeyedMap };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A Map implementation that uses a custom key function to determine key equality.
|
|
3
|
+
* Keys with the same computed internal key are considered equal.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* const map = new KeyedMap<{ x: number; y: number }, string, string>(
|
|
7
|
+
* (key) => `${key.x},${key.y}`,
|
|
8
|
+
* );
|
|
9
|
+
* map.set({ x: 1, y: 2 }, 'point A');
|
|
10
|
+
* map.get({ x: 1, y: 2 }); // 'point A' (different object, same computed key)
|
|
11
|
+
*
|
|
12
|
+
* @template K - The type of the external key
|
|
13
|
+
* @template V - The type of the value
|
|
14
|
+
* @template InternalKey - The type of the internal key used for comparison
|
|
15
|
+
*/
|
|
16
|
+
declare class KeyedMap<K, V, InternalKey = string> {
|
|
17
|
+
private map;
|
|
18
|
+
private getKey;
|
|
19
|
+
/**
|
|
20
|
+
* @param getKey - Function to compute an internal key from the external key
|
|
21
|
+
* @param entries - Optional initial entries to add to the map
|
|
22
|
+
*/
|
|
23
|
+
constructor(getKey: (key: K) => InternalKey, entries?: Iterable<[K, V]>);
|
|
24
|
+
/** The number of entries in the map */
|
|
25
|
+
get size(): number;
|
|
26
|
+
/** Sets a value for the given key. If the key exists, replaces both key and value. */
|
|
27
|
+
set(key: K, value: V): this;
|
|
28
|
+
/** Sets multiple entries at once. */
|
|
29
|
+
setMultiple(entries: Iterable<[K, V]>): this;
|
|
30
|
+
/** Gets the value for the given key, or undefined if not found. */
|
|
31
|
+
get(key: K): V | undefined;
|
|
32
|
+
/** Checks if the map contains the given key. */
|
|
33
|
+
has(key: K): boolean;
|
|
34
|
+
/** Removes the entry for the given key. Returns true if the entry was removed. */
|
|
35
|
+
delete(key: K): boolean;
|
|
36
|
+
/** Removes multiple entries. Returns the number of entries removed. */
|
|
37
|
+
deleteMultiple(keys: Iterable<K>): number;
|
|
38
|
+
/** Removes all entries from the map. */
|
|
39
|
+
clear(): void;
|
|
40
|
+
/** Executes a callback for each entry in the map. */
|
|
41
|
+
forEach(callback: (value: V, key: K, map: KeyedMap<K, V, InternalKey>) => void, thisArg?: unknown): void;
|
|
42
|
+
/** Finds the first entry matching the predicate. */
|
|
43
|
+
find(predicate: (value: V, key: K) => boolean): {
|
|
44
|
+
key: K;
|
|
45
|
+
value: V;
|
|
46
|
+
} | undefined;
|
|
47
|
+
/** Gets the value for the given key, or throws if not found. */
|
|
48
|
+
getOrThrow(key: K): V;
|
|
49
|
+
/** Gets the value for the given key, or inserts and returns the fallback value. */
|
|
50
|
+
getOrInsert(key: K, fallback: () => V): V;
|
|
51
|
+
/** Returns values that match the predicate. */
|
|
52
|
+
toFilteredValues(predicate: (value: V, key: K) => boolean): V[];
|
|
53
|
+
/** Returns all values as an array. */
|
|
54
|
+
toValues(): V[];
|
|
55
|
+
/** Returns all keys as an array. */
|
|
56
|
+
toKeys(): K[];
|
|
57
|
+
keys(): IterableIterator<K>;
|
|
58
|
+
values(): IterableIterator<V>;
|
|
59
|
+
entries(): IterableIterator<[K, V]>;
|
|
60
|
+
[Symbol.iterator](): IterableIterator<[K, V]>;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* A Map that compares keys by value instead of reference.
|
|
64
|
+
* Uses `getCompositeKey` to generate a stable string key for any value.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* const map = new CompositeKeyMap<{ x: number; y: number }, string>();
|
|
68
|
+
* map.set({ x: 1, y: 2 }, 'point A');
|
|
69
|
+
* map.get({ x: 1, y: 2 }); // 'point A' (different object, same value)
|
|
70
|
+
*/
|
|
71
|
+
declare class CompositeKeyMap<K, V> extends KeyedMap<K, V, string> {
|
|
72
|
+
constructor(entries?: Iterable<[K, V]>);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export { CompositeKeyMap, KeyedMap };
|
package/dist/keyedMap.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getCompositeKey
|
|
3
|
+
} from "./chunk-6FIBVC2P.js";
|
|
4
|
+
import "./chunk-C2SVCIWE.js";
|
|
5
|
+
import "./chunk-JF2MDHOJ.js";
|
|
6
|
+
|
|
7
|
+
// src/keyedMap.ts
|
|
8
|
+
var KeyedMap = class {
|
|
9
|
+
map;
|
|
10
|
+
getKey;
|
|
11
|
+
/**
|
|
12
|
+
* @param getKey - Function to compute an internal key from the external key
|
|
13
|
+
* @param entries - Optional initial entries to add to the map
|
|
14
|
+
*/
|
|
15
|
+
constructor(getKey, entries) {
|
|
16
|
+
this.getKey = getKey;
|
|
17
|
+
this.map = /* @__PURE__ */ new Map();
|
|
18
|
+
if (entries) {
|
|
19
|
+
for (const [key, value] of entries) {
|
|
20
|
+
this.set(key, value);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/** The number of entries in the map */
|
|
25
|
+
get size() {
|
|
26
|
+
return this.map.size;
|
|
27
|
+
}
|
|
28
|
+
/** Sets a value for the given key. If the key exists, replaces both key and value. */
|
|
29
|
+
set(key, value) {
|
|
30
|
+
const internalKey = this.getKey(key);
|
|
31
|
+
this.map.set(internalKey, { key, value });
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
/** Sets multiple entries at once. */
|
|
35
|
+
setMultiple(entries) {
|
|
36
|
+
for (const [key, value] of entries) {
|
|
37
|
+
this.set(key, value);
|
|
38
|
+
}
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
/** Gets the value for the given key, or undefined if not found. */
|
|
42
|
+
get(key) {
|
|
43
|
+
const internalKey = this.getKey(key);
|
|
44
|
+
return this.map.get(internalKey)?.value;
|
|
45
|
+
}
|
|
46
|
+
/** Checks if the map contains the given key. */
|
|
47
|
+
has(key) {
|
|
48
|
+
const internalKey = this.getKey(key);
|
|
49
|
+
return this.map.has(internalKey);
|
|
50
|
+
}
|
|
51
|
+
/** Removes the entry for the given key. Returns true if the entry was removed. */
|
|
52
|
+
delete(key) {
|
|
53
|
+
const internalKey = this.getKey(key);
|
|
54
|
+
return this.map.delete(internalKey);
|
|
55
|
+
}
|
|
56
|
+
/** Removes multiple entries. Returns the number of entries removed. */
|
|
57
|
+
deleteMultiple(keys) {
|
|
58
|
+
let count = 0;
|
|
59
|
+
for (const key of keys) {
|
|
60
|
+
if (this.delete(key)) {
|
|
61
|
+
count++;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return count;
|
|
65
|
+
}
|
|
66
|
+
/** Removes all entries from the map. */
|
|
67
|
+
clear() {
|
|
68
|
+
this.map.clear();
|
|
69
|
+
}
|
|
70
|
+
/** Executes a callback for each entry in the map. */
|
|
71
|
+
forEach(callback, thisArg) {
|
|
72
|
+
for (const { key, value } of this.map.values()) {
|
|
73
|
+
callback.call(thisArg, value, key, this);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/** Finds the first entry matching the predicate. */
|
|
77
|
+
find(predicate) {
|
|
78
|
+
for (const { key, value } of this.map.values()) {
|
|
79
|
+
if (predicate(value, key)) {
|
|
80
|
+
return { key, value };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return void 0;
|
|
84
|
+
}
|
|
85
|
+
/** Gets the value for the given key, or throws if not found. */
|
|
86
|
+
getOrThrow(key) {
|
|
87
|
+
const value = this.get(key);
|
|
88
|
+
if (value === void 0 && !this.has(key)) {
|
|
89
|
+
throw new Error(`Key not found in KeyedMap`);
|
|
90
|
+
}
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
/** Gets the value for the given key, or inserts and returns the fallback value. */
|
|
94
|
+
getOrInsert(key, fallback) {
|
|
95
|
+
if (!this.has(key)) {
|
|
96
|
+
this.set(key, fallback());
|
|
97
|
+
}
|
|
98
|
+
return this.getOrThrow(key);
|
|
99
|
+
}
|
|
100
|
+
/** Returns values that match the predicate. */
|
|
101
|
+
toFilteredValues(predicate) {
|
|
102
|
+
const values = [];
|
|
103
|
+
for (const { key, value } of this.map.values()) {
|
|
104
|
+
if (predicate(value, key)) {
|
|
105
|
+
values.push(value);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return values;
|
|
109
|
+
}
|
|
110
|
+
/** Returns all values as an array. */
|
|
111
|
+
toValues() {
|
|
112
|
+
return [...this.values()];
|
|
113
|
+
}
|
|
114
|
+
/** Returns all keys as an array. */
|
|
115
|
+
toKeys() {
|
|
116
|
+
return [...this.keys()];
|
|
117
|
+
}
|
|
118
|
+
*keys() {
|
|
119
|
+
for (const { key } of this.map.values()) {
|
|
120
|
+
yield key;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
*values() {
|
|
124
|
+
for (const { value } of this.map.values()) {
|
|
125
|
+
yield value;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
*entries() {
|
|
129
|
+
for (const { key, value } of this.map.values()) {
|
|
130
|
+
yield [key, value];
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
[Symbol.iterator]() {
|
|
134
|
+
return this.entries();
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
var CompositeKeyMap = class extends KeyedMap {
|
|
138
|
+
constructor(entries) {
|
|
139
|
+
super(getCompositeKey, entries);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
export {
|
|
143
|
+
CompositeKeyMap,
|
|
144
|
+
KeyedMap
|
|
145
|
+
};
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/keyedSet.ts
|
|
21
|
+
var keyedSet_exports = {};
|
|
22
|
+
__export(keyedSet_exports, {
|
|
23
|
+
CompositeKeySet: () => CompositeKeySet,
|
|
24
|
+
KeyedSet: () => KeyedSet
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(keyedSet_exports);
|
|
27
|
+
|
|
28
|
+
// src/typeGuards.ts
|
|
29
|
+
function isObject(value) {
|
|
30
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// src/assertions.ts
|
|
34
|
+
var isObject2 = isObject;
|
|
35
|
+
|
|
36
|
+
// src/getCompositeKey.ts
|
|
37
|
+
function getCompositeKey(input, maxSortingDepth = 3) {
|
|
38
|
+
if (typeof input === "string") return `"${input}`;
|
|
39
|
+
if (!input || typeof input !== "object") return `$${input}`;
|
|
40
|
+
return stringifyCompact(input, maxSortingDepth, 0, /* @__PURE__ */ new WeakSet());
|
|
41
|
+
}
|
|
42
|
+
function stringifyCompact(input, maxSortingDepth, depth, refs) {
|
|
43
|
+
const isJsObj = input && typeof input === "object";
|
|
44
|
+
if (isJsObj) {
|
|
45
|
+
if (refs.has(input)) {
|
|
46
|
+
throw new Error("Circular reference detected");
|
|
47
|
+
}
|
|
48
|
+
refs.add(input);
|
|
49
|
+
}
|
|
50
|
+
let result;
|
|
51
|
+
if (Array.isArray(input)) {
|
|
52
|
+
result = "[";
|
|
53
|
+
for (const v of input) {
|
|
54
|
+
if (result.length > 1) result += ",";
|
|
55
|
+
result += stringifyCompact(v, maxSortingDepth, depth + 1, refs);
|
|
56
|
+
}
|
|
57
|
+
result += "]";
|
|
58
|
+
} else if (isObject2(input)) {
|
|
59
|
+
let entries = Object.entries(input);
|
|
60
|
+
if (entries.length === 0) {
|
|
61
|
+
result = "{}";
|
|
62
|
+
} else {
|
|
63
|
+
if (depth < maxSortingDepth) {
|
|
64
|
+
entries = entries.sort(
|
|
65
|
+
([a], [b]) => a < b ? -1 : a > b ? 1 : 0
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
result = "{";
|
|
69
|
+
for (const [k, v] of entries) {
|
|
70
|
+
if (v === void 0) continue;
|
|
71
|
+
if (result.length > 1) result += ",";
|
|
72
|
+
result += `${k}:${stringifyCompact(v, maxSortingDepth, depth + 1, refs)}`;
|
|
73
|
+
}
|
|
74
|
+
result += "}";
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
result = JSON.stringify(input);
|
|
78
|
+
}
|
|
79
|
+
if (isJsObj) {
|
|
80
|
+
refs.delete(input);
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// src/keyedSet.ts
|
|
86
|
+
var KeyedSet = class {
|
|
87
|
+
map;
|
|
88
|
+
getKey;
|
|
89
|
+
/**
|
|
90
|
+
* @param getKey - Function to extract a unique key from each item
|
|
91
|
+
* @param iterable - Optional initial items to add to the set
|
|
92
|
+
*/
|
|
93
|
+
constructor(getKey, iterable) {
|
|
94
|
+
this.getKey = getKey;
|
|
95
|
+
this.map = /* @__PURE__ */ new Map();
|
|
96
|
+
if (iterable) {
|
|
97
|
+
for (const item of iterable) {
|
|
98
|
+
this.add(item);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/** The number of items in the set */
|
|
103
|
+
get size() {
|
|
104
|
+
return this.map.size;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Adds an item to the set. If an item with the same key exists, it will be
|
|
108
|
+
* replaced.
|
|
109
|
+
*/
|
|
110
|
+
add(item) {
|
|
111
|
+
const key = this.getKey(item);
|
|
112
|
+
this.map.set(key, item);
|
|
113
|
+
return this;
|
|
114
|
+
}
|
|
115
|
+
/** Adds multiple items to the set. */
|
|
116
|
+
addMultiple(items) {
|
|
117
|
+
for (const item of items) {
|
|
118
|
+
this.add(item);
|
|
119
|
+
}
|
|
120
|
+
return this;
|
|
121
|
+
}
|
|
122
|
+
/** Checks if an item with the same key exists in the set. */
|
|
123
|
+
has(item) {
|
|
124
|
+
const key = this.getKey(item);
|
|
125
|
+
return this.map.has(key);
|
|
126
|
+
}
|
|
127
|
+
/** Checks if an item with the given key exists in the set. */
|
|
128
|
+
hasKey(key) {
|
|
129
|
+
return this.map.has(key);
|
|
130
|
+
}
|
|
131
|
+
/** Gets an item by its key, or undefined if not found. */
|
|
132
|
+
getByKey(key) {
|
|
133
|
+
return this.map.get(key);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Removes an item from the set by computing its key. Returns true if the item
|
|
137
|
+
* was removed.
|
|
138
|
+
*/
|
|
139
|
+
delete(item) {
|
|
140
|
+
const key = this.getKey(item);
|
|
141
|
+
return this.map.delete(key);
|
|
142
|
+
}
|
|
143
|
+
/** Removes an item by its key. Returns true if the item was removed. */
|
|
144
|
+
deleteByKey(key) {
|
|
145
|
+
return this.map.delete(key);
|
|
146
|
+
}
|
|
147
|
+
/** Removes multiple items from the set. Returns the number of items removed. */
|
|
148
|
+
deleteMultiple(items) {
|
|
149
|
+
let count = 0;
|
|
150
|
+
for (const item of items) {
|
|
151
|
+
if (this.delete(item)) {
|
|
152
|
+
count++;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return count;
|
|
156
|
+
}
|
|
157
|
+
/** Removes multiple items by their keys. Returns the number of items removed. */
|
|
158
|
+
deleteMultipleByKeys(keys) {
|
|
159
|
+
let count = 0;
|
|
160
|
+
for (const key of keys) {
|
|
161
|
+
if (this.deleteByKey(key)) {
|
|
162
|
+
count++;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return count;
|
|
166
|
+
}
|
|
167
|
+
/** Removes all items from the set. */
|
|
168
|
+
clear() {
|
|
169
|
+
this.map.clear();
|
|
170
|
+
}
|
|
171
|
+
/** Executes a callback for each item in the set. */
|
|
172
|
+
forEach(callback, thisArg) {
|
|
173
|
+
for (const value of this.map.values()) {
|
|
174
|
+
callback.call(thisArg, value, value, this);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
*values() {
|
|
178
|
+
yield* this.map.values();
|
|
179
|
+
}
|
|
180
|
+
*keys() {
|
|
181
|
+
yield* this.map.values();
|
|
182
|
+
}
|
|
183
|
+
*entries() {
|
|
184
|
+
for (const value of this.map.values()) {
|
|
185
|
+
yield [value, value];
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
[Symbol.iterator]() {
|
|
189
|
+
return this.values();
|
|
190
|
+
}
|
|
191
|
+
/** Returns all items as an array. */
|
|
192
|
+
toArray() {
|
|
193
|
+
return [...this.map.values()];
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
var CompositeKeySet = class extends KeyedSet {
|
|
197
|
+
constructor(iterable) {
|
|
198
|
+
super(getCompositeKey, iterable);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
202
|
+
0 && (module.exports = {
|
|
203
|
+
CompositeKeySet,
|
|
204
|
+
KeyedSet
|
|
205
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A Set implementation that uses a custom key function to determine uniqueness.
|
|
3
|
+
* Items with the same key are considered equal, and adding a duplicate replaces
|
|
4
|
+
* the existing item.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* const set = new KeyedSet<{ id: number; name: string }, number>(
|
|
8
|
+
* (item) => item.id,
|
|
9
|
+
* );
|
|
10
|
+
* set.add({ id: 1, name: 'one' });
|
|
11
|
+
* set.add({ id: 1, name: 'replaced' }); // replaces previous item
|
|
12
|
+
* set.getByKey(1); // { id: 1, name: 'replaced' }
|
|
13
|
+
*
|
|
14
|
+
* @template T - The type of items stored in the set
|
|
15
|
+
* @template K - The type of the key extracted from items
|
|
16
|
+
*/
|
|
17
|
+
declare class KeyedSet<T, K = string> {
|
|
18
|
+
private map;
|
|
19
|
+
private getKey;
|
|
20
|
+
/**
|
|
21
|
+
* @param getKey - Function to extract a unique key from each item
|
|
22
|
+
* @param iterable - Optional initial items to add to the set
|
|
23
|
+
*/
|
|
24
|
+
constructor(getKey: (item: T) => K, iterable?: Iterable<T>);
|
|
25
|
+
/** The number of items in the set */
|
|
26
|
+
get size(): number;
|
|
27
|
+
/**
|
|
28
|
+
* Adds an item to the set. If an item with the same key exists, it will be
|
|
29
|
+
* replaced.
|
|
30
|
+
*/
|
|
31
|
+
add(item: T): this;
|
|
32
|
+
/** Adds multiple items to the set. */
|
|
33
|
+
addMultiple(items: Iterable<T>): this;
|
|
34
|
+
/** Checks if an item with the same key exists in the set. */
|
|
35
|
+
has(item: T): boolean;
|
|
36
|
+
/** Checks if an item with the given key exists in the set. */
|
|
37
|
+
hasKey(key: K): boolean;
|
|
38
|
+
/** Gets an item by its key, or undefined if not found. */
|
|
39
|
+
getByKey(key: K): T | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Removes an item from the set by computing its key. Returns true if the item
|
|
42
|
+
* was removed.
|
|
43
|
+
*/
|
|
44
|
+
delete(item: T): boolean;
|
|
45
|
+
/** Removes an item by its key. Returns true if the item was removed. */
|
|
46
|
+
deleteByKey(key: K): boolean;
|
|
47
|
+
/** Removes multiple items from the set. Returns the number of items removed. */
|
|
48
|
+
deleteMultiple(items: Iterable<T>): number;
|
|
49
|
+
/** Removes multiple items by their keys. Returns the number of items removed. */
|
|
50
|
+
deleteMultipleByKeys(keys: Iterable<K>): number;
|
|
51
|
+
/** Removes all items from the set. */
|
|
52
|
+
clear(): void;
|
|
53
|
+
/** Executes a callback for each item in the set. */
|
|
54
|
+
forEach(callback: (value: T, value2: T, set: KeyedSet<T, K>) => void, thisArg?: unknown): void;
|
|
55
|
+
values(): IterableIterator<T>;
|
|
56
|
+
keys(): IterableIterator<T>;
|
|
57
|
+
entries(): IterableIterator<[T, T]>;
|
|
58
|
+
[Symbol.iterator](): IterableIterator<T>;
|
|
59
|
+
/** Returns all items as an array. */
|
|
60
|
+
toArray(): T[];
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* A Set that compares items by value instead of reference. Uses
|
|
64
|
+
* `getCompositeKey` to generate a stable string key for any value.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* const set = new ValueSet<{ x: number; y: number }>();
|
|
68
|
+
* set.add({ x: 1, y: 2 });
|
|
69
|
+
* set.add({ x: 1, y: 2 }); // ignored, same value already exists
|
|
70
|
+
* set.size; // 1
|
|
71
|
+
*/
|
|
72
|
+
declare class CompositeKeySet<T> extends KeyedSet<T, string> {
|
|
73
|
+
constructor(iterable?: Iterable<T>);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export { CompositeKeySet, KeyedSet };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A Set implementation that uses a custom key function to determine uniqueness.
|
|
3
|
+
* Items with the same key are considered equal, and adding a duplicate replaces
|
|
4
|
+
* the existing item.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* const set = new KeyedSet<{ id: number; name: string }, number>(
|
|
8
|
+
* (item) => item.id,
|
|
9
|
+
* );
|
|
10
|
+
* set.add({ id: 1, name: 'one' });
|
|
11
|
+
* set.add({ id: 1, name: 'replaced' }); // replaces previous item
|
|
12
|
+
* set.getByKey(1); // { id: 1, name: 'replaced' }
|
|
13
|
+
*
|
|
14
|
+
* @template T - The type of items stored in the set
|
|
15
|
+
* @template K - The type of the key extracted from items
|
|
16
|
+
*/
|
|
17
|
+
declare class KeyedSet<T, K = string> {
|
|
18
|
+
private map;
|
|
19
|
+
private getKey;
|
|
20
|
+
/**
|
|
21
|
+
* @param getKey - Function to extract a unique key from each item
|
|
22
|
+
* @param iterable - Optional initial items to add to the set
|
|
23
|
+
*/
|
|
24
|
+
constructor(getKey: (item: T) => K, iterable?: Iterable<T>);
|
|
25
|
+
/** The number of items in the set */
|
|
26
|
+
get size(): number;
|
|
27
|
+
/**
|
|
28
|
+
* Adds an item to the set. If an item with the same key exists, it will be
|
|
29
|
+
* replaced.
|
|
30
|
+
*/
|
|
31
|
+
add(item: T): this;
|
|
32
|
+
/** Adds multiple items to the set. */
|
|
33
|
+
addMultiple(items: Iterable<T>): this;
|
|
34
|
+
/** Checks if an item with the same key exists in the set. */
|
|
35
|
+
has(item: T): boolean;
|
|
36
|
+
/** Checks if an item with the given key exists in the set. */
|
|
37
|
+
hasKey(key: K): boolean;
|
|
38
|
+
/** Gets an item by its key, or undefined if not found. */
|
|
39
|
+
getByKey(key: K): T | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Removes an item from the set by computing its key. Returns true if the item
|
|
42
|
+
* was removed.
|
|
43
|
+
*/
|
|
44
|
+
delete(item: T): boolean;
|
|
45
|
+
/** Removes an item by its key. Returns true if the item was removed. */
|
|
46
|
+
deleteByKey(key: K): boolean;
|
|
47
|
+
/** Removes multiple items from the set. Returns the number of items removed. */
|
|
48
|
+
deleteMultiple(items: Iterable<T>): number;
|
|
49
|
+
/** Removes multiple items by their keys. Returns the number of items removed. */
|
|
50
|
+
deleteMultipleByKeys(keys: Iterable<K>): number;
|
|
51
|
+
/** Removes all items from the set. */
|
|
52
|
+
clear(): void;
|
|
53
|
+
/** Executes a callback for each item in the set. */
|
|
54
|
+
forEach(callback: (value: T, value2: T, set: KeyedSet<T, K>) => void, thisArg?: unknown): void;
|
|
55
|
+
values(): IterableIterator<T>;
|
|
56
|
+
keys(): IterableIterator<T>;
|
|
57
|
+
entries(): IterableIterator<[T, T]>;
|
|
58
|
+
[Symbol.iterator](): IterableIterator<T>;
|
|
59
|
+
/** Returns all items as an array. */
|
|
60
|
+
toArray(): T[];
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* A Set that compares items by value instead of reference. Uses
|
|
64
|
+
* `getCompositeKey` to generate a stable string key for any value.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* const set = new ValueSet<{ x: number; y: number }>();
|
|
68
|
+
* set.add({ x: 1, y: 2 });
|
|
69
|
+
* set.add({ x: 1, y: 2 }); // ignored, same value already exists
|
|
70
|
+
* set.size; // 1
|
|
71
|
+
*/
|
|
72
|
+
declare class CompositeKeySet<T> extends KeyedSet<T, string> {
|
|
73
|
+
constructor(iterable?: Iterable<T>);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export { CompositeKeySet, KeyedSet };
|
package/dist/keyedSet.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getCompositeKey
|
|
3
|
+
} from "./chunk-6FIBVC2P.js";
|
|
4
|
+
import "./chunk-C2SVCIWE.js";
|
|
5
|
+
import "./chunk-JF2MDHOJ.js";
|
|
6
|
+
|
|
7
|
+
// src/keyedSet.ts
|
|
8
|
+
var KeyedSet = class {
|
|
9
|
+
map;
|
|
10
|
+
getKey;
|
|
11
|
+
/**
|
|
12
|
+
* @param getKey - Function to extract a unique key from each item
|
|
13
|
+
* @param iterable - Optional initial items to add to the set
|
|
14
|
+
*/
|
|
15
|
+
constructor(getKey, iterable) {
|
|
16
|
+
this.getKey = getKey;
|
|
17
|
+
this.map = /* @__PURE__ */ new Map();
|
|
18
|
+
if (iterable) {
|
|
19
|
+
for (const item of iterable) {
|
|
20
|
+
this.add(item);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/** The number of items in the set */
|
|
25
|
+
get size() {
|
|
26
|
+
return this.map.size;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Adds an item to the set. If an item with the same key exists, it will be
|
|
30
|
+
* replaced.
|
|
31
|
+
*/
|
|
32
|
+
add(item) {
|
|
33
|
+
const key = this.getKey(item);
|
|
34
|
+
this.map.set(key, item);
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
/** Adds multiple items to the set. */
|
|
38
|
+
addMultiple(items) {
|
|
39
|
+
for (const item of items) {
|
|
40
|
+
this.add(item);
|
|
41
|
+
}
|
|
42
|
+
return this;
|
|
43
|
+
}
|
|
44
|
+
/** Checks if an item with the same key exists in the set. */
|
|
45
|
+
has(item) {
|
|
46
|
+
const key = this.getKey(item);
|
|
47
|
+
return this.map.has(key);
|
|
48
|
+
}
|
|
49
|
+
/** Checks if an item with the given key exists in the set. */
|
|
50
|
+
hasKey(key) {
|
|
51
|
+
return this.map.has(key);
|
|
52
|
+
}
|
|
53
|
+
/** Gets an item by its key, or undefined if not found. */
|
|
54
|
+
getByKey(key) {
|
|
55
|
+
return this.map.get(key);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Removes an item from the set by computing its key. Returns true if the item
|
|
59
|
+
* was removed.
|
|
60
|
+
*/
|
|
61
|
+
delete(item) {
|
|
62
|
+
const key = this.getKey(item);
|
|
63
|
+
return this.map.delete(key);
|
|
64
|
+
}
|
|
65
|
+
/** Removes an item by its key. Returns true if the item was removed. */
|
|
66
|
+
deleteByKey(key) {
|
|
67
|
+
return this.map.delete(key);
|
|
68
|
+
}
|
|
69
|
+
/** Removes multiple items from the set. Returns the number of items removed. */
|
|
70
|
+
deleteMultiple(items) {
|
|
71
|
+
let count = 0;
|
|
72
|
+
for (const item of items) {
|
|
73
|
+
if (this.delete(item)) {
|
|
74
|
+
count++;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return count;
|
|
78
|
+
}
|
|
79
|
+
/** Removes multiple items by their keys. Returns the number of items removed. */
|
|
80
|
+
deleteMultipleByKeys(keys) {
|
|
81
|
+
let count = 0;
|
|
82
|
+
for (const key of keys) {
|
|
83
|
+
if (this.deleteByKey(key)) {
|
|
84
|
+
count++;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return count;
|
|
88
|
+
}
|
|
89
|
+
/** Removes all items from the set. */
|
|
90
|
+
clear() {
|
|
91
|
+
this.map.clear();
|
|
92
|
+
}
|
|
93
|
+
/** Executes a callback for each item in the set. */
|
|
94
|
+
forEach(callback, thisArg) {
|
|
95
|
+
for (const value of this.map.values()) {
|
|
96
|
+
callback.call(thisArg, value, value, this);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
*values() {
|
|
100
|
+
yield* this.map.values();
|
|
101
|
+
}
|
|
102
|
+
*keys() {
|
|
103
|
+
yield* this.map.values();
|
|
104
|
+
}
|
|
105
|
+
*entries() {
|
|
106
|
+
for (const value of this.map.values()) {
|
|
107
|
+
yield [value, value];
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
[Symbol.iterator]() {
|
|
111
|
+
return this.values();
|
|
112
|
+
}
|
|
113
|
+
/** Returns all items as an array. */
|
|
114
|
+
toArray() {
|
|
115
|
+
return [...this.map.values()];
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
var CompositeKeySet = class extends KeyedSet {
|
|
119
|
+
constructor(iterable) {
|
|
120
|
+
super(getCompositeKey, iterable);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
export {
|
|
124
|
+
CompositeKeySet,
|
|
125
|
+
KeyedSet
|
|
126
|
+
};
|
package/dist/objUtils.js
CHANGED
|
@@ -14,9 +14,9 @@ import {
|
|
|
14
14
|
pick,
|
|
15
15
|
rejectObjUndefinedValues,
|
|
16
16
|
sortObjectKeys
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-ZXIKIA5B.js";
|
|
18
18
|
import "./chunk-GMJTLFM6.js";
|
|
19
|
-
import "./chunk-
|
|
19
|
+
import "./chunk-WFQJUJTC.js";
|
|
20
20
|
import "./chunk-C2SVCIWE.js";
|
|
21
21
|
import "./chunk-JF2MDHOJ.js";
|
|
22
22
|
export {
|
package/dist/serializeXML.js
CHANGED
package/dist/testUtils.js
CHANGED
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
omit,
|
|
6
6
|
pick
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-ZXIKIA5B.js";
|
|
8
8
|
import "./chunk-GMJTLFM6.js";
|
|
9
9
|
import {
|
|
10
10
|
filterObjectOrArrayKeys
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-MI4UE2PQ.js";
|
|
12
12
|
import "./chunk-IATIXMCE.js";
|
|
13
13
|
import {
|
|
14
14
|
deepEqual
|
|
@@ -26,7 +26,7 @@ import "./chunk-BM4PYVOX.js";
|
|
|
26
26
|
import {
|
|
27
27
|
arrayWithPrevAndIndex,
|
|
28
28
|
filterAndMap
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-WFQJUJTC.js";
|
|
30
30
|
import {
|
|
31
31
|
isObject
|
|
32
32
|
} from "./chunk-C2SVCIWE.js";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ls-stack/utils",
|
|
3
3
|
"description": "Universal TypeScript utilities for browser and Node.js",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.65.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist",
|
|
@@ -120,6 +120,10 @@
|
|
|
120
120
|
"import": "./dist/keepPrevIfUnchanged.js",
|
|
121
121
|
"require": "./dist/keepPrevIfUnchanged.cjs"
|
|
122
122
|
},
|
|
123
|
+
"./keyedMap": {
|
|
124
|
+
"import": "./dist/keyedMap.js",
|
|
125
|
+
"require": "./dist/keyedMap.cjs"
|
|
126
|
+
},
|
|
123
127
|
"./levenshtein": {
|
|
124
128
|
"import": "./dist/levenshtein.js",
|
|
125
129
|
"require": "./dist/levenshtein.cjs"
|
|
@@ -176,6 +180,10 @@
|
|
|
176
180
|
"import": "./dist/serializeXML.js",
|
|
177
181
|
"require": "./dist/serializeXML.cjs"
|
|
178
182
|
},
|
|
183
|
+
"./keyedSet": {
|
|
184
|
+
"import": "./dist/keyedSet.js",
|
|
185
|
+
"require": "./dist/keyedSet.cjs"
|
|
186
|
+
},
|
|
179
187
|
"./shallowEqual": {
|
|
180
188
|
"import": "./dist/shallowEqual.js",
|
|
181
189
|
"require": "./dist/shallowEqual.cjs"
|