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.
- package/LICENSE +201 -0
- package/README.md +534 -0
- package/package.json +101 -0
- package/src/array/array-utils-creation.test.mts +443 -0
- package/src/array/array-utils-modification.test.mts +197 -0
- package/src/array/array-utils-overload-type-error.test.mts +149 -0
- package/src/array/array-utils-reducing-value.test.mts +425 -0
- package/src/array/array-utils-search.test.mts +169 -0
- package/src/array/array-utils-set-op.test.mts +335 -0
- package/src/array/array-utils-slice-clamped.test.mts +113 -0
- package/src/array/array-utils-slicing.test.mts +316 -0
- package/src/array/array-utils-transformation.test.mts +790 -0
- package/src/array/array-utils-validation.test.mts +492 -0
- package/src/array/array-utils.mts +4000 -0
- package/src/array/array.test.mts +146 -0
- package/src/array/index.mts +2 -0
- package/src/array/tuple-utils.mts +519 -0
- package/src/array/tuple-utils.test.mts +518 -0
- package/src/collections/imap-mapped.mts +801 -0
- package/src/collections/imap-mapped.test.mts +860 -0
- package/src/collections/imap.mts +651 -0
- package/src/collections/imap.test.mts +932 -0
- package/src/collections/index.mts +6 -0
- package/src/collections/iset-mapped.mts +889 -0
- package/src/collections/iset-mapped.test.mts +1187 -0
- package/src/collections/iset.mts +682 -0
- package/src/collections/iset.test.mts +1084 -0
- package/src/collections/queue.mts +390 -0
- package/src/collections/queue.test.mts +282 -0
- package/src/collections/stack.mts +423 -0
- package/src/collections/stack.test.mts +225 -0
- package/src/expect-type.mts +206 -0
- package/src/functional/index.mts +4 -0
- package/src/functional/match.mts +300 -0
- package/src/functional/match.test.mts +177 -0
- package/src/functional/optional.mts +733 -0
- package/src/functional/optional.test.mts +619 -0
- package/src/functional/pipe.mts +212 -0
- package/src/functional/pipe.test.mts +85 -0
- package/src/functional/result.mts +1134 -0
- package/src/functional/result.test.mts +777 -0
- package/src/globals.d.mts +38 -0
- package/src/guard/has-key.mts +119 -0
- package/src/guard/has-key.test.mts +219 -0
- package/src/guard/index.mts +7 -0
- package/src/guard/is-non-empty-string.mts +108 -0
- package/src/guard/is-non-empty-string.test.mts +91 -0
- package/src/guard/is-non-null-object.mts +106 -0
- package/src/guard/is-non-null-object.test.mts +90 -0
- package/src/guard/is-primitive.mts +165 -0
- package/src/guard/is-primitive.test.mts +102 -0
- package/src/guard/is-record.mts +153 -0
- package/src/guard/is-record.test.mts +112 -0
- package/src/guard/is-type.mts +450 -0
- package/src/guard/is-type.test.mts +496 -0
- package/src/guard/key-is-in.mts +163 -0
- package/src/guard/key-is-in.test.mts +19 -0
- package/src/index.mts +10 -0
- package/src/iterator/index.mts +1 -0
- package/src/iterator/range.mts +120 -0
- package/src/iterator/range.test.mts +33 -0
- package/src/json/index.mts +1 -0
- package/src/json/json.mts +711 -0
- package/src/json/json.test.mts +628 -0
- package/src/number/branded-types/finite-number.mts +354 -0
- package/src/number/branded-types/finite-number.test.mts +135 -0
- package/src/number/branded-types/index.mts +26 -0
- package/src/number/branded-types/int.mts +278 -0
- package/src/number/branded-types/int.test.mts +140 -0
- package/src/number/branded-types/int16.mts +192 -0
- package/src/number/branded-types/int16.test.mts +170 -0
- package/src/number/branded-types/int32.mts +193 -0
- package/src/number/branded-types/int32.test.mts +170 -0
- package/src/number/branded-types/non-negative-finite-number.mts +223 -0
- package/src/number/branded-types/non-negative-finite-number.test.mts +188 -0
- package/src/number/branded-types/non-negative-int16.mts +187 -0
- package/src/number/branded-types/non-negative-int16.test.mts +201 -0
- package/src/number/branded-types/non-negative-int32.mts +187 -0
- package/src/number/branded-types/non-negative-int32.test.mts +204 -0
- package/src/number/branded-types/non-zero-finite-number.mts +229 -0
- package/src/number/branded-types/non-zero-finite-number.test.mts +198 -0
- package/src/number/branded-types/non-zero-int.mts +167 -0
- package/src/number/branded-types/non-zero-int.test.mts +177 -0
- package/src/number/branded-types/non-zero-int16.mts +196 -0
- package/src/number/branded-types/non-zero-int16.test.mts +195 -0
- package/src/number/branded-types/non-zero-int32.mts +196 -0
- package/src/number/branded-types/non-zero-int32.test.mts +197 -0
- package/src/number/branded-types/non-zero-safe-int.mts +196 -0
- package/src/number/branded-types/non-zero-safe-int.test.mts +232 -0
- package/src/number/branded-types/non-zero-uint16.mts +189 -0
- package/src/number/branded-types/non-zero-uint16.test.mts +199 -0
- package/src/number/branded-types/non-zero-uint32.mts +189 -0
- package/src/number/branded-types/non-zero-uint32.test.mts +199 -0
- package/src/number/branded-types/positive-finite-number.mts +241 -0
- package/src/number/branded-types/positive-finite-number.test.mts +204 -0
- package/src/number/branded-types/positive-int.mts +304 -0
- package/src/number/branded-types/positive-int.test.mts +176 -0
- package/src/number/branded-types/positive-int16.mts +188 -0
- package/src/number/branded-types/positive-int16.test.mts +197 -0
- package/src/number/branded-types/positive-int32.mts +188 -0
- package/src/number/branded-types/positive-int32.test.mts +197 -0
- package/src/number/branded-types/positive-safe-int.mts +187 -0
- package/src/number/branded-types/positive-safe-int.test.mts +210 -0
- package/src/number/branded-types/positive-uint16.mts +188 -0
- package/src/number/branded-types/positive-uint16.test.mts +203 -0
- package/src/number/branded-types/positive-uint32.mts +188 -0
- package/src/number/branded-types/positive-uint32.test.mts +203 -0
- package/src/number/branded-types/safe-int.mts +291 -0
- package/src/number/branded-types/safe-int.test.mts +170 -0
- package/src/number/branded-types/safe-uint.mts +187 -0
- package/src/number/branded-types/safe-uint.test.mts +176 -0
- package/src/number/branded-types/uint.mts +179 -0
- package/src/number/branded-types/uint.test.mts +158 -0
- package/src/number/branded-types/uint16.mts +186 -0
- package/src/number/branded-types/uint16.test.mts +170 -0
- package/src/number/branded-types/uint32.mts +218 -0
- package/src/number/branded-types/uint32.test.mts +170 -0
- package/src/number/enum/index.mts +2 -0
- package/src/number/enum/int8.mts +344 -0
- package/src/number/enum/int8.test.mts +180 -0
- package/src/number/enum/uint8.mts +293 -0
- package/src/number/enum/uint8.test.mts +164 -0
- package/src/number/index.mts +4 -0
- package/src/number/num.mts +604 -0
- package/src/number/num.test.mts +242 -0
- package/src/number/refined-number-utils.mts +566 -0
- package/src/object/index.mts +1 -0
- package/src/object/object.mts +447 -0
- package/src/object/object.test.mts +124 -0
- package/src/others/cast-mutable.mts +113 -0
- package/src/others/cast-readonly.mts +192 -0
- package/src/others/cast-readonly.test.mts +89 -0
- package/src/others/if-then.mts +98 -0
- package/src/others/if-then.test.mts +75 -0
- package/src/others/index.mts +7 -0
- package/src/others/map-nullable.mts +172 -0
- package/src/others/map-nullable.test.mts +297 -0
- package/src/others/memoize-function.mts +196 -0
- package/src/others/memoize-function.test.mts +168 -0
- package/src/others/tuple.mts +160 -0
- package/src/others/tuple.test.mts +11 -0
- package/src/others/unknown-to-string.mts +215 -0
- package/src/others/unknown-to-string.test.mts +114 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { expectType } from '../expect-type.mjs';
|
|
2
|
+
import { Optional } from '../functional/optional.mjs';
|
|
3
|
+
import { asInt32, asUint32 } from '../number/index.mjs';
|
|
4
|
+
import { Arr } from './array-utils.mjs';
|
|
5
|
+
|
|
6
|
+
describe('Arr search operations', () => {
|
|
7
|
+
describe('findIndex', () => {
|
|
8
|
+
test('should find index of matching element', () => {
|
|
9
|
+
const arr = ['a', 'b', 'c'];
|
|
10
|
+
const result = Arr.findIndex(arr, (x) => x === 'b');
|
|
11
|
+
|
|
12
|
+
expect(result).toBeGreaterThanOrEqual(0);
|
|
13
|
+
expectType<typeof result, SizeType.Arr | -1>('=');
|
|
14
|
+
expect(result).toBe(1);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('should return None for no match', () => {
|
|
18
|
+
const arr = ['a', 'b', 'c'];
|
|
19
|
+
const result = Arr.findIndex(arr, (x) => x === 'd');
|
|
20
|
+
|
|
21
|
+
expect(result).toBe(-1);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
describe('indexOf', () => {
|
|
26
|
+
test('should find index of element', () => {
|
|
27
|
+
const arr = ['a', 'b', 'c', 'b'];
|
|
28
|
+
const result = Arr.indexOf(arr, 'b');
|
|
29
|
+
|
|
30
|
+
expect(result).toBeGreaterThanOrEqual(0);
|
|
31
|
+
if (result !== -1) {
|
|
32
|
+
expectType<typeof result, SizeType.Arr>('=');
|
|
33
|
+
expect(result).toBe(1);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('should return -1 for non-existent element', () => {
|
|
38
|
+
const arr = ['a', 'b', 'c'];
|
|
39
|
+
const result = Arr.indexOf(arr, 'd');
|
|
40
|
+
|
|
41
|
+
expect(result).toBe(-1);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe('indexOfFrom', () => {
|
|
46
|
+
test('should find index of element from specified index', () => {
|
|
47
|
+
const arr = ['a', 'b', 'c', 'b'];
|
|
48
|
+
const result = Arr.indexOfFrom(arr, 'b', 2);
|
|
49
|
+
|
|
50
|
+
expect(result).toBeGreaterThanOrEqual(0);
|
|
51
|
+
if (result !== -1) {
|
|
52
|
+
expectType<typeof result, SizeType.Arr>('=');
|
|
53
|
+
expect(result).toBe(3);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('should return -1 when element not found from index', () => {
|
|
58
|
+
const arr = ['a', 'b', 'c', 'b'];
|
|
59
|
+
const result = Arr.indexOfFrom(arr, 'a', 1);
|
|
60
|
+
|
|
61
|
+
expect(result).toBe(-1);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('should find first occurrence when fromIndex is 0', () => {
|
|
65
|
+
const arr = ['a', 'b', 'c', 'b'];
|
|
66
|
+
const result = Arr.indexOfFrom(arr, 'b', 0);
|
|
67
|
+
|
|
68
|
+
expect(result).toBe(1);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('should handle negative fromIndex', () => {
|
|
72
|
+
const arr = ['a', 'b', 'c', 'b'];
|
|
73
|
+
const result = Arr.indexOfFrom(arr, 'b', -2);
|
|
74
|
+
|
|
75
|
+
expect(result).toBe(3);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('should handle fromIndex beyond array length', () => {
|
|
79
|
+
const arr = ['a', 'b', 'c'];
|
|
80
|
+
const result = Arr.indexOfFrom(arr, 'a', 10);
|
|
81
|
+
|
|
82
|
+
expect(result).toBe(-1);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe('lastIndexOf', () => {
|
|
87
|
+
test('should find last index of element', () => {
|
|
88
|
+
const arr = ['a', 'b', 'c', 'b'];
|
|
89
|
+
const result = Arr.lastIndexOf(arr, 'b');
|
|
90
|
+
|
|
91
|
+
expect(result).toBeGreaterThanOrEqual(0);
|
|
92
|
+
if (result !== -1) {
|
|
93
|
+
expectType<typeof result, SizeType.Arr>('=');
|
|
94
|
+
expect(result).toBe(3);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test('should return -1 for non-existent element', () => {
|
|
99
|
+
const arr = ['a', 'b', 'c'];
|
|
100
|
+
const result = Arr.lastIndexOf(arr, 'd');
|
|
101
|
+
|
|
102
|
+
expect(result).toBe(-1);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
describe('lastIndexOfFrom', () => {
|
|
107
|
+
test('should find last index of element from specified index', () => {
|
|
108
|
+
const arr = ['a', 'b', 'c', 'b', 'e'];
|
|
109
|
+
const result = Arr.lastIndexOfFrom(arr, 'b', 2);
|
|
110
|
+
|
|
111
|
+
expect(result).toBeGreaterThanOrEqual(0);
|
|
112
|
+
if (result !== -1) {
|
|
113
|
+
expectType<typeof result, SizeType.Arr>('=');
|
|
114
|
+
expect(result).toBe(1);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('should return -1 when element not found before index', () => {
|
|
119
|
+
const arr = ['a', 'b', 'c', 'b'];
|
|
120
|
+
const result = Arr.lastIndexOfFrom(arr, 'b', 0);
|
|
121
|
+
|
|
122
|
+
expect(result).toBe(-1);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test('should find last occurrence when fromIndex covers all elements', () => {
|
|
126
|
+
const arr = ['a', 'b', 'c', 'b'];
|
|
127
|
+
const result = Arr.lastIndexOfFrom(arr, 'b', 10);
|
|
128
|
+
|
|
129
|
+
expect(result).toBe(3);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test('should handle negative fromIndex', () => {
|
|
133
|
+
const arr = ['a', 'b', 'c', 'b'];
|
|
134
|
+
const result = Arr.lastIndexOfFrom(arr, 'b', -1);
|
|
135
|
+
|
|
136
|
+
expect(result).toBe(3);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test('should handle fromIndex of 0', () => {
|
|
140
|
+
const arr = ['a', 'b', 'c', 'b'];
|
|
141
|
+
const result = Arr.lastIndexOfFrom(arr, 'a', 0);
|
|
142
|
+
|
|
143
|
+
expect(result).toBe(0);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
describe('at', () => {
|
|
148
|
+
test('should handle very large positive indices', () => {
|
|
149
|
+
const array = [1, 2, 3];
|
|
150
|
+
const result = Arr.at(array, asUint32(1000));
|
|
151
|
+
expect(Optional.isNone(result)).toBe(true);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
test('should handle very large negative indices', () => {
|
|
155
|
+
const array = [1, 2, 3];
|
|
156
|
+
const result = Arr.at(array, asInt32(-1000));
|
|
157
|
+
expect(Optional.isNone(result)).toBe(true);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test('should work with valid indices', () => {
|
|
161
|
+
const array = [10, 20, 30];
|
|
162
|
+
const result = Arr.at(array, 1);
|
|
163
|
+
expect(Optional.isSome(result)).toBe(true);
|
|
164
|
+
if (Optional.isSome(result)) {
|
|
165
|
+
expect(result.value).toBe(20);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
});
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import { expectType } from '../expect-type.mjs';
|
|
2
|
+
import { Arr } from './array-utils.mjs';
|
|
3
|
+
|
|
4
|
+
describe('Arr set operations', () => {
|
|
5
|
+
describe('eq', () => {
|
|
6
|
+
{
|
|
7
|
+
const xs = [1, 2, 3] as const;
|
|
8
|
+
const ys = [1, 2, 3] as const;
|
|
9
|
+
const result = Arr.eq(xs, ys);
|
|
10
|
+
expectType<typeof result, boolean>('=');
|
|
11
|
+
test('should return true for equal arrays of numbers', () => {
|
|
12
|
+
expect(result).toBe(true);
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
{
|
|
16
|
+
const xs = [1, 2, 3] as const;
|
|
17
|
+
const ys = [1, 2, 4] as const;
|
|
18
|
+
const result = Arr.eq(xs, ys);
|
|
19
|
+
expectType<typeof result, boolean>('=');
|
|
20
|
+
test('should return false for different arrays of numbers', () => {
|
|
21
|
+
expect(result).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
{
|
|
25
|
+
const xs = [1, 2, 3] as const;
|
|
26
|
+
const ys = [1, 2] as const;
|
|
27
|
+
const result = Arr.eq(xs, ys);
|
|
28
|
+
expectType<typeof result, boolean>('=');
|
|
29
|
+
test('should return false for arrays of different lengths', () => {
|
|
30
|
+
expect(result).toBe(false);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
{
|
|
34
|
+
const xs = ['a', 'b'] as const;
|
|
35
|
+
const ys = ['a', 'b'] as const;
|
|
36
|
+
const result = Arr.eq(xs, ys);
|
|
37
|
+
expectType<typeof result, boolean>('=');
|
|
38
|
+
test('should return true for equal arrays of strings', () => {
|
|
39
|
+
expect(result).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
{
|
|
43
|
+
const xs = [] as const;
|
|
44
|
+
const ys = [] as const;
|
|
45
|
+
const result = Arr.eq(xs, ys);
|
|
46
|
+
expectType<typeof result, boolean>('=');
|
|
47
|
+
test('should return true for empty arrays', () => {
|
|
48
|
+
expect(result).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
{
|
|
52
|
+
const xs = [{ a: 1 }, { b: 2 }] as const;
|
|
53
|
+
const ys = [{ a: 1 }, { b: 2 }] as const;
|
|
54
|
+
// Default eq uses reference equality for objects
|
|
55
|
+
const result = Arr.eq(xs, ys);
|
|
56
|
+
expectType<typeof result, boolean>('=');
|
|
57
|
+
test('should return false for arrays of objects with default equality (reference check)', () => {
|
|
58
|
+
expect(result).toBe(false);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
{
|
|
62
|
+
const objA = { a: 1 };
|
|
63
|
+
const objB = { b: 2 };
|
|
64
|
+
const xs = [objA, objB] as const;
|
|
65
|
+
const ys = [objA, objB] as const;
|
|
66
|
+
const result = Arr.eq(xs, ys);
|
|
67
|
+
expectType<typeof result, boolean>('=');
|
|
68
|
+
test('should return true for arrays of same object references', () => {
|
|
69
|
+
expect(result).toBe(true);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
{
|
|
73
|
+
const xs = [{ a: 1 }, { b: 2 }] as const;
|
|
74
|
+
const ys = [{ a: 1 }, { b: 2 }] as const;
|
|
75
|
+
const result = Arr.eq(
|
|
76
|
+
xs,
|
|
77
|
+
ys,
|
|
78
|
+
(o1, o2) => JSON.stringify(o1) === JSON.stringify(o2),
|
|
79
|
+
);
|
|
80
|
+
expectType<typeof result, boolean>('=');
|
|
81
|
+
test('should return true for arrays of objects with custom equality function', () => {
|
|
82
|
+
expect(result).toBe(true);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe('isSubset', () => {
|
|
88
|
+
{
|
|
89
|
+
const xs = [1, 2, 3] as const;
|
|
90
|
+
const ys = [3, 2] as const;
|
|
91
|
+
|
|
92
|
+
const result = Arr.isSubset(ys, xs);
|
|
93
|
+
|
|
94
|
+
expectType<typeof result, boolean>('=');
|
|
95
|
+
|
|
96
|
+
test('case 1', () => {
|
|
97
|
+
expect(result).toBe(true);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
{
|
|
101
|
+
const xs = [1, 2, 3] as const;
|
|
102
|
+
const ys = [3, 2, 4] as const;
|
|
103
|
+
|
|
104
|
+
const result = Arr.isSubset(ys, xs);
|
|
105
|
+
|
|
106
|
+
expectType<typeof result, boolean>('=');
|
|
107
|
+
|
|
108
|
+
test('case 2', () => {
|
|
109
|
+
expect(result).toBe(false);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe('isSuperset', () => {
|
|
115
|
+
{
|
|
116
|
+
const xs = [1, 2, 3] as const;
|
|
117
|
+
const ys = [3, 2] as const;
|
|
118
|
+
|
|
119
|
+
const result = Arr.isSuperset(ys, xs);
|
|
120
|
+
|
|
121
|
+
expectType<typeof result, boolean>('=');
|
|
122
|
+
|
|
123
|
+
test('case 1', () => {
|
|
124
|
+
expect(result).toBe(false);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const result2 = Arr.isSuperset(xs, ys);
|
|
128
|
+
|
|
129
|
+
test('case 2', () => {
|
|
130
|
+
expect(result2).toBe(true);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
{
|
|
134
|
+
const xs = [1, 2, 3] as const;
|
|
135
|
+
const ys = [3, 2, 4] as const;
|
|
136
|
+
|
|
137
|
+
const result = Arr.isSuperset(ys, xs);
|
|
138
|
+
|
|
139
|
+
expectType<typeof result, boolean>('=');
|
|
140
|
+
|
|
141
|
+
test('case 3', () => {
|
|
142
|
+
expect(result).toBe(false);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
describe('setIntersection', () => {
|
|
148
|
+
{
|
|
149
|
+
const xs = [1, 2, 3] as const;
|
|
150
|
+
const ys = [2, 3, 4] as const;
|
|
151
|
+
const result = Arr.setIntersection(xs, ys);
|
|
152
|
+
expectType<typeof result, readonly (2 | 3)[]>('=');
|
|
153
|
+
test('should return the intersection of two number arrays', () => {
|
|
154
|
+
expect(result).toStrictEqual([2, 3]);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
{
|
|
158
|
+
const xs = ['a', 'b', 'c'] as const;
|
|
159
|
+
const ys = ['b', 'c', 'd'] as const;
|
|
160
|
+
const result = Arr.setIntersection(xs, ys);
|
|
161
|
+
expectType<typeof result, readonly ('b' | 'c')[]>('=');
|
|
162
|
+
test('should return the intersection of two string arrays', () => {
|
|
163
|
+
expect(result).toStrictEqual(['b', 'c']);
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
{
|
|
167
|
+
const xs = [1, 2, 3] as const;
|
|
168
|
+
const ys = [4, 5, 6] as const;
|
|
169
|
+
const result = Arr.setIntersection(xs, ys);
|
|
170
|
+
expectType<typeof result, readonly never[]>('=');
|
|
171
|
+
test('should return an empty array if there is no intersection', () => {
|
|
172
|
+
expect(result).toStrictEqual([]);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
{
|
|
176
|
+
const xs = [1, 2, 3] as const;
|
|
177
|
+
const ys = [] as const;
|
|
178
|
+
const result = Arr.setIntersection(xs, ys);
|
|
179
|
+
expectType<typeof result, readonly never[]>('=');
|
|
180
|
+
test('should return an empty array if one array is empty', () => {
|
|
181
|
+
expect(result).toStrictEqual([]);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
{
|
|
185
|
+
const xs = [] as const;
|
|
186
|
+
const ys = [1, 2, 3] as const;
|
|
187
|
+
const result = Arr.setIntersection(xs, ys);
|
|
188
|
+
expectType<typeof result, readonly never[]>('=');
|
|
189
|
+
test('should return an empty array if the first array is empty', () => {
|
|
190
|
+
expect(result).toStrictEqual([]);
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
describe('setDifference', () => {
|
|
196
|
+
{
|
|
197
|
+
const xs = [1, 2, 3] as const;
|
|
198
|
+
const ys = [2, 3, 4] as const;
|
|
199
|
+
const result = Arr.setDifference(xs, ys);
|
|
200
|
+
expectType<typeof result, readonly (1 | 2 | 3 | 4)[]>('=');
|
|
201
|
+
test('should return the difference xs - ys for number arrays', () => {
|
|
202
|
+
expect(result).toStrictEqual([1]);
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
{
|
|
206
|
+
const xs = ['a', 'b', 'c'] as const;
|
|
207
|
+
const ys = ['b', 'c', 'd'] as const;
|
|
208
|
+
const result = Arr.setDifference(xs, ys);
|
|
209
|
+
expectType<typeof result, readonly ('a' | 'b' | 'c' | 'd')[]>('=');
|
|
210
|
+
test('should return the difference xs - ys for string arrays', () => {
|
|
211
|
+
expect(result).toStrictEqual(['a']);
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
{
|
|
215
|
+
const xs = [1, 2, 3] as const;
|
|
216
|
+
const ys = [1, 2, 3] as const;
|
|
217
|
+
const result = Arr.setDifference(xs, ys);
|
|
218
|
+
expectType<typeof result, readonly (1 | 2 | 3)[]>('=');
|
|
219
|
+
test('should return an empty array if xs is a subset of ys', () => {
|
|
220
|
+
expect(result).toStrictEqual([]);
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
{
|
|
224
|
+
const xs = [1, 2, 3] as const;
|
|
225
|
+
const ys = [4, 5, 6] as const;
|
|
226
|
+
const result = Arr.setDifference(xs, ys);
|
|
227
|
+
expectType<typeof result, readonly (1 | 2 | 3 | 4 | 5 | 6)[]>('=');
|
|
228
|
+
test('should return xs if there is no intersection', () => {
|
|
229
|
+
expect(result).toStrictEqual([1, 2, 3]);
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
{
|
|
233
|
+
const xs = [1, 2, 3] as const;
|
|
234
|
+
const ys = [] as const;
|
|
235
|
+
const result = Arr.setDifference(xs, ys);
|
|
236
|
+
expectType<typeof result, readonly (1 | 2 | 3)[]>('=');
|
|
237
|
+
test('should return xs if ys is empty', () => {
|
|
238
|
+
expect(result).toStrictEqual([1, 2, 3]);
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
{
|
|
242
|
+
const xs = [] as const;
|
|
243
|
+
const ys = [1, 2, 3] as const;
|
|
244
|
+
const result = Arr.setDifference(xs, ys);
|
|
245
|
+
expectType<typeof result, readonly (1 | 2 | 3)[]>('=');
|
|
246
|
+
test('should return an empty array if xs is empty', () => {
|
|
247
|
+
expect(result).toStrictEqual([]);
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
describe('sortedNumSetDifference', () => {
|
|
253
|
+
{
|
|
254
|
+
const xs = [1, 2, 3, 5] as const;
|
|
255
|
+
const ys = [2, 3, 4] as const;
|
|
256
|
+
const result = Arr.sortedNumSetDifference(xs, ys);
|
|
257
|
+
expectType<typeof result, readonly (1 | 2 | 3 | 4 | 5)[]>('=');
|
|
258
|
+
test('should return the difference for sorted number arrays (xs - ys)', () => {
|
|
259
|
+
expect(result).toStrictEqual([1, 5]);
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
{
|
|
263
|
+
const xs = [1, 2, 3] as const;
|
|
264
|
+
const ys = [1, 2, 3] as const;
|
|
265
|
+
const result = Arr.sortedNumSetDifference(xs, ys);
|
|
266
|
+
expectType<typeof result, readonly (1 | 2 | 3)[]>('=');
|
|
267
|
+
test('should return an empty array if sets are equal', () => {
|
|
268
|
+
expect(result).toStrictEqual([]);
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
{
|
|
272
|
+
const xs = [1, 2, 3] as const;
|
|
273
|
+
const ys = [4, 5, 6] as const;
|
|
274
|
+
const result = Arr.sortedNumSetDifference(xs, ys);
|
|
275
|
+
expectType<typeof result, readonly (1 | 2 | 3 | 4 | 5 | 6)[]>('=');
|
|
276
|
+
test('should return xs if no common elements', () => {
|
|
277
|
+
expect(result).toStrictEqual([1, 2, 3]);
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
{
|
|
281
|
+
const xs = [4, 5, 6] as const;
|
|
282
|
+
const ys = [1, 2, 3] as const;
|
|
283
|
+
const result = Arr.sortedNumSetDifference(xs, ys);
|
|
284
|
+
expectType<typeof result, readonly (1 | 2 | 3 | 4 | 5 | 6)[]>('=');
|
|
285
|
+
test('should return xs if no common elements (ys < xs)', () => {
|
|
286
|
+
expect(result).toStrictEqual([4, 5, 6]);
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
{
|
|
290
|
+
const xs = [1, 2, 3, 4, 5] as const;
|
|
291
|
+
const ys = [2, 4] as const;
|
|
292
|
+
const result = Arr.sortedNumSetDifference(xs, ys);
|
|
293
|
+
expectType<typeof result, readonly (1 | 2 | 3 | 4 | 5)[]>('=');
|
|
294
|
+
test('should return correct difference when ys is subset of xs', () => {
|
|
295
|
+
expect(result).toStrictEqual([1, 3, 5]);
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
{
|
|
299
|
+
const xs = [2, 4] as const;
|
|
300
|
+
const ys = [1, 2, 3, 4, 5] as const;
|
|
301
|
+
const result = Arr.sortedNumSetDifference(xs, ys);
|
|
302
|
+
expectType<typeof result, readonly (1 | 2 | 3 | 4 | 5)[]>('=');
|
|
303
|
+
test('should return empty array when xs is subset of ys', () => {
|
|
304
|
+
expect(result).toStrictEqual([]);
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
{
|
|
308
|
+
const xs = [] as const;
|
|
309
|
+
const ys = [1, 2, 3] as const;
|
|
310
|
+
const result = Arr.sortedNumSetDifference(xs, ys);
|
|
311
|
+
expectType<typeof result, readonly (1 | 2 | 3)[]>('='); // Type is `readonly number[]` due to `ys`
|
|
312
|
+
test('should return an empty array if xs is empty', () => {
|
|
313
|
+
expect(result).toStrictEqual([]);
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
{
|
|
317
|
+
const xs = [1, 2, 3] as const;
|
|
318
|
+
const ys = [] as const;
|
|
319
|
+
const result = Arr.sortedNumSetDifference(xs, ys);
|
|
320
|
+
expectType<typeof result, readonly (1 | 2 | 3)[]>('=');
|
|
321
|
+
test('should return xs if ys is empty', () => {
|
|
322
|
+
expect(result).toStrictEqual([1, 2, 3]);
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
{
|
|
326
|
+
const xs = [] as const;
|
|
327
|
+
const ys = [] as const;
|
|
328
|
+
const result = Arr.sortedNumSetDifference(xs, ys);
|
|
329
|
+
expectType<typeof result, readonly never[]>('='); // Type is `readonly number[]`
|
|
330
|
+
test('should return an empty array if both are empty', () => {
|
|
331
|
+
expect(result).toStrictEqual([]);
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
});
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { asInt32, asUint32 } from '../number/index.mjs';
|
|
2
|
+
import { Arr } from './array-utils.mjs';
|
|
3
|
+
|
|
4
|
+
describe('Arr', () => {
|
|
5
|
+
describe('sliceClamped', () => {
|
|
6
|
+
const list = [0, 1, 2, 3, 4] as const;
|
|
7
|
+
|
|
8
|
+
test.each([
|
|
9
|
+
{
|
|
10
|
+
start: 0,
|
|
11
|
+
end: 5,
|
|
12
|
+
expected: [0, 1, 2, 3, 4],
|
|
13
|
+
}, // normal
|
|
14
|
+
{
|
|
15
|
+
start: 0,
|
|
16
|
+
end: 6,
|
|
17
|
+
expected: [0, 1, 2, 3, 4],
|
|
18
|
+
}, // one side overflow
|
|
19
|
+
{
|
|
20
|
+
start: -1,
|
|
21
|
+
end: 5,
|
|
22
|
+
expected: [0, 1, 2, 3, 4],
|
|
23
|
+
}, // one side overflow
|
|
24
|
+
{
|
|
25
|
+
start: -1,
|
|
26
|
+
end: 6,
|
|
27
|
+
expected: [0, 1, 2, 3, 4],
|
|
28
|
+
}, // both sides overflow
|
|
29
|
+
{
|
|
30
|
+
start: 0,
|
|
31
|
+
end: 3,
|
|
32
|
+
expected: [0, 1, 2],
|
|
33
|
+
}, // normal
|
|
34
|
+
{
|
|
35
|
+
start: 1,
|
|
36
|
+
end: 3,
|
|
37
|
+
expected: [1, 2],
|
|
38
|
+
}, // normal
|
|
39
|
+
{
|
|
40
|
+
start: -1,
|
|
41
|
+
end: 3,
|
|
42
|
+
expected: [0, 1, 2],
|
|
43
|
+
}, // one side overflow
|
|
44
|
+
{
|
|
45
|
+
start: 3,
|
|
46
|
+
end: 5,
|
|
47
|
+
expected: [3, 4],
|
|
48
|
+
}, // normal
|
|
49
|
+
{
|
|
50
|
+
start: 3,
|
|
51
|
+
end: 6,
|
|
52
|
+
expected: [3, 4],
|
|
53
|
+
}, // one side overflow
|
|
54
|
+
{
|
|
55
|
+
start: 4,
|
|
56
|
+
end: 3,
|
|
57
|
+
expected: [],
|
|
58
|
+
}, // start > end
|
|
59
|
+
{
|
|
60
|
+
start: 0,
|
|
61
|
+
end: -1,
|
|
62
|
+
expected: [],
|
|
63
|
+
}, // start > end
|
|
64
|
+
{
|
|
65
|
+
start: -1,
|
|
66
|
+
end: -2,
|
|
67
|
+
expected: [],
|
|
68
|
+
}, // start > end
|
|
69
|
+
{
|
|
70
|
+
start: 6,
|
|
71
|
+
end: 9,
|
|
72
|
+
expected: [],
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
start: 6,
|
|
76
|
+
end: 3,
|
|
77
|
+
expected: [],
|
|
78
|
+
},
|
|
79
|
+
] as const)('sliceClamped($start, $end)', ({ start, end, expected }) => {
|
|
80
|
+
expect(Arr.sliceClamped(list, start, end)).toStrictEqual(expected);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('should slice with clamped indices', () => {
|
|
84
|
+
const array = [1, 2, 3, 4, 5];
|
|
85
|
+
const result = Arr.sliceClamped(array, 1, 3);
|
|
86
|
+
expect(result).toStrictEqual([2, 3]);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test('should clamp start index below 0', () => {
|
|
90
|
+
const array = [1, 2, 3, 4, 5];
|
|
91
|
+
const result = Arr.sliceClamped(array, -10, 3);
|
|
92
|
+
expect(result).toStrictEqual([1, 2, 3]);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test('should clamp end index above length', () => {
|
|
96
|
+
const array = [1, 2, 3, 4, 5];
|
|
97
|
+
const result = Arr.sliceClamped(array, asUint32(2), asUint32(100));
|
|
98
|
+
expect(result).toStrictEqual([3, 4, 5]);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test('should work with both indices out of range', () => {
|
|
102
|
+
const array = [1, 2, 3];
|
|
103
|
+
const result = Arr.sliceClamped(array, asInt32(-10), asUint32(100));
|
|
104
|
+
expect(result).toStrictEqual([1, 2, 3]);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test('should work with empty array', () => {
|
|
108
|
+
const array: readonly number[] = [];
|
|
109
|
+
const result = Arr.sliceClamped(array, 0, 5);
|
|
110
|
+
expect(result).toStrictEqual([]);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
});
|