@ocavue/utils 1.4.0 → 1.6.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/index.d.ts CHANGED
@@ -70,17 +70,17 @@ declare function isNotNullish<T>(value: T): value is NonNullable<T>;
70
70
  * console.log(events) // [['click', 7], ['hover', 3]]
71
71
  * ```
72
72
  */
73
- declare class Counter<K$1> extends Map<K$1, number> {
74
- constructor(iterable?: Iterable<readonly [K$1, number]>);
75
- get(key: K$1): number;
73
+ declare class Counter<K> extends Map<K, number> {
74
+ constructor(iterable?: Iterable<readonly [K, number]>);
75
+ get(key: K): number;
76
76
  /**
77
77
  * Increments the count for a key by a given amount (default 1).
78
78
  */
79
- increment(key: K$1, amount?: number): void;
79
+ increment(key: K, amount?: number): void;
80
80
  /**
81
81
  * Decrements the count for a key by a given amount (default 1).
82
82
  */
83
- decrement(key: K$1, amount?: number): void;
83
+ decrement(key: K, amount?: number): void;
84
84
  }
85
85
  /**
86
86
  * A weak map that counts occurrences of object keys.
@@ -148,17 +148,17 @@ declare class Counter<K$1> extends Map<K$1, number> {
148
148
  * console.log(hitCounter.get(cache2)) // 5
149
149
  * ```
150
150
  */
