ts-data-forge 1.0.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 (143) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +534 -0
  3. package/package.json +101 -0
  4. package/src/array/array-utils-creation.test.mts +443 -0
  5. package/src/array/array-utils-modification.test.mts +197 -0
  6. package/src/array/array-utils-overload-type-error.test.mts +149 -0
  7. package/src/array/array-utils-reducing-value.test.mts +425 -0
  8. package/src/array/array-utils-search.test.mts +169 -0
  9. package/src/array/array-utils-set-op.test.mts +335 -0
  10. package/src/array/array-utils-slice-clamped.test.mts +113 -0
  11. package/src/array/array-utils-slicing.test.mts +316 -0
  12. package/src/array/array-utils-transformation.test.mts +790 -0
  13. package/src/array/array-utils-validation.test.mts +492 -0
  14. package/src/array/array-utils.mts +4000 -0
  15. package/src/array/array.test.mts +146 -0
  16. package/src/array/index.mts +2 -0
  17. package/src/array/tuple-utils.mts +519 -0
  18. package/src/array/tuple-utils.test.mts +518 -0
  19. package/src/collections/imap-mapped.mts +801 -0
  20. package/src/collections/imap-mapped.test.mts +860 -0
  21. package/src/collections/imap.mts +651 -0
  22. package/src/collections/imap.test.mts +932 -0
  23. package/src/collections/index.mts +6 -0
  24. package/src/collections/iset-mapped.mts +889 -0
  25. package/src/collections/iset-mapped.test.mts +1187 -0
  26. package/src/collections/iset.mts +682 -0
  27. package/src/collections/iset.test.mts +1084 -0
  28. package/src/collections/queue.mts +390 -0
  29. package/src/collections/queue.test.mts +282 -0
  30. package/src/collections/stack.mts +423 -0
  31. package/src/collections/stack.test.mts +225 -0
  32. package/src/expect-type.mts +206 -0
  33. package/src/functional/index.mts +4 -0
  34. package/src/functional/match.mts +300 -0
  35. package/src/functional/match.test.mts +177 -0
  36. package/src/functional/optional.mts +733 -0
  37. package/src/functional/optional.test.mts +619 -0
  38. package/src/functional/pipe.mts +212 -0
  39. package/src/functional/pipe.test.mts +85 -0
  40. package/src/functional/result.mts +1134 -0
  41. package/src/functional/result.test.mts +777 -0
  42. package/src/globals.d.mts +38 -0
  43. package/src/guard/has-key.mts +119 -0
  44. package/src/guard/has-key.test.mts +219 -0
  45. package/src/guard/index.mts +7 -0
  46. package/src/guard/is-non-empty-string.mts +108 -0
  47. package/src/guard/is-non-empty-string.test.mts +91 -0
  48. package/src/guard/is-non-null-object.mts +106 -0
  49. package/src/guard/is-non-null-object.test.mts +90 -0
  50. package/src/guard/is-primitive.mts +165 -0
  51. package/src/guard/is-primitive.test.mts +102 -0
  52. package/src/guard/is-record.mts +153 -0
  53. package/src/guard/is-record.test.mts +112 -0
  54. package/src/guard/is-type.mts +450 -0
  55. package/src/guard/is-type.test.mts +496 -0
  56. package/src/guard/key-is-in.mts +163 -0
  57. package/src/guard/key-is-in.test.mts +19 -0
  58. package/src/index.mts +10 -0
  59. package/src/iterator/index.mts +1 -0
  60. package/src/iterator/range.mts +120 -0
  61. package/src/iterator/range.test.mts +33 -0
  62. package/src/json/index.mts +1 -0
  63. package/src/json/json.mts +711 -0
  64. package/src/json/json.test.mts +628 -0
  65. package/src/number/branded-types/finite-number.mts +354 -0
  66. package/src/number/branded-types/finite-number.test.mts +135 -0
  67. package/src/number/branded-types/index.mts +26 -0
  68. package/src/number/branded-types/int.mts +278 -0
  69. package/src/number/branded-types/int.test.mts +140 -0
  70. package/src/number/branded-types/int16.mts +192 -0
  71. package/src/number/branded-types/int16.test.mts +170 -0
  72. package/src/number/branded-types/int32.mts +193 -0
  73. package/src/number/branded-types/int32.test.mts +170 -0
  74. package/src/number/branded-types/non-negative-finite-number.mts +223 -0
  75. package/src/number/branded-types/non-negative-finite-number.test.mts +188 -0
  76. package/src/number/branded-types/non-negative-int16.mts +187 -0
  77. package/src/number/branded-types/non-negative-int16.test.mts +201 -0
  78. package/src/number/branded-types/non-negative-int32.mts +187 -0
  79. package/src/number/branded-types/non-negative-int32.test.mts +204 -0
  80. package/src/number/branded-types/non-zero-finite-number.mts +229 -0
  81. package/src/number/branded-types/non-zero-finite-number.test.mts +198 -0
  82. package/src/number/branded-types/non-zero-int.mts +167 -0
  83. package/src/number/branded-types/non-zero-int.test.mts +177 -0
  84. package/src/number/branded-types/non-zero-int16.mts +196 -0
  85. package/src/number/branded-types/non-zero-int16.test.mts +195 -0
  86. package/src/number/branded-types/non-zero-int32.mts +196 -0
  87. package/src/number/branded-types/non-zero-int32.test.mts +197 -0
  88. package/src/number/branded-types/non-zero-safe-int.mts +196 -0
  89. package/src/number/branded-types/non-zero-safe-int.test.mts +232 -0
  90. package/src/number/branded-types/non-zero-uint16.mts +189 -0
  91. package/src/number/branded-types/non-zero-uint16.test.mts +199 -0
  92. package/src/number/branded-types/non-zero-uint32.mts +189 -0
  93. package/src/number/branded-types/non-zero-uint32.test.mts +199 -0
  94. package/src/number/branded-types/positive-finite-number.mts +241 -0
  95. package/src/number/branded-types/positive-finite-number.test.mts +204 -0
  96. package/src/number/branded-types/positive-int.mts +304 -0
  97. package/src/number/branded-types/positive-int.test.mts +176 -0
  98. package/src/number/branded-types/positive-int16.mts +188 -0
  99. package/src/number/branded-types/positive-int16.test.mts +197 -0
  100. package/src/number/branded-types/positive-int32.mts +188 -0
  101. package/src/number/branded-types/positive-int32.test.mts +197 -0
  102. package/src/number/branded-types/positive-safe-int.mts +187 -0
  103. package/src/number/branded-types/positive-safe-int.test.mts +210 -0
  104. package/src/number/branded-types/positive-uint16.mts +188 -0
  105. package/src/number/branded-types/positive-uint16.test.mts +203 -0
  106. package/src/number/branded-types/positive-uint32.mts +188 -0
  107. package/src/number/branded-types/positive-uint32.test.mts +203 -0
  108. package/src/number/branded-types/safe-int.mts +291 -0
  109. package/src/number/branded-types/safe-int.test.mts +170 -0
  110. package/src/number/branded-types/safe-uint.mts +187 -0
  111. package/src/number/branded-types/safe-uint.test.mts +176 -0
  112. package/src/number/branded-types/uint.mts +179 -0
  113. package/src/number/branded-types/uint.test.mts +158 -0
  114. package/src/number/branded-types/uint16.mts +186 -0
  115. package/src/number/branded-types/uint16.test.mts +170 -0
  116. package/src/number/branded-types/uint32.mts +218 -0
  117. package/src/number/branded-types/uint32.test.mts +170 -0
  118. package/src/number/enum/index.mts +2 -0
  119. package/src/number/enum/int8.mts +344 -0
  120. package/src/number/enum/int8.test.mts +180 -0
  121. package/src/number/enum/uint8.mts +293 -0
  122. package/src/number/enum/uint8.test.mts +164 -0
  123. package/src/number/index.mts +4 -0
  124. package/src/number/num.mts +604 -0
  125. package/src/number/num.test.mts +242 -0
  126. package/src/number/refined-number-utils.mts +566 -0
  127. package/src/object/index.mts +1 -0
  128. package/src/object/object.mts +447 -0
  129. package/src/object/object.test.mts +124 -0
  130. package/src/others/cast-mutable.mts +113 -0
  131. package/src/others/cast-readonly.mts +192 -0
  132. package/src/others/cast-readonly.test.mts +89 -0
  133. package/src/others/if-then.mts +98 -0
  134. package/src/others/if-then.test.mts +75 -0
  135. package/src/others/index.mts +7 -0
  136. package/src/others/map-nullable.mts +172 -0
  137. package/src/others/map-nullable.test.mts +297 -0
  138. package/src/others/memoize-function.mts +196 -0
  139. package/src/others/memoize-function.test.mts +168 -0
  140. package/src/others/tuple.mts +160 -0
  141. package/src/others/tuple.test.mts +11 -0
  142. package/src/others/unknown-to-string.mts +215 -0
  143. package/src/others/unknown-to-string.test.mts +114 -0
