ts-data-forge 4.1.0 → 5.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.
- package/dist/json/json.d.mts +9 -3
- package/dist/json/json.d.mts.map +1 -1
- package/dist/json/json.mjs +6 -0
- package/dist/json/json.mjs.map +1 -1
- package/package.json +13 -13
- package/src/array/impl/array-utils-creation.test.mts +187 -74
- package/src/array/impl/array-utils-element-access.test.mts +19 -3
- package/src/array/impl/array-utils-iterators.test.mts +44 -24
- package/src/array/impl/array-utils-modification.test.mts +36 -33
- package/src/array/impl/array-utils-reducing-value.test.mts +47 -16
- package/src/array/impl/array-utils-search.test.mts +42 -9
- package/src/array/impl/array-utils-set-op.test.mts +54 -26
- package/src/array/impl/array-utils-size.test.mts +1 -0
- package/src/array/impl/array-utils-slice-clamped.test.mts +20 -11
- package/src/array/impl/array-utils-slicing.test.mts +27 -21
- package/src/array/impl/array-utils-transformation.test.mts +140 -92
- package/src/array/impl/array-utils-validation.test.mts +58 -10
- package/src/array/impl/array.test.mts +5 -5
- package/src/collections/imap-mapped.test.mts +63 -18
- package/src/collections/imap.test.mts +74 -26
- package/src/collections/iset-mapped.test.mts +81 -30
- package/src/collections/iset.test.mts +168 -68
- package/src/collections/queue.test.mts +32 -1
- package/src/collections/stack.test.mts +22 -8
- package/src/functional/match.test.mts +1 -1
- package/src/functional/optional.test.mts +61 -4
- package/src/functional/pipe.test.mts +10 -1
- package/src/functional/result.test.mts +127 -4
- package/src/functional/ternary-result.test.mts +34 -18
- package/src/guard/is-non-empty-string.test.mts +5 -2
- package/src/guard/is-non-null-object.test.mts +3 -5
- package/src/guard/is-primitive.test.mts +5 -3
- package/src/guard/is-record.test.mts +1 -1
- package/src/guard/is-type.test.mts +35 -20
- package/src/guard/key-is-in.test.mts +1 -1
- package/src/iterator/range.test.mts +22 -16
- package/src/json/json.mts +9 -3
- package/src/json/json.test.mts +140 -64
- package/src/number/branded-types/finite-number.test.mts +3 -2
- package/src/number/branded-types/int.test.mts +4 -3
- package/src/number/branded-types/int16.test.mts +9 -3
- package/src/number/branded-types/int32.test.mts +9 -3
- package/src/number/branded-types/non-negative-finite-number.test.mts +6 -4
- package/src/number/branded-types/non-negative-int16.test.mts +8 -3
- package/src/number/branded-types/non-negative-int32.test.mts +8 -3
- package/src/number/branded-types/non-zero-finite-number.test.mts +6 -3
- package/src/number/branded-types/non-zero-int.test.mts +6 -3
- package/src/number/branded-types/non-zero-int16.test.mts +9 -3
- package/src/number/branded-types/non-zero-int32.test.mts +9 -3
- package/src/number/branded-types/non-zero-safe-int.test.mts +10 -3
- package/src/number/branded-types/non-zero-uint16.test.mts +8 -3
- package/src/number/branded-types/non-zero-uint32.test.mts +8 -3
- package/src/number/branded-types/positive-finite-number.test.mts +7 -3
- package/src/number/branded-types/positive-int.test.mts +5 -3
- package/src/number/branded-types/positive-int16.test.mts +8 -3
- package/src/number/branded-types/positive-int32.test.mts +8 -3
- package/src/number/branded-types/positive-safe-int.test.mts +8 -3
- package/src/number/branded-types/positive-uint16.test.mts +8 -3
- package/src/number/branded-types/positive-uint32.test.mts +8 -3
- package/src/number/branded-types/safe-int.test.mts +8 -2
- package/src/number/branded-types/safe-uint.test.mts +8 -3
- package/src/number/branded-types/uint.test.mts +5 -3
- package/src/number/branded-types/uint16.test.mts +8 -3
- package/src/number/branded-types/uint32.test.mts +8 -3
- package/src/number/enum/int8.test.mts +8 -3
- package/src/number/enum/uint8.test.mts +6 -3
- package/src/number/num.test.mts +16 -2
- package/src/object/object.test.mts +26 -13
- package/src/others/cast-mutable.test.mts +10 -8
- package/src/others/cast-readonly.test.mts +9 -5
- package/src/others/if-then.test.mts +4 -1
- package/src/others/map-nullable.test.mts +28 -1
- package/src/others/memoize-function.test.mts +20 -17
- package/src/others/tuple.test.mts +3 -2
- package/src/others/unknown-to-string.test.mts +15 -2
- package/src/promise/promise.test.mts +6 -1
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from './array-utils-reducing-value.mjs';
|
|
16
16
|
|
|
17
17
|
describe('Arr reducing value', () => {
|
|
18
|
-
describe(
|
|
18
|
+
describe(min, () => {
|
|
19
19
|
{
|
|
20
20
|
const xs = [3, 5, 4] as const;
|
|
21
21
|
const result = min(xs);
|
|
@@ -24,6 +24,7 @@ describe('Arr reducing value', () => {
|
|
|
24
24
|
|
|
25
25
|
test('case 1', () => {
|
|
26
26
|
expect(Optional.isSome(result)).toBe(true);
|
|
27
|
+
|
|
27
28
|
if (Optional.isSome(result)) {
|
|
28
29
|
expect(result.value).toBe(3);
|
|
29
30
|
}
|
|
@@ -37,6 +38,7 @@ describe('Arr reducing value', () => {
|
|
|
37
38
|
|
|
38
39
|
test('case 2', () => {
|
|
39
40
|
expect(Optional.isSome(result)).toBe(true);
|
|
41
|
+
|
|
40
42
|
if (Optional.isSome(result)) {
|
|
41
43
|
expect(result.value).toBe(3);
|
|
42
44
|
}
|
|
@@ -50,6 +52,7 @@ describe('Arr reducing value', () => {
|
|
|
50
52
|
|
|
51
53
|
test('case 3', () => {
|
|
52
54
|
expect(Optional.isSome(result)).toBe(true);
|
|
55
|
+
|
|
53
56
|
if (Optional.isSome(result)) {
|
|
54
57
|
expect(result.value).toBe(3);
|
|
55
58
|
}
|
|
@@ -57,7 +60,7 @@ describe('Arr reducing value', () => {
|
|
|
57
60
|
}
|
|
58
61
|
});
|
|
59
62
|
|
|
60
|
-
describe(
|
|
63
|
+
describe(max, () => {
|
|
61
64
|
const xs = [3, 5, 4] as const;
|
|
62
65
|
const result = max(xs, (a, b) => a - b);
|
|
63
66
|
|
|
@@ -65,6 +68,7 @@ describe('Arr reducing value', () => {
|
|
|
65
68
|
|
|
66
69
|
test('case 1', () => {
|
|
67
70
|
expect(Optional.isSome(result)).toBe(true);
|
|
71
|
+
|
|
68
72
|
if (Optional.isSome(result)) {
|
|
69
73
|
expect(result.value).toBe(5);
|
|
70
74
|
}
|
|
@@ -73,7 +77,9 @@ describe('Arr reducing value', () => {
|
|
|
73
77
|
test('case 2: no comparator', () => {
|
|
74
78
|
const res = max(xs);
|
|
75
79
|
expectType<typeof res, Some<3 | 4 | 5>>('=');
|
|
80
|
+
|
|
76
81
|
expect(Optional.isSome(res)).toBe(true);
|
|
82
|
+
|
|
77
83
|
if (Optional.isSome(res)) {
|
|
78
84
|
expect(res.value).toBe(5);
|
|
79
85
|
}
|
|
@@ -83,7 +89,9 @@ describe('Arr reducing value', () => {
|
|
|
83
89
|
const arr: readonly number[] = [1, 5, 2];
|
|
84
90
|
const res = max(arr);
|
|
85
91
|
expectType<typeof res, Optional<number>>('=');
|
|
92
|
+
|
|
86
93
|
expect(Optional.isSome(res)).toBe(true);
|
|
94
|
+
|
|
87
95
|
if (Optional.isSome(res)) {
|
|
88
96
|
expect(res.value).toBe(5);
|
|
89
97
|
}
|
|
@@ -93,11 +101,12 @@ describe('Arr reducing value', () => {
|
|
|
93
101
|
const arr: readonly number[] = [];
|
|
94
102
|
const res = max(arr);
|
|
95
103
|
expectType<typeof res, Optional<number>>('=');
|
|
104
|
+
|
|
96
105
|
expect(Optional.isNone(res)).toBe(true);
|
|
97
106
|
});
|
|
98
107
|
});
|
|
99
108
|
|
|
100
|
-
describe(
|
|
109
|
+
describe(minBy, () => {
|
|
101
110
|
const xs = [
|
|
102
111
|
{ x: 5, y: 1 },
|
|
103
112
|
{ x: 4, y: 1 },
|
|
@@ -125,8 +134,9 @@ describe('Arr reducing value', () => {
|
|
|
125
134
|
|
|
126
135
|
test('case 1', () => {
|
|
127
136
|
expect(Optional.isSome(result)).toBe(true);
|
|
137
|
+
|
|
128
138
|
if (Optional.isSome(result)) {
|
|
129
|
-
|
|
139
|
+
assert.deepStrictEqual(result.value, { x: 1, y: 2 });
|
|
130
140
|
}
|
|
131
141
|
});
|
|
132
142
|
|
|
@@ -134,6 +144,7 @@ describe('Arr reducing value', () => {
|
|
|
134
144
|
const arr: readonly { x: number }[] = [];
|
|
135
145
|
const res = minBy(arr, (a) => a.x);
|
|
136
146
|
expectType<typeof res, Optional<{ x: number }>>('=');
|
|
147
|
+
|
|
137
148
|
expect(Optional.isNone(res)).toBe(true);
|
|
138
149
|
});
|
|
139
150
|
|
|
@@ -162,13 +173,14 @@ describe('Arr reducing value', () => {
|
|
|
162
173
|
>('=');
|
|
163
174
|
|
|
164
175
|
expect(Optional.isSome(res)).toBe(true);
|
|
176
|
+
|
|
165
177
|
if (Optional.isSome(res)) {
|
|
166
|
-
|
|
178
|
+
assert.deepStrictEqual(res.value, { name: 'apple', score: 10 });
|
|
167
179
|
}
|
|
168
180
|
});
|
|
169
181
|
});
|
|
170
182
|
|
|
171
|
-
describe(
|
|
183
|
+
describe(maxBy, () => {
|
|
172
184
|
const xs = [
|
|
173
185
|
{ x: 5, y: 1 },
|
|
174
186
|
{ x: 4, y: 1 },
|
|
@@ -196,8 +208,9 @@ describe('Arr reducing value', () => {
|
|
|
196
208
|
|
|
197
209
|
test('case 1', () => {
|
|
198
210
|
expect(Optional.isSome(result)).toBe(true);
|
|
211
|
+
|
|
199
212
|
if (Optional.isSome(result)) {
|
|
200
|
-
|
|
213
|
+
assert.deepStrictEqual(result.value, { x: 6, y: 1 });
|
|
201
214
|
}
|
|
202
215
|
});
|
|
203
216
|
|
|
@@ -205,6 +218,7 @@ describe('Arr reducing value', () => {
|
|
|
205
218
|
const arr: readonly { x: number }[] = [];
|
|
206
219
|
const res = maxBy(arr, (a) => a.x);
|
|
207
220
|
expectType<typeof res, Optional<{ x: number }>>('=');
|
|
221
|
+
|
|
208
222
|
expect(Optional.isNone(res)).toBe(true);
|
|
209
223
|
});
|
|
210
224
|
|
|
@@ -233,13 +247,14 @@ describe('Arr reducing value', () => {
|
|
|
233
247
|
>('=');
|
|
234
248
|
|
|
235
249
|
expect(Optional.isSome(res)).toBe(true);
|
|
250
|
+
|
|
236
251
|
if (Optional.isSome(res)) {
|
|
237
|
-
|
|
252
|
+
assert.deepStrictEqual(res.value, { name: 'cherry', score: 12 });
|
|
238
253
|
}
|
|
239
254
|
});
|
|
240
255
|
});
|
|
241
256
|
|
|
242
|
-
describe(
|
|
257
|
+
describe(count, () => {
|
|
243
258
|
const xs = [
|
|
244
259
|
{ x: 1, y: 1 },
|
|
245
260
|
{ x: 2, y: 1 },
|
|
@@ -261,11 +276,12 @@ describe('Arr reducing value', () => {
|
|
|
261
276
|
const arr: readonly number[] = [];
|
|
262
277
|
const res = count(arr, (x) => x > 0);
|
|
263
278
|
expectType<typeof res, Uint32>('=');
|
|
279
|
+
|
|
264
280
|
expect(res).toBe(0);
|
|
265
281
|
});
|
|
266
282
|
});
|
|
267
283
|
|
|
268
|
-
describe(
|
|
284
|
+
describe(countBy, () => {
|
|
269
285
|
const xs = [
|
|
270
286
|
{ x: 1, y: 1 },
|
|
271
287
|
{ x: 2, y: 1 },
|
|
@@ -280,8 +296,9 @@ describe('Arr reducing value', () => {
|
|
|
280
296
|
expectType<typeof result, IMap<1 | 2 | 3, 0 | 1 | 2 | 3 | 4 | 5>>('=');
|
|
281
297
|
|
|
282
298
|
test('case 1', () => {
|
|
283
|
-
|
|
284
|
-
|
|
299
|
+
assert.deepStrictEqual(
|
|
300
|
+
result,
|
|
301
|
+
IMap.create<1 | 2 | 3, 0 | 1 | 2 | 3 | 4 | 5>([
|
|
285
302
|
[1, 3],
|
|
286
303
|
[2, 2],
|
|
287
304
|
[3, 1],
|
|
@@ -293,20 +310,23 @@ describe('Arr reducing value', () => {
|
|
|
293
310
|
const arr: readonly { x: number }[] = [];
|
|
294
311
|
const res = countBy(arr, (a) => a.x);
|
|
295
312
|
expectType<typeof res, IMap<number, Uint32>>('=');
|
|
313
|
+
|
|
296
314
|
expect(res.size).toBe(0);
|
|
297
315
|
});
|
|
298
316
|
});
|
|
299
317
|
|
|
300
|
-
describe(
|
|
318
|
+
describe(foldl, () => {
|
|
301
319
|
test('empty array', () => {
|
|
302
320
|
const result = foldl([], (acc, curr: number) => acc + curr, 0);
|
|
303
321
|
expectType<typeof result, number>('=');
|
|
322
|
+
|
|
304
323
|
expect(result).toBe(0);
|
|
305
324
|
});
|
|
306
325
|
|
|
307
326
|
test('sum numbers', () => {
|
|
308
327
|
const result = foldl([1, 2, 3] as const, (acc, curr) => acc + curr, 0);
|
|
309
328
|
expectType<typeof result, number>('=');
|
|
329
|
+
|
|
310
330
|
expect(result).toBe(6);
|
|
311
331
|
});
|
|
312
332
|
|
|
@@ -317,14 +337,16 @@ describe('Arr reducing value', () => {
|
|
|
317
337
|
'',
|
|
318
338
|
);
|
|
319
339
|
expectType<typeof result, string>('=');
|
|
340
|
+
|
|
320
341
|
expect(result).toBe('abc');
|
|
321
342
|
});
|
|
322
343
|
});
|
|
323
344
|
|
|
324
|
-
describe(
|
|
345
|
+
describe(foldr, () => {
|
|
325
346
|
test('empty array', () => {
|
|
326
347
|
const result = foldr([], (acc, curr: number) => acc + curr, 0);
|
|
327
348
|
expectType<typeof result, number>('=');
|
|
349
|
+
|
|
328
350
|
expect(result).toBe(0);
|
|
329
351
|
});
|
|
330
352
|
|
|
@@ -332,6 +354,7 @@ describe('Arr reducing value', () => {
|
|
|
332
354
|
// (1 - (2 - (3 - 0))) = 1 - (2 - 3) = 1 - (-1) = 2
|
|
333
355
|
const result = foldr([1, 2, 3] as const, (acc, curr) => curr - acc, 0);
|
|
334
356
|
expectType<typeof result, number>('=');
|
|
357
|
+
|
|
335
358
|
expect(result).toBe(2); // 3 - (2 - (1 - 0)) = 3 - (2 - 1) = 3 - 1 = 2. No, this is (acc, curr) => acc - curr.
|
|
336
359
|
// The callback is (previousValue: S, currentValue: A) => S
|
|
337
360
|
// So it's initialValue for S.
|
|
@@ -347,6 +370,7 @@ describe('Arr reducing value', () => {
|
|
|
347
370
|
'',
|
|
348
371
|
);
|
|
349
372
|
expectType<typeof result, string>('=');
|
|
373
|
+
|
|
350
374
|
expect(result).toBe('abc'); // c + (b + (a + "")) = cba. No, it's curr + acc.
|
|
351
375
|
// Iteration 1: prev = "", curr = "c". Result = "c" + "" = "c".
|
|
352
376
|
// Iteration 2: prev = "c", curr = "b". Result = "b" + "c" = "bc".
|
|
@@ -354,38 +378,43 @@ describe('Arr reducing value', () => {
|
|
|
354
378
|
});
|
|
355
379
|
});
|
|
356
380
|
|
|
357
|
-
describe(
|
|
381
|
+
describe(sum, () => {
|
|
358
382
|
test('empty array', () => {
|
|
359
383
|
const result = sum([]);
|
|
360
384
|
expectType<typeof result, 0>('=');
|
|
385
|
+
|
|
361
386
|
expect(result).toBe(0);
|
|
362
387
|
});
|
|
363
388
|
|
|
364
389
|
test('one element array', () => {
|
|
365
390
|
const result = sum([23]);
|
|
366
391
|
expectType<typeof result, 23>('=');
|
|
392
|
+
|
|
367
393
|
expect(result).toBe(23);
|
|
368
394
|
});
|
|
369
395
|
|
|
370
396
|
test('positive numbers', () => {
|
|
371
397
|
const result = sum([1, 2, 3, 4, 5] as const);
|
|
372
398
|
expectType<typeof result, number>('=');
|
|
399
|
+
|
|
373
400
|
expect(result).toBe(15);
|
|
374
401
|
});
|
|
375
402
|
|
|
376
403
|
test('mixed numbers', () => {
|
|
377
404
|
const result = sum([1, -2, 3, 0, -5] as const);
|
|
378
405
|
expectType<typeof result, number>('=');
|
|
406
|
+
|
|
379
407
|
expect(result).toBe(-3);
|
|
380
408
|
});
|
|
381
409
|
});
|
|
382
410
|
|
|
383
|
-
describe(
|
|
411
|
+
describe(join, () => {
|
|
384
412
|
test('should join array elements', () => {
|
|
385
413
|
const arr = ['Hello', 'World'];
|
|
386
414
|
const result = join(arr, ' ');
|
|
387
415
|
|
|
388
416
|
expect(Result.isOk(result)).toBe(true);
|
|
417
|
+
|
|
389
418
|
if (Result.isOk(result)) {
|
|
390
419
|
expect(result.value).toBe('Hello World');
|
|
391
420
|
}
|
|
@@ -396,6 +425,7 @@ describe('Arr reducing value', () => {
|
|
|
396
425
|
const result = join(arr, '');
|
|
397
426
|
|
|
398
427
|
expect(Result.isOk(result)).toBe(true);
|
|
428
|
+
|
|
399
429
|
if (Result.isOk(result)) {
|
|
400
430
|
expect(result.value).toBe('abc');
|
|
401
431
|
}
|
|
@@ -406,6 +436,7 @@ describe('Arr reducing value', () => {
|
|
|
406
436
|
const result = join(arr);
|
|
407
437
|
|
|
408
438
|
expect(Result.isOk(result)).toBe(true);
|
|
439
|
+
|
|
409
440
|
if (Result.isOk(result)) {
|
|
410
441
|
expect(result.value).toBe('a,b,c');
|
|
411
442
|
}
|
|
@@ -12,10 +12,11 @@ import {
|
|
|
12
12
|
} from './array-utils-search.mjs';
|
|
13
13
|
|
|
14
14
|
describe('Arr search operations', () => {
|
|
15
|
-
describe(
|
|
15
|
+
describe(find, () => {
|
|
16
16
|
test('should find first element matching predicate', () => {
|
|
17
17
|
const numbers = [1, 2, 3, 4, 5];
|
|
18
18
|
const firstEven = find(numbers, (n) => n % 2 === 0);
|
|
19
|
+
|
|
19
20
|
expect(Optional.isSome(firstEven)).toBe(true);
|
|
20
21
|
expect(Optional.unwrap(firstEven)).toBe(2);
|
|
21
22
|
});
|
|
@@ -23,6 +24,7 @@ describe('Arr search operations', () => {
|
|
|
23
24
|
test('should return None when no element matches', () => {
|
|
24
25
|
const odds = [1, 3, 5];
|
|
25
26
|
const firstEven = find(odds, (n) => n % 2 === 0);
|
|
27
|
+
|
|
26
28
|
expect(Optional.isNone(firstEven)).toBe(true);
|
|
27
29
|
});
|
|
28
30
|
|
|
@@ -46,6 +48,7 @@ describe('Arr search operations', () => {
|
|
|
46
48
|
);
|
|
47
49
|
|
|
48
50
|
expectType<typeof firstString, Optional<string>>('=');
|
|
51
|
+
|
|
49
52
|
expect(Optional.isSome(firstString)).toBe(true);
|
|
50
53
|
expect(Optional.unwrap(firstString)).toBe('a');
|
|
51
54
|
});
|
|
@@ -54,6 +57,7 @@ describe('Arr search operations', () => {
|
|
|
54
57
|
const numbers = [10, 20, 30];
|
|
55
58
|
const foundWithIndex = find(numbers, (value, index, arr) => {
|
|
56
59
|
expect(arr).toBe(numbers);
|
|
60
|
+
|
|
57
61
|
return index === 1 && value === 20;
|
|
58
62
|
});
|
|
59
63
|
|
|
@@ -63,20 +67,23 @@ describe('Arr search operations', () => {
|
|
|
63
67
|
test('should return first match when multiple elements match', () => {
|
|
64
68
|
const numbers = [2, 4, 6, 8];
|
|
65
69
|
const firstEven = find(numbers, (n) => n % 2 === 0);
|
|
70
|
+
|
|
66
71
|
expect(Optional.unwrap(firstEven)).toBe(2);
|
|
67
72
|
});
|
|
68
73
|
|
|
69
74
|
test('should work with empty array', () => {
|
|
70
75
|
const empty: readonly number[] = [];
|
|
71
76
|
const result = find(empty, () => true);
|
|
77
|
+
|
|
72
78
|
expect(Optional.isNone(result)).toBe(true);
|
|
73
79
|
});
|
|
74
80
|
});
|
|
75
81
|
|
|
76
|
-
describe(
|
|
82
|
+
describe(findLast, () => {
|
|
77
83
|
test('should find last element matching predicate', () => {
|
|
78
84
|
const numbers = [1, 2, 3, 4, 5];
|
|
79
85
|
const lastEven = findLast(numbers, (n) => n % 2 === 0);
|
|
86
|
+
|
|
80
87
|
expect(Optional.isSome(lastEven)).toBe(true);
|
|
81
88
|
expect(Optional.unwrap(lastEven)).toBe(4);
|
|
82
89
|
});
|
|
@@ -84,6 +91,7 @@ describe('Arr search operations', () => {
|
|
|
84
91
|
test('should return None when no element matches', () => {
|
|
85
92
|
const odds = [1, 3, 5];
|
|
86
93
|
const lastEven = findLast(odds, (n) => n % 2 === 0);
|
|
94
|
+
|
|
87
95
|
expect(Optional.isNone(lastEven)).toBe(true);
|
|
88
96
|
});
|
|
89
97
|
|
|
@@ -91,6 +99,7 @@ describe('Arr search operations', () => {
|
|
|
91
99
|
const isPositive = (n: number): boolean => n > 0;
|
|
92
100
|
const findLastPositive = findLast(isPositive);
|
|
93
101
|
const result = findLastPositive([-1, 2, -3, 4]);
|
|
102
|
+
|
|
94
103
|
expect(Optional.isSome(result)).toBe(true);
|
|
95
104
|
expect(Optional.unwrap(result)).toBe(4);
|
|
96
105
|
});
|
|
@@ -98,6 +107,7 @@ describe('Arr search operations', () => {
|
|
|
98
107
|
test('should work with empty array', () => {
|
|
99
108
|
const empty: number[] = [];
|
|
100
109
|
const result = findLast(empty, (n) => n > 0);
|
|
110
|
+
|
|
101
111
|
expect(Optional.isNone(result)).toBe(true);
|
|
102
112
|
});
|
|
103
113
|
|
|
@@ -105,29 +115,35 @@ describe('Arr search operations', () => {
|
|
|
105
115
|
const numbers = [10, 20, 30, 40];
|
|
106
116
|
const lastWithIndex2 = findLast(numbers, (_, idx, arr) => {
|
|
107
117
|
expect(arr).toBe(numbers);
|
|
118
|
+
|
|
108
119
|
return idx === 2;
|
|
109
120
|
});
|
|
121
|
+
|
|
110
122
|
expect(Optional.unwrap(lastWithIndex2)).toBe(30);
|
|
111
123
|
});
|
|
112
124
|
|
|
113
125
|
test('should find last occurrence', () => {
|
|
114
126
|
const numbers = [1, 2, 2, 3, 2, 4];
|
|
115
127
|
const lastTwo = findLast(numbers, (n) => n === 2);
|
|
128
|
+
|
|
116
129
|
expect(Optional.unwrap(lastTwo)).toBe(2);
|
|
117
130
|
|
|
118
131
|
// Verify it's actually the last occurrence by checking behavior
|
|
119
132
|
const index = numbers.lastIndexOf(2);
|
|
133
|
+
|
|
120
134
|
expect(index).toBe(4); // Last 2 is at index 4
|
|
121
135
|
});
|
|
122
136
|
});
|
|
123
137
|
|
|
124
|
-
describe(
|
|
138
|
+
describe(findIndex, () => {
|
|
125
139
|
test('should find index of matching element', () => {
|
|
126
140
|
const arr = ['a', 'b', 'c'];
|
|
127
141
|
const result = findIndex(arr, (x) => x === 'b');
|
|
128
142
|
|
|
129
143
|
expect(result).toBeGreaterThanOrEqual(0);
|
|
144
|
+
|
|
130
145
|
expectType<typeof result, SizeType.Arr | -1>('=');
|
|
146
|
+
|
|
131
147
|
expect(result).toBe(1);
|
|
132
148
|
});
|
|
133
149
|
|
|
@@ -139,16 +155,18 @@ describe('Arr search operations', () => {
|
|
|
139
155
|
});
|
|
140
156
|
});
|
|
141
157
|
|
|
142
|
-
describe(
|
|
158
|
+
describe(findLastIndex, () => {
|
|
143
159
|
test('should find last index matching predicate', () => {
|
|
144
160
|
const numbers = [1, 2, 3, 4, 2, 5];
|
|
145
161
|
const lastTwoIndex = findLastIndex(numbers, (n) => n === 2);
|
|
162
|
+
|
|
146
163
|
expect(lastTwoIndex).toBe(4);
|
|
147
164
|
});
|
|
148
165
|
|
|
149
166
|
test('should return -1 when no element matches', () => {
|
|
150
167
|
const odds = [1, 3, 5];
|
|
151
168
|
const lastEvenIndex = findLastIndex(odds, (n) => n % 2 === 0);
|
|
169
|
+
|
|
152
170
|
expect(lastEvenIndex).toBe(-1);
|
|
153
171
|
});
|
|
154
172
|
|
|
@@ -156,12 +174,14 @@ describe('Arr search operations', () => {
|
|
|
156
174
|
const isPositive = (n: number): boolean => n > 0;
|
|
157
175
|
const findLastPositiveIndex = findLastIndex(isPositive);
|
|
158
176
|
const result = findLastPositiveIndex([-1, 2, -3, 4, -5]);
|
|
177
|
+
|
|
159
178
|
expect(result).toBe(3); // index of last positive number (4)
|
|
160
179
|
});
|
|
161
180
|
|
|
162
181
|
test('should work with empty array', () => {
|
|
163
182
|
const empty: number[] = [];
|
|
164
183
|
const result = findLastIndex(empty, (n) => n > 0);
|
|
184
|
+
|
|
165
185
|
expect(result).toBe(-1);
|
|
166
186
|
});
|
|
167
187
|
|
|
@@ -169,8 +189,10 @@ describe('Arr search operations', () => {
|
|
|
169
189
|
const numbers = [10, 20, 30, 40];
|
|
170
190
|
const lastWithIndex2OrHigher = findLastIndex(numbers, (_, idx, arr) => {
|
|
171
191
|
expect(arr).toBe(numbers);
|
|
192
|
+
|
|
172
193
|
return idx >= 2;
|
|
173
194
|
});
|
|
195
|
+
|
|
174
196
|
expect(lastWithIndex2OrHigher).toBe(3); // last index >= 2
|
|
175
197
|
});
|
|
176
198
|
|
|
@@ -183,12 +205,14 @@ describe('Arr search operations', () => {
|
|
|
183
205
|
{ id: 5, active: true },
|
|
184
206
|
];
|
|
185
207
|
const lastActiveIndex = findLastIndex(data, (item) => item.active);
|
|
208
|
+
|
|
186
209
|
expect(lastActiveIndex).toBe(4); // last active item
|
|
187
210
|
});
|
|
188
211
|
|
|
189
212
|
test('should work with tuples', () => {
|
|
190
213
|
const tuple = [10, 20, 30, 20, 40] as const;
|
|
191
214
|
const lastTwentyIndex = findLastIndex(tuple, (x) => x === 20);
|
|
215
|
+
|
|
192
216
|
expect(lastTwentyIndex).toBe(3); // last occurrence of 20
|
|
193
217
|
});
|
|
194
218
|
|
|
@@ -203,7 +227,7 @@ describe('Arr search operations', () => {
|
|
|
203
227
|
});
|
|
204
228
|
|
|
205
229
|
// Should search from end: 4, 3, 2 (stops at 2 when found)
|
|
206
|
-
|
|
230
|
+
assert.deepStrictEqual(mut_searchOrder, [4, 3, 2]);
|
|
207
231
|
});
|
|
208
232
|
|
|
209
233
|
test('should handle single element array', () => {
|
|
@@ -218,18 +242,21 @@ describe('Arr search operations', () => {
|
|
|
218
242
|
test('should work with string arrays', () => {
|
|
219
243
|
const words = ['hello', 'world', 'test', 'hello', 'end'];
|
|
220
244
|
const lastHelloIndex = findLastIndex(words, (word) => word === 'hello');
|
|
245
|
+
|
|
221
246
|
expect(lastHelloIndex).toBe(3);
|
|
222
247
|
});
|
|
223
248
|
});
|
|
224
249
|
|
|
225
|
-
describe(
|
|
250
|
+
describe(indexOf, () => {
|
|
226
251
|
test('should find index of element', () => {
|
|
227
252
|
const arr = ['a', 'b', 'c', 'b'];
|
|
228
253
|
const result = indexOf(arr, 'b');
|
|
229
254
|
|
|
230
255
|
expect(result).toBeGreaterThanOrEqual(0);
|
|
256
|
+
|
|
231
257
|
if (result !== -1) {
|
|
232
258
|
expectType<typeof result, SizeType.Arr>('=');
|
|
259
|
+
|
|
233
260
|
expect(result).toBe(1);
|
|
234
261
|
}
|
|
235
262
|
});
|
|
@@ -242,14 +269,16 @@ describe('Arr search operations', () => {
|
|
|
242
269
|
});
|
|
243
270
|
});
|
|
244
271
|
|
|
245
|
-
describe(
|
|
272
|
+
describe(indexOfFrom, () => {
|
|
246
273
|
test('should find index of element from specified index', () => {
|
|
247
274
|
const arr = ['a', 'b', 'c', 'b'];
|
|
248
275
|
const result = indexOfFrom(arr, 'b', 2);
|
|
249
276
|
|
|
250
277
|
expect(result).toBeGreaterThanOrEqual(0);
|
|
278
|
+
|
|
251
279
|
if (result !== -1) {
|
|
252
280
|
expectType<typeof result, SizeType.Arr>('=');
|
|
281
|
+
|
|
253
282
|
expect(result).toBe(3);
|
|
254
283
|
}
|
|
255
284
|
});
|
|
@@ -283,14 +312,16 @@ describe('Arr search operations', () => {
|
|
|
283
312
|
});
|
|
284
313
|
});
|
|
285
314
|
|
|
286
|
-
describe(
|
|
315
|
+
describe(lastIndexOf, () => {
|
|
287
316
|
test('should find last index of element', () => {
|
|
288
317
|
const arr = ['a', 'b', 'c', 'b'];
|
|
289
318
|
const result = lastIndexOf(arr, 'b');
|
|
290
319
|
|
|
291
320
|
expect(result).toBeGreaterThanOrEqual(0);
|
|
321
|
+
|
|
292
322
|
if (result !== -1) {
|
|
293
323
|
expectType<typeof result, SizeType.Arr>('=');
|
|
324
|
+
|
|
294
325
|
expect(result).toBe(3);
|
|
295
326
|
}
|
|
296
327
|
});
|
|
@@ -303,14 +334,16 @@ describe('Arr search operations', () => {
|
|
|
303
334
|
});
|
|
304
335
|
});
|
|
305
336
|
|
|
306
|
-
describe(
|
|
337
|
+
describe(lastIndexOfFrom, () => {
|
|
307
338
|
test('should find last index of element from specified index', () => {
|
|
308
339
|
const arr = ['a', 'b', 'c', 'b', 'e'];
|
|
309
340
|
const result = lastIndexOfFrom(arr, 'b', 2);
|
|
310
341
|
|
|
311
342
|
expect(result).toBeGreaterThanOrEqual(0);
|
|
343
|
+
|
|
312
344
|
if (result !== -1) {
|
|
313
345
|
expectType<typeof result, SizeType.Arr>('=');
|
|
346
|
+
|
|
314
347
|
expect(result).toBe(1);
|
|
315
348
|
}
|
|
316
349
|
});
|