151
- declare class WeakCounter<K$1 extends WeakKey> extends WeakMap<K$1, number> {
152
- constructor(entries?: readonly (readonly [K$1, number])[] | null);
153
- get(key: K$1): number;
151
+ declare class WeakCounter<K extends WeakKey> extends WeakMap<K, number> {
152
+ constructor(entries?: readonly (readonly [K, number])[] | null);
153
+ get(key: K): number;
154
154
  /**
155
155
  * Increments the count for a key by a given amount (default 1).
156
156
  */
157
- increment(key: K$1, amount?: number): void;
157
+ increment(key: K, amount?: number): void;
158
158
  /**
159
159
  * Decrements the count for a key by a given amount (default 1).
160
160
  */
161
- decrement(key: K$1, amount?: number): void;
161
+ decrement(key: K, amount?: number): void;
162
162
  }
163
163
  //#endregion
164
164
  //#region src/default-map.d.ts
@@ -229,10 +229,10 @@ declare class WeakCounter<K$1 extends WeakKey> extends WeakMap<K$1, number> {
229
229
  * console.log(matrix.get(2).get(3)) // 0 (both auto-created)
230
230
  * ```
231
231
  */
232
- declare class DefaultMap<K$1, V> extends Map<K$1, V> {
232
+ declare class DefaultMap<K, V> extends Map<K, V> {
233
233
  private readonly defaultFactory;
234
- constructor(defaultFactory: () => V, iterable?: Iterable<readonly [K$1, V]>);
235
- get(key: K$1): V;
234
+ constructor(defaultFactory: () => V, iterable?: Iterable<readonly [K, V]>);
235
+ get(key: K): V;
236
236
  }
237
237
  /**
238
238
  * A weak map that automatically creates values for missing keys using a factory function.
@@ -325,10 +325,10 @@ declare class DefaultMap<K$1, V> extends Map<K$1, V> {
325
325
  * // No need for has() checks or null assertions - everything auto-initializes!
326
326
  * ```
327
327
  */
328
- declare class DefaultWeakMap<K$1 extends WeakKey, V> extends WeakMap<K$1, V> {
328
+ declare class DefaultWeakMap<K extends WeakKey, V> extends WeakMap<K, V> {
329
329
  private readonly defaultFactory;
330
- constructor(defaultFactory: () => V, entries?: readonly (readonly [K$1, V])[] | null);
331
- get(key: K$1): V;
330
+ constructor(defaultFactory: () => V, entries?: readonly (readonly [K, V])[] | null);
331
+ get(key: K): V;
332
332
  }
333
333
  //#endregion
334
334
  //#region src/dom.d.ts
@@ -417,7 +417,7 @@ declare function isDeepEqual(a: unknown, b: unknown): boolean;
417
417
  *
418
418
  * @public
419
419
  */
420
- declare function mapGroupBy<K$1, T>(items: Iterable<T>, keySelector: (item: T, index: number) => K$1): Map<K$1, T[]>;
420
+ declare function mapGroupBy<K, T>(items: Iterable<T>, keySelector: (item: T, index: number) => K): Map<K, T[]>;
421
421
  //#endregion
422
422
  //#region src/map-values.d.ts
423
423
  /**
@@ -519,7 +519,7 @@ declare function objectEntries<T extends Record<string, any>>(obj: T): ObjectEnt
519
519
  *
520
520
  * @public
521
521
  */
522
- declare function objectGroupBy<K$1 extends PropertyKey, T>(items: Iterable<T>, keySelector: (item: T, index: number) => K$1): Partial<Record<K$1, T[]>>;
522
+ declare function objectGroupBy<K extends PropertyKey, T>(items: Iterable<T>, keySelector: (item: T, index: number) => K): Partial<Record<K, T[]>>;
523
523
  //#endregion
524
524
  //#region src/once.d.ts
525
525
  /**
@@ -537,6 +537,14 @@ declare function objectGroupBy<K$1 extends PropertyKey, T>(items: Iterable<T>, k
537
537
  */
538
538
  declare function once<T>(fn: () => T): () => T;
539
539
  //#endregion
540
+ //#region src/regex.d.ts
541
+ /**
542
+ * Checks if current environment supports [regex lookbehind assertion](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Lookbehind_assertion).
543
+ *
544
+ * @returns `true` if the current environment supports regex lookbehind assertion, `false` otherwise.
545
+ */
546
+ declare const supportsRegexLookbehind: () => boolean;
547
+ //#endregion
540
548
  //#region src/sleep.d.ts
541
549
  /**
542
550
  * Returns a Promise that resolves after a specified number of milliseconds.
@@ -550,5 +558,25 @@ declare function once<T>(fn: () => T): () => T;
550
558
  */
551
559
  declare function sleep(ms: number): Promise<void>;
552
560
  //#endregion
553
- export { Counter, DefaultMap, DefaultWeakMap, type ObjectEntries, WeakCounter, formatBytes, getDocument, getDocumentElement, getId, getWindow, isDeepEqual, isDocument, isDocumentFragment, isElement, isElementLike, isHTMLElement, isMap, isMathMLElement, isNodeLike, isNotNullish, isObject, isSVGElement, isSet, isShadowRoot, isTextNode, isWindowLike, mapGroupBy, mapValues, objectEntries, objectGroupBy, once, sleep };
554
- //# sourceMappingURL=index.d.ts.map
561
+ //#region src/throttle.d.ts
562
+ /**
563
+ * Creates a throttled function that only invokes `fn` at most once per every
564
+ * `wait` milliseconds. The first call executes immediately (leading edge).
565
+ * If called again during the wait period, the last call will be executed at
566
+ * the end of the wait period (trailing edge).
567
+ *
568
+ * @param callback The function to throttle
569
+ * @param wait The number of milliseconds to throttle invocations to
570
+ * @returns A throttled version of the function
571
+ * @example
572
+ * ```js
573
+ * const throttled = throttle((name) => console.log('called', name), 1000)
574
+ * throttled('Alice') // logs 'called Alice' immediately
575
+ * throttled('Bob') // skipped (within 1000ms)
576
+ * throttled('Charlie') // skipped (within 1000ms)
577
+ * // after 1000ms, logs 'called Charlie' again (trailing call)
578
+ * ```
579
+ */
580
+ declare function throttle<T extends (this: any, ...args: any[]) => unknown>(callback: T, wait: number): (this: ThisParameterType<T>, ...args: Parameters<T>) => void;
581
+ //#endregion
582
+ export { Counter, DefaultMap, DefaultWeakMap, type ObjectEntries, WeakCounter, formatBytes, getDocument, getDocumentElement, getId, getWindow, isDeepEqual, isDocument, isDocumentFragment, isElement, isElementLike, isHTMLElement, isMap, isMathMLElement, isNodeLike, isNotNullish, isObject, isSVGElement, isSet, isShadowRoot, isTextNode, isWindowLike, mapGroupBy, mapValues, objectEntries, objectGroupBy, once, sleep, supportsRegexLookbehind, throttle };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/checker.ts","../src/counter.ts","../src/default-map.ts","../src/dom.ts","../src/format-bytes.ts","../src/get-id.ts","../src/is-deep-equal.ts","../src/map-group-by.ts","../src/map-values.ts","../src/object-entries.ts","../src/object-group-by.ts","../src/once.ts","../src/sleep.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/checker.ts","../src/counter.ts","../src/default-map.ts","../src/dom.ts","../src/format-bytes.ts","../src/get-id.ts","../src/is-deep-equal.ts","../src/map-group-by.ts","../src/map-values.ts","../src/object-entries.ts","../src/object-group-by.ts","../src/once.ts","../src/regex.ts","../src/sleep.ts","../src/throttle.ts"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,15 +1,83 @@
1
+ //#region src/checker.ts
2
+ /**
3
+ * Checks if the given value is an object.
4
+ */
1
5
  function isObject(value) {
2
6
  return typeof value == "object" && !!value;
3
7
  }
8
+ /**
9
+ * Checks if the given value is a Map.
10
+ */
4
11
  function isMap(value) {
5
12
  return value instanceof Map;
6
13
  }
14
+ /**
15
+ * Checks if the given value is a Set.
16
+ */
7
17
  function isSet(value) {
8
18
  return value instanceof Set;
9
19
  }
20
+ /**
21
+ * Returns true if the given value is not null or undefined.
22
+ */
10
23
  function isNotNullish(value) {
11
24
  return value != null;
12
25
  }
26
+ //#endregion
27
+ //#region src/counter.ts
28
+ /**
29
+ * A map that counts occurrences of keys.
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * // Count word occurrences
34
+ * const wordCounter = new Counter<string>()
35
+ * const words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']
36
+ *
37
+ * for (const word of words) {
38
+ * wordCounter.increment(word)
39
+ * }
40
+ *
41
+ * console.log(wordCounter.get('apple')) // 3
42
+ * console.log(wordCounter.get('banana')) // 2
43
+ * console.log(wordCounter.get('cherry')) // 1
44
+ * console.log(wordCounter.get('orange')) // 0 (defaults to 0)
45
+ * ```
46
+ *
47
+ * @example
48
+ * ```typescript
49
+ * // Initialize with existing counts
50
+ * const counter = new Counter<string>([
51
+ * ['red', 5],
52
+ * ['blue', 3],
53
+ * ['green', 7]
54
+ * ])
55
+ *
56
+ * counter.increment('red', 2) // red: 5 -> 7
57
+ * counter.decrement('blue') // blue: 3 -> 2
58
+ * counter.increment('yellow') // yellow: 0 -> 1
59
+ *
60
+ * console.log(counter.get('red')) // 7
61
+ * console.log(counter.get('blue')) // 2
62
+ * console.log(counter.get('yellow')) // 1
63
+ * ```
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * // Track event frequencies
68
+ * const eventCounter = new Counter<string>()
69
+ *
70
+ * eventCounter.increment('click', 5)
71
+ * eventCounter.increment('hover', 3)
72
+ * eventCounter.increment('click', 2)
73
+ *
74
+ * // Get most common events
75
+ * const events = [...eventCounter.entries()]
76
+ * .sort((a, b) => b[1] - a[1])
77
+ *
78
+ * console.log(events) // [['click', 7], ['hover', 3]]
79
+ * ```
80
+ */
13
81
  var Counter = class extends Map {
14
82
  constructor(iterable) {
15
83
  super(iterable);
@@ -17,9 +85,15 @@ var Counter = class extends Map {
17
85
  get(key) {
18
86
  return super.get(key) ?? 0;
19
87
  }
88
+ /**
89
+ * Increments the count for a key by a given amount (default 1).
90
+ */
20
91
  increment(key, amount = 1) {
21
92
  this.set(key, this.get(key) + amount);
22
93
  }
94
+ /**
95
+ * Decrements the count for a key by a given amount (default 1).
96
+ */
23
97
  decrement(key, amount = 1) {
24
98
  this.set(key, this.get(key) - amount);
25
99
  }
@@ -30,9 +104,15 @@ var Counter = class extends Map {
30
104
  get(key) {
31
105
  return super.get(key) ?? 0;
32
106
  }
107
+ /**
108
+ * Increments the count for a key by a given amount (default 1).
109
+ */
33
110
  increment(key, amount = 1) {
34
111
  this.set(key, this.get(key) + amount);
35
112
  }
113
+ /**
114
+ * Decrements the count for a key by a given amount (default 1).
115
+ */
36
116
  decrement(key, amount = 1) {
37
117
  this.set(key, this.get(key) - amount);
38
118
  }
@@ -55,39 +135,78 @@ var Counter = class extends Map {
55
135
  return this.set(key, value), value;
56
136
  }
57
137
  };
138
+ //#endregion
139
+ //#region src/dom.ts
140
+ /**
141
+ * Checks if the given DOM node is an Element.
142
+ */
58
143
  function isElement(node) {
59
144
  return node.nodeType === 1;
60
145
  }
146
+ /**
147
+ * Checks if the given DOM node is a Text node.
148
+ */
61
149
  function isTextNode(node) {
62
150
  return node.nodeType === 3;
63
151
  }
152
+ /**
153
+ * Checks if the given DOM node is an HTMLElement.
154
+ */
64
155
  function isHTMLElement(node) {
65
156
  return isElement(node) && node.namespaceURI === "http://www.w3.org/1999/xhtml";
66
157
  }
158
+ /**
159
+ * Checks if the given DOM node is an SVGElement.
160
+ */
67
161
  function isSVGElement(node) {
68
162
  return isElement(node) && node.namespaceURI === "http://www.w3.org/2000/svg";
69
163
  }
164
+ /**
165
+ * Checks if the given DOM node is an MathMLElement.
166
+ */
70
167
  function isMathMLElement(node) {
71
168
  return isElement(node) && node.namespaceURI === "http://www.w3.org/1998/Math/MathML";
72
169
  }
170
+ /**
171
+ * Checks if the given DOM node is a Document.
172
+ */
73
173
  function isDocument(node) {
74
174
  return node.nodeType === 9;
75
175
  }
176
+ /**
177
+ * Checks if the given DOM node is a DocumentFragment.
178
+ */
76
179
  function isDocumentFragment(node) {
77
180
  return node.nodeType === 11;
78
181
  }
182
+ /**
183
+ * Checks if the given DOM node is a ShadowRoot.
184
+ */
79
185
  function isShadowRoot(node) {
80
186
  return isDocumentFragment(node) && "host" in node && isElementLike(node.host);
81
187
  }
188
+ /**
189
+ * Checks if an unknown value is likely a DOM node.
190
+ */
82
191
  function isNodeLike(value) {
83
192
  return isObject(value) && value.nodeType !== void 0;
84
193
  }
194
+ /**
195
+ * Checks if an unknown value is likely a DOM element.
196
+ */
85
197
  function isElementLike(value) {
86
198
  return isObject(value) && value.nodeType === 1 && typeof value.nodeName == "string";
87
199
  }
200
+ /**
201
+ * Checks if the given value is likely a Window object.
202
+ */
88
203
  function isWindowLike(value) {
89
204
  return isObject(value) && value.window === value;
90
205
  }
206
+ /**
207
+ * Gets the window object for the given target or the global window object if no
208
+ * target is provided.
209
+ */
91
210
  function getWindow(target) {
92
211
  if (target) {
93
212
  if (isShadowRoot(target)) return getWindow(target.host);
@@ -96,12 +215,26 @@ function getWindow(target) {
96
215
  }
97
216
  return window;
98
217
  }
218
+ /**
219
+ * Gets the document for the given target or the global document if no target is
220
+ * provided.
221
+ */
99
222
  function getDocument(target) {
100
223
  return target ? isWindowLike(target) ? target.document : isDocument(target) ? target : target.ownerDocument || document : document;
101
224
  }
225
+ /**
226
+ * Gets a reference to the root node of the document based on the given target.
227
+ */
102
228
  function getDocumentElement(target) {
103
229
  return getDocument(target).documentElement;
104
230
  }
231
+ //#endregion
232
+ //#region src/format-bytes.ts
233
+ /**
234
+ * Formats a number of bytes into a human-readable string.
235
+ * @param bytes - The number of bytes to format.
236
+ * @returns A string representing the number of bytes in a human-readable format.
237
+ */
105
238
  function formatBytes(bytes) {
106
239
  let units = [
107
240
  "B",
@@ -113,10 +246,20 @@ function formatBytes(bytes) {
113
246
  let fraction = unitIndex === 0 && num % 1 == 0 ? 0 : 1;
114
247
  return `${num.toFixed(fraction)}${units[unitIndex]}`;
115
248
  }
249
+ //#endregion
250
+ //#region src/get-id.ts
116
251
  let id = 0, maxSafeInteger = 2 ** 53 - 1;
252
+ /**
253
+ * Generates a unique positive integer.
254
+ */
117
255
  function getId() {
118
256
  return id++, id >= maxSafeInteger && (id = 1), id;
119
257
  }
258
+ //#endregion
259
+ //#region src/is-deep-equal.ts
260
+ /**
261
+ * Whether two values are deeply equal.
262
+ */
120
263
  function isDeepEqual(a, b) {
121
264
  if (a === b) return !0;
122
265
  if (a == null || b == null) return !1;
@@ -147,6 +290,11 @@ function isDeepEqual(a, b) {
147
290
  }
148
291
  return !1;
149
292
  }
293
+ //#endregion
294
+ //#region src/map-group-by.ts
295
+ /**
296
+ * @internal
297
+ */
150
298
  function mapGroupByPolyfill(items, keySelector) {
151
299
  let map = /* @__PURE__ */ new Map(), index = 0;
152
300
  for (let item of items) {
@@ -155,17 +303,104 @@ function mapGroupByPolyfill(items, keySelector) {
155
303
  }
156
304
  return map;
157
305
  }
306
+ /**
307
+ * A polyfill for the [`Map.groupBy()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/groupBy) static method.
308
+ *
309
+ * @public
310
+ */
158
311
  function mapGroupBy(items, keySelector) {
159
312
  return Map.groupBy ? Map.groupBy(items, keySelector) : mapGroupByPolyfill(items, keySelector);
160
313
  }
314
+ //#endregion
315
+ //#region src/map-values.ts
316
+ /**
317
+ * Creates a new object with the same keys as the input object, but with values
318
+ * transformed by the provided callback function. Similar to `Array.prototype.map()`
319
+ * but for object values.
320
+
321
+ * @param object - The object whose values will be transformed.
322
+ * @param callback - A function that transforms each value. Receives the value and
323
+ * its corresponding key as arguments.
324
+ * @returns A new object with the same keys but transformed values.
325
+ *
326
+ * @example
327
+ * ```typescript
328
+ * const prices = { apple: 1, banana: 2, orange: 3 }
329
+ * const doubled = mapValues(prices, (price) => price * 2)
330
+ * // Result: { apple: 2, banana: 4, orange: 6 }
331
+ * ```
332
+ *
333
+ * @example
334
+ * ```typescript
335
+ * const users = { john: 25, jane: 30, bob: 35 }
336
+ * const greetings = mapValues(users, (age, name) => `${name} is ${age} years old`)
337
+ * // Result: { john: 'john is 25 years old', jane: 'jane is 30 years old', bob: 'bob is 35 years old' }
338
+ * ```
339
+ *
340
+ * @example
341
+ * ```typescript
342
+ * const data = { a: '1', b: '2', c: '3' }
343
+ * const numbers = mapValues(data, (str) => parseInt(str, 10))
344
+ * // Result: { a: 1, b: 2, c: 3 }
345
+ * ```
346
+ *
347
+ * @public
348
+ */
161
349
  function mapValues(object, callback) {
162
350
  let result = {};
163
351
  for (let [key, value] of Object.entries(object)) result[key] = callback(value, key);
164
352
  return result;
165
353
  }
354
+ //#endregion
355
+ //#region src/object-entries.ts
356
+ /**
357
+ * A type-safe wrapper around
358
+ * [`Object.entries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries)
359
+ * that preserves the exact types of object keys and values. Unlike the standard
360
+ * `Object.entries()` which returns `[string, any][]`, this function returns an
361
+ * array of tuples where each tuple is precisely typed according to the input
362
+ * object's structure.
363
+ *
364
+ * This is particularly useful when working with objects that have known, fixed
365
+ * property types and you want to maintain type safety when iterating over
366
+ * entries.
367
+ *
368
+ * @example
369
+ * ```typescript
370
+ * const myObject = { a: 1, b: 'hello', c: true } as const
371
+ * const entries = objectEntries(myObject)
372
+ * // Type: (["a", 1] | ["b", "hello"] | ["c", true])[]
373
+ *
374
+ * for (const [key, value] of entries) {
375
+ * // key is typed as "a" | "b" | "c"
376
+ * // value is typed as 1 | "hello" | true
377
+ * console.log(`${key}: ${value}`)
378
+ * }
379
+ * ```
380
+ *
381
+ * @example
382
+ * ```typescript
383
+ * interface User {
384
+ * name: string
385
+ * age: number
386
+ * active: boolean
387
+ * }
388
+ *
389
+ * const user: User = { name: 'Alice', age: 30, active: true }
390
+ * const entries = objectEntries(user)
391
+ * // Type: (["name", string] | ["age", number] | ["active", boolean])[]
392
+ * ```
393
+ *
394
+ * @public
395
+ */
166
396
  function objectEntries(obj) {
167
397
  return Object.entries(obj);
168
398
  }
399
+ //#endregion
400
+ //#region src/object-group-by.ts
401
+ /**
402
+ * @internal
403
+ */
169
404
  function objectGroupByPolyfill(items, keySelector) {
170
405
  let result = {}, index = 0;
171
406
  for (let item of items) {
@@ -174,16 +409,92 @@ function objectGroupByPolyfill(items, keySelector) {
174
409
  }
175
410
  return result;
176
411
  }
412
+ /**
413
+ * A polyfill for the [`Object.groupBy()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/groupBy) static method.
414
+ *
415
+ * @public
416
+ */
177
417
  function objectGroupBy(items, keySelector) {
178
418
  return Object.groupBy ? Object.groupBy(items, keySelector) : objectGroupByPolyfill(items, keySelector);
179
419
  }
420
+ //#endregion
421
+ //#region src/once.ts
422
+ /**
423
+ * Creates a function that will only execute the provided function once.
424
+ * Subsequent calls will return the cached result from the first execution.
425
+ *
426
+ * @param fn The function to execute once
427
+ * @returns A function that will only execute the provided function once
428
+ * @example
429
+ * ```ts
430
+ * const getValue = once(() => expensiveOperation())
431
+ * getValue() // executes expensiveOperation
432
+ * getValue() // returns cached result
433
+ * ```
434
+ */
180
435
  function once(fn) {
181
436
  let called = !1, result;
182
437
  return () => (called || (result = fn(), called = !0, fn = void 0), result);
183
438
  }
439
+ //#endregion
440
+ //#region src/regex.ts
441
+ /**
442
+ * Checks if current environment supports [regex lookbehind assertion](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Lookbehind_assertion).
443
+ *
444
+ * @returns `true` if the current environment supports regex lookbehind assertion, `false` otherwise.
445
+ */
446
+ const supportsRegexLookbehind = /* @__PURE__ */ once(() => {
447
+ try {
448
+ return "ab".replaceAll(/* @__PURE__ */ RegExp("(?<=a)b", "g"), "c") === "ac";
449
+ } catch {
450
+ /* v8 ignore start */
451
+ return !1;
452
+ }
453
+ });
454
+ //#endregion
455
+ //#region src/sleep.ts
456
+ /**
457
+ * Returns a Promise that resolves after a specified number of milliseconds.
458
+ *
459
+ * @param ms - The number of milliseconds to wait.
460
+ *
461
+ * @example
462
+ * ```js
463
+ * await sleep(1000) // Wait 1 second
464
+ * ```
465
+ */
184
466
  function sleep(ms) {
185
467
  return new Promise((resolve) => setTimeout(resolve, ms));
186
468
  }
187
- export { Counter, DefaultMap, DefaultWeakMap, WeakCounter, formatBytes, getDocument, getDocumentElement, getId, getWindow, isDeepEqual, isDocument, isDocumentFragment, isElement, isElementLike, isHTMLElement, isMap, isMathMLElement, isNodeLike, isNotNullish, isObject, isSVGElement, isSet, isShadowRoot, isTextNode, isWindowLike, mapGroupBy, mapValues, objectEntries, objectGroupBy, once, sleep };
188
-
189
- //# sourceMappingURL=index.js.map
469
+ //#endregion
470
+ //#region src/throttle.ts
471
+ /**
472
+ * Creates a throttled function that only invokes `fn` at most once per every
473
+ * `wait` milliseconds. The first call executes immediately (leading edge).
474
+ * If called again during the wait period, the last call will be executed at
475
+ * the end of the wait period (trailing edge).
476
+ *
477
+ * @param callback The function to throttle
478
+ * @param wait The number of milliseconds to throttle invocations to
479
+ * @returns A throttled version of the function
480
+ * @example
481
+ * ```js
482
+ * const throttled = throttle((name) => console.log('called', name), 1000)
483
+ * throttled('Alice') // logs 'called Alice' immediately
484
+ * throttled('Bob') // skipped (within 1000ms)
485
+ * throttled('Charlie') // skipped (within 1000ms)
486
+ * // after 1000ms, logs 'called Charlie' again (trailing call)
487
+ * ```
488
+ */
489
+ function throttle(callback, wait) {
490
+ let timeoutId, lastCallTime = 0;
491
+ return function(...args) {
492
+ clearTimeout(timeoutId);
493
+ let now = Date.now(), delay = wait + lastCallTime - now;
494
+ delay <= 0 ? (lastCallTime = now, callback.apply(this, args)) : timeoutId = setTimeout(() => {
495
+ lastCallTime = Date.now(), callback.apply(this, args);
496
+ }, delay);
497
+ };
498
+ }
499
+ //#endregion
500
+ export { Counter, DefaultMap, DefaultWeakMap, WeakCounter, formatBytes, getDocument, getDocumentElement, getId, getWindow, isDeepEqual, isDocument, isDocumentFragment, isElement, isElementLike, isHTMLElement, isMap, isMathMLElement, isNodeLike, isNotNullish, isObject, isSVGElement, isSet, isShadowRoot, isTextNode, isWindowLike, mapGroupBy, mapValues, objectEntries, objectGroupBy, once, sleep, supportsRegexLookbehind, throttle };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["NodeType.ELEMENT_NODE","NodeType.TEXT_NODE","NodeType.DOCUMENT_NODE","NodeType.DOCUMENT_FRAGMENT_NODE","result: Partial<Record<K, T[]>>","result: T"],"sources":["../src/checker.ts","../src/counter.ts","../src/default-map.ts","../src/dom-node-type.ts","../src/dom.ts","../src/format-bytes.ts","../src/get-id.ts","../src/is-deep-equal.ts","../src/map-group-by.ts","../src/map-values.ts","../src/object-entries.ts","../src/object-group-by.ts","../src/once.ts","../src/sleep.ts"],"sourcesContent":["/**\n * Checks if the given value is an object.\n */\nexport function isObject(\n value: unknown,\n): value is Record<string | symbol | number, unknown> {\n return value != null && typeof value === 'object'\n}\n\n/**\n * Checks if the given value is a Map.\n */\nexport function isMap(value: unknown): value is Map<unknown, unknown> {\n return value instanceof Map\n}\n\n/**\n * Checks if the given value is a Set.\n */\nexport function isSet(value: unknown): value is Set<unknown> {\n return value instanceof Set\n}\n\n/**\n * Returns true if the given value is not null or undefined.\n */\nexport function isNotNullish<T>(value: T): value is NonNullable<T> {\n return value != null\n}\n","/**\n * A map that counts occurrences of keys.\n *\n * @example\n * ```typescript\n * // Count word occurrences\n * const wordCounter = new Counter<string>()\n * const words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']\n *\n * for (const word of words) {\n * wordCounter.increment(word)\n * }\n *\n * console.log(wordCounter.get('apple')) // 3\n * console.log(wordCounter.get('banana')) // 2\n * console.log(wordCounter.get('cherry')) // 1\n * console.log(wordCounter.get('orange')) // 0 (defaults to 0)\n * ```\n *\n * @example\n * ```typescript\n * // Initialize with existing counts\n * const counter = new Counter<string>([\n * ['red', 5],\n * ['blue', 3],\n * ['green', 7]\n * ])\n *\n * counter.increment('red', 2) // red: 5 -> 7\n * counter.decrement('blue') // blue: 3 -> 2\n * counter.increment('yellow') // yellow: 0 -> 1\n *\n * console.log(counter.get('red')) // 7\n * console.log(counter.get('blue')) // 2\n * console.log(counter.get('yellow')) // 1\n * ```\n *\n * @example\n * ```typescript\n * // Track event frequencies\n * const eventCounter = new Counter<string>()\n *\n * eventCounter.increment('click', 5)\n * eventCounter.increment('hover', 3)\n * eventCounter.increment('click', 2)\n *\n * // Get most common events\n * const events = [...eventCounter.entries()]\n * .sort((a, b) => b[1] - a[1])\n *\n * console.log(events) // [['click', 7], ['hover', 3]]\n * ```\n */\nexport class Counter<K> extends Map<K, number> {\n constructor(iterable?: Iterable<readonly [K, number]>) {\n super(iterable)\n }\n\n override get(key: K): number {\n return super.get(key) ?? 0\n }\n\n /**\n * Increments the count for a key by a given amount (default 1).\n */\n increment(key: K, amount = 1): void {\n this.set(key, this.get(key) + amount)\n }\n\n /**\n * Decrements the count for a key by a given amount (default 1).\n */\n decrement(key: K, amount = 1): void {\n this.set(key, this.get(key) - amount)\n }\n}\n\n/**\n * A weak map that counts occurrences of object keys.\n *\n * Similar to {@link Counter} but uses WeakMap as the base, allowing garbage collection of keys.\n *\n * @example\n * ```typescript\n * // Track reference counts for DOM elements\n * const elementRefs = new WeakCounter<HTMLElement>()\n *\n * function addReference(element: HTMLElement) {\n * elementRefs.increment(element)\n * console.log(`References: ${elementRefs.get(element)}`)\n * }\n *\n * function removeReference(element: HTMLElement) {\n * elementRefs.decrement(element)\n * console.log(`References: ${elementRefs.get(element)}`)\n * }\n *\n * const div = document.createElement('div')\n * addReference(div) // References: 1\n * addReference(div) // References: 2\n * removeReference(div) // References: 1\n * ```\n *\n * @example\n * ```typescript\n * // Count object interactions without preventing garbage collection\n * const objectInteractions = new WeakCounter<object>()\n *\n * function handleInteraction(obj: object, count = 1) {\n * objectInteractions.increment(obj, count)\n * }\n *\n * const user = { id: 1, name: 'Alice' }\n * const session = { sessionId: 'abc123' }\n *\n * handleInteraction(user, 3)\n * handleInteraction(session, 1)\n * handleInteraction(user, 2)\n *\n * console.log(objectInteractions.get(user)) // 5\n * console.log(objectInteractions.get(session)) // 1\n * // When user and session are no longer referenced elsewhere,\n * // they can be garbage collected along with their counts\n * ```\n *\n * @example\n * ```typescript\n * // Initialize with existing counts\n * const cache1 = {}\n * const cache2 = {}\n * const cache3 = {}\n *\n * const hitCounter = new WeakCounter<object>([\n * [cache1, 10],\n * [cache2, 5],\n * [cache3, 15]\n * ])\n *\n * hitCounter.increment(cache1, 3) // 10 -> 13\n * console.log(hitCounter.get(cache1)) // 13\n * console.log(hitCounter.get(cache2)) // 5\n * ```\n */\nexport class WeakCounter<K extends WeakKey> extends WeakMap<K, number> {\n constructor(entries?: readonly (readonly [K, number])[] | null) {\n super(entries)\n }\n\n override get(key: K): number {\n return super.get(key) ?? 0\n }\n\n /**\n * Increments the count for a key by a given amount (default 1).\n */\n increment(key: K, amount = 1): void {\n this.set(key, this.get(key) + amount)\n }\n\n /**\n * Decrements the count for a key by a given amount (default 1).\n */\n decrement(key: K, amount = 1): void {\n this.set(key, this.get(key) - amount)\n }\n}\n","/**\n * A map that automatically creates values for missing keys using a factory function.\n *\n * Similar to Python's [defaultdict](https://docs.python.org/3.13/library/collections.html#collections.defaultdict).\n *\n * @example\n * ```typescript\n * // Group items by category using arrays\n * const groupByCategory = new DefaultMap<string, string[]>(() => [])\n *\n * groupByCategory.get('fruits').push('apple', 'banana')\n * groupByCategory.get('vegetables').push('carrot')\n * groupByCategory.get('fruits').push('orange')\n *\n * console.log(groupByCategory.get('fruits')) // ['apple', 'banana', 'orange']\n * console.log(groupByCategory.get('vegetables')) // ['carrot']\n * console.log(groupByCategory.get('dairy')) // [] (auto-created)\n * ```\n *\n * @example\n * ```typescript\n * // Build a graph with adjacency lists\n * const graph = new DefaultMap<string, Set<string>>(() => new Set())\n *\n * graph.get('A').add('B').add('C')\n * graph.get('B').add('C').add('D')\n * graph.get('C').add('D')\n *\n * console.log([...graph.get('A')]) // ['B', 'C']\n * console.log([...graph.get('B')]) // ['C', 'D']\n * console.log([...graph.get('E')]) // [] (auto-created empty set)\n * ```\n *\n * @example\n * ```typescript\n * // Initialize with existing entries\n * const scores = new DefaultMap<string, number>(\n * () => 0,\n * [\n * ['Alice', 100],\n * ['Bob', 85]\n * ]\n * )\n *\n * scores.set('Alice', scores.get('Alice') + 10) // 100 -> 110\n * console.log(scores.get('Alice')) // 110\n * console.log(scores.get('Bob')) // 85\n * console.log(scores.get('Charlie')) // 0 (auto-created)\n * ```\n *\n * @example\n * ```typescript\n * // Nested DefaultMaps for 2D data structures\n * const matrix = new DefaultMap<number, DefaultMap<number, number>>(\n * () => new DefaultMap<number, number>(() => 0)\n * )\n *\n * matrix.get(0).set(0, 1)\n * matrix.get(0).set(1, 2)\n * matrix.get(1).set(1, 3)\n *\n * console.log(matrix.get(0).get(0)) // 1\n * console.log(matrix.get(0).get(1)) // 2\n * console.log(matrix.get(1).get(0)) // 0 (auto-created)\n * console.log(matrix.get(2).get(3)) // 0 (both auto-created)\n * ```\n */\nexport class DefaultMap<K, V> extends Map<K, V> {\n private readonly defaultFactory: () => V\n\n constructor(defaultFactory: () => V, iterable?: Iterable<readonly [K, V]>) {\n super(iterable)\n this.defaultFactory = defaultFactory\n }\n\n override get(key: K): V {\n if (this.has(key)) {\n return super.get(key)!\n }\n const value = this.defaultFactory()\n this.set(key, value)\n return value\n }\n}\n\n/**\n * A weak map that automatically creates values for missing keys using a factory function.\n *\n * Similar to {@link DefaultMap} but uses WeakMap as the base, allowing garbage collection of keys.\n *\n * @example\n * ```typescript\n * // Store metadata for DOM elements without preventing garbage collection\n * const elementMetadata = new DefaultWeakMap<HTMLElement, { clicks: number; hovers: number }>(\n * () => ({ clicks: 0, hovers: 0 })\n * )\n *\n * const button = document.querySelector('button')!\n * const div = document.querySelector('div')!\n *\n * elementMetadata.get(button).clicks++\n * elementMetadata.get(button).clicks++\n * elementMetadata.get(div).hovers++\n *\n * console.log(elementMetadata.get(button)) // { clicks: 2, hovers: 0 }\n * console.log(elementMetadata.get(div)) // { clicks: 0, hovers: 1 }\n * // When elements are removed from DOM and not referenced,\n * // their metadata can be garbage collected\n * ```\n *\n * @example\n * ```typescript\n * // Cache computed properties for objects\n * const computedCache = new DefaultWeakMap<object, Map<string, any>>(\n * () => new Map()\n * )\n *\n * function getOrCompute(obj: object, key: string, compute: () => any) {\n * const cache = computedCache.get(obj)\n * if (!cache.has(key)) {\n * cache.set(key, compute())\n * }\n * return cache.get(key)\n * }\n *\n * const user = { name: 'Alice', age: 30 }\n * const displayName = getOrCompute(user, 'displayName', () => user.name.toUpperCase())\n * const birthYear = getOrCompute(user, 'birthYear', () => new Date().getFullYear() - user.age)\n *\n * console.log(displayName) // 'ALICE'\n * console.log(birthYear) // 1994 (or current year - 30)\n * ```\n *\n * @example\n * ```typescript\n * // Initialize with existing entries\n * const obj1 = {}\n * const obj2 = {}\n *\n * const objectData = new DefaultWeakMap<object, string[]>(\n * () => [],\n * [\n * [obj1, ['tag1', 'tag2']],\n * [obj2, ['tag3']]\n * ]\n * )\n *\n * objectData.get(obj1).push('tag4')\n * console.log(objectData.get(obj1)) // ['tag1', 'tag2', 'tag4']\n * console.log(objectData.get(obj2)) // ['tag3']\n *\n * const obj3 = {}\n * console.log(objectData.get(obj3)) // [] (auto-created)\n * ```\n *\n * @example\n * ```typescript\n * // Track event listeners per element using both DefaultWeakMap and DefaultMap\n * const eventListeners = new DefaultWeakMap<EventTarget, DefaultMap<string, Function[]>>(\n * () => new DefaultMap<string, Function[]>(() => [])\n * )\n *\n * function addListener(target: EventTarget, event: string, handler: Function) {\n * eventListeners.get(target).get(event).push(handler)\n * }\n *\n * const element = document.createElement('button')\n * addListener(element, 'click', () => console.log('clicked'))\n * addListener(element, 'click', () => console.log('also clicked'))\n * addListener(element, 'hover', () => console.log('hovered'))\n *\n * console.log(eventListeners.get(element).get('click').length) // 2\n * console.log(eventListeners.get(element).get('hover').length) // 1\n * // No need for has() checks or null assertions - everything auto-initializes!\n * ```\n */\nexport class DefaultWeakMap<K extends WeakKey, V> extends WeakMap<K, V> {\n private readonly defaultFactory: () => V\n\n constructor(\n defaultFactory: () => V,\n entries?: readonly (readonly [K, V])[] | null,\n ) {\n super(entries)\n this.defaultFactory = defaultFactory\n }\n\n override get(key: K): V {\n if (this.has(key)) {\n return super.get(key)!\n }\n const value = this.defaultFactory()\n this.set(key, value)\n return value\n }\n}\n","// prettier-ignore\nexport const ELEMENT_NODE = 1 satisfies typeof Node.ELEMENT_NODE;\n// prettier-ignore\nexport const ATTRIBUTE_NODE = 2 satisfies typeof Node.ATTRIBUTE_NODE;\n// prettier-ignore\nexport const TEXT_NODE = 3 satisfies typeof Node.TEXT_NODE;\n// prettier-ignore\nexport const CDATA_SECTION_NODE = 4 satisfies typeof Node.CDATA_SECTION_NODE;\n// prettier-ignore\nexport const ENTITY_REFERENCE_NODE = 5 satisfies typeof Node.ENTITY_REFERENCE_NODE;\n// prettier-ignore\nexport const ENTITY_NODE = 6 satisfies typeof Node.ENTITY_NODE;\n// prettier-ignore\nexport const PROCESSING_INSTRUCTION_NODE = 7 satisfies typeof Node.PROCESSING_INSTRUCTION_NODE;\n// prettier-ignore\nexport const COMMENT_NODE = 8 satisfies typeof Node.COMMENT_NODE;\n// prettier-ignore\nexport const DOCUMENT_NODE = 9 satisfies typeof Node.DOCUMENT_NODE;\n// prettier-ignore\nexport const DOCUMENT_TYPE_NODE = 10 satisfies typeof Node.DOCUMENT_TYPE_NODE;\n// prettier-ignore\nexport const DOCUMENT_FRAGMENT_NODE = 11 satisfies typeof Node.DOCUMENT_FRAGMENT_NODE;\n// prettier-ignore\nexport const NOTATION_NODE = 12 satisfies typeof Node.NOTATION_NODE;\n","import { isObject } from './checker'\nimport * as NodeType from './dom-node-type'\n\n/**\n * Checks if the given DOM node is an Element.\n */\nexport function isElement(node: Node): node is Element {\n return node.nodeType === NodeType.ELEMENT_NODE\n}\n\n/**\n * Checks if the given DOM node is a Text node.\n */\nexport function isTextNode(node: Node): node is Text {\n return node.nodeType === NodeType.TEXT_NODE\n}\n\n/**\n * Checks if the given DOM node is an HTMLElement.\n */\nexport function isHTMLElement(node: Node): node is HTMLElement {\n return isElement(node) && node.namespaceURI === 'http://www.w3.org/1999/xhtml'\n}\n\n/**\n * Checks if the given DOM node is an SVGElement.\n */\nexport function isSVGElement(node: Node): node is SVGElement {\n return isElement(node) && node.namespaceURI === 'http://www.w3.org/2000/svg'\n}\n\n/**\n * Checks if the given DOM node is an MathMLElement.\n */\nexport function isMathMLElement(node: Node): node is MathMLElement {\n return (\n isElement(node) &&\n node.namespaceURI === 'http://www.w3.org/1998/Math/MathML'\n )\n}\n\n/**\n * Checks if the given DOM node is a Document.\n */\nexport function isDocument(node: Node): node is Document {\n return node.nodeType === NodeType.DOCUMENT_NODE\n}\n\n/**\n * Checks if the given DOM node is a DocumentFragment.\n */\nexport function isDocumentFragment(node: Node): node is DocumentFragment {\n return node.nodeType === NodeType.DOCUMENT_FRAGMENT_NODE\n}\n\n/**\n * Checks if the given DOM node is a ShadowRoot.\n */\nexport function isShadowRoot(node: Node): node is ShadowRoot {\n return isDocumentFragment(node) && 'host' in node && isElementLike(node.host)\n}\n\n/**\n * Checks if an unknown value is likely a DOM node.\n */\nexport function isNodeLike(value: unknown): value is Node {\n return isObject(value) && value.nodeType !== undefined\n}\n\n/**\n * Checks if an unknown value is likely a DOM element.\n */\nexport function isElementLike(value: unknown): value is Element {\n return (\n isObject(value) &&\n value.nodeType === NodeType.ELEMENT_NODE &&\n typeof value.nodeName === 'string'\n )\n}\n\n/**\n * Checks if the given value is likely a Window object.\n */\nexport function isWindowLike(value: unknown): value is Window {\n return isObject(value) && value.window === value\n}\n\n/**\n * Gets the window object for the given target or the global window object if no\n * target is provided.\n */\nexport function getWindow(\n target?: Node | ShadowRoot | Document | null,\n): Window & typeof globalThis {\n if (target) {\n if (isShadowRoot(target)) {\n return getWindow(target.host)\n }\n if (isDocument(target)) {\n return target.defaultView || window\n }\n if (isElement(target)) {\n return target.ownerDocument?.defaultView || window\n }\n }\n return window\n}\n\n/**\n * Gets the document for the given target or the global document if no target is\n * provided.\n */\nexport function getDocument(\n target?: Element | Window | Node | Document | null,\n): Document {\n if (target) {\n if (isWindowLike(target)) {\n return target.document\n }\n if (isDocument(target)) {\n return target\n }\n return target.ownerDocument || document\n }\n return document\n}\n\n/**\n * Gets a reference to the root node of the document based on the given target.\n */\nexport function getDocumentElement(\n target?: Element | Node | Window | Document | null,\n): HTMLElement {\n return getDocument(target).documentElement\n}\n","/**\n * Formats a number of bytes into a human-readable string.\n * @param bytes - The number of bytes to format.\n * @returns A string representing the number of bytes in a human-readable format.\n */\nexport function formatBytes(bytes: number): string {\n const units = ['B', 'KB', 'MB', 'GB']\n let unitIndex = 0\n let num = bytes\n while (Math.abs(num) >= 1024 && unitIndex < units.length - 1) {\n num /= 1024\n unitIndex++\n }\n const fraction = unitIndex === 0 && num % 1 === 0 ? 0 : 1\n return `${num.toFixed(fraction)}${units[unitIndex]}`\n}\n","let id = 0\n\nlet maxSafeInteger = Number.MAX_SAFE_INTEGER\n\n/**\n * Sets the maximum safe integer for the id generator. Only for testing purposes.\n *\n * @internal\n */\nexport function setMaxSafeInteger(max: number) {\n maxSafeInteger = max\n}\n\n/**\n * Generates a unique positive integer.\n */\nexport function getId(): number {\n id++\n if (id >= maxSafeInteger) {\n id = 1\n }\n return id\n}\n","import { isMap, isSet } from './checker'\n\n/**\n * Whether two values are deeply equal.\n */\nexport function isDeepEqual(a: unknown, b: unknown): boolean {\n if (a === b) {\n return true\n }\n\n // Handle null and undefined early\n if (a == null || b == null) {\n return false\n }\n\n const aType = typeof a\n const bType = typeof b\n if (aType !== bType) {\n return false\n }\n\n if (aType === 'number' && Number.isNaN(a) && Number.isNaN(b)) {\n return true\n }\n\n if (Array.isArray(a)) {\n if (!Array.isArray(b)) {\n return false\n }\n if (a.length !== b.length) {\n return false\n }\n const size = a.length\n for (let i = 0; i < size; i++) {\n if (!isDeepEqual(a[i], b[i])) {\n return false\n }\n }\n return true\n }\n\n if (isSet(a)) {\n if (!isSet(b)) {\n return false\n }\n if (a.size !== b.size) {\n return false\n }\n for (const value of a) {\n if (!b.has(value)) {\n return false\n }\n }\n return true\n }\n\n if (isMap(a)) {\n if (!isMap(b)) {\n return false\n }\n if (a.size !== b.size) {\n return false\n }\n for (const key of a.keys()) {\n if (!b.has(key)) {\n return false\n }\n if (!isDeepEqual(a.get(key), b.get(key))) {\n return false\n }\n }\n return true\n }\n\n if (typeof a === 'object' && typeof b === 'object') {\n const aKeys = Object.keys(a)\n const bKeys = Object.keys(b)\n if (aKeys.length !== bKeys.length) {\n return false\n }\n for (const key of aKeys) {\n if (\n !isDeepEqual(\n (a as Record<string, unknown>)[key],\n (b as Record<string, unknown>)[key],\n )\n ) {\n return false\n }\n }\n return true\n }\n\n return false\n}\n","/**\n * @internal\n */\nexport function mapGroupByPolyfill<K, T>(\n items: Iterable<T>,\n keySelector: (item: T, index: number) => K,\n): Map<K, T[]> {\n const map = new Map<K, T[]>()\n let index = 0\n for (const item of items) {\n const key = keySelector(item, index)\n const group = map.get(key)\n if (group) {\n group.push(item)\n } else {\n map.set(key, [item])\n }\n index++\n }\n return map\n}\n\n/**\n * A polyfill for the [`Map.groupBy()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/groupBy) static method.\n *\n * @public\n */\nexport function mapGroupBy<K, T>(\n items: Iterable<T>,\n keySelector: (item: T, index: number) => K,\n): Map<K, T[]> {\n return Map.groupBy\n ? Map.groupBy(items, keySelector)\n : mapGroupByPolyfill(items, keySelector)\n}\n","/**\n * Creates a new object with the same keys as the input object, but with values\n * transformed by the provided callback function. Similar to `Array.prototype.map()`\n * but for object values.\n\n * @param object - The object whose values will be transformed.\n * @param callback - A function that transforms each value. Receives the value and\n * its corresponding key as arguments.\n * @returns A new object with the same keys but transformed values.\n *\n * @example\n * ```typescript\n * const prices = { apple: 1, banana: 2, orange: 3 }\n * const doubled = mapValues(prices, (price) => price * 2)\n * // Result: { apple: 2, banana: 4, orange: 6 }\n * ```\n *\n * @example\n * ```typescript\n * const users = { john: 25, jane: 30, bob: 35 }\n * const greetings = mapValues(users, (age, name) => `${name} is ${age} years old`)\n * // Result: { john: 'john is 25 years old', jane: 'jane is 30 years old', bob: 'bob is 35 years old' }\n * ```\n *\n * @example\n * ```typescript\n * const data = { a: '1', b: '2', c: '3' }\n * const numbers = mapValues(data, (str) => parseInt(str, 10))\n * // Result: { a: 1, b: 2, c: 3 }\n * ```\n *\n * @public\n */\nexport function mapValues<ValueIn, ValueOut>(\n object: Record<string, ValueIn>,\n callback: (value: ValueIn, key: string) => ValueOut,\n): Record<string, ValueOut> {\n const result = {} as Record<string, ValueOut>\n for (const [key, value] of Object.entries(object)) {\n result[key] = callback(value, key)\n }\n return result\n}\n","/**\n * A TypeScript utility type that represents the entries of an object as a union of tuple types.\n * Each tuple contains a key-value pair where the key and value types are precisely typed\n * according to the input object type.\n *\n * @example\n * ```typescript\n * type MyObject = { a: 1; b: 'B' }\n * type MyEntries = ObjectEntries<MyObject>\n * // ^ [\"a\", 1] | [\"b\", \"B\"]\n * ```\n *\n * @public\n */\nexport type ObjectEntries<T extends Record<string, any>> = {\n [K in keyof T]: [K, T[K]]\n}[keyof T]\n\n/**\n * A type-safe wrapper around\n * [`Object.entries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries)\n * that preserves the exact types of object keys and values. Unlike the standard\n * `Object.entries()` which returns `[string, any][]`, this function returns an\n * array of tuples where each tuple is precisely typed according to the input\n * object's structure.\n *\n * This is particularly useful when working with objects that have known, fixed\n * property types and you want to maintain type safety when iterating over\n * entries.\n *\n * @example\n * ```typescript\n * const myObject = { a: 1, b: 'hello', c: true } as const\n * const entries = objectEntries(myObject)\n * // Type: ([\"a\", 1] | [\"b\", \"hello\"] | [\"c\", true])[]\n *\n * for (const [key, value] of entries) {\n * // key is typed as \"a\" | \"b\" | \"c\"\n * // value is typed as 1 | \"hello\" | true\n * console.log(`${key}: ${value}`)\n * }\n * ```\n *\n * @example\n * ```typescript\n * interface User {\n * name: string\n * age: number\n * active: boolean\n * }\n *\n * const user: User = { name: 'Alice', age: 30, active: true }\n * const entries = objectEntries(user)\n * // Type: ([\"name\", string] | [\"age\", number] | [\"active\", boolean])[]\n * ```\n *\n * @public\n */\nexport function objectEntries<T extends Record<string, any>>(\n obj: T,\n): ObjectEntries<T>[] {\n return Object.entries(obj)\n}\n","/**\n * @internal\n */\nexport function objectGroupByPolyfill<K extends PropertyKey, T>(\n items: Iterable<T>,\n keySelector: (item: T, index: number) => K,\n): Partial<Record<K, T[]>> {\n const result: Partial<Record<K, T[]>> = {}\n let index = 0\n for (const item of items) {\n const key = keySelector(item, index)\n const group = result[key]\n if (group) {\n group.push(item)\n } else {\n result[key] = [item]\n }\n index++\n }\n return result\n}\n\n/**\n * A polyfill for the [`Object.groupBy()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/groupBy) static method.\n *\n * @public\n */\nexport function objectGroupBy<K extends PropertyKey, T>(\n items: Iterable<T>,\n keySelector: (item: T, index: number) => K,\n): Partial<Record<K, T[]>> {\n return Object.groupBy\n ? Object.groupBy(items, keySelector)\n : objectGroupByPolyfill(items, keySelector)\n}\n","/**\n * Creates a function that will only execute the provided function once.\n * Subsequent calls will return the cached result from the first execution.\n *\n * @param fn The function to execute once\n * @returns A function that will only execute the provided function once\n * @example\n * ```ts\n * const getValue = once(() => expensiveOperation())\n * getValue() // executes expensiveOperation\n * getValue() // returns cached result\n * ```\n */\nexport function once<T>(fn: () => T): () => T {\n let called = false\n let result: T\n return () => {\n if (!called) {\n result = fn()\n called = true\n // @ts-expect-error - micro-optimization for memory management\n fn = undefined\n }\n return result\n }\n}\n","/**\n * Returns a Promise that resolves after a specified number of milliseconds.\n *\n * @param ms - The number of milliseconds to wait.\n *\n * @example\n * ```js\n * await sleep(1000) // Wait 1 second\n * ```\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/checker.ts","../src/counter.ts","../src/default-map.ts","../src/dom.ts","../src/format-bytes.ts","../src/get-id.ts","../src/is-deep-equal.ts","../src/map-group-by.ts","../src/map-values.ts","../src/object-entries.ts","../src/object-group-by.ts","../src/once.ts","../src/regex.ts","../src/sleep.ts","../src/throttle.ts"],"sourcesContent":["/**\n * Checks if the given value is an object.\n */\nexport function isObject(\n value: unknown,\n): value is Record<string | symbol | number, unknown> {\n return value != null && typeof value === 'object'\n}\n\n/**\n * Checks if the given value is a Map.\n */\nexport function isMap(value: unknown): value is Map<unknown, unknown> {\n return value instanceof Map\n}\n\n/**\n * Checks if the given value is a Set.\n */\nexport function isSet(value: unknown): value is Set<unknown> {\n return value instanceof Set\n}\n\n/**\n * Returns true if the given value is not null or undefined.\n */\nexport function isNotNullish<T>(value: T): value is NonNullable<T> {\n return value != null\n}\n","/**\n * A map that counts occurrences of keys.\n *\n * @example\n * ```typescript\n * // Count word occurrences\n * const wordCounter = new Counter<string>()\n * const words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']\n *\n * for (const word of words) {\n * wordCounter.increment(word)\n * }\n *\n * console.log(wordCounter.get('apple')) // 3\n * console.log(wordCounter.get('banana')) // 2\n * console.log(wordCounter.get('cherry')) // 1\n * console.log(wordCounter.get('orange')) // 0 (defaults to 0)\n * ```\n *\n * @example\n * ```typescript\n * // Initialize with existing counts\n * const counter = new Counter<string>([\n * ['red', 5],\n * ['blue', 3],\n * ['green', 7]\n * ])\n *\n * counter.increment('red', 2) // red: 5 -> 7\n * counter.decrement('blue') // blue: 3 -> 2\n * counter.increment('yellow') // yellow: 0 -> 1\n *\n * console.log(counter.get('red')) // 7\n * console.log(counter.get('blue')) // 2\n * console.log(counter.get('yellow')) // 1\n * ```\n *\n * @example\n * ```typescript\n * // Track event frequencies\n * const eventCounter = new Counter<string>()\n *\n * eventCounter.increment('click', 5)\n * eventCounter.increment('hover', 3)\n * eventCounter.increment('click', 2)\n *\n * // Get most common events\n * const events = [...eventCounter.entries()]\n * .sort((a, b) => b[1] - a[1])\n *\n * console.log(events) // [['click', 7], ['hover', 3]]\n * ```\n */\nexport class Counter<K> extends Map<K, number> {\n constructor(iterable?: Iterable<readonly [K, number]>) {\n super(iterable)\n }\n\n override get(key: K): number {\n return super.get(key) ?? 0\n }\n\n /**\n * Increments the count for a key by a given amount (default 1).\n */\n increment(key: K, amount = 1): void {\n this.set(key, this.get(key) + amount)\n }\n\n /**\n * Decrements the count for a key by a given amount (default 1).\n */\n decrement(key: K, amount = 1): void {\n this.set(key, this.get(key) - amount)\n }\n}\n\n/**\n * A weak map that counts occurrences of object keys.\n *\n * Similar to {@link Counter} but uses WeakMap as the base, allowing garbage collection of keys.\n *\n * @example\n * ```typescript\n * // Track reference counts for DOM elements\n * const elementRefs = new WeakCounter<HTMLElement>()\n *\n * function addReference(element: HTMLElement) {\n * elementRefs.increment(element)\n * console.log(`References: ${elementRefs.get(element)}`)\n * }\n *\n * function removeReference(element: HTMLElement) {\n * elementRefs.decrement(element)\n * console.log(`References: ${elementRefs.get(element)}`)\n * }\n *\n * const div = document.createElement('div')\n * addReference(div) // References: 1\n * addReference(div) // References: 2\n * removeReference(div) // References: 1\n * ```\n *\n * @example\n * ```typescript\n * // Count object interactions without preventing garbage collection\n * const objectInteractions = new WeakCounter<object>()\n *\n * function handleInteraction(obj: object, count = 1) {\n * objectInteractions.increment(obj, count)\n * }\n *\n * const user = { id: 1, name: 'Alice' }\n * const session = { sessionId: 'abc123' }\n *\n * handleInteraction(user, 3)\n * handleInteraction(session, 1)\n * handleInteraction(user, 2)\n *\n * console.log(objectInteractions.get(user)) // 5\n * console.log(objectInteractions.get(session)) // 1\n * // When user and session are no longer referenced elsewhere,\n * // they can be garbage collected along with their counts\n * ```\n *\n * @example\n * ```typescript\n * // Initialize with existing counts\n * const cache1 = {}\n * const cache2 = {}\n * const cache3 = {}\n *\n * const hitCounter = new WeakCounter<object>([\n * [cache1, 10],\n * [cache2, 5],\n * [cache3, 15]\n * ])\n *\n * hitCounter.increment(cache1, 3) // 10 -> 13\n * console.log(hitCounter.get(cache1)) // 13\n * console.log(hitCounter.get(cache2)) // 5\n * ```\n */\nexport class WeakCounter<K extends WeakKey> extends WeakMap<K, number> {\n constructor(entries?: readonly (readonly [K, number])[] | null) {\n super(entries)\n }\n\n override get(key: K): number {\n return super.get(key) ?? 0\n }\n\n /**\n * Increments the count for a key by a given amount (default 1).\n */\n increment(key: K, amount = 1): void {\n this.set(key, this.get(key) + amount)\n }\n\n /**\n * Decrements the count for a key by a given amount (default 1).\n */\n decrement(key: K, amount = 1): void {\n this.set(key, this.get(key) - amount)\n }\n}\n","/**\n * A map that automatically creates values for missing keys using a factory function.\n *\n * Similar to Python's [defaultdict](https://docs.python.org/3.13/library/collections.html#collections.defaultdict).\n *\n * @example\n * ```typescript\n * // Group items by category using arrays\n * const groupByCategory = new DefaultMap<string, string[]>(() => [])\n *\n * groupByCategory.get('fruits').push('apple', 'banana')\n * groupByCategory.get('vegetables').push('carrot')\n * groupByCategory.get('fruits').push('orange')\n *\n * console.log(groupByCategory.get('fruits')) // ['apple', 'banana', 'orange']\n * console.log(groupByCategory.get('vegetables')) // ['carrot']\n * console.log(groupByCategory.get('dairy')) // [] (auto-created)\n * ```\n *\n * @example\n * ```typescript\n * // Build a graph with adjacency lists\n * const graph = new DefaultMap<string, Set<string>>(() => new Set())\n *\n * graph.get('A').add('B').add('C')\n * graph.get('B').add('C').add('D')\n * graph.get('C').add('D')\n *\n * console.log([...graph.get('A')]) // ['B', 'C']\n * console.log([...graph.get('B')]) // ['C', 'D']\n * console.log([...graph.get('E')]) // [] (auto-created empty set)\n * ```\n *\n * @example\n * ```typescript\n * // Initialize with existing entries\n * const scores = new DefaultMap<string, number>(\n * () => 0,\n * [\n * ['Alice', 100],\n * ['Bob', 85]\n * ]\n * )\n *\n * scores.set('Alice', scores.get('Alice') + 10) // 100 -> 110\n * console.log(scores.get('Alice')) // 110\n * console.log(scores.get('Bob')) // 85\n * console.log(scores.get('Charlie')) // 0 (auto-created)\n * ```\n *\n * @example\n * ```typescript\n * // Nested DefaultMaps for 2D data structures\n * const matrix = new DefaultMap<number, DefaultMap<number, number>>(\n * () => new DefaultMap<number, number>(() => 0)\n * )\n *\n * matrix.get(0).set(0, 1)\n * matrix.get(0).set(1, 2)\n * matrix.get(1).set(1, 3)\n *\n * console.log(matrix.get(0).get(0)) // 1\n * console.log(matrix.get(0).get(1)) // 2\n * console.log(matrix.get(1).get(0)) // 0 (auto-created)\n * console.log(matrix.get(2).get(3)) // 0 (both auto-created)\n * ```\n */\nexport class DefaultMap<K, V> extends Map<K, V> {\n private readonly defaultFactory: () => V\n\n constructor(defaultFactory: () => V, iterable?: Iterable<readonly [K, V]>) {\n super(iterable)\n this.defaultFactory = defaultFactory\n }\n\n override get(key: K): V {\n if (this.has(key)) {\n return super.get(key)!\n }\n const value = this.defaultFactory()\n this.set(key, value)\n return value\n }\n}\n\n/**\n * A weak map that automatically creates values for missing keys using a factory function.\n *\n * Similar to {@link DefaultMap} but uses WeakMap as the base, allowing garbage collection of keys.\n *\n * @example\n * ```typescript\n * // Store metadata for DOM elements without preventing garbage collection\n * const elementMetadata = new DefaultWeakMap<HTMLElement, { clicks: number; hovers: number }>(\n * () => ({ clicks: 0, hovers: 0 })\n * )\n *\n * const button = document.querySelector('button')!\n * const div = document.querySelector('div')!\n *\n * elementMetadata.get(button).clicks++\n * elementMetadata.get(button).clicks++\n * elementMetadata.get(div).hovers++\n *\n * console.log(elementMetadata.get(button)) // { clicks: 2, hovers: 0 }\n * console.log(elementMetadata.get(div)) // { clicks: 0, hovers: 1 }\n * // When elements are removed from DOM and not referenced,\n * // their metadata can be garbage collected\n * ```\n *\n * @example\n * ```typescript\n * // Cache computed properties for objects\n * const computedCache = new DefaultWeakMap<object, Map<string, any>>(\n * () => new Map()\n * )\n *\n * function getOrCompute(obj: object, key: string, compute: () => any) {\n * const cache = computedCache.get(obj)\n * if (!cache.has(key)) {\n * cache.set(key, compute())\n * }\n * return cache.get(key)\n * }\n *\n * const user = { name: 'Alice', age: 30 }\n * const displayName = getOrCompute(user, 'displayName', () => user.name.toUpperCase())\n * const birthYear = getOrCompute(user, 'birthYear', () => new Date().getFullYear() - user.age)\n *\n * console.log(displayName) // 'ALICE'\n * console.log(birthYear) // 1994 (or current year - 30)\n * ```\n *\n * @example\n * ```typescript\n * // Initialize with existing entries\n * const obj1 = {}\n * const obj2 = {}\n *\n * const objectData = new DefaultWeakMap<object, string[]>(\n * () => [],\n * [\n * [obj1, ['tag1', 'tag2']],\n * [obj2, ['tag3']]\n * ]\n * )\n *\n * objectData.get(obj1).push('tag4')\n * console.log(objectData.get(obj1)) // ['tag1', 'tag2', 'tag4']\n * console.log(objectData.get(obj2)) // ['tag3']\n *\n * const obj3 = {}\n * console.log(objectData.get(obj3)) // [] (auto-created)\n * ```\n *\n * @example\n * ```typescript\n * // Track event listeners per element using both DefaultWeakMap and DefaultMap\n * const eventListeners = new DefaultWeakMap<EventTarget, DefaultMap<string, Function[]>>(\n * () => new DefaultMap<string, Function[]>(() => [])\n * )\n *\n * function addListener(target: EventTarget, event: string, handler: Function) {\n * eventListeners.get(target).get(event).push(handler)\n * }\n *\n * const element = document.createElement('button')\n * addListener(element, 'click', () => console.log('clicked'))\n * addListener(element, 'click', () => console.log('also clicked'))\n * addListener(element, 'hover', () => console.log('hovered'))\n *\n * console.log(eventListeners.get(element).get('click').length) // 2\n * console.log(eventListeners.get(element).get('hover').length) // 1\n * // No need for has() checks or null assertions - everything auto-initializes!\n * ```\n */\nexport class DefaultWeakMap<K extends WeakKey, V> extends WeakMap<K, V> {\n private readonly defaultFactory: () => V\n\n constructor(\n defaultFactory: () => V,\n entries?: readonly (readonly [K, V])[] | null,\n ) {\n super(entries)\n this.defaultFactory = defaultFactory\n }\n\n override get(key: K): V {\n if (this.has(key)) {\n return super.get(key)!\n }\n const value = this.defaultFactory()\n this.set(key, value)\n return value\n }\n}\n","import { isObject } from './checker'\nimport * as NodeType from './dom-node-type'\n\n/**\n * Checks if the given DOM node is an Element.\n */\nexport function isElement(node: Node): node is Element {\n return node.nodeType === NodeType.ELEMENT_NODE\n}\n\n/**\n * Checks if the given DOM node is a Text node.\n */\nexport function isTextNode(node: Node): node is Text {\n return node.nodeType === NodeType.TEXT_NODE\n}\n\n/**\n * Checks if the given DOM node is an HTMLElement.\n */\nexport function isHTMLElement(node: Node): node is HTMLElement {\n return isElement(node) && node.namespaceURI === 'http://www.w3.org/1999/xhtml'\n}\n\n/**\n * Checks if the given DOM node is an SVGElement.\n */\nexport function isSVGElement(node: Node): node is SVGElement {\n return isElement(node) && node.namespaceURI === 'http://www.w3.org/2000/svg'\n}\n\n/**\n * Checks if the given DOM node is an MathMLElement.\n */\nexport function isMathMLElement(node: Node): node is MathMLElement {\n return (\n isElement(node) &&\n node.namespaceURI === 'http://www.w3.org/1998/Math/MathML'\n )\n}\n\n/**\n * Checks if the given DOM node is a Document.\n */\nexport function isDocument(node: Node): node is Document {\n return node.nodeType === NodeType.DOCUMENT_NODE\n}\n\n/**\n * Checks if the given DOM node is a DocumentFragment.\n */\nexport function isDocumentFragment(node: Node): node is DocumentFragment {\n return node.nodeType === NodeType.DOCUMENT_FRAGMENT_NODE\n}\n\n/**\n * Checks if the given DOM node is a ShadowRoot.\n */\nexport function isShadowRoot(node: Node): node is ShadowRoot {\n return isDocumentFragment(node) && 'host' in node && isElementLike(node.host)\n}\n\n/**\n * Checks if an unknown value is likely a DOM node.\n */\nexport function isNodeLike(value: unknown): value is Node {\n return isObject(value) && value.nodeType !== undefined\n}\n\n/**\n * Checks if an unknown value is likely a DOM element.\n */\nexport function isElementLike(value: unknown): value is Element {\n return (\n isObject(value) &&\n value.nodeType === NodeType.ELEMENT_NODE &&\n typeof value.nodeName === 'string'\n )\n}\n\n/**\n * Checks if the given value is likely a Window object.\n */\nexport function isWindowLike(value: unknown): value is Window {\n return isObject(value) && value.window === value\n}\n\n/**\n * Gets the window object for the given target or the global window object if no\n * target is provided.\n */\nexport function getWindow(\n target?: Node | ShadowRoot | Document | null,\n): Window & typeof globalThis {\n if (target) {\n if (isShadowRoot(target)) {\n return getWindow(target.host)\n }\n if (isDocument(target)) {\n return target.defaultView || window\n }\n if (isElement(target)) {\n return target.ownerDocument?.defaultView || window\n }\n }\n return window\n}\n\n/**\n * Gets the document for the given target or the global document if no target is\n * provided.\n */\nexport function getDocument(\n target?: Element | Window | Node | Document | null,\n): Document {\n if (target) {\n if (isWindowLike(target)) {\n return target.document\n }\n if (isDocument(target)) {\n return target\n }\n return target.ownerDocument || document\n }\n return document\n}\n\n/**\n * Gets a reference to the root node of the document based on the given target.\n */\nexport function getDocumentElement(\n target?: Element | Node | Window | Document | null,\n): HTMLElement {\n return getDocument(target).documentElement\n}\n","/**\n * Formats a number of bytes into a human-readable string.\n * @param bytes - The number of bytes to format.\n * @returns A string representing the number of bytes in a human-readable format.\n */\nexport function formatBytes(bytes: number): string {\n const units = ['B', 'KB', 'MB', 'GB']\n let unitIndex = 0\n let num = bytes\n while (Math.abs(num) >= 1024 && unitIndex < units.length - 1) {\n num /= 1024\n unitIndex++\n }\n const fraction = unitIndex === 0 && num % 1 === 0 ? 0 : 1\n return `${num.toFixed(fraction)}${units[unitIndex]}`\n}\n","let id = 0\n\nlet maxSafeInteger = Number.MAX_SAFE_INTEGER\n\n/**\n * Sets the maximum safe integer for the id generator. Only for testing purposes.\n *\n * @internal\n */\nexport function setMaxSafeInteger(max: number) {\n maxSafeInteger = max\n}\n\n/**\n * Generates a unique positive integer.\n */\nexport function getId(): number {\n id++\n if (id >= maxSafeInteger) {\n id = 1\n }\n return id\n}\n","import { isMap, isSet } from './checker'\n\n/**\n * Whether two values are deeply equal.\n */\nexport function isDeepEqual(a: unknown, b: unknown): boolean {\n if (a === b) {\n return true\n }\n\n // Handle null and undefined early\n if (a == null || b == null) {\n return false\n }\n\n const aType = typeof a\n const bType = typeof b\n if (aType !== bType) {\n return false\n }\n\n if (aType === 'number' && Number.isNaN(a) && Number.isNaN(b)) {\n return true\n }\n\n if (Array.isArray(a)) {\n if (!Array.isArray(b)) {\n return false\n }\n if (a.length !== b.length) {\n return false\n }\n const size = a.length\n for (let i = 0; i < size; i++) {\n if (!isDeepEqual(a[i], b[i])) {\n return false\n }\n }\n return true\n }\n\n if (isSet(a)) {\n if (!isSet(b)) {\n return false\n }\n if (a.size !== b.size) {\n return false\n }\n for (const value of a) {\n if (!b.has(value)) {\n return false\n }\n }\n return true\n }\n\n if (isMap(a)) {\n if (!isMap(b)) {\n return false\n }\n if (a.size !== b.size) {\n return false\n }\n for (const key of a.keys()) {\n if (!b.has(key)) {\n return false\n }\n if (!isDeepEqual(a.get(key), b.get(key))) {\n return false\n }\n }\n return true\n }\n\n if (typeof a === 'object' && typeof b === 'object') {\n const aKeys = Object.keys(a)\n const bKeys = Object.keys(b)\n if (aKeys.length !== bKeys.length) {\n return false\n }\n for (const key of aKeys) {\n if (\n !isDeepEqual(\n (a as Record<string, unknown>)[key],\n (b as Record<string, unknown>)[key],\n )\n ) {\n return false\n }\n }\n return true\n }\n\n return false\n}\n","/**\n * @internal\n */\nexport function mapGroupByPolyfill<K, T>(\n items: Iterable<T>,\n keySelector: (item: T, index: number) => K,\n): Map<K, T[]> {\n const map = new Map<K, T[]>()\n let index = 0\n for (const item of items) {\n const key = keySelector(item, index)\n const group = map.get(key)\n if (group) {\n group.push(item)\n } else {\n map.set(key, [item])\n }\n index++\n }\n return map\n}\n\n/**\n * A polyfill for the [`Map.groupBy()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/groupBy) static method.\n *\n * @public\n */\nexport function mapGroupBy<K, T>(\n items: Iterable<T>,\n keySelector: (item: T, index: number) => K,\n): Map<K, T[]> {\n return Map.groupBy\n ? Map.groupBy(items, keySelector)\n : mapGroupByPolyfill(items, keySelector)\n}\n","/**\n * Creates a new object with the same keys as the input object, but with values\n * transformed by the provided callback function. Similar to `Array.prototype.map()`\n * but for object values.\n\n * @param object - The object whose values will be transformed.\n * @param callback - A function that transforms each value. Receives the value and\n * its corresponding key as arguments.\n * @returns A new object with the same keys but transformed values.\n *\n * @example\n * ```typescript\n * const prices = { apple: 1, banana: 2, orange: 3 }\n * const doubled = mapValues(prices, (price) => price * 2)\n * // Result: { apple: 2, banana: 4, orange: 6 }\n * ```\n *\n * @example\n * ```typescript\n * const users = { john: 25, jane: 30, bob: 35 }\n * const greetings = mapValues(users, (age, name) => `${name} is ${age} years old`)\n * // Result: { john: 'john is 25 years old', jane: 'jane is 30 years old', bob: 'bob is 35 years old' }\n * ```\n *\n * @example\n * ```typescript\n * const data = { a: '1', b: '2', c: '3' }\n * const numbers = mapValues(data, (str) => parseInt(str, 10))\n * // Result: { a: 1, b: 2, c: 3 }\n * ```\n *\n * @public\n */\nexport function mapValues<ValueIn, ValueOut>(\n object: Record<string, ValueIn>,\n callback: (value: ValueIn, key: string) => ValueOut,\n): Record<string, ValueOut> {\n const result = {} as Record<string, ValueOut>\n for (const [key, value] of Object.entries(object)) {\n result[key] = callback(value, key)\n }\n return result\n}\n","/**\n * A TypeScript utility type that represents the entries of an object as a union of tuple types.\n * Each tuple contains a key-value pair where the key and value types are precisely typed\n * according to the input object type.\n *\n * @example\n * ```typescript\n * type MyObject = { a: 1; b: 'B' }\n * type MyEntries = ObjectEntries<MyObject>\n * // ^ [\"a\", 1] | [\"b\", \"B\"]\n * ```\n *\n * @public\n */\nexport type ObjectEntries<T extends Record<string, any>> = {\n [K in keyof T]: [K, T[K]]\n}[keyof T]\n\n/**\n * A type-safe wrapper around\n * [`Object.entries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries)\n * that preserves the exact types of object keys and values. Unlike the standard\n * `Object.entries()` which returns `[string, any][]`, this function returns an\n * array of tuples where each tuple is precisely typed according to the input\n * object's structure.\n *\n * This is particularly useful when working with objects that have known, fixed\n * property types and you want to maintain type safety when iterating over\n * entries.\n *\n * @example\n * ```typescript\n * const myObject = { a: 1, b: 'hello', c: true } as const\n * const entries = objectEntries(myObject)\n * // Type: ([\"a\", 1] | [\"b\", \"hello\"] | [\"c\", true])[]\n *\n * for (const [key, value] of entries) {\n * // key is typed as \"a\" | \"b\" | \"c\"\n * // value is typed as 1 | \"hello\" | true\n * console.log(`${key}: ${value}`)\n * }\n * ```\n *\n * @example\n * ```typescript\n * interface User {\n * name: string\n * age: number\n * active: boolean\n * }\n *\n * const user: User = { name: 'Alice', age: 30, active: true }\n * const entries = objectEntries(user)\n * // Type: ([\"name\", string] | [\"age\", number] | [\"active\", boolean])[]\n * ```\n *\n * @public\n */\nexport function objectEntries<T extends Record<string, any>>(\n obj: T,\n): ObjectEntries<T>[] {\n return Object.entries(obj)\n}\n","/**\n * @internal\n */\nexport function objectGroupByPolyfill<K extends PropertyKey, T>(\n items: Iterable<T>,\n keySelector: (item: T, index: number) => K,\n): Partial<Record<K, T[]>> {\n const result: Partial<Record<K, T[]>> = {}\n let index = 0\n for (const item of items) {\n const key = keySelector(item, index)\n const group = result[key]\n if (group) {\n group.push(item)\n } else {\n result[key] = [item]\n }\n index++\n }\n return result\n}\n\n/**\n * A polyfill for the [`Object.groupBy()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/groupBy) static method.\n *\n * @public\n */\nexport function objectGroupBy<K extends PropertyKey, T>(\n items: Iterable<T>,\n keySelector: (item: T, index: number) => K,\n): Partial<Record<K, T[]>> {\n return Object.groupBy\n ? Object.groupBy(items, keySelector)\n : objectGroupByPolyfill(items, keySelector)\n}\n","/**\n * Creates a function that will only execute the provided function once.\n * Subsequent calls will return the cached result from the first execution.\n *\n * @param fn The function to execute once\n * @returns A function that will only execute the provided function once\n * @example\n * ```ts\n * const getValue = once(() => expensiveOperation())\n * getValue() // executes expensiveOperation\n * getValue() // returns cached result\n * ```\n */\nexport function once<T>(fn: () => T): () => T {\n let called = false\n let result: T\n return () => {\n if (!called) {\n result = fn()\n called = true\n // @ts-expect-error - micro-optimization for memory management\n fn = undefined\n }\n return result\n }\n}\n","import { once } from './once'\n\n/**\n * Checks if current environment supports [regex lookbehind assertion](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Lookbehind_assertion).\n *\n * @returns `true` if the current environment supports regex lookbehind assertion, `false` otherwise.\n */\nexport const supportsRegexLookbehind: () => boolean = /* @__PURE__ */ once(\n () => {\n try {\n return 'ab'.replaceAll(new RegExp('(?<=a)b', 'g'), 'c') === 'ac'\n } catch {\n /* v8 ignore start */\n return false\n /* v8 ignore stop */\n }\n },\n)\n","/**\n * Returns a Promise that resolves after a specified number of milliseconds.\n *\n * @param ms - The number of milliseconds to wait.\n *\n * @example\n * ```js\n * await sleep(1000) // Wait 1 second\n * ```\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n","/**\n * Creates a throttled function that only invokes `fn` at most once per every\n * `wait` milliseconds. The first call executes immediately (leading edge).\n * If called again during the wait period, the last call will be executed at\n * the end of the wait period (trailing edge).\n *\n * @param callback The function to throttle\n * @param wait The number of milliseconds to throttle invocations to\n * @returns A throttled version of the function\n * @example\n * ```js\n * const throttled = throttle((name) => console.log('called', name), 1000)\n * throttled('Alice') // logs 'called Alice' immediately\n * throttled('Bob') // skipped (within 1000ms)\n * throttled('Charlie') // skipped (within 1000ms)\n * // after 1000ms, logs 'called Charlie' again (trailing call)\n * ```\n */\nexport function throttle<T extends (this: any, ...args: any[]) => unknown>(\n callback: T,\n wait: number,\n): (this: ThisParameterType<T>, ...args: Parameters<T>) => void {\n let timeoutId: ReturnType<typeof setTimeout> | undefined\n let lastCallTime = 0\n\n return function throttled(\n this: ThisParameterType<T>,\n ...args: Parameters<T>\n ): void {\n clearTimeout(timeoutId)\n\n const now = Date.now()\n const delay = wait + lastCallTime - now\n\n if (delay <= 0) {\n lastCallTime = now\n callback.apply(this, args)\n } else {\n timeoutId = setTimeout(() => {\n lastCallTime = Date.now()\n callback.apply(this, args)\n }, delay)\n }\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ocavue/utils",
3
3
  "type": "module",
4
- "version": "1.4.0",
4
+ "version": "1.6.0",
5
5
  "description": "A collection of utility functions for the browser and other environments",
6
6
  "author": "ocavue <ocavue@gmail.com>",
7
7
  "license": "MIT",
@@ -37,22 +37,22 @@
37
37
  "dist"
38
38
  ],
39
39
  "devDependencies": {
40
- "@ocavue/eslint-config": "^3.10.0",
41
- "@ocavue/tsconfig": "^0.6.2",
40
+ "@ocavue/eslint-config": "^4.2.0",
41
+ "@ocavue/tsconfig": "^0.6.3",
42
42
  "@size-limit/preset-small-lib": "^12.0.0",
43
43
  "@types/node": "^24.9.2",
44
- "@vitest/coverage-v8": "^4.0.16",
45
- "eslint": "^9.39.2",
46
- "jsdom": "^27.4.0",
47
- "knip": "^5.79.0",
48
- "pkg-pr-new": "^0.0.62",
49
- "prettier": "^3.7.4",
44
+ "@vitest/coverage-v8": "^4.0.18",
45
+ "eslint": "^10.0.2",
46
+ "jsdom": "^28.1.0",
47
+ "knip": "^5.85.0",
48
+ "pkg-pr-new": "^0.0.65",
49
+ "prettier": "^3.8.1",
50
50
  "size-limit": "^12.0.0",
51
51
  "tinyexec": "^1.0.2",
52
52
  "tinyglobby": "^0.2.15",
53
- "tsdown": "^0.18.4",
53
+ "tsdown": "^0.21.2",
54
54
  "typescript": "^5.9.3",
55
- "vitest": "^4.0.16"
55
+ "vitest": "^4.0.18"
56
56
  },
57
57
  "publishConfig": {
58
58
  "access": "public"
@@ -37,7 +37,7 @@ function e(t) {
37
37
  function o() {
38
38
  console.log('function_2')
39
39
  }
40
- var c = e(o)
40
+ var f = e(o)
41
41
  function u() {
42
42
  console.log('function_3')
43
43
  }
@@ -57,7 +57,7 @@ function e(t) {
57
57
  function u() {
58
58
  console.log('function_2')
59
59
  }
60
- var c = e(u)
60
+ var f = e(u)
61
61
  function o() {
62
62
  console.log('function_3')
63
63
  }
package/src/index.ts CHANGED
@@ -10,4 +10,6 @@ export { mapValues } from './map-values'
10
10
  export { objectEntries, type ObjectEntries } from './object-entries'
11
11
  export { objectGroupBy } from './object-group-by'
12
12
  export { once } from './once'
13
+ export { supportsRegexLookbehind } from './regex'
13
14
  export { sleep } from './sleep'
15
+ export { throttle } from './throttle'
@@ -0,0 +1,15 @@
1
+ // @vitest-environment node
2
+
3
+ import { describe, expect, it } from 'vitest'
4
+
5
+ import { supportsRegexLookbehind } from './regex'
6
+
7
+ describe('supportsRegexLookbehind', () => {
8
+ it('returns a boolean', () => {
9
+ expect(typeof supportsRegexLookbehind()).toBe('boolean')
10
+ })
11
+
12
+ it('returns true in modern environments', () => {
13
+ expect(supportsRegexLookbehind()).toBe(true)
14
+ })
15
+ })
package/src/regex.ts ADDED
@@ -0,0 +1,18 @@
1
+ import { once } from './once'
2
+
3
+ /**
4
+ * Checks if current environment supports [regex lookbehind assertion](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Lookbehind_assertion).
5
+ *
6
+ * @returns `true` if the current environment supports regex lookbehind assertion, `false` otherwise.
7
+ */
8
+ export const supportsRegexLookbehind: () => boolean = /* @__PURE__ */ once(
9
+ () => {
10
+ try {
11
+ return 'ab'.replaceAll(new RegExp('(?<=a)b', 'g'), 'c') === 'ac'
12
+ } catch {
13
+ /* v8 ignore start */
14
+ return false
15
+ /* v8 ignore stop */
16
+ }
17
+ },
18
+ )
@@ -0,0 +1,143 @@
1
+ // @vitest-environment node
2
+
3
+ import { describe, expect, it, vi } from 'vitest'
4
+
5
+ import { throttle } from './throttle'
6
+
7
+ describe('throttle', () => {
8
+ it('calls the function immediately on first invocation', () => {
9
+ vi.useFakeTimers()
10
+
11
+ const spy = vi.fn()
12
+ const throttled = throttle(spy, 100)
13
+
14
+ throttled()
15
+ expect(spy).toHaveBeenCalledTimes(1)
16
+
17
+ vi.useRealTimers()
18
+ })
19
+
20
+ it('passes arguments correctly', () => {
21
+ vi.useFakeTimers()
22
+
23
+ const spy = vi.fn()
24
+ const throttled = throttle(spy, 100)
25
+
26
+ throttled('a', 'b')
27
+ expect(spy).toHaveBeenCalledWith('a', 'b')
28
+
29
+ vi.useRealTimers()
30
+ })
31
+
32
+ it('ignores calls during the wait period', () => {
33
+ vi.useFakeTimers()
34
+
35
+ const spy = vi.fn()
36
+ const throttled = throttle(spy, 100)
37
+
38
+ throttled()
39
+ throttled()
40
+ throttled()
41
+
42
+ expect(spy).toHaveBeenCalledTimes(1)
43
+
44
+ vi.useRealTimers()
45
+ })
46
+
47
+ it('executes trailing call with latest args after wait period', () => {
48
+ vi.useFakeTimers()
49
+
50
+ const spy = vi.fn()
51
+ const throttled = throttle(spy, 100)
52
+
53
+ throttled('first')
54
+ throttled('second')
55
+ throttled('third')
56
+
57
+ expect(spy).toHaveBeenCalledTimes(1)
58
+ expect(spy).toHaveBeenCalledWith('first')
59
+
60
+ vi.advanceTimersByTime(100)
61
+
62
+ expect(spy).toHaveBeenCalledTimes(2)
63
+ expect(spy).toHaveBeenLastCalledWith('third')
64
+
65
+ vi.useRealTimers()
66
+ })
67
+
68
+ it('allows a new call after the wait period has elapsed', () => {
69
+ vi.useFakeTimers()
70
+
71
+ const spy = vi.fn()
72
+ const throttled = throttle(spy, 100)
73
+
74
+ throttled()
75
+ expect(spy).toHaveBeenCalledTimes(1)
76
+
77
+ vi.advanceTimersByTime(100)
78
+
79
+ throttled()
80
+ expect(spy).toHaveBeenCalledTimes(2)
81
+
82
+ vi.useRealTimers()
83
+ })
84
+
85
+ it('preserves this context on leading call', () => {
86
+ vi.useFakeTimers()
87
+
88
+ const obj = {
89
+ value: 42,
90
+ throttled: throttle(function (this: { value: number }) {
91
+ return this.value
92
+ }, 100),
93
+ }
94
+
95
+ const spy = vi.fn()
96
+ obj.throttled = throttle(function (this: { value: number }) {
97
+ spy(this.value)
98
+ }, 100)
99
+
100
+ obj.throttled()
101
+ expect(spy).toHaveBeenCalledWith(42)
102
+
103
+ vi.useRealTimers()
104
+ })
105
+
106
+ it('preserves this context on trailing call', () => {
107
+ vi.useFakeTimers()
108
+
109
+ const spy = vi.fn()
110
+ const obj = {
111
+ value: 42,
112
+ throttled: throttle(function (this: { value: number }) {
113
+ spy(this.value)
114
+ }, 100),
115
+ }
116
+
117
+ obj.throttled()
118
+ obj.throttled()
119
+
120
+ vi.advanceTimersByTime(100)
121
+
122
+ expect(spy).toHaveBeenCalledTimes(2)
123
+ expect(spy).toHaveBeenLastCalledWith(42)
124
+
125
+ vi.useRealTimers()
126
+ })
127
+
128
+ it('does not fire trailing call if no calls during wait', () => {
129
+ vi.useFakeTimers()
130
+
131
+ const spy = vi.fn()
132
+ const throttled = throttle(spy, 100)
133
+
134
+ throttled()
135
+ expect(spy).toHaveBeenCalledTimes(1)
136
+
137
+ vi.advanceTimersByTime(200)
138
+
139
+ expect(spy).toHaveBeenCalledTimes(1)
140
+
141
+ vi.useRealTimers()
142
+ })
143
+ })
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Creates a throttled function that only invokes `fn` at most once per every
3
+ * `wait` milliseconds. The first call executes immediately (leading edge).
4
+ * If called again during the wait period, the last call will be executed at
5
+ * the end of the wait period (trailing edge).
6
+ *
7
+ * @param callback The function to throttle
8
+ * @param wait The number of milliseconds to throttle invocations to
9
+ * @returns A throttled version of the function
10
+ * @example
11
+ * ```js
12
+ * const throttled = throttle((name) => console.log('called', name), 1000)
13
+ * throttled('Alice') // logs 'called Alice' immediately
14
+ * throttled('Bob') // skipped (within 1000ms)
15
+ * throttled('Charlie') // skipped (within 1000ms)
16
+ * // after 1000ms, logs 'called Charlie' again (trailing call)
17
+ * ```
18
+ */
19
+ export function throttle<T extends (this: any, ...args: any[]) => unknown>(
20
+ callback: T,
21
+ wait: number,
22
+ ): (this: ThisParameterType<T>, ...args: Parameters<T>) => void {
23
+ let timeoutId: ReturnType<typeof setTimeout> | undefined
24
+ let lastCallTime = 0
25
+
26
+ return function throttled(
27
+ this: ThisParameterType<T>,
28
+ ...args: Parameters<T>
29
+ ): void {
30
+ clearTimeout(timeoutId)
31
+
32
+ const now = Date.now()
33
+ const delay = wait + lastCallTime - now
34
+
35
+ if (delay <= 0) {
36
+ lastCallTime = now
37
+ callback.apply(this, args)
38
+ } else {
39
+ timeoutId = setTimeout(() => {
40
+ lastCallTime = Date.now()
41
+ callback.apply(this, args)
42
+ }, delay)
43
+ }
44
+ }
45
+ }