ts-data-forge 2.1.1 → 2.1.3
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/README.md +13 -15
- package/dist/array/array-utils.d.mts.map +1 -1
- package/dist/array/array-utils.mjs +9 -13
- package/dist/array/array-utils.mjs.map +1 -1
- package/dist/collections/imap.d.mts +1 -1
- package/dist/collections/imap.d.mts.map +1 -1
- package/dist/collections/imap.mjs +5 -5
- package/dist/collections/imap.mjs.map +1 -1
- package/dist/collections/iset-mapped.d.mts +1 -1
- package/dist/collections/iset-mapped.mjs +1 -1
- package/dist/collections/iset.d.mts +2 -2
- package/dist/collections/iset.mjs +4 -5
- package/dist/collections/iset.mjs.map +1 -1
- package/dist/collections/queue.d.mts +1 -1
- package/dist/collections/queue.d.mts.map +1 -1
- package/dist/collections/queue.mjs +7 -8
- package/dist/collections/queue.mjs.map +1 -1
- package/dist/collections/stack.d.mts +1 -1
- package/dist/collections/stack.d.mts.map +1 -1
- package/dist/collections/stack.mjs +6 -7
- package/dist/collections/stack.mjs.map +1 -1
- package/dist/entry-point.d.mts.map +1 -1
- package/dist/functional/match.d.mts.map +1 -1
- package/dist/functional/match.mjs +1 -6
- package/dist/functional/match.mjs.map +1 -1
- package/dist/functional/optional.d.mts.map +1 -1
- package/dist/functional/optional.mjs +6 -4
- package/dist/functional/optional.mjs.map +1 -1
- package/dist/functional/result.d.mts.map +1 -1
- package/dist/functional/result.mjs +1 -6
- package/dist/functional/result.mjs.map +1 -1
- package/dist/json/json.d.mts.map +1 -1
- package/dist/json/json.mjs +3 -3
- package/dist/json/json.mjs.map +1 -1
- package/dist/others/memoize-function.d.mts +1 -1
- package/dist/others/memoize-function.mjs +1 -1
- package/dist/others/unknown-to-string.d.mts +44 -77
- package/dist/others/unknown-to-string.d.mts.map +1 -1
- package/dist/others/unknown-to-string.mjs +51 -85
- package/dist/others/unknown-to-string.mjs.map +1 -1
- package/package.json +10 -1
- package/src/array/array-utils-creation.test.mts +9 -8
- package/src/array/array-utils-overload-type-error.test.mts +6 -2
- package/src/array/array-utils-search.test.mts +1 -1
- package/src/array/array-utils-slicing.test.mts +0 -42
- package/src/array/array-utils-transformation.test.mts +11 -186
- package/src/array/array-utils-validation.test.mts +27 -27
- package/src/array/array-utils.mts +8 -12
- package/src/collections/imap-mapped.test.mts +15 -11
- package/src/collections/imap.mts +6 -13
- package/src/collections/imap.test.mts +20 -19
- package/src/collections/iset-mapped.mts +1 -1
- package/src/collections/iset-mapped.test.mts +14 -104
- package/src/collections/iset.mts +5 -7
- package/src/collections/iset.test.mts +43 -34
- package/src/collections/queue.mts +12 -10
- package/src/collections/queue.test.mts +46 -44
- package/src/collections/stack.mts +10 -9
- package/src/collections/stack.test.mts +12 -10
- package/src/entry-point.mts +1 -0
- package/src/functional/match.mts +1 -5
- package/src/functional/optional.mts +6 -6
- package/src/functional/optional.test.mts +7 -7
- package/src/functional/result.mts +1 -5
- package/src/guard/is-non-empty-string.test.mts +1 -1
- package/src/guard/is-non-null-object.test.mts +3 -3
- package/src/guard/is-primitive.test.mts +6 -6
- package/src/guard/is-type.test.mts +8 -12
- package/src/iterator/range.test.mts +1 -1
- package/src/json/json.mts +4 -11
- package/src/json/json.test.mts +25 -28
- package/src/number/branded-types/finite-number.test.mts +2 -1
- package/src/number/branded-types/int.test.mts +2 -1
- package/src/number/branded-types/int16.test.mts +3 -2
- package/src/number/branded-types/int32.test.mts +3 -2
- package/src/number/branded-types/non-negative-finite-number.test.mts +3 -2
- package/src/number/branded-types/non-negative-int16.test.mts +3 -2
- package/src/number/branded-types/non-negative-int32.test.mts +3 -2
- package/src/number/branded-types/non-zero-finite-number.test.mts +4 -3
- package/src/number/branded-types/non-zero-int.test.mts +4 -3
- package/src/number/branded-types/non-zero-int16.test.mts +3 -2
- package/src/number/branded-types/non-zero-int32.test.mts +3 -2
- package/src/number/branded-types/non-zero-safe-int.test.mts +4 -3
- package/src/number/branded-types/non-zero-uint16.test.mts +3 -2
- package/src/number/branded-types/non-zero-uint32.test.mts +3 -2
- package/src/number/branded-types/positive-finite-number.test.mts +3 -2
- package/src/number/branded-types/positive-int.test.mts +3 -2
- package/src/number/branded-types/positive-int16.test.mts +3 -2
- package/src/number/branded-types/positive-int32.test.mts +3 -2
- package/src/number/branded-types/positive-safe-int.test.mts +3 -2
- package/src/number/branded-types/positive-uint16.test.mts +3 -2
- package/src/number/branded-types/positive-uint32.test.mts +3 -2
- package/src/number/branded-types/safe-int.test.mts +3 -2
- package/src/number/branded-types/safe-uint.test.mts +3 -2
- package/src/number/branded-types/uint.test.mts +3 -2
- package/src/number/branded-types/uint16.test.mts +3 -2
- package/src/number/branded-types/uint32.test.mts +3 -2
- package/src/object/object.test.mts +10 -10
- package/src/others/cast-readonly.test.mts +8 -8
- package/src/others/memoize-function.mts +1 -1
- package/src/others/memoize-function.test.mts +2 -2
- package/src/others/unknown-to-string.mts +52 -87
- package/src/others/unknown-to-string.test.mts +26 -58
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Arr } from '../array/index.mjs';
|
|
2
2
|
import { Optional } from '../functional/index.mjs';
|
|
3
|
+
import { range } from '../iterator/index.mjs';
|
|
3
4
|
import { asUint32 } from '../number/index.mjs';
|
|
4
5
|
import { createQueue, type Queue } from './queue.mjs';
|
|
5
6
|
|
|
@@ -19,22 +20,23 @@ describe('Queue', () => {
|
|
|
19
20
|
});
|
|
20
21
|
|
|
21
22
|
describe('enqueue', () => {
|
|
22
|
-
let
|
|
23
|
+
let mut_q: Queue<number>;
|
|
23
24
|
|
|
25
|
+
// eslint-disable-next-line vitest/no-hooks
|
|
24
26
|
beforeEach(() => {
|
|
25
|
-
|
|
27
|
+
mut_q = createQueue();
|
|
26
28
|
});
|
|
27
29
|
|
|
28
30
|
test('should increase size and not be empty after enqueueing to an empty queue', () => {
|
|
29
|
-
|
|
30
|
-
expect(
|
|
31
|
-
expect(
|
|
31
|
+
mut_q.enqueue(1);
|
|
32
|
+
expect(mut_q.isEmpty).toBe(false);
|
|
33
|
+
expect(mut_q.size).toBe(1);
|
|
32
34
|
});
|
|
33
35
|
|
|
34
36
|
test('should increase size when enqueueing to a non-empty queue', () => {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
expect(
|
|
37
|
+
mut_q.enqueue(1);
|
|
38
|
+
mut_q.enqueue(2);
|
|
39
|
+
expect(mut_q.size).toBe(2);
|
|
38
40
|
});
|
|
39
41
|
});
|
|
40
42
|
|
|
@@ -86,35 +88,35 @@ describe('Queue', () => {
|
|
|
86
88
|
|
|
87
89
|
expect(q.size).toBe(3);
|
|
88
90
|
|
|
89
|
-
let
|
|
90
|
-
expect(Optional.isSome(
|
|
91
|
+
let mut_result = q.dequeue(); // Dequeues 1 (first in)
|
|
92
|
+
expect(Optional.isSome(mut_result) && mut_result.value === 1).toBe(true);
|
|
91
93
|
expect(q.size).toBe(2);
|
|
92
94
|
|
|
93
|
-
|
|
94
|
-
expect(Optional.isSome(
|
|
95
|
+
mut_result = q.dequeue(); // Dequeues 2
|
|
96
|
+
expect(Optional.isSome(mut_result) && mut_result.value === 2).toBe(true);
|
|
95
97
|
expect(q.size).toBe(1);
|
|
96
98
|
|
|
97
|
-
|
|
98
|
-
expect(Optional.isSome(
|
|
99
|
+
mut_result = q.dequeue(); // Dequeues 3
|
|
100
|
+
expect(Optional.isSome(mut_result) && mut_result.value === 3).toBe(true);
|
|
99
101
|
expect(q.size).toBe(0);
|
|
100
102
|
expect(q.isEmpty).toBe(true);
|
|
101
103
|
|
|
102
|
-
|
|
103
|
-
expect(Optional.isNone(
|
|
104
|
+
mut_result = q.dequeue();
|
|
105
|
+
expect(Optional.isNone(mut_result)).toBe(true);
|
|
104
106
|
});
|
|
105
107
|
|
|
106
108
|
test('initial values are dequeued in the same order (FIFO)', () => {
|
|
107
109
|
const q = createQueue([1, 2, 3]); // Internal: [1, 2, 3]
|
|
108
110
|
expect(q.size).toBe(3);
|
|
109
111
|
|
|
110
|
-
|
|
111
|
-
expect(Optional.isSome(
|
|
112
|
+
const result1 = q.dequeue(); // Dequeues 1 (first element)
|
|
113
|
+
expect(Optional.isSome(result1) && result1.value === 1).toBe(true);
|
|
112
114
|
|
|
113
|
-
|
|
114
|
-
expect(Optional.isSome(
|
|
115
|
+
const result2 = q.dequeue(); // Dequeues 2
|
|
116
|
+
expect(Optional.isSome(result2) && result2.value === 2).toBe(true);
|
|
115
117
|
|
|
116
|
-
|
|
117
|
-
expect(Optional.isSome(
|
|
118
|
+
const result3 = q.dequeue(); // Dequeues 3
|
|
119
|
+
expect(Optional.isSome(result3) && result3.value === 3).toBe(true);
|
|
118
120
|
|
|
119
121
|
expect(q.isEmpty).toBe(true);
|
|
120
122
|
});
|
|
@@ -125,20 +127,20 @@ describe('Queue', () => {
|
|
|
125
127
|
q.enqueue('A');
|
|
126
128
|
q.enqueue('B');
|
|
127
129
|
|
|
128
|
-
|
|
129
|
-
expect(Optional.isSome(
|
|
130
|
+
const result1 = q.dequeue();
|
|
131
|
+
expect(Optional.isSome(result1) && result1.value === 'A').toBe(true);
|
|
130
132
|
|
|
131
133
|
q.enqueue('C');
|
|
132
134
|
q.enqueue('D');
|
|
133
135
|
|
|
134
|
-
|
|
135
|
-
expect(Optional.isSome(
|
|
136
|
+
const result2 = q.dequeue();
|
|
137
|
+
expect(Optional.isSome(result2) && result2.value === 'B').toBe(true);
|
|
136
138
|
|
|
137
|
-
|
|
138
|
-
expect(Optional.isSome(
|
|
139
|
+
const result3 = q.dequeue();
|
|
140
|
+
expect(Optional.isSome(result3) && result3.value === 'C').toBe(true);
|
|
139
141
|
|
|
140
|
-
|
|
141
|
-
expect(Optional.isSome(
|
|
142
|
+
const result4 = q.dequeue();
|
|
143
|
+
expect(Optional.isSome(result4) && result4.value === 'D').toBe(true);
|
|
142
144
|
|
|
143
145
|
expect(q.isEmpty).toBe(true);
|
|
144
146
|
});
|
|
@@ -149,7 +151,7 @@ describe('Queue', () => {
|
|
|
149
151
|
const q = createQueue<number>();
|
|
150
152
|
|
|
151
153
|
// Fill and partially empty the queue to create wraparound conditions
|
|
152
|
-
for (
|
|
154
|
+
for (const i of range(1, 6)) {
|
|
153
155
|
q.enqueue(i);
|
|
154
156
|
}
|
|
155
157
|
|
|
@@ -177,14 +179,14 @@ describe('Queue', () => {
|
|
|
177
179
|
const q = createQueue<number>();
|
|
178
180
|
|
|
179
181
|
// Add more elements than initial capacity (8) to trigger resize
|
|
180
|
-
for (
|
|
182
|
+
for (const i of range(1, 21)) {
|
|
181
183
|
q.enqueue(i);
|
|
182
184
|
}
|
|
183
185
|
|
|
184
186
|
expect(q.size).toBe(20);
|
|
185
187
|
|
|
186
188
|
// Verify all elements can be dequeued in correct order
|
|
187
|
-
for (
|
|
189
|
+
for (const i of range(1, 21)) {
|
|
188
190
|
const result = q.dequeue();
|
|
189
191
|
expect(Optional.isSome(result) && result.value === i).toBe(true);
|
|
190
192
|
}
|
|
@@ -196,29 +198,29 @@ describe('Queue', () => {
|
|
|
196
198
|
const q = createQueue<number>();
|
|
197
199
|
|
|
198
200
|
// Add many elements to trigger multiple resizes
|
|
199
|
-
for (
|
|
201
|
+
for (const i of range(1, 101)) {
|
|
200
202
|
q.enqueue(i);
|
|
201
203
|
}
|
|
202
204
|
|
|
203
205
|
expect(q.size).toBe(100);
|
|
204
206
|
|
|
205
207
|
// Remove half
|
|
206
|
-
for (
|
|
208
|
+
for (const i of range(1, 51)) {
|
|
207
209
|
expect(Optional.unwrap(q.dequeue())).toBe(i);
|
|
208
210
|
}
|
|
209
211
|
|
|
210
212
|
// Add more to trigger another resize
|
|
211
|
-
for (
|
|
213
|
+
for (const i of range(101, 151)) {
|
|
212
214
|
q.enqueue(i);
|
|
213
215
|
}
|
|
214
216
|
|
|
215
217
|
expect(q.size).toBe(100); // 50 remaining + 50 new
|
|
216
218
|
|
|
217
219
|
// Verify correct order
|
|
218
|
-
for (
|
|
220
|
+
for (const i of range(51, 101)) {
|
|
219
221
|
expect(Optional.unwrap(q.dequeue())).toBe(i);
|
|
220
222
|
}
|
|
221
|
-
for (
|
|
223
|
+
for (const i of range(101, 151)) {
|
|
222
224
|
expect(Optional.unwrap(q.dequeue())).toBe(i);
|
|
223
225
|
}
|
|
224
226
|
|
|
@@ -229,7 +231,7 @@ describe('Queue', () => {
|
|
|
229
231
|
const q = createQueue<string>();
|
|
230
232
|
|
|
231
233
|
// Test single element enqueue/dequeue cycles
|
|
232
|
-
for (
|
|
234
|
+
for (const i of range(10)) {
|
|
233
235
|
q.enqueue(`item-${i}`);
|
|
234
236
|
expect(q.size).toBe(1);
|
|
235
237
|
|
|
@@ -248,7 +250,7 @@ describe('Queue', () => {
|
|
|
248
250
|
expect(q.size).toBe(50);
|
|
249
251
|
|
|
250
252
|
// Verify all elements are in correct order
|
|
251
|
-
for (
|
|
253
|
+
for (const i of range(1, 51)) {
|
|
252
254
|
expect(Optional.unwrap(q.dequeue())).toBe(i);
|
|
253
255
|
}
|
|
254
256
|
|
|
@@ -260,18 +262,18 @@ describe('Queue', () => {
|
|
|
260
262
|
const objects = Arr.seq(10).map((i) => ({ id: i }));
|
|
261
263
|
|
|
262
264
|
// Add all objects
|
|
263
|
-
|
|
265
|
+
for (const obj of objects) {
|
|
264
266
|
q.enqueue(obj);
|
|
265
|
-
}
|
|
267
|
+
}
|
|
266
268
|
|
|
267
269
|
// Remove first 5 objects
|
|
268
|
-
for (
|
|
270
|
+
for (const i of range(0, 5)) {
|
|
269
271
|
const result = q.dequeue();
|
|
270
272
|
expect(Optional.isSome(result) && result.value.id === i).toBe(true);
|
|
271
273
|
}
|
|
272
274
|
|
|
273
275
|
// Remaining objects should still be accessible
|
|
274
|
-
for (
|
|
276
|
+
for (const i of range(5, 10)) {
|
|
275
277
|
const result = q.dequeue();
|
|
276
278
|
expect(Optional.isSome(result) && result.value.id === i).toBe(true);
|
|
277
279
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { Arr } from '../array/index.mjs';
|
|
2
1
|
import { Optional } from '../functional/index.mjs';
|
|
2
|
+
import { range } from '../iterator/index.mjs';
|
|
3
3
|
import { asUint32, Uint32 } from '../number/index.mjs';
|
|
4
|
-
import { castMutable } from '../others/index.mjs';
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Interface for a high-performance stack with LIFO (Last-In, First-Out) behavior.
|
|
@@ -116,8 +115,9 @@ class StackClass<T> implements Stack<T> {
|
|
|
116
115
|
Math.max(StackClass.#INITIAL_CAPACITY, initialValues.length * 2),
|
|
117
116
|
);
|
|
118
117
|
|
|
119
|
-
this.#buffer =
|
|
120
|
-
|
|
118
|
+
this.#buffer = Array.from<unknown, T | undefined>(
|
|
119
|
+
{ length: initialCapacity },
|
|
120
|
+
() => undefined,
|
|
121
121
|
);
|
|
122
122
|
this.#mut_size = asUint32(0);
|
|
123
123
|
this.#capacity = initialCapacity;
|
|
@@ -238,7 +238,7 @@ class StackClass<T> implements Stack<T> {
|
|
|
238
238
|
* // High-volume pushing (demonstrates amortized O(1) performance)
|
|
239
239
|
* const dataStack = createStack<number>();
|
|
240
240
|
*
|
|
241
|
-
* for (
|
|
241
|
+
* for (const i of range(1000000)) {
|
|
242
242
|
* dataStack.push(i); // Each operation is O(1) amortized
|
|
243
243
|
* }
|
|
244
244
|
*
|
|
@@ -274,12 +274,13 @@ class StackClass<T> implements Stack<T> {
|
|
|
274
274
|
*/
|
|
275
275
|
#resize(): void {
|
|
276
276
|
const newCapacity = asUint32(this.#capacity * 2);
|
|
277
|
-
const newBuffer =
|
|
278
|
-
|
|
277
|
+
const newBuffer = Array.from<unknown, T | undefined>(
|
|
278
|
+
{ length: newCapacity },
|
|
279
|
+
() => undefined,
|
|
279
280
|
);
|
|
280
281
|
|
|
281
282
|
// Copy existing elements
|
|
282
|
-
for (
|
|
283
|
+
for (const i of range(this.#mut_size)) {
|
|
283
284
|
newBuffer[i] = this.#buffer[i];
|
|
284
285
|
}
|
|
285
286
|
|
|
@@ -384,7 +385,7 @@ class StackClass<T> implements Stack<T> {
|
|
|
384
385
|
* const processingStack = createStack<number>();
|
|
385
386
|
*
|
|
386
387
|
* // Add large amount of data (demonstrates amortized O(1) performance)
|
|
387
|
-
* for (
|
|
388
|
+
* for (const i of range(100000)) {
|
|
388
389
|
* processingStack.push(i); // Each push is O(1) amortized
|
|
389
390
|
* }
|
|
390
391
|
*
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { expectType } from '../expect-type.mjs';
|
|
2
2
|
import { Optional } from '../functional/index.mjs';
|
|
3
|
+
import { range } from '../iterator/index.mjs';
|
|
4
|
+
import { asPositiveSafeInt, asSafeInt } from '../number/index.mjs';
|
|
3
5
|
import { createStack, type Stack } from './stack.mjs';
|
|
4
6
|
|
|
5
7
|
describe('Stack', () => {
|
|
@@ -125,10 +127,10 @@ describe('Stack', () => {
|
|
|
125
127
|
|
|
126
128
|
test('should handle large number of operations efficiently', () => {
|
|
127
129
|
const stack = createStack<number>();
|
|
128
|
-
const n = 10000;
|
|
130
|
+
const n = asPositiveSafeInt(10000);
|
|
129
131
|
|
|
130
132
|
// Push many elements
|
|
131
|
-
for (
|
|
133
|
+
for (const i of range(n)) {
|
|
132
134
|
stack.push(i);
|
|
133
135
|
}
|
|
134
136
|
|
|
@@ -136,7 +138,7 @@ describe('Stack', () => {
|
|
|
136
138
|
expect(stack.isEmpty).toBe(false);
|
|
137
139
|
|
|
138
140
|
// Pop all elements and verify LIFO order
|
|
139
|
-
for (
|
|
141
|
+
for (const i of range(asSafeInt(n - 1), -1, -1)) {
|
|
140
142
|
const result = stack.pop();
|
|
141
143
|
expect(Optional.isSome(result)).toBe(true);
|
|
142
144
|
expect(Optional.unwrap(result)).toBe(i);
|
|
@@ -157,7 +159,7 @@ describe('Stack', () => {
|
|
|
157
159
|
Optional.unwrap(stack.pop());
|
|
158
160
|
|
|
159
161
|
// Original array should be unchanged
|
|
160
|
-
expect(initialValues
|
|
162
|
+
expect(initialValues).toHaveLength(originalLength);
|
|
161
163
|
expect(initialValues).toStrictEqual([1, 2, 3]);
|
|
162
164
|
});
|
|
163
165
|
|
|
@@ -170,8 +172,8 @@ describe('Stack', () => {
|
|
|
170
172
|
stack.push('another');
|
|
171
173
|
|
|
172
174
|
expect(Optional.unwrap(stack.pop())).toBe('another');
|
|
173
|
-
expect(Optional.unwrap(stack.pop())).
|
|
174
|
-
expect(Optional.unwrap(stack.pop())).
|
|
175
|
+
expect(Optional.unwrap(stack.pop())).toBeUndefined();
|
|
176
|
+
expect(Optional.unwrap(stack.pop())).toBeNull();
|
|
175
177
|
expect(Optional.unwrap(stack.pop())).toBe('value');
|
|
176
178
|
expect(stack.isEmpty).toBe(true);
|
|
177
179
|
});
|
|
@@ -183,7 +185,7 @@ describe('Stack', () => {
|
|
|
183
185
|
const startTime = performance.now();
|
|
184
186
|
|
|
185
187
|
// Push operations should be O(1) amortized
|
|
186
|
-
for (
|
|
188
|
+
for (const i of range(511)) {
|
|
187
189
|
stack.push(i);
|
|
188
190
|
}
|
|
189
191
|
|
|
@@ -195,14 +197,14 @@ describe('Stack', () => {
|
|
|
195
197
|
const endTime = performance.now();
|
|
196
198
|
const duration = endTime - startTime;
|
|
197
199
|
|
|
198
|
-
// Should complete in reasonable time (much less than 100ms for
|
|
200
|
+
// Should complete in reasonable time (much less than 100ms for 512 operations)
|
|
199
201
|
expect(duration).toBeLessThan(100);
|
|
200
202
|
});
|
|
201
203
|
|
|
202
204
|
test('should handle alternating push/pop operations', () => {
|
|
203
205
|
const stack = createStack<number>();
|
|
204
206
|
|
|
205
|
-
for (
|
|
207
|
+
for (const i of range(100)) {
|
|
206
208
|
stack.push(i);
|
|
207
209
|
if (i % 2 === 1) {
|
|
208
210
|
// Pop every other time
|
|
@@ -215,7 +217,7 @@ describe('Stack', () => {
|
|
|
215
217
|
expect(stack.size).toBe(50);
|
|
216
218
|
|
|
217
219
|
// Verify elements are in correct LIFO order
|
|
218
|
-
for (
|
|
220
|
+
for (const i of range(98, -1, -2)) {
|
|
219
221
|
const result = stack.pop();
|
|
220
222
|
expect(Optional.unwrap(result)).toBe(i);
|
|
221
223
|
}
|
package/src/entry-point.mts
CHANGED
package/src/functional/match.mts
CHANGED
|
@@ -186,11 +186,7 @@ export function match<
|
|
|
186
186
|
}
|
|
187
187
|
case 3: {
|
|
188
188
|
const [target, cases, defaultValue] = args;
|
|
189
|
-
|
|
190
|
-
return cases[target];
|
|
191
|
-
} else {
|
|
192
|
-
return defaultValue;
|
|
193
|
-
}
|
|
189
|
+
return keyIsIn(target, cases) ? cases[target] : defaultValue;
|
|
194
190
|
}
|
|
195
191
|
}
|
|
196
192
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { isRecord } from '../guard/index.mjs';
|
|
2
|
-
import { pipe } from './pipe.mjs';
|
|
3
2
|
|
|
4
3
|
/** @internal String literal tag to identify the 'Some' variant of Optional. */
|
|
5
4
|
const SomeTypeTagName = 'ts-data-forge::Optional.some';
|
|
@@ -451,11 +450,12 @@ export namespace Optional {
|
|
|
451
450
|
switch (args.length) {
|
|
452
451
|
case 2: {
|
|
453
452
|
const [optional, predicate] = args;
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
453
|
+
if (isSome(optional)) {
|
|
454
|
+
const value = unwrap(optional);
|
|
455
|
+
return predicate(value) ? some(value) : none;
|
|
456
|
+
}
|
|
457
|
+
// If the optional is None, return None
|
|
458
|
+
return none;
|
|
459
459
|
}
|
|
460
460
|
|
|
461
461
|
case 1: {
|
|
@@ -55,7 +55,7 @@ describe('Optional', () => {
|
|
|
55
55
|
expect(Optional.isNone(Optional.none)).toBe(true);
|
|
56
56
|
expect(Optional.isSome(Optional.none)).toBe(false);
|
|
57
57
|
// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
|
|
58
|
-
expect(Optional.unwrapOr(Optional.none, undefined)).
|
|
58
|
+
expect(Optional.unwrapOr(Optional.none, undefined)).toBeUndefined();
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
test('should always reference the same instance', () => {
|
|
@@ -158,12 +158,12 @@ describe('Optional', () => {
|
|
|
158
158
|
test('should return the value for Some', () => {
|
|
159
159
|
expect(Optional.unwrap(Optional.some(42))).toBe(42);
|
|
160
160
|
expect(Optional.unwrap(Optional.some('hello'))).toBe('hello');
|
|
161
|
-
expect(Optional.unwrap(Optional.some(null))).
|
|
161
|
+
expect(Optional.unwrap(Optional.some(null))).toBeNull();
|
|
162
162
|
});
|
|
163
163
|
|
|
164
164
|
test('should return undefined for None', () => {
|
|
165
165
|
// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
|
|
166
|
-
expect(Optional.unwrapOr(Optional.none, undefined)).
|
|
166
|
+
expect(Optional.unwrapOr(Optional.none, undefined)).toBeUndefined();
|
|
167
167
|
});
|
|
168
168
|
|
|
169
169
|
test('should have correct return types', () => {
|
|
@@ -579,12 +579,12 @@ describe('Optional', () => {
|
|
|
579
579
|
test('should convert Some to its value', () => {
|
|
580
580
|
expect(Optional.toNullable(Optional.some(42))).toBe(42);
|
|
581
581
|
expect(Optional.toNullable(Optional.some('hello'))).toBe('hello');
|
|
582
|
-
expect(Optional.toNullable(Optional.some(null))).
|
|
582
|
+
expect(Optional.toNullable(Optional.some(null))).toBeNull();
|
|
583
583
|
});
|
|
584
584
|
|
|
585
585
|
test('should convert None to null', () => {
|
|
586
586
|
// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
|
|
587
|
-
expect(Optional.toNullable(Optional.none)).
|
|
587
|
+
expect(Optional.toNullable(Optional.none)).toBeUndefined();
|
|
588
588
|
});
|
|
589
589
|
|
|
590
590
|
test('should have correct return type', () => {
|
|
@@ -598,7 +598,7 @@ describe('Optional', () => {
|
|
|
598
598
|
const someUndefined = Optional.some(undefined);
|
|
599
599
|
expect(Optional.isSome(someUndefined)).toBe(true);
|
|
600
600
|
// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
|
|
601
|
-
expect(Optional.unwrap(someUndefined)).
|
|
601
|
+
expect(Optional.unwrap(someUndefined)).toBeUndefined();
|
|
602
602
|
|
|
603
603
|
// This is different from None
|
|
604
604
|
expect(someUndefined).not.toBe(Optional.none);
|
|
@@ -607,7 +607,7 @@ describe('Optional', () => {
|
|
|
607
607
|
test('should handle null as a Some value', () => {
|
|
608
608
|
const someNull = Optional.some(null);
|
|
609
609
|
expect(Optional.isSome(someNull)).toBe(true);
|
|
610
|
-
expect(Optional.unwrap(someNull)).
|
|
610
|
+
expect(Optional.unwrap(someNull)).toBeNull();
|
|
611
611
|
});
|
|
612
612
|
|
|
613
613
|
test('should handle nested Optionals', () => {
|
|
@@ -852,11 +852,7 @@ export namespace Result {
|
|
|
852
852
|
return err(error);
|
|
853
853
|
}
|
|
854
854
|
const msg = unknownToString(error);
|
|
855
|
-
|
|
856
|
-
return err(new Error(String(error)));
|
|
857
|
-
} else {
|
|
858
|
-
return err(new Error(msg.value));
|
|
859
|
-
}
|
|
855
|
+
return err(new Error(msg));
|
|
860
856
|
}
|
|
861
857
|
};
|
|
862
858
|
|
|
@@ -85,7 +85,7 @@ describe('isNonEmptyString', () => {
|
|
|
85
85
|
|
|
86
86
|
test('should not accept String objects', () => {
|
|
87
87
|
// @ts-expect-error Testing non-string types
|
|
88
|
-
// eslint-disable-next-line no-new-wrappers
|
|
88
|
+
// eslint-disable-next-line no-new-wrappers, unicorn/new-for-builtins
|
|
89
89
|
expect(isNonEmptyString(new String('hello') as unknown)).toBe(false);
|
|
90
90
|
});
|
|
91
91
|
});
|
|
@@ -31,11 +31,11 @@ describe('isNonNullObject', () => {
|
|
|
31
31
|
});
|
|
32
32
|
|
|
33
33
|
test('should return true for boxed primitives', () => {
|
|
34
|
-
// eslint-disable-next-line no-new-wrappers
|
|
34
|
+
// eslint-disable-next-line no-new-wrappers, unicorn/new-for-builtins
|
|
35
35
|
expect(isNonNullObject(new String('hello'))).toBe(true);
|
|
36
|
-
// eslint-disable-next-line no-new-wrappers
|
|
36
|
+
// eslint-disable-next-line no-new-wrappers, unicorn/new-for-builtins
|
|
37
37
|
expect(isNonNullObject(new Number(42))).toBe(true);
|
|
38
|
-
// eslint-disable-next-line no-new-wrappers
|
|
38
|
+
// eslint-disable-next-line no-new-wrappers, unicorn/new-for-builtins
|
|
39
39
|
expect(isNonNullObject(new Boolean(true))).toBe(true);
|
|
40
40
|
});
|
|
41
41
|
|
|
@@ -66,11 +66,11 @@ describe('isPrimitive', () => {
|
|
|
66
66
|
});
|
|
67
67
|
|
|
68
68
|
test('should return false for boxed primitives', () => {
|
|
69
|
-
// eslint-disable-next-line no-new-wrappers
|
|
69
|
+
// eslint-disable-next-line no-new-wrappers, unicorn/new-for-builtins
|
|
70
70
|
expect(isPrimitive(new String('hello'))).toBe(false);
|
|
71
|
-
// eslint-disable-next-line no-new-wrappers
|
|
71
|
+
// eslint-disable-next-line no-new-wrappers, unicorn/new-for-builtins
|
|
72
72
|
expect(isPrimitive(new Number(42))).toBe(false);
|
|
73
|
-
// eslint-disable-next-line no-new-wrappers
|
|
73
|
+
// eslint-disable-next-line no-new-wrappers, unicorn/new-for-builtins
|
|
74
74
|
expect(isPrimitive(new Boolean(true))).toBe(false);
|
|
75
75
|
});
|
|
76
76
|
|
|
@@ -89,12 +89,12 @@ describe('isPrimitive', () => {
|
|
|
89
89
|
const primitives = values.filter(isPrimitive);
|
|
90
90
|
const nonPrimitives = values.filter((v) => !isPrimitive(v));
|
|
91
91
|
|
|
92
|
-
expect(primitives
|
|
92
|
+
expect(primitives).toHaveLength(6); // string, 42, true, null, undefined, symbol
|
|
93
93
|
expect(primitives[0]).toBe('string');
|
|
94
94
|
expect(primitives[1]).toBe(42);
|
|
95
95
|
expect(primitives[2]).toBe(true);
|
|
96
|
-
expect(primitives[3]).
|
|
97
|
-
expect(primitives[4]).
|
|
96
|
+
expect(primitives[3]).toBeNull();
|
|
97
|
+
expect(primitives[4]).toBeUndefined();
|
|
98
98
|
expect(typeof primitives[5]).toBe('symbol');
|
|
99
99
|
|
|
100
100
|
expect(nonPrimitives).toStrictEqual([{}, []]);
|
|
@@ -112,7 +112,7 @@ describe('isString', () => {
|
|
|
112
112
|
expect(isString(true)).toBe(false);
|
|
113
113
|
expect(isString(null)).toBe(false);
|
|
114
114
|
expect(isString(undefined)).toBe(false);
|
|
115
|
-
// eslint-disable-next-line no-new-wrappers
|
|
115
|
+
// eslint-disable-next-line no-new-wrappers, unicorn/new-for-builtins
|
|
116
116
|
expect(isString(new String('hello'))).toBe(false);
|
|
117
117
|
});
|
|
118
118
|
|
|
@@ -120,7 +120,7 @@ describe('isString', () => {
|
|
|
120
120
|
const value: unknown = 'test';
|
|
121
121
|
if (isString(value)) {
|
|
122
122
|
expectType<typeof value, string>('=');
|
|
123
|
-
expect(value
|
|
123
|
+
expect(value).toHaveLength(4);
|
|
124
124
|
}
|
|
125
125
|
});
|
|
126
126
|
});
|
|
@@ -140,7 +140,7 @@ describe('isNumber', () => {
|
|
|
140
140
|
expect(isNumber(true)).toBe(false);
|
|
141
141
|
expect(isNumber(null)).toBe(false);
|
|
142
142
|
expect(isNumber(BigInt(123))).toBe(false);
|
|
143
|
-
// eslint-disable-next-line no-new-wrappers
|
|
143
|
+
// eslint-disable-next-line no-new-wrappers, unicorn/new-for-builtins
|
|
144
144
|
expect(isNumber(new Number(42))).toBe(false);
|
|
145
145
|
});
|
|
146
146
|
|
|
@@ -187,7 +187,7 @@ describe('isBoolean', () => {
|
|
|
187
187
|
expect(isBoolean(0)).toBe(false);
|
|
188
188
|
expect(isBoolean('true')).toBe(false);
|
|
189
189
|
expect(isBoolean(null)).toBe(false);
|
|
190
|
-
// eslint-disable-next-line no-new-wrappers
|
|
190
|
+
// eslint-disable-next-line no-new-wrappers, unicorn/new-for-builtins
|
|
191
191
|
expect(isBoolean(new Boolean(true))).toBe(false);
|
|
192
192
|
});
|
|
193
193
|
|
|
@@ -424,7 +424,7 @@ describe('isNonNullish', () => {
|
|
|
424
424
|
const value: string | null | undefined = 'test';
|
|
425
425
|
if (isNonNullish(value)) {
|
|
426
426
|
expectType<typeof value, string>('<=');
|
|
427
|
-
expect(value
|
|
427
|
+
expect(value).toHaveLength(4);
|
|
428
428
|
}
|
|
429
429
|
});
|
|
430
430
|
|
|
@@ -460,13 +460,9 @@ describe('type guard behavior in complex scenarios', () => {
|
|
|
460
460
|
test('should work with nested conditions', () => {
|
|
461
461
|
const value: string | number | boolean | null | undefined = 'test';
|
|
462
462
|
|
|
463
|
-
if (isNonNullish(value)) {
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
expectType<typeof value, string>('<=');
|
|
467
|
-
expect(typeof value).toBe('string');
|
|
468
|
-
}
|
|
469
|
-
}
|
|
463
|
+
if (isNonNullish(value) && isNotBoolean(value) && isNotNumber(value)) {
|
|
464
|
+
expectType<typeof value, string>('<=');
|
|
465
|
+
expect(typeof value).toBe('string');
|
|
470
466
|
}
|
|
471
467
|
});
|
|
472
468
|
|
package/src/json/json.mts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Arr } from '../array/index.mjs';
|
|
2
2
|
import { pipe, Result } from '../functional/index.mjs';
|
|
3
3
|
import { isRecord } from '../guard/index.mjs';
|
|
4
|
-
import { castMutable } from '../others/index.mjs';
|
|
5
|
-
import { unknownToString } from '../others/unknown-to-string.mjs';
|
|
4
|
+
import { castMutable, unknownToString } from '../others/index.mjs';
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* A collection of type-safe JSON utility functions that provide safe parsing,
|
|
@@ -74,9 +73,7 @@ export namespace Json {
|
|
|
74
73
|
);
|
|
75
74
|
} catch (error: unknown) {
|
|
76
75
|
const errStr = unknownToString(error);
|
|
77
|
-
return Result.err(
|
|
78
|
-
Result.isOk(errStr) ? errStr.value : 'Failed to parse JSON',
|
|
79
|
-
);
|
|
76
|
+
return Result.err(errStr);
|
|
80
77
|
}
|
|
81
78
|
};
|
|
82
79
|
|
|
@@ -129,9 +126,7 @@ export namespace Json {
|
|
|
129
126
|
return Result.ok(JSON.stringify(value, replacer, space));
|
|
130
127
|
} catch (error) {
|
|
131
128
|
const errStr = unknownToString(error);
|
|
132
|
-
return Result.err(
|
|
133
|
-
Result.isOk(errStr) ? errStr.value : 'Failed to stringify JSON',
|
|
134
|
-
);
|
|
129
|
+
return Result.err(errStr);
|
|
135
130
|
}
|
|
136
131
|
};
|
|
137
132
|
|
|
@@ -182,9 +177,7 @@ export namespace Json {
|
|
|
182
177
|
);
|
|
183
178
|
} catch (error) {
|
|
184
179
|
const errStr = unknownToString(error);
|
|
185
|
-
return Result.err(
|
|
186
|
-
Result.isOk(errStr) ? errStr.value : 'Failed to stringify JSON',
|
|
187
|
-
);
|
|
180
|
+
return Result.err(errStr);
|
|
188
181
|
}
|
|
189
182
|
};
|
|
190
183
|
|