@@ -0,0 +1,1084 @@
1
+ import { expectType } from '../expect-type.mjs';
2
+ import { ISet } from './iset.mjs';
3
+
4
+ describe('ISet.create', () => {
5
+ test('case 1', () => {
6
+ const s0 = ISet.create(ISet.create(ISet.create([1, 2, 3] as const)));
7
+
8
+ expectType<typeof s0, ISet<1 | 2 | 3>>('<=');
9
+ expect(s0).toStrictEqual(ISet.create([1, 2, 3] as const));
10
+ });
11
+
12
+ test('should create empty set', () => {
13
+ const set = ISet.create<string>([]);
14
+ expect(set.size).toBe(0);
15
+ expect(set.isEmpty).toBe(true);
16
+ });
17
+
18
+ test('should create set from array', () => {
19
+ const set = ISet.create([1, 2, 3, 2, 1]);
20
+ expect(set.size).toBe(3);
21
+ expect(set.has(1)).toBe(true);
22
+ expect(set.has(2)).toBe(true);
23
+ expect(set.has(3)).toBe(true);
24
+ });
25
+
26
+ test('should create set from JavaScript Set', () => {
27
+ const jsSet = new Set(['a', 'b', 'c']);
28
+ const set = ISet.create(jsSet);
29
+ expect(set.size).toBe(3);
30
+ expect(set.has('a')).toBe(true);
31
+ expect(set.has('b')).toBe(true);
32
+ expect(set.has('c')).toBe(true);
33
+ });
34
+
35
+ test('should create set from another ISet', () => {
36
+ const original = ISet.create([1, 2, 3]);
37
+ const copy = ISet.create(original);
38
+ expect(copy.size).toBe(3);
39
+ expect(copy.has(1)).toBe(true);
40
+ expect(copy.has(2)).toBe(true);
41
+ expect(copy.has(3)).toBe(true);
42
+ });
43
+ });
44
+
45
+ describe('ISet.size', () => {
46
+ test('case 1', () => {
47
+ const s0 = ISet.create([1, 2, 3] as const);
48
+
49
+ expectType<typeof s0.size, number>('<=');
50
+ expect(s0.size).toBe(3);
51
+ });
52
+
53
+ test('case 2', () => {
54
+ const s0 = ISet.create<number>([]);
55
+
56
+ expect(s0.size).toBe(0);
57
+ });
58
+ });
59
+
60
+ describe('isEmpty property', () => {
61
+ test('should return true for empty set', () => {
62
+ const set = ISet.create<string>([]);
63
+ expect(set.isEmpty).toBe(true);
64
+ });
65
+
66
+ test('should return false for non-empty set', () => {
67
+ const set = ISet.create([1, 2, 3]);
68
+ expect(set.isEmpty).toBe(false);
69
+ });
70
+ });
71
+
72
+ describe('ISet.has', () => {
73
+ test('case 1', () => {
74
+ const s0 = ISet.create([1, 2, 3] as const);
75
+
76
+ expectType<typeof s0.has, (value: 1 | 2 | 3) => boolean>('<=');
77
+ expect(s0.has(2)).toBe(true);
78
+ });
79
+
80
+ test('case 2', () => {
81
+ const s0 = ISet.create<number>([1, 2, 3]);
82
+
83
+ expect(s0.has(4)).toBe(false);
84
+ });
85
+
86
+ test('case 3', () => {
87
+ const s0 = ISet.create<number>([]);
88
+
89
+ expect(s0.has(1)).toBe(false);
90
+ });
91
+
92
+ test('case 4', () => {
93
+ const s0 = ISet.create([1, 2, 3, Number.NaN] as const);
94
+
95
+ expect(s0.has(Number.NaN)).toBe(true);
96
+ });
97
+
98
+ test('should handle boolean values', () => {
99
+ const set = ISet.create([true, false]);
100
+ expect(set.has(true)).toBe(true);
101
+ expect(set.has(false)).toBe(true);
102
+ });
103
+
104
+ test('should handle null and undefined', () => {
105
+ const set = ISet.create([null, undefined]);
106
+ expect(set.has(null)).toBe(true);
107
+ expect(set.has(undefined)).toBe(true);
108
+ });
109
+ });
110
+
111
+ describe('ISet.every', () => {
112
+ test('case 1', () => {
113
+ const s0 = ISet.create([2, 4, 6] as const);
114
+
115
+ expectType<
116
+ typeof s0.every,
117
+ (predicate: (value: 2 | 4 | 6) => boolean) => boolean
118
+ >('<=');
119
+ expect(s0.every((x) => x % 2 === 0)).toBe(true);
120
+ });
121
+
122
+ test('case 2', () => {
123
+ const s0 = ISet.create([1, 2, 3] as const);
124
+
125
+ expect(s0.every((x) => x % 2 === 0)).toBe(false);
126
+ });
127
+
128
+ test('case 3', () => {
129
+ const s0 = ISet.create<number>([]);
130
+
131
+ expect(s0.every((x) => x % 2 === 0)).toBe(true);
132
+ });
133
+
134
+ test('should return true when all elements satisfy predicate', () => {
135
+ const set = ISet.create([2, 4, 6, 8]);
136
+ expect(set.every((x) => x % 2 === 0)).toBe(true);
137
+ });
138
+
139
+ test('should return false when some elements do not satisfy predicate', () => {
140
+ const set = ISet.create([1, 2, 3, 4]);
141
+ expect(set.every((x) => x % 2 === 0)).toBe(false);
142
+ });
143
+
144
+ test('should return true for empty set', () => {
145
+ const set = ISet.create<number>([]);
146
+ expect(set.every((x) => x > 0)).toBe(true);
147
+ });
148
+ });
149
+
150
+ describe('every method as type guard', () => {
151
+ test('should narrow type when used as type guard', () => {
152
+ const set = ISet.create<string | number>(['hello', 'world']);
153
+ if (set.every((value): value is string => typeof value === 'string')) {
154
+ // Type should be narrowed to ISet<string>
155
+ const values = set.toArray();
156
+ for (const value of values) {
157
+ expect(typeof value).toBe('string');
158
+ }
159
+ }
160
+ });
161
+
162
+ test('should work with mixed types that fail guard', () => {
163
+ const set = ISet.create<string | number>(['hello', 42, 'world']);
164
+ expect(
165
+ set.every((value): value is string => typeof value === 'string'),
166
+ ).toBe(false);
167
+ });
168
+ });
169
+
170
+ describe('ISet.some', () => {
171
+ test('case 1', () => {
172
+ const s0 = ISet.create([1, 3, 5] as const);
173
+
174
+ expectType<
175
+ typeof s0.some,
176
+ (predicate: (value: 1 | 3 | 5) => boolean) => boolean
177
+ >('<=');
178
+ expect(s0.some((x) => x % 2 === 0)).toBe(false);
179
+ });
180
+
181
+ test('case 2', () => {
182
+ const s0 = ISet.create([1, 2, 3] as const);
183
+
184
+ expect(s0.some((x) => x % 2 === 0)).toBe(true);
185
+ });
186
+
187
+ test('case 3', () => {
188
+ const s0 = ISet.create<number>([]);
189
+
190
+ expect(s0.some((x) => x % 2 === 0)).toBe(false);
191
+ });
192
+
193
+ test('should return true when at least one element satisfies predicate', () => {
194
+ const set = ISet.create([1, 3, 5, 6]);
195
+ expect(set.some((x) => x % 2 === 0)).toBe(true);
196
+ });
197
+
198
+ test('should return false when no elements satisfy predicate', () => {
199
+ const set = ISet.create([1, 3, 5, 7]);
200
+ expect(set.some((x) => x % 2 === 0)).toBe(false);
201
+ });
202
+
203
+ test('should return false for empty set', () => {
204
+ const set = ISet.create<number>([]);
205
+ expect(set.some((x) => x > 0)).toBe(false);
206
+ });
207
+
208
+ test('should work with complex predicates', () => {
209
+ const set = ISet.create(['hello', 'world', 'test']);
210
+ expect(set.some((str) => str.includes('o'))).toBe(true);
211
+ expect(set.some((str) => str.includes('z'))).toBe(false);
212
+ });
213
+ });
214
+
215
+ describe('ISet.add', () => {
216
+ test('case 1', () => {
217
+ const s0 = ISet.create<number>([1, 2, 3]);
218
+
219
+ expectType<typeof s0.add, (value: number) => ISet<number>>('<=');
220
+ const s1 = ISet.create<number>([1, 2, 3, 4]);
221
+ expect(s0.add(4)).toStrictEqual(s1);
222
+ expect(s0).toStrictEqual(ISet.create<number>([1, 2, 3]));
223
+ });
224
+
225
+ test('case 2', () => {
226
+ const s0 = ISet.create([1, 2, 3]);
227
+
228
+ expect(s0.add(2)).toStrictEqual(ISet.create([1, 2, 3]));
229
+ expect(s0).toStrictEqual(ISet.create([1, 2, 3]));
230
+ });
231
+
232
+ test('case 3', () => {
233
+ const s0 = ISet.create<number>([]);
234
+
235
+ expect(s0.add(1)).toStrictEqual(ISet.create([1]));
236
+ expect(s0).toStrictEqual(ISet.create([]));
237
+ });
238
+
239
+ test('should add new elements and maintain immutability', () => {
240
+ const original = ISet.create<number>([1, 2, 3]);
241
+ const modified = original.add(4);
242
+
243
+ expect(original.size).toBe(3);
244
+ expect(modified.size).toBe(4);
245
+ expect(original.has(4)).toBe(false);
246
+ expect(modified.has(4)).toBe(true);
247
+ });
248
+
249
+ test('should return same instance when adding existing element', () => {
250
+ const set = ISet.create([1, 2, 3]);
251
+ const result = set.add(2);
252
+ expect(result).toBe(set);
253
+ });
254
+
255
+ test('should handle special values', () => {
256
+ const set = ISet.create<number | null | undefined>([]);
257
+ const withNull = set.add(null);
258
+ const withUndefined = withNull.add(undefined);
259
+ const withNaN = withUndefined.add(Number.NaN);
260
+
261
+ expect(withNaN.has(null)).toBe(true);
262
+ expect(withNaN.has(undefined)).toBe(true);
263
+ expect(withNaN.has(Number.NaN)).toBe(true);
264
+ });
265
+ });
266
+
267
+ describe('ISet.delete', () => {
268
+ test('case 1', () => {
269
+ const s0 = ISet.create<number>([1, 2, 3]);
270
+
271
+ expectType<typeof s0.delete, (value: number) => ISet<number>>('<=');
272
+ expect(s0.delete(4)).toStrictEqual(ISet.create<number>([1, 2, 3]));
273
+ expect(s0).toStrictEqual(ISet.create<number>([1, 2, 3]));
274
+ });
275
+
276
+ test('case 2', () => {
277
+ const s0 = ISet.create([1, 2, 3]);
278
+
279
+ expect(s0.delete(2)).toStrictEqual(ISet.create([1, 3]));
280
+ expect(s0).toStrictEqual(ISet.create([1, 2, 3]));
281
+ });
282
+
283
+ test('case 3', () => {
284
+ const s0 = ISet.create<number>([]);
285
+
286
+ expect(s0.delete(1)).toStrictEqual(ISet.create([]));
287
+ expect(s0).toStrictEqual(ISet.create([]));
288
+ });
289
+
290
+ test('should delete existing elements and maintain immutability', () => {
291
+ const original = ISet.create([1, 2, 3, 4]);
292
+ const modified = original.delete(2);
293
+
294
+ expect(original.size).toBe(4);
295
+ expect(modified.size).toBe(3);
296
+ expect(original.has(2)).toBe(true);
297
+ expect(modified.has(2)).toBe(false);
298
+ });
299
+
300
+ test('should return same instance when deleting non-existent element', () => {
301
+ const set = ISet.create<number>([1, 2, 3]);
302
+ const result = set.delete(4);
303
+ expect(result).toBe(set);
304
+ });
305
+ });
306
+
307
+ describe('ISet.map', () => {
308
+ test('case 1', () => {
309
+ const s0 = ISet.create([1, 2, 3] as const);
310
+
311
+ expectType<
312
+ typeof s0.map,
313
+ <U extends MapSetKeyType>(mapper: (value: 1 | 2 | 3) => U) => ISet<U>
314
+ >('<=');
315
+ expect(s0.map((x) => x * 2)).toStrictEqual(ISet.create([2, 4, 6]));
316
+ });
317
+
318
+ test('case 2', () => {
319
+ const s0 = ISet.create<number>([]);
320
+
321
+ expect(s0.map((x) => x * 2)).toStrictEqual(ISet.create([]));
322
+ });
323
+
324
+ test('should transform all elements', () => {
325
+ const set = ISet.create([1, 2, 3]);
326
+ const doubled = set.map((x) => x * 2);
327
+
328
+ expect([...doubled.toArray()].sort((a, b) => a - b)).toStrictEqual([
329
+ 2, 4, 6,
330
+ ]);
331
+ });
332
+
333
+ test('should handle type transformations', () => {
334
+ const set = ISet.create([1, 2, 3]);
335
+ const strings = set.map((x) => x.toString());
336
+
337
+ expect(strings.has('1')).toBe(true);
338
+ expect(strings.has('2')).toBe(true);
339
+ expect(strings.has('3')).toBe(true);
340
+ });
341
+ });
342
+
343
+ describe('ISet.filter', () => {
344
+ test('case 1', () => {
345
+ const s0 = ISet.create([1, 2, 3, 4, 5] as const);
346
+
347
+ expectType<
348
+ typeof s0.filter,
349
+ (
350
+ predicate: (value: 1 | 2 | 3 | 4 | 5) => boolean,
351
+ ) => ISet<1 | 2 | 3 | 4 | 5>
352
+ >('<=');
353
+ expect(s0.filter((x) => x % 2 === 0)).toStrictEqual(ISet.create([2, 4]));
354
+ });
355
+
356
+ test('case 2', () => {
357
+ const s0 = ISet.create<number>([]);
358
+
359
+ expect(s0.filter((x) => x % 2 === 0)).toStrictEqual(ISet.create([]));
360
+ });
361
+
362
+ test('should filter elements based on predicate', () => {
363
+ const set = ISet.create([1, 2, 3, 4, 5, 6]);
364
+ const evens = set.filter((x) => x % 2 === 0);
365
+
366
+ expect(evens.size).toBe(3);
367
+ expect(evens.has(2)).toBe(true);
368
+ expect(evens.has(4)).toBe(true);
369
+ expect(evens.has(6)).toBe(true);
370
+ });
371
+
372
+ test('should work as type guard', () => {
373
+ const set = ISet.create<string | number>(['hello', 42, 'world', 123]);
374
+ const strings = set.filter(
375
+ (value): value is string => typeof value === 'string',
376
+ );
377
+
378
+ expect(strings.size).toBe(2);
379
+ expect(strings.has('hello')).toBe(true);
380
+ expect(strings.has('world')).toBe(true);
381
+ });
382
+
383
+ test('should return empty set when no elements match', () => {
384
+ const set = ISet.create([1, 3, 5]);
385
+ const evens = set.filter((x) => x % 2 === 0);
386
+
387
+ expect(evens.size).toBe(0);
388
+ expect(evens.isEmpty).toBe(true);
389
+ });
390
+ });
391
+
392
+ describe('ISet.filterNot', () => {
393
+ test('should filter out elements that satisfy predicate', () => {
394
+ const set = ISet.create([1, 2, 3, 4, 5, 6]);
395
+ const odds = set.filterNot((x) => x % 2 === 0);
396
+
397
+ expect(odds.size).toBe(3);
398
+ expect(odds.has(1)).toBe(true);
399
+ expect(odds.has(3)).toBe(true);
400
+ expect(odds.has(5)).toBe(true);
401
+ });
402
+
403
+ test('should return same set when no elements satisfy predicate', () => {
404
+ const set = ISet.create([1, 3, 5]);
405
+ const nonEvens = set.filterNot((x) => x % 2 === 0);
406
+ expect(nonEvens.size).toBe(3);
407
+ expect(ISet.equal(set, nonEvens)).toBe(true);
408
+ });
409
+
410
+ test('should return empty set when all elements satisfy predicate', () => {
411
+ const set = ISet.create([2, 4, 6]);
412
+ const nonEvens = set.filterNot((x) => x % 2 === 0);
413
+ expect(nonEvens.isEmpty).toBe(true);
414
+ });
415
+ });
416
+
417
+ describe('ISet.isSubsetOf', () => {
418
+ test('case 1', () => {
419
+ const s0 = ISet.create<number>([1, 2]);
420
+ const s1 = ISet.create<number>([1, 2, 3]);
421
+
422
+ expectType<typeof s0.isSubsetOf, (other: ISet<number>) => boolean>('<=');
423
+ expect(s0.isSubsetOf(s1)).toBe(true);
424
+ });
425
+
426
+ test('case 2', () => {
427
+ const s0 = ISet.create<number>([1, 2, 3]);
428
+ const s1 = ISet.create<number>([1, 2]);
429
+
430
+ expect(s0.isSubsetOf(s1)).toBe(false);
431
+ });
432
+
433
+ test('case 3', () => {
434
+ const s0 = ISet.create<number>([]);
435
+ const s1 = ISet.create<number>([1, 2, 3]);
436
+
437
+ expect(s0.isSubsetOf(s1)).toBe(true);
438
+ });
439
+
440
+ test('should return true for subset relationship', () => {
441
+ const subset = ISet.create<number>([1, 2]);
442
+ const superset = ISet.create<number>([1, 2, 3, 4]);
443
+ expect(subset.isSubsetOf(superset)).toBe(true);
444
+ });
445
+
446
+ test('should return true for equal sets', () => {
447
+ const set1 = ISet.create<number>([1, 2, 3]);
448
+ const set2 = ISet.create<number>([1, 2, 3]);
449
+ expect(set1.isSubsetOf(set2)).toBe(true);
450
+ });
451
+
452
+ test('should return false for non-subset', () => {
453
+ const set1 = ISet.create<number>([1, 2, 5]);
454
+ const set2 = ISet.create<number>([1, 2, 3, 4]);
455
+ expect(set1.isSubsetOf(set2)).toBe(false);
456
+ });
457
+ });
458
+
459
+ describe('ISet.isSupersetOf', () => {
460
+ test('case 1', () => {
461
+ const s0 = ISet.create<number>([1, 2, 3]);
462
+ const s1 = ISet.create<number>([1, 2]);
463
+
464
+ expectType<typeof s0.isSupersetOf, (other: ISet<number>) => boolean>('<=');
465
+ expect(s0.isSupersetOf(s1)).toBe(true);
466
+ });
467
+
468
+ test('case 2', () => {
469
+ const s0 = ISet.create<number>([1, 2]);
470
+ const s1 = ISet.create<number>([1, 2, 3]);
471
+
472
+ expect(s0.isSupersetOf(s1)).toBe(false);
473
+ });
474
+
475
+ test('case 3', () => {
476
+ const s0 = ISet.create<number>([1, 2, 3]);
477
+ const s1 = ISet.create<number>([]);
478
+
479
+ expect(s0.isSupersetOf(s1)).toBe(true);
480
+ });
481
+
482
+ test('should return true for superset relationship', () => {
483
+ const superset = ISet.create<number>([1, 2, 3, 4]);
484
+ const subset = ISet.create<number>([1, 2]);
485
+ expect(superset.isSupersetOf(subset)).toBe(true);
486
+ });
487
+
488
+ test('should return true for equal sets', () => {
489
+ const set1 = ISet.create<number>([1, 2, 3]);
490
+ const set2 = ISet.create<number>([1, 2, 3]);
491
+ expect(set1.isSupersetOf(set2)).toBe(true);
492
+ });
493
+
494
+ test('should return false for non-superset', () => {
495
+ const set1 = ISet.create<number>([1, 2, 3]);
496
+ const set2 = ISet.create<number>([1, 2, 3, 4]);
497
+ expect(set1.isSupersetOf(set2)).toBe(false);
498
+ });
499
+ });
500
+
501
+ describe('ISet.subtract', () => {
502
+ test('case 1', () => {
503
+ const s0 = ISet.create<number>([1, 2, 3]);
504
+ const s1 = ISet.create<number>([2, 4]);
505
+
506
+ expectType<typeof s0.subtract, (other: ISet<number>) => ISet<number>>('<=');
507
+ expect(s0.subtract(s1)).toStrictEqual(ISet.create<number>([1, 3]));
508
+ });
509
+
510
+ test('case 2', () => {
511
+ const s0 = ISet.create<number>([1, 2, 3]);
512
+ const s1 = ISet.create<number>([]);
513
+
514
+ expect(s0.subtract(s1)).toStrictEqual(ISet.create<number>([1, 2, 3]));
515
+ });
516
+
517
+ test('case 3', () => {
518
+ const s0 = ISet.create<number>([]);
519
+ const s1 = ISet.create<number>([1, 2, 3]);
520
+
521
+ expect(s0.subtract(s1)).toStrictEqual(ISet.create<number>([]));
522
+ });
523
+
524
+ test('should return elements in first set but not in second', () => {
525
+ const set1 = ISet.create<number>([1, 2, 3, 4, 5]);
526
+ const set2 = ISet.create<number>([3, 4, 5, 6, 7]);
527
+ const result = set1.subtract(set2);
528
+
529
+ expect(result.size).toBe(2);
530
+ expect(result.has(1)).toBe(true);
531
+ expect(result.has(2)).toBe(true);
532
+ });
533
+
534
+ test('should return empty set when all elements are removed', () => {
535
+ const set1 = ISet.create<number>([1, 2, 3]);
536
+ const set2 = ISet.create<number>([1, 2, 3, 4, 5]);
537
+ const result = set1.subtract(set2);
538
+
539
+ expect(result.isEmpty).toBe(true);
540
+ });
541
+ });
542
+
543
+ describe('ISet.intersection', () => {
544
+ test('case 1', () => {
545
+ const s0 = ISet.create<number>([1, 2, 3]);
546
+ const s1 = ISet.create<number>([2, 3, 4]);
547
+
548
+ expectType<
549
+ typeof ISet.intersection,
550
+ <T extends Primitive>(a: ISet<T>, b: ISet<T>) => ISet<T>
551
+ >('<=');
552
+ expect(ISet.intersection(s0, s1)).toStrictEqual(
553
+ ISet.create<number>([2, 3]),
554
+ );
555
+ });
556
+
557
+ test('case 2', () => {
558
+ const s0 = ISet.create<number>([1, 2, 3]);
559
+ const s1 = ISet.create<number>([]);
560
+
561
+ expect(ISet.intersection(s0, s1)).toStrictEqual(ISet.create<number>([]));
562
+ });
563
+
564
+ test('case 3', () => {
565
+ const s0 = ISet.create<number>([]);
566
+ const s1 = ISet.create<number>([1, 2, 3]);
567
+
568
+ expect(ISet.intersection(s0, s1)).toStrictEqual(ISet.create<number>([]));
569
+ });
570
+
571
+ test('should return common elements', () => {
572
+ const set1 = ISet.create<number>([1, 2, 3, 4]);
573
+ const set2 = ISet.create<number>([3, 4, 5, 6]);
574
+ const result = ISet.intersection(set1, set2);
575
+
576
+ expect(result.size).toBe(2);
577
+ expect(result.has(3)).toBe(true);
578
+ expect(result.has(4)).toBe(true);
579
+ });
580
+
581
+ test('should return empty set when no common elements', () => {
582
+ const set1 = ISet.create<number>([1, 2]);
583
+ const set2 = ISet.create<number>([3, 4]);
584
+ const result = ISet.intersection(set1, set2);
585
+
586
+ expect(result.isEmpty).toBe(true);
587
+ });
588
+ });
589
+
590
+ describe('ISet.intersect', () => {
591
+ test('case 1', () => {
592
+ const s0 = ISet.create<number>([1, 2, 3]);
593
+ const s1 = ISet.create<number>([2, 3, 4]);
594
+
595
+ expectType<typeof s0.intersect, (other: ISet<number>) => ISet<number>>(
596
+ '<=',
597
+ );
598
+ expect(s0.intersect(s1)).toStrictEqual(ISet.create<number>([2, 3]));
599
+ });
600
+
601
+ test('case 2', () => {
602
+ const s0 = ISet.create<number>([1, 2, 3]);
603
+ const s1 = ISet.create<number>([]);
604
+
605
+ expect(s0.intersect(s1)).toStrictEqual(ISet.create<number>([]));
606
+ });
607
+
608
+ test('case 3', () => {
609
+ const s0 = ISet.create<number>([]);
610
+ const s1 = ISet.create<number>([1, 2, 3]);
611
+
612
+ expect(s0.intersect(s1)).toStrictEqual(ISet.create<number>([]));
613
+ });
614
+
615
+ test('should return common elements using instance method', () => {
616
+ const set1 = ISet.create<number>([1, 2, 3, 4]);
617
+ const set2 = ISet.create<number>([3, 4, 5, 6]);
618
+ const result = set1.intersect(set2);
619
+
620
+ expect(result.size).toBe(2);
621
+ expect(result.has(3)).toBe(true);
622
+ expect(result.has(4)).toBe(true);
623
+ });
624
+ });
625
+
626
+ describe('ISet.union', () => {
627
+ test('case 1', () => {
628
+ const s0 = ISet.create<number>([1, 2, 3]);
629
+ const s1 = ISet.create<number>([3, 4, 5]);
630
+
631
+ expectType<
632
+ typeof ISet.union,
633
+ <T extends Primitive>(a: ISet<T>, b: ISet<T>) => ISet<T>
634
+ >('!=');
635
+ expect(ISet.union(s0, s1)).toStrictEqual(
636
+ ISet.create<number>([1, 2, 3, 4, 5]),
637
+ );
638
+ });
639
+
640
+ test('case 2', () => {
641
+ const s0 = ISet.create([1, 2, 3]);
642
+ const s1 = ISet.create<number>([]);
643
+
644
+ expect(ISet.union(s0, s1)).toStrictEqual(ISet.create([1, 2, 3]));
645
+ });
646
+
647
+ test('case 3', () => {
648
+ const s0 = ISet.create<number>([]);
649
+ const s1 = ISet.create([1, 2, 3]);
650
+
651
+ expect(ISet.union(s0, s1)).toStrictEqual(ISet.create([1, 2, 3]));
652
+ });
653
+
654
+ test('should return combined elements using static method', () => {
655
+ const set1 = ISet.create([1, 2, 3]);
656
+ const set2 = ISet.create([3, 4, 5]);
657
+ const result = ISet.union(set1, set2);
658
+
659
+ expect(result.size).toBe(5);
660
+ expect(result.has(1)).toBe(true);
661
+ expect(result.has(2)).toBe(true);
662
+ expect(result.has(3)).toBe(true);
663
+ expect(result.has(4)).toBe(true);
664
+ expect(result.has(5)).toBe(true);
665
+ });
666
+
667
+ describe('instance method', () => {
668
+ test('case 1', () => {
669
+ const s0 = ISet.create([1, 2, 3] as const);
670
+ const s1 = ISet.create([3, 4, 5] as const);
671
+
672
+ expectType<typeof s0.union, (other: ISet<number>) => ISet<number>>('<=');
673
+ expect(s0.union(s1)).toStrictEqual(ISet.create([1, 2, 3, 4, 5]));
674
+ });
675
+
676
+ test('case 2', () => {
677
+ const s0 = ISet.create([1, 2, 3]);
678
+ const s1 = ISet.create<number>([]);
679
+
680
+ expect(s0.union(s1)).toStrictEqual(ISet.create([1, 2, 3]));
681
+ });
682
+
683
+ test('case 3', () => {
684
+ const s0 = ISet.create<number>([]);
685
+ const s1 = ISet.create([1, 2, 3]);
686
+
687
+ expect(s0.union(s1)).toStrictEqual(ISet.create([1, 2, 3]));
688
+ });
689
+
690
+ test('should return combined elements using instance method', () => {
691
+ const set1 = ISet.create([1, 2, 3]);
692
+ const set2 = ISet.create([3, 4, 5]);
693
+ const result = set1.union(set2);
694
+
695
+ expect(result.size).toBe(5);
696
+ expect(result.has(1)).toBe(true);
697
+ expect(result.has(2)).toBe(true);
698
+ expect(result.has(3)).toBe(true);
699
+ expect(result.has(4)).toBe(true);
700
+ expect(result.has(5)).toBe(true);
701
+ });
702
+ });
703
+ });
704
+
705
+ describe('ISet.forEach', () => {
706
+ test('case 1', () => {
707
+ const s0 = ISet.create([1, 2, 3] as const);
708
+
709
+ expectType<
710
+ typeof s0.forEach,
711
+ (callback: (value: 1 | 2 | 3) => void) => void
712
+ >('<=');
713
+
714
+ const result: (1 | 2 | 3)[] = [];
715
+ s0.forEach((x) => {
716
+ result.push(x);
717
+ });
718
+
719
+ expect(result.sort((a, b) => a - b)).toStrictEqual([1, 2, 3]);
720
+ });
721
+
722
+ test('should execute callback for each element', () => {
723
+ const set = ISet.create([1, 2, 3]);
724
+ const collected: number[] = [];
725
+
726
+ set.forEach((value) => {
727
+ collected.push(value);
728
+ });
729
+
730
+ expect(collected.sort((a, b) => a - b)).toStrictEqual([1, 2, 3]);
731
+ });
732
+
733
+ test('should not call callback for empty set', () => {
734
+ const set = ISet.create<number>([]);
735
+ let callCount = 0;
736
+
737
+ set.forEach(() => {
738
+ callCount += 1;
739
+ });
740
+
741
+ expect(callCount).toBe(0);
742
+ });
743
+ });
744
+
745
+ describe('ISet.keys', () => {
746
+ test('case 1', () => {
747
+ const s0 = ISet.create([1, 2, 3] as const);
748
+
749
+ expectType<typeof s0.keys, () => IterableIterator<1 | 2 | 3>>('<=');
750
+
751
+ const result: (1 | 2 | 3)[] = [];
752
+ for (const x of s0.keys()) {
753
+ result.push(x);
754
+ }
755
+
756
+ expect(result.sort((a, b) => a - b)).toStrictEqual([1, 2, 3]);
757
+ });
758
+ });
759
+
760
+ describe('ISet.values', () => {
761
+ test('case 1', () => {
762
+ const s0 = ISet.create([1, 2, 3] as const);
763
+
764
+ expectType<typeof s0.values, () => IterableIterator<1 | 2 | 3>>('<=');
765
+
766
+ const result: (1 | 2 | 3)[] = [];
767
+ for (const x of s0.values()) {
768
+ result.push(x);
769
+ }
770
+
771
+ expect(result.sort((a, b) => a - b)).toStrictEqual([1, 2, 3]);
772
+ });
773
+ });
774
+
775
+ describe('ISet.entries', () => {
776
+ test('case 1', () => {
777
+ const s0 = ISet.create([1, 2, 3] as const);
778
+
779
+ expectType<
780
+ typeof s0.entries,
781
+ () => IterableIterator<readonly [1 | 2 | 3, 1 | 2 | 3]>
782
+ >('<=');
783
+
784
+ const result: [1 | 2 | 3, 1 | 2 | 3][] = [];
785
+ for (const x of s0.entries()) {
786
+ result.push([x[0], x[1]]);
787
+ }
788
+
789
+ expect(result.sort((a, b) => a[0] - b[0])).toStrictEqual([
790
+ [1, 1],
791
+ [2, 2],
792
+ [3, 3],
793
+ ]);
794
+ });
795
+ });
796
+
797
+ describe('ISet.toArray', () => {
798
+ test('case 1', () => {
799
+ const s0 = ISet.create([1, 2, 3] as const);
800
+
801
+ expectType<typeof s0.toArray, () => readonly (1 | 2 | 3)[]>('<=');
802
+ expect([...s0.toArray()].sort((a, b) => a - b)).toStrictEqual([1, 2, 3]);
803
+ });
804
+
805
+ test('case 2', () => {
806
+ const s0 = ISet.create<number>([]);
807
+
808
+ expect(s0.toArray()).toStrictEqual([]);
809
+ });
810
+
811
+ test('should convert set to array', () => {
812
+ const set = ISet.create([1, 3, 2]);
813
+ const array = set.toArray();
814
+
815
+ expect(array.length).toBe(3);
816
+ expect([...array].sort((a, b) => a - b)).toStrictEqual([1, 2, 3]);
817
+ });
818
+ });
819
+
820
+ describe('ISet.toRawSet', () => {
821
+ test('should return underlying ReadonlySet', () => {
822
+ const set = ISet.create([1, 2, 3]);
823
+ const rawSet = set.toRawSet();
824
+
825
+ expect(rawSet.size).toBe(3);
826
+ expect(rawSet.has(1)).toBe(true);
827
+ expect(rawSet.has(2)).toBe(true);
828
+ expect(rawSet.has(3)).toBe(true);
829
+ });
830
+
831
+ test('should return empty ReadonlySet for empty ISet', () => {
832
+ const set = ISet.create<number>([]);
833
+ const rawSet = set.toRawSet();
834
+
835
+ expect(rawSet.size).toBe(0);
836
+ });
837
+ });
838
+
839
+ describe('ISet.equal', () => {
840
+ test('should return true for equal sets', () => {
841
+ const set1 = ISet.create([1, 2, 3]);
842
+ const set2 = ISet.create([3, 2, 1]); // Different order
843
+ expect(ISet.equal(set1, set2)).toBe(true);
844
+ });
845
+
846
+ test('should return false for sets with different sizes', () => {
847
+ const set1 = ISet.create<'a' | 'b' | 'c' | 'd'>(['a', 'b']);
848
+ const set2 = ISet.create<'a' | 'b' | 'c' | 'd'>(['a', 'b', 'c']);
849
+ expect(ISet.equal(set1, set2)).toBe(false);
850
+ });
851
+
852
+ test('should return false for sets with different elements', () => {
853
+ const set1 = ISet.create<'a' | 'b' | 'c' | 'd'>(['a', 'b', 'c']);
854
+ const set2 = ISet.create<'a' | 'b' | 'c' | 'd'>(['a', 'b', 'd']);
855
+ expect(ISet.equal(set1, set2)).toBe(false);
856
+ });
857
+
858
+ test('should return true for empty sets', () => {
859
+ const set1 = ISet.create<string>([]);
860
+ const set2 = ISet.create<string>([]);
861
+ expect(ISet.equal(set1, set2)).toBe(true);
862
+ });
863
+
864
+ test('should handle sets with special values', () => {
865
+ const set1 = ISet.create([Number.NaN, null, undefined]);
866
+ const set2 = ISet.create([undefined, Number.NaN, null]);
867
+ expect(ISet.equal(set1, set2)).toBe(true);
868
+ });
869
+ });
870
+
871
+ describe('ISet.diff', () => {
872
+ test('should compute differences between sets', () => {
873
+ const oldSet = ISet.create<'a' | 'b' | 'c' | 'd'>(['a', 'b', 'c']);
874
+ const newSet = ISet.create<'a' | 'b' | 'c' | 'd'>(['b', 'c', 'd']);
875
+
876
+ const diff = ISet.diff(oldSet, newSet);
877
+
878
+ expect(diff.deleted.size).toBe(1);
879
+ expect(diff.deleted.has('a')).toBe(true);
880
+
881
+ expect(diff.added.size).toBe(1);
882
+ expect(diff.added.has('d')).toBe(true);
883
+ });
884
+
885
+ test('should handle no changes', () => {
886
+ const set1 = ISet.create(['a', 'b', 'c']);
887
+ const set2 = ISet.create(['a', 'b', 'c']);
888
+
889
+ const diff = ISet.diff(set1, set2);
890
+
891
+ expect(diff.deleted.isEmpty).toBe(true);
892
+ expect(diff.added.isEmpty).toBe(true);
893
+ });
894
+
895
+ test('should handle complete replacement', () => {
896
+ const oldSet = ISet.create<'a' | 'b' | 'c' | 'd'>(['a', 'b']);
897
+ const newSet = ISet.create<'a' | 'b' | 'c' | 'd'>(['c', 'd']);
898
+
899
+ const diff = ISet.diff(oldSet, newSet);
900
+
901
+ expect(diff.deleted.size).toBe(2);
902
+ expect(diff.deleted.has('a')).toBe(true);
903
+ expect(diff.deleted.has('b')).toBe(true);
904
+
905
+ expect(diff.added.size).toBe(2);
906
+ expect(diff.added.has('c')).toBe(true);
907
+ expect(diff.added.has('d')).toBe(true);
908
+ });
909
+
910
+ test('should handle empty sets', () => {
911
+ const emptySet = ISet.create<string>([]);
912
+ const nonEmptySet = ISet.create<string>(['a', 'b']);
913
+
914
+ const diff1 = ISet.diff(emptySet, nonEmptySet);
915
+ expect(diff1.deleted.isEmpty).toBe(true);
916
+ expect(diff1.added.size).toBe(2);
917
+
918
+ const diff2 = ISet.diff(nonEmptySet, emptySet);
919
+ expect(diff2.deleted.size).toBe(2);
920
+ expect(diff2.added.isEmpty).toBe(true);
921
+ });
922
+ });
923
+
924
+ describe('ISet.withMutations', () => {
925
+ test('should apply multiple mutations', () => {
926
+ const set = ISet.create<string>(['a', 'b']);
927
+
928
+ const updated = set.withMutations([
929
+ { type: 'add', key: 'c' },
930
+ { type: 'delete', key: 'a' },
931
+ { type: 'add', key: 'd' },
932
+ ]);
933
+
934
+ expect(updated.size).toBe(3);
935
+ expect(updated.has('b')).toBe(true);
936
+ expect(updated.has('c')).toBe(true);
937
+ expect(updated.has('d')).toBe(true);
938
+ expect(updated.has('a')).toBe(false);
939
+ });
940
+
941
+ test('should handle empty mutations array', () => {
942
+ const set = ISet.create(['a', 'b', 'c']);
943
+ const updated = set.withMutations([]);
944
+ expect(updated.size).toBe(set.size);
945
+ expect(ISet.equal(set, updated)).toBe(true);
946
+ });
947
+
948
+ test('should handle duplicate operations', () => {
949
+ const set = ISet.create<'a' | 'b'>(['a']);
950
+ const updated = set.withMutations([
951
+ { type: 'add', key: 'a' }, // Already exists
952
+ { type: 'delete', key: 'b' }, // Doesn't exist
953
+ { type: 'add', key: 'b' },
954
+ ]);
955
+ expect(updated.size).toBe(2);
956
+ expect(updated.has('a')).toBe(true);
957
+ expect(updated.has('b')).toBe(true);
958
+ });
959
+ });
960
+
961
+ describe('iterable functionality', () => {
962
+ test('should work with for-of loops', () => {
963
+ const set = ISet.create([1, 2, 3]);
964
+ const collected: number[] = [];
965
+
966
+ for (const value of set) {
967
+ collected.push(value);
968
+ }
969
+
970
+ expect(collected.sort((a, b) => a - b)).toStrictEqual([1, 2, 3]);
971
+ });
972
+
973
+ test('should work with spread operator', () => {
974
+ const set = ISet.create([1, 2, 3]);
975
+ const array = [...set];
976
+
977
+ expect([...array].sort((a, b) => a - b)).toStrictEqual([1, 2, 3]);
978
+ });
979
+
980
+ test('should work with Array.from', () => {
981
+ const set = ISet.create([1, 2, 3]);
982
+ const array = Array.from(set);
983
+
984
+ expect([...array].sort((a, b) => a - b)).toStrictEqual([1, 2, 3]);
985
+ });
986
+
987
+ test('should work with destructuring', () => {
988
+ const set = ISet.create([1, 2]);
989
+ const values = [...set];
990
+
991
+ expect(values.sort((a, b) => a - b)).toStrictEqual([1, 2]);
992
+ });
993
+ });
994
+
995
+ describe('edge cases', () => {
996
+ test('should handle NaN correctly', () => {
997
+ const set = ISet.create([Number.NaN, 1, 2]);
998
+ expect(set.has(Number.NaN)).toBe(true);
999
+ expect(set.size).toBe(3);
1000
+ });
1001
+
1002
+ test('should handle boolean values', () => {
1003
+ const set = ISet.create([true, false, true]);
1004
+ expect(set.size).toBe(2);
1005
+ expect(set.has(true)).toBe(true);
1006
+ expect(set.has(false)).toBe(true);
1007
+ });
1008
+
1009
+ test('should handle null and undefined', () => {
1010
+ const set = ISet.create([null, undefined, null]);
1011
+ expect(set.size).toBe(2);
1012
+ expect(set.has(null)).toBe(true);
1013
+ expect(set.has(undefined)).toBe(true);
1014
+ });
1015
+
1016
+ test('should handle symbols by reference', () => {
1017
+ const sym1 = Symbol('test');
1018
+ const sym2 = Symbol('test'); // Different symbol, same description
1019
+ const set = ISet.create([sym1, sym2]);
1020
+
1021
+ expect(set.size).toBe(2);
1022
+ expect(set.has(sym1)).toBe(true);
1023
+ expect(set.has(sym2)).toBe(true);
1024
+ expect(set.has(Symbol('test'))).toBe(false); // Different symbol
1025
+ });
1026
+ });
1027
+
1028
+ describe('immutability', () => {
1029
+ test('should not modify original set when adding', () => {
1030
+ const original = ISet.create<number>([1, 2, 3]);
1031
+ const modified = original.add(4);
1032
+
1033
+ expect(original.size).toBe(3);
1034
+ expect(modified.size).toBe(4);
1035
+ expect(original.has(4)).toBe(false);
1036
+ expect(modified.has(4)).toBe(true);
1037
+ });
1038
+
1039
+ test('should not modify original set when deleting', () => {
1040
+ const original = ISet.create([1, 2, 3]);
1041
+ const modified = original.delete(2);
1042
+
1043
+ expect(original.size).toBe(3);
1044
+ expect(modified.size).toBe(2);
1045
+ expect(original.has(2)).toBe(true);
1046
+ expect(modified.has(2)).toBe(false);
1047
+ });
1048
+
1049
+ test('should not modify original set when filtering', () => {
1050
+ const original = ISet.create([1, 2, 3, 4, 5]);
1051
+ const filtered = original.filter((x) => x % 2 === 0);
1052
+
1053
+ expect(original.size).toBe(5);
1054
+ expect(filtered.size).toBe(2);
1055
+ expect(original.has(1)).toBe(true);
1056
+ expect(filtered.has(1)).toBe(false);
1057
+ });
1058
+
1059
+ test('should not modify original set when mapping', () => {
1060
+ const original = ISet.create([1, 2, 3]);
1061
+ const mapped = original.map((x) => x * 2);
1062
+
1063
+ expect(original.size).toBe(3);
1064
+ expect(mapped.size).toBe(3);
1065
+ expect(original.has(1)).toBe(true);
1066
+ expect(mapped.has(1)).toBe(false);
1067
+ expect(mapped.has(2)).toBe(true);
1068
+ });
1069
+
1070
+ test('should not modify original sets during set operations', () => {
1071
+ const set1 = ISet.create<number>([1, 2, 3]);
1072
+ const set2 = ISet.create<number>([3, 4, 5]);
1073
+
1074
+ const union = set1.union(set2);
1075
+ const intersection = set1.intersect(set2);
1076
+ const difference = set1.subtract(set2);
1077
+
1078
+ expect(set1.size).toBe(3);
1079
+ expect(set2.size).toBe(3);
1080
+ expect(union.size).toBe(5);
1081
+ expect(intersection.size).toBe(1);
1082
+ expect(difference.size).toBe(2);
1083
+ });
1084
+ });