atomic-fns 1.1.7 → 1.2.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.
Files changed (46) hide show
  1. package/README.md +51 -12
  2. package/dist/collections/BTree.d.ts +11 -10
  3. package/dist/collections/BTree.js +58 -80
  4. package/dist/collections/Heap.js +1 -1
  5. package/dist/collections/LRUCache.d.ts +6 -3
  6. package/dist/collections/LRUCache.js +24 -11
  7. package/dist/collections/SortedMap.js +2 -2
  8. package/dist/collections/SortedTree.d.ts +2 -2
  9. package/dist/collections/SortedTree.js +3 -2
  10. package/dist/collections/SplayTree.d.ts +7 -5
  11. package/dist/collections/SplayTree.js +39 -26
  12. package/dist/collections/Trie.d.ts +1 -1
  13. package/dist/collections/Trie.js +26 -26
  14. package/dist/collections/deque.d.ts +1 -1
  15. package/dist/collections/deque.js +17 -10
  16. package/dist/collections/frozenset.js +4 -1
  17. package/dist/collections/index.d.ts +13 -32
  18. package/dist/collections/index.js +210 -82
  19. package/dist/decimal/index.d.ts +5 -2
  20. package/dist/decimal/index.js +63 -27
  21. package/dist/functools/index.d.ts +6 -30
  22. package/dist/functools/index.js +24 -56
  23. package/dist/globals/index.d.ts +3 -20
  24. package/dist/globals/index.js +23 -39
  25. package/dist/i18n/currency.d.ts +3 -0
  26. package/dist/i18n/currency.js +22 -7
  27. package/dist/i18n/date/index.d.ts +17 -10
  28. package/dist/i18n/date/index.js +79 -58
  29. package/dist/i18n/date/utils.d.ts +4 -5
  30. package/dist/i18n/date/utils.js +15 -113
  31. package/dist/i18n/duration.d.ts +11 -10
  32. package/dist/i18n/duration.js +38 -32
  33. package/dist/i18n/format.d.ts +5 -2
  34. package/dist/i18n/format.js +81 -209
  35. package/dist/i18n/index.d.ts +2 -1
  36. package/dist/itertools/index.d.ts +9 -13
  37. package/dist/itertools/index.js +38 -41
  38. package/dist/math/index.d.ts +10 -27
  39. package/dist/math/index.js +16 -33
  40. package/dist/operators/index.d.ts +1 -5
  41. package/dist/operators/index.js +60 -40
  42. package/dist/random/index.js +9 -6
  43. package/dist/string/index.d.ts +1 -1
  44. package/dist/string/index.js +2 -4
  45. package/dist/types.d.ts +3 -3
  46. package/package.json +16 -21
@@ -6,6 +6,7 @@ import { Mapping } from './abc.js';
6
6
  export declare class LRUCache<K = any, V = any> extends Mapping<K, V> {
7
7
  protected items: Map<K, V>;
8
8
  protected maxSize: number;
9
+ private eviction;
9
10
  /**
10
11
  * Creates a new instance of fixed size.
11
12
  * @param {number} capacity
@@ -18,6 +19,8 @@ export declare class LRUCache<K = any, V = any> extends Mapping<K, V> {
18
19
  * @returns {this}
19
20
  */
20
21
  set(key: K, value: V): this;
22
+ /** An idle Map iterator pins every hash table the Map has outgrown, so it cannot live forever. */
23
+ private wrote;
21
24
  /**
22
25
  * This is just an alias of {@link LRUCache.set}.
23
26
  * @param {K} key The key to add (note value will be `undefined`)
@@ -62,17 +65,17 @@ export declare class LRUCache<K = any, V = any> extends Mapping<K, V> {
62
65
  */
63
66
  get capacity(): number;
64
67
  /**
65
- * Returns an iterable of all the keys in the cache, in insertion order.
68
+ * Returns an iterable of all the keys in the cache, from least to most recently used.
66
69
  * @returns {IterableIterator<K>}
67
70
  */
68
71
  keys(): IterableIterator<K>;
69
72
  /**
70
- * Returns an iterable of all the values in the cache, in insertion order.
73
+ * Returns an iterable of all the values in the cache, from least to most recently used.
71
74
  * @returns {IterableIterator<V>}
72
75
  */
73
76
  values(): IterableIterator<V>;
74
77
  /**
75
- * Returns an iterable of all the [key, value] pairs in the cache, in insertion order.
78
+ * Returns an iterable of all the [key, value] pairs in the cache, from least to most recently used.
76
79
  * @returns {IterableIterator<[K, V]>}
77
80
  */
78
81
  entries(): IterableIterator<[K, V]>;
@@ -13,6 +13,8 @@ export class LRUCache extends Mapping {
13
13
  constructor(capacity = 1024) {
14
14
  super();
15
15
  this.maxSize = capacity;
16
+ // Not enumerable, so two caches compare by their items
17
+ Object.defineProperty(this, 'eviction', { value: { keys: this.items.keys(), writes: 0 } });
16
18
  }
17
19
  /**
18
20
  * Adds a new element with a specified `key` and `value` to the cache. If an element with the same key already exists, the element will be updated.
@@ -21,16 +23,25 @@ export class LRUCache extends Mapping {
21
23
  * @returns {this}
22
24
  */
23
25
  set(key, value) {
24
- if (this.items.size === this.maxSize) {
25
- // Because ES6 maps remember insertion order, we can evict the first key
26
- const lastKey = this.items.keys().next().value;
27
- this.items.delete(lastKey);
28
- }
29
26
  // Delete the previous key to update the new insertion order
30
27
  this.items.delete(key);
31
28
  this.items.set(key, value);
29
+ this.wrote();
30
+ if (this.items.size > this.maxSize) {
31
+ // Because ES6 maps remember insertion order, we can evict the first key
32
+ const lastKey = this.eviction.keys.next().value;
33
+ this.items.delete(lastKey);
34
+ }
32
35
  return this;
33
36
  }
37
+ /** An idle Map iterator pins every hash table the Map has outgrown, so it cannot live forever. */
38
+ wrote() {
39
+ const { eviction } = this;
40
+ if (++eviction.writes >= this.items.size) {
41
+ eviction.writes = 0;
42
+ eviction.keys = this.items.keys();
43
+ }
44
+ }
34
45
  /**
35
46
  * This is just an alias of {@link LRUCache.set}.
36
47
  * @param {K} key The key to add (note value will be `undefined`)
@@ -58,6 +69,7 @@ export class LRUCache extends Mapping {
58
69
  // Delete the previous key to update the new insertion order
59
70
  this.items.delete(key);
60
71
  this.items.set(key, value);
72
+ this.wrote();
61
73
  return value;
62
74
  }
63
75
  }
@@ -100,25 +112,26 @@ export class LRUCache extends Mapping {
100
112
  return this.maxSize;
101
113
  }
102
114
  /**
103
- * Returns an iterable of all the keys in the cache, in insertion order.
115
+ * Returns an iterable of all the keys in the cache, from least to most recently used.
104
116
  * @returns {IterableIterator<K>}
105
117
  */
106
118
  keys() {
107
- return this.items.keys();
119
+ // A snapshot: get and set re-insert keys, so a live Map iterator would never reach the end
120
+ return [...this.items.keys()].values();
108
121
  }
109
122
  /**
110
- * Returns an iterable of all the values in the cache, in insertion order.
123
+ * Returns an iterable of all the values in the cache, from least to most recently used.
111
124
  * @returns {IterableIterator<V>}
112
125
  */
113
126
  values() {
114
- return this.items.values();
127
+ return [...this.items.values()].values();
115
128
  }
116
129
  /**
117
- * Returns an iterable of all the [key, value] pairs in the cache, in insertion order.
130
+ * Returns an iterable of all the [key, value] pairs in the cache, from least to most recently used.
118
131
  * @returns {IterableIterator<[K, V]>}
119
132
  */
120
133
  entries() {
121
- return this.items.entries();
134
+ return [...this.items.entries()].values();
122
135
  }
123
136
  [Symbol.iterator]() {
124
137
  return this.entries();
@@ -28,7 +28,7 @@ export class SortedMap extends Mapping {
28
28
  * @returns {this} Returns the Map object.
29
29
  */
30
30
  add(key) {
31
- this.store.set(key, null);
31
+ this.store.add(key);
32
32
  return this;
33
33
  }
34
34
  /**
@@ -69,7 +69,7 @@ export class SortedMap extends Mapping {
69
69
  * @returns {boolean} `true` if key was removed, otherwise `false`.
70
70
  */
71
71
  delete(item) {
72
- return this.store.remove(item) !== undefined;
72
+ return this.store.delete(item);
73
73
  }
74
74
  /**
75
75
  * Removes all key/value pairs in the tree.
@@ -1,4 +1,4 @@
1
- import { Comparer } from '../operators/index.js';
1
+ import type { Comparer } from '../operators/index.js';
2
2
  import { Mapping } from './abc.js';
3
3
  /**
4
4
  * A `SortedTree` is a map that holds key value pairs ordered by keys. Any primitive value (and objects that implement {@link Comparable} or {@link Ordered} interfaces) can be used as keys or values.
@@ -15,7 +15,7 @@ export declare class SortedTree<K, V> extends Mapping<K, V> {
15
15
  */
16
16
  constructor(iterable?: Iterable<[K, V]>, compareFn?: Comparer);
17
17
  /**
18
- * Adds a new `key` with a `null` value.
18
+ * Adds a new `key` with a `null` value, if the `key` doesn't exist.
19
19
  * @param {K} key
20
20
  * @returns {this} Returns the Tree object.
21
21
  */
@@ -18,12 +18,13 @@ export class SortedTree extends Mapping {
18
18
  this.store = new BTree(iterable, compareFn);
19
19
  }
20
20
  /**
21
- * Adds a new `key` with a `null` value.
21
+ * Adds a new `key` with a `null` value, if the `key` doesn't exist.
22
22
  * @param {K} key
23
23
  * @returns {this} Returns the Tree object.
24
24
  */
25
25
  add(key) {
26
- this.store.set(key, null);
26
+ if (!this.store.contains(key))
27
+ this.store.set(key, null);
27
28
  return this;
28
29
  }
29
30
  /**
@@ -1,4 +1,4 @@
1
- import { Comparer } from '../operators/index.js';
1
+ import { type Comparer } from '../operators/index.js';
2
2
  import { Mapping } from './abc.js';
3
3
  /**
4
4
  * Base SplayTree node class.
@@ -41,13 +41,15 @@ export declare class SplayTree<K, V = any> extends Mapping<K, V> {
41
41
  * @returns {?V} The value for the key or `undefined`.
42
42
  */
43
43
  get(key: K): V | undefined;
44
+ private findNode;
44
45
  /**
45
- * Inserts the `key` and `value` in the tree if the `key` does not exist.
46
+ * Inserts the `key` and `value` in the tree, or updates the value if the `key` exists.
46
47
  * @param {K} key A key which can be any comparable value
47
48
  * @param {V} value A value associated with the key
48
49
  * @returns
49
50
  */
50
51
  set(key: K, value: V): void;
52
+ private insert;
51
53
  /**
52
54
  * Removes a specified key if it exists in the tree. The removed value is returned or `undefined` if not found.
53
55
  * @param {K} key The key to remove.
@@ -83,7 +85,7 @@ export declare class SplayTree<K, V = any> extends Mapping<K, V> {
83
85
  * @returns `true` if found.
84
86
  */
85
87
  contains(key: K): boolean;
86
- /** Alias of remove but just returns `true` instead of the deleted value. */
88
+ /** Alias of remove but returns `true` if the key was found instead of the deleted value. */
87
89
  delete(key: K): boolean;
88
90
  clear(): void;
89
91
  /**
@@ -97,8 +99,8 @@ export declare class SplayTree<K, V = any> extends Mapping<K, V> {
97
99
  */
98
100
  entries(): Iterable<[K, V]>;
99
101
  /**
100
- * Returns an ordered iterable of all the keys and values in the tree.
101
- * @returns {Iterable<V>} A iterable of `[key, value]` pairs sorted by key.
102
+ * Returns an ordered iterable of all the values in the tree.
103
+ * @returns {Iterable<V>} An iterable of values sorted by key.
102
104
  */
103
105
  values(): Iterable<V>;
104
106
  }
@@ -1,4 +1,4 @@
1
- import { compare, eq } from '../operators/index.js';
1
+ import { compare } from '../operators/index.js';
2
2
  import { Mapping } from './abc.js';
3
3
  /**
4
4
  * Base SplayTree node class.
@@ -14,22 +14,29 @@ class Node {
14
14
  this.value = value;
15
15
  }
16
16
  get height() {
17
- if (this.left && this.right)
18
- return 1 + Math.max(this.right.height, this.left.height);
19
- if (this.right)
20
- return 1 + this.right.height;
21
- if (this.left)
22
- return 1 + this.left.height;
23
- return 0;
17
+ let height = -1;
18
+ let level = [this];
19
+ while (level.length) {
20
+ height += 1;
21
+ level = level.flatMap((node) => [node.left, node.right].filter(Boolean));
22
+ }
23
+ return height;
24
24
  }
25
25
  }
26
- // In-order traversal of a tree
27
- function* traverse(node) {
28
- while (node) {
29
- yield* traverse(node.left);
30
- yield node;
26
+ // In-order snapshot of a tree: reads splay it, so a live walk would lose its place
27
+ function traverse(node) {
28
+ const nodes = [];
29
+ const stack = [];
30
+ while (node || stack.length) {
31
+ while (node) {
32
+ stack.push(node);
33
+ node = node.left;
34
+ }
35
+ node = stack.pop();
36
+ nodes.push(node);
31
37
  node = node.right;
32
38
  }
39
+ return nodes;
33
40
  }
34
41
  /**
35
42
  * A splay tree is a *self-balancing binary* search tree with the additional property that recently accessed elements are quick to access again.
@@ -75,6 +82,9 @@ export class SplayTree extends Mapping {
75
82
  * @returns {?V} The value for the key or `undefined`.
76
83
  */
77
84
  get(key) {
85
+ return this.findNode(key)?.value;
86
+ }
87
+ findNode(key) {
78
88
  if (!this.root)
79
89
  return;
80
90
  // Note: deterministic splaying (always moves key to front):
@@ -86,7 +96,7 @@ export class SplayTree extends Mapping {
86
96
  if (Math.random() <= this.randSplay) {
87
97
  this.splay(key);
88
98
  if (this.cmp(key, this.root.key) === 0)
89
- return this.root.value;
99
+ return this.root;
90
100
  else
91
101
  return undefined;
92
102
  }
@@ -95,7 +105,7 @@ export class SplayTree extends Mapping {
95
105
  while (current) {
96
106
  const rank = this.cmp(key, current.key);
97
107
  if (rank === 0)
98
- return current.value;
108
+ return current;
99
109
  if (rank < 0)
100
110
  current = current.left;
101
111
  else
@@ -103,12 +113,15 @@ export class SplayTree extends Mapping {
103
113
  }
104
114
  }
105
115
  /**
106
- * Inserts the `key` and `value` in the tree if the `key` does not exist.
116
+ * Inserts the `key` and `value` in the tree, or updates the value if the `key` exists.
107
117
  * @param {K} key A key which can be any comparable value
108
118
  * @param {V} value A value associated with the key
109
119
  * @returns
110
120
  */
111
121
  set(key, value) {
122
+ this.insert(key, value, true);
123
+ }
124
+ insert(key, value, overwrite) {
112
125
  if (!this.root) {
113
126
  this.root = new Node(key, value);
114
127
  this.count += 1;
@@ -120,7 +133,8 @@ export class SplayTree extends Mapping {
120
133
  const rank = this.cmp(key, this.root.key);
121
134
  if (rank === 0) {
122
135
  // Update the value
123
- this.root.value = value;
136
+ if (overwrite)
137
+ this.root.value = value;
124
138
  return;
125
139
  }
126
140
  const node = new Node(key, value);
@@ -147,7 +161,7 @@ export class SplayTree extends Mapping {
147
161
  return;
148
162
  }
149
163
  this.splay(key);
150
- if (!eq(key, this.root.key)) {
164
+ if (this.cmp(key, this.root.key) !== 0) {
151
165
  return;
152
166
  }
153
167
  const removed = this.root;
@@ -229,7 +243,6 @@ export class SplayTree extends Mapping {
229
243
  if (!this.root)
230
244
  return;
231
245
  let stub, left, right;
232
- // eslint-disable-next-line
233
246
  stub = left = right = new Node(null, null);
234
247
  let root = this.root;
235
248
  while (true) {
@@ -284,7 +297,7 @@ export class SplayTree extends Mapping {
284
297
  this.root = root;
285
298
  }
286
299
  add(key) {
287
- return this.set(key, null);
300
+ this.insert(key, null, false);
288
301
  }
289
302
  /**
290
303
  * Returns `true` if the given key is in the tree.
@@ -292,13 +305,13 @@ export class SplayTree extends Mapping {
292
305
  * @returns `true` if found.
293
306
  */
294
307
  contains(key) {
295
- return this.get(key) !== undefined;
308
+ return this.findNode(key) !== undefined;
296
309
  }
297
- /** Alias of remove but just returns `true` instead of the deleted value. */
310
+ /** Alias of remove but returns `true` if the key was found instead of the deleted value. */
298
311
  delete(key) {
299
- // since remove throws, this will throw too
312
+ const size = this.count;
300
313
  this.remove(key);
301
- return true;
314
+ return this.count < size;
302
315
  }
303
316
  clear() {
304
317
  if (!this.root)
@@ -327,8 +340,8 @@ export class SplayTree extends Mapping {
327
340
  }
328
341
  }
329
342
  /**
330
- * Returns an ordered iterable of all the keys and values in the tree.
331
- * @returns {Iterable<V>} A iterable of `[key, value]` pairs sorted by key.
343
+ * Returns an ordered iterable of all the values in the tree.
344
+ * @returns {Iterable<V>} An iterable of values sorted by key.
332
345
  */
333
346
  *values() {
334
347
  for (const node of traverse(this.root)) {
@@ -23,7 +23,7 @@ export declare class Trie extends Collection {
23
23
  /**
24
24
  * Generates all results that start with the given string.
25
25
  * @param word A prefix string
26
- * @param {number} [limit=20] The number of results to return.
26
+ * @param {number} [limit] The number of results to return. Defaults to every result.
27
27
  */
28
28
  matches: (word: string, limit?: number) => Generator<string>;
29
29
  /**
@@ -1,11 +1,14 @@
1
+ import { itake } from '../itertools/index.js';
1
2
  import { Collection } from './abc.js';
2
- function* traverse(node, path, total = 20, count = 0) {
3
- if (node.isWord) {
4
- count++;
5
- yield path;
6
- }
7
- for (const key of Object.keys(node)) {
8
- yield* traverse(node[key], path + key, total, count);
3
+ function* traverse(root, prefix) {
4
+ const stack = [[root, prefix]];
5
+ while (stack.length) {
6
+ const [node, path] = stack.pop();
7
+ if (node.isWord)
8
+ yield path;
9
+ for (const key of Object.keys(node).reverse()) {
10
+ stack.push([node[key], path + key]);
11
+ }
9
12
  }
10
13
  }
11
14
  /**
@@ -14,7 +17,7 @@ function* traverse(node, path, total = 20, count = 0) {
14
17
  * @see {@link https://en.wikipedia.org/wiki/Trie Trie}
15
18
  */
16
19
  export class Trie extends Collection {
17
- root = {};
20
+ root = Object.create(null);
18
21
  count = 0;
19
22
  constructor(words) {
20
23
  super();
@@ -33,16 +36,17 @@ export class Trie extends Collection {
33
36
  for (let i = 0; i < word.length; i++) {
34
37
  const c = word[i];
35
38
  if (!current[c])
36
- current[c] = {};
39
+ current[c] = Object.create(null);
37
40
  current = current[c];
38
41
  }
42
+ if (!current.isWord)
43
+ this.count++;
39
44
  // Set as end of the word
40
45
  Object.defineProperty(current, 'isWord', {
41
46
  value: true,
42
47
  enumerable: false,
43
48
  writable: true
44
49
  });
45
- this.count++;
46
50
  return this;
47
51
  }
48
52
  /**
@@ -51,15 +55,12 @@ export class Trie extends Collection {
51
55
  * @returns {boolean} Returns `true` if the string was found and removed.
52
56
  */
53
57
  remove(word) {
54
- for (let i = 0, node = this.root; i < word.length && node; i++) {
55
- node = node[word[i]];
56
- if (i === word.length - 1 && node.isWord) {
57
- node.isWord = false;
58
- this.count--;
59
- return true;
60
- }
61
- }
62
- return false;
58
+ const node = this.findNode(word);
59
+ if (!node?.isWord)
60
+ return false;
61
+ node.isWord = false;
62
+ this.count--;
63
+ return true;
63
64
  }
64
65
  findNode(word) {
65
66
  let node = this.root;
@@ -72,13 +73,12 @@ export class Trie extends Collection {
72
73
  /**
73
74
  * Generates all results that start with the given string.
74
75
  * @param word A prefix string
75
- * @param {number} [limit=20] The number of results to return.
76
+ * @param {number} [limit] The number of results to return. Defaults to every result.
76
77
  */
77
- matches = function* (word, limit = 20) {
78
+ matches = function* (word, limit) {
78
79
  const node = this.findNode(word);
79
- if (node) {
80
- yield* traverse(node, word, limit);
81
- }
80
+ if (node)
81
+ yield* itake(limit ?? Infinity, traverse(node, word));
82
82
  };
83
83
  /**
84
84
  * Returns `true` if the given string is found in the tree.
@@ -86,13 +86,13 @@ export class Trie extends Collection {
86
86
  */
87
87
  contains(word) {
88
88
  const node = this.findNode(word);
89
- return node?.isWord;
89
+ return !!node?.isWord;
90
90
  }
91
91
  /**
92
92
  * Removes all strings from the tree.
93
93
  */
94
94
  clear() {
95
- this.root = {};
95
+ this.root = Object.create(null);
96
96
  this.count = 0;
97
97
  }
98
98
  /**
@@ -1,4 +1,4 @@
1
- import { Iteratee } from '../types.js';
1
+ import type { Iteratee } from '../types.js';
2
2
  import { Sequence } from './abc.js';
3
3
  /**
4
4
  * Fixed capacity double-ended queue implemented as ring deque.
@@ -1,7 +1,14 @@
1
1
  import { KeyError, ValueError } from '../globals/index.js';
2
- import { IterableIterator } from '../itertools/index.js';
3
2
  import { eq } from '../operators/index.js';
4
3
  import { Sequence } from './abc.js';
4
+ function IterableIterator(next) {
5
+ return {
6
+ next,
7
+ [Symbol.iterator]() {
8
+ return this;
9
+ }
10
+ };
11
+ }
5
12
  /**
6
13
  * Fixed capacity double-ended queue implemented as ring deque.
7
14
  * @template T
@@ -23,7 +30,9 @@ export class Deque extends Sequence {
23
30
  throw new ValueError(`Deque capacity should be a positive integer.`);
24
31
  this.ArrayConstructor = arrType.constructor;
25
32
  this.capacity = capacity;
26
- this.items = new this.ArrayConstructor(arrType.length || this.capacity);
33
+ // A typed array cannot grow, so it takes the whole capacity up front
34
+ const length = ArrayBuffer.isView(arrType) ? capacity : arrType.length || capacity;
35
+ this.items = new this.ArrayConstructor(length);
27
36
  this.clear();
28
37
  if (arrType.length) {
29
38
  for (const item of arrType) {
@@ -125,14 +134,11 @@ export class Deque extends Sequence {
125
134
  * @returns {?T} The element if exists
126
135
  */
127
136
  get(index) {
128
- if (this.count === 0)
129
- return;
130
- index = this.start + index;
131
137
  if (index < 0)
132
138
  index += this.count;
133
- if (index > this.capacity)
134
- index -= this.capacity;
135
- return this.items[index];
139
+ if (index < 0 || index >= this.count)
140
+ return;
141
+ return this.items[(this.start + index) % this.capacity];
136
142
  }
137
143
  /**
138
144
  * Update the element at a given `index`.
@@ -141,9 +147,10 @@ export class Deque extends Sequence {
141
147
  set(index, value) {
142
148
  if (index < 0)
143
149
  index += this.count;
144
- if (index > this.count)
150
+ if (index < 0 || index >= this.count) {
145
151
  throw new KeyError(`Invalid index: ${index} not in Deque.`);
146
- this.items[index] = value;
152
+ }
153
+ this.items[(this.start + index) % this.capacity] = value;
147
154
  }
148
155
  /**
149
156
  * Check if a given element is in the deque.
@@ -8,7 +8,10 @@
8
8
  */
9
9
  export class FrozenSet extends Set {
10
10
  constructor(iterable) {
11
- super(iterable);
11
+ super();
12
+ // The Set constructor would call the no-op add below and drop every item
13
+ for (const item of iterable ?? [])
14
+ super.add(item);
12
15
  return this.freeze();
13
16
  }
14
17
  /** @private */