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.
Files changed (103) hide show
  1. package/README.md +13 -15
  2. package/dist/array/array-utils.d.mts.map +1 -1
  3. package/dist/array/array-utils.mjs +9 -13
  4. package/dist/array/array-utils.mjs.map +1 -1
  5. package/dist/collections/imap.d.mts +1 -1
  6. package/dist/collections/imap.d.mts.map +1 -1
  7. package/dist/collections/imap.mjs +5 -5
  8. package/dist/collections/imap.mjs.map +1 -1
  9. package/dist/collections/iset-mapped.d.mts +1 -1
  10. package/dist/collections/iset-mapped.mjs +1 -1
  11. package/dist/collections/iset.d.mts +2 -2
  12. package/dist/collections/iset.mjs +4 -5
  13. package/dist/collections/iset.mjs.map +1 -1
  14. package/dist/collections/queue.d.mts +1 -1
  15. package/dist/collections/queue.d.mts.map +1 -1
  16. package/dist/collections/queue.mjs +7 -8
  17. package/dist/collections/queue.mjs.map +1 -1
  18. package/dist/collections/stack.d.mts +1 -1
  19. package/dist/collections/stack.d.mts.map +1 -1
  20. package/dist/collections/stack.mjs +6 -7
  21. package/dist/collections/stack.mjs.map +1 -1
  22. package/dist/entry-point.d.mts.map +1 -1
  23. package/dist/functional/match.d.mts.map +1 -1
  24. package/dist/functional/match.mjs +1 -6
  25. package/dist/functional/match.mjs.map +1 -1
  26. package/dist/functional/optional.d.mts.map +1 -1
  27. package/dist/functional/optional.mjs +6 -4
  28. package/dist/functional/optional.mjs.map +1 -1
  29. package/dist/functional/result.d.mts.map +1 -1
  30. package/dist/functional/result.mjs +1 -6
  31. package/dist/functional/result.mjs.map +1 -1
  32. package/dist/json/json.d.mts.map +1 -1
  33. package/dist/json/json.mjs +3 -3
  34. package/dist/json/json.mjs.map +1 -1
  35. package/dist/others/memoize-function.d.mts +1 -1
  36. package/dist/others/memoize-function.mjs +1 -1
  37. package/dist/others/unknown-to-string.d.mts +44 -77
  38. package/dist/others/unknown-to-string.d.mts.map +1 -1
  39. package/dist/others/unknown-to-string.mjs +51 -85
  40. package/dist/others/unknown-to-string.mjs.map +1 -1
  41. package/package.json +10 -1
  42. package/src/array/array-utils-creation.test.mts +9 -8
  43. package/src/array/array-utils-overload-type-error.test.mts +6 -2
  44. package/src/array/array-utils-search.test.mts +1 -1
  45. package/src/array/array-utils-slicing.test.mts +0 -42
  46. package/src/array/array-utils-transformation.test.mts +11 -186
  47. package/src/array/array-utils-validation.test.mts +27 -27
  48. package/src/array/array-utils.mts +8 -12
  49. package/src/collections/imap-mapped.test.mts +15 -11
  50. package/src/collections/imap.mts +6 -13
  51. package/src/collections/imap.test.mts +20 -19
  52. package/src/collections/iset-mapped.mts +1 -1
  53. package/src/collections/iset-mapped.test.mts +14 -104
  54. package/src/collections/iset.mts +5 -7
  55. package/src/collections/iset.test.mts +43 -34
  56. package/src/collections/queue.mts +12 -10
  57. package/src/collections/queue.test.mts +46 -44
  58. package/src/collections/stack.mts +10 -9
  59. package/src/collections/stack.test.mts +12 -10
  60. package/src/entry-point.mts +1 -0
  61. package/src/functional/match.mts +1 -5
  62. package/src/functional/optional.mts +6 -6
  63. package/src/functional/optional.test.mts +7 -7
  64. package/src/functional/result.mts +1 -5
  65. package/src/guard/is-non-empty-string.test.mts +1 -1
  66. package/src/guard/is-non-null-object.test.mts +3 -3
  67. package/src/guard/is-primitive.test.mts +6 -6
  68. package/src/guard/is-type.test.mts +8 -12
  69. package/src/iterator/range.test.mts +1 -1
  70. package/src/json/json.mts +4 -11
  71. package/src/json/json.test.mts +25 -28
  72. package/src/number/branded-types/finite-number.test.mts +2 -1
  73. package/src/number/branded-types/int.test.mts +2 -1
  74. package/src/number/branded-types/int16.test.mts +3 -2
  75. package/src/number/branded-types/int32.test.mts +3 -2
  76. package/src/number/branded-types/non-negative-finite-number.test.mts +3 -2
  77. package/src/number/branded-types/non-negative-int16.test.mts +3 -2
  78. package/src/number/branded-types/non-negative-int32.test.mts +3 -2
  79. package/src/number/branded-types/non-zero-finite-number.test.mts +4 -3
  80. package/src/number/branded-types/non-zero-int.test.mts +4 -3
  81. package/src/number/branded-types/non-zero-int16.test.mts +3 -2
  82. package/src/number/branded-types/non-zero-int32.test.mts +3 -2
  83. package/src/number/branded-types/non-zero-safe-int.test.mts +4 -3
  84. package/src/number/branded-types/non-zero-uint16.test.mts +3 -2
  85. package/src/number/branded-types/non-zero-uint32.test.mts +3 -2
  86. package/src/number/branded-types/positive-finite-number.test.mts +3 -2
  87. package/src/number/branded-types/positive-int.test.mts +3 -2
  88. package/src/number/branded-types/positive-int16.test.mts +3 -2
  89. package/src/number/branded-types/positive-int32.test.mts +3 -2
  90. package/src/number/branded-types/positive-safe-int.test.mts +3 -2
  91. package/src/number/branded-types/positive-uint16.test.mts +3 -2
  92. package/src/number/branded-types/positive-uint32.test.mts +3 -2
  93. package/src/number/branded-types/safe-int.test.mts +3 -2
  94. package/src/number/branded-types/safe-uint.test.mts +3 -2
  95. package/src/number/branded-types/uint.test.mts +3 -2
  96. package/src/number/branded-types/uint16.test.mts +3 -2
  97. package/src/number/branded-types/uint32.test.mts +3 -2
  98. package/src/object/object.test.mts +10 -10
  99. package/src/others/cast-readonly.test.mts +8 -8
  100. package/src/others/memoize-function.mts +1 -1
  101. package/src/others/memoize-function.test.mts +2 -2
  102. package/src/others/unknown-to-string.mts +52 -87
  103. 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 q: Queue<number>;
23
+ let mut_q: Queue<number>;
23
24
 
25
+ // eslint-disable-next-line vitest/no-hooks
24
26
  beforeEach(() => {
25
- q = createQueue();
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
- q.enqueue(1);
30
- expect(q.isEmpty).toBe(false);
31
- expect(q.size).toBe(1);
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
- q.enqueue(1);
36
- q.enqueue(2);
37
- expect(q.size).toBe(2);
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 result = q.dequeue(); // Dequeues 1 (first in)
90
- expect(Optional.isSome(result) && result.value === 1).toBe(true);
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
- result = q.dequeue(); // Dequeues 2
94
- expect(Optional.isSome(result) && result.value === 2).toBe(true);
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
- result = q.dequeue(); // Dequeues 3
98
- expect(Optional.isSome(result) && result.value === 3).toBe(true);
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
- result = q.dequeue();
103
- expect(Optional.isNone(result)).toBe(true);
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
- let result = q.dequeue(); // Dequeues 1 (first element)
111
- expect(Optional.isSome(result) && result.value === 1).toBe(true);
112
+ const result1 = q.dequeue(); // Dequeues 1 (first element)
113
+ expect(Optional.isSome(result1) && result1.value === 1).toBe(true);
112
114
 
113
- result = q.dequeue(); // Dequeues 2
114
- expect(Optional.isSome(result) && result.value === 2).toBe(true);
115
+ const result2 = q.dequeue(); // Dequeues 2
116
+ expect(Optional.isSome(result2) && result2.value === 2).toBe(true);
115
117
 
116
- result = q.dequeue(); // Dequeues 3
117
- expect(Optional.isSome(result) && result.value === 3).toBe(true);
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
- let result = q.dequeue();
129
- expect(Optional.isSome(result) && result.value === 'A').toBe(true);
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
- result = q.dequeue();
135
- expect(Optional.isSome(result) && result.value === 'B').toBe(true);
136
+ const result2 = q.dequeue();
137
+ expect(Optional.isSome(result2) && result2.value === 'B').toBe(true);
136
138
 
137
- result = q.dequeue();
138
- expect(Optional.isSome(result) && result.value === 'C').toBe(true);
139
+ const result3 = q.dequeue();
140
+ expect(Optional.isSome(result3) && result3.value === 'C').toBe(true);
139
141
 
140
- result = q.dequeue();
141
- expect(Optional.isSome(result) && result.value === 'D').toBe(true);
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 (let i = 1; i <= 5; i++) {
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 (let i = 1; i <= 20; i++) {
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 (let i = 1; i <= 20; i++) {
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 (let i = 1; i <= 100; i++) {
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 (let i = 1; i <= 50; i++) {
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 (let i = 101; i <= 150; i++) {
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 (let i = 51; i <= 100; i++) {
220
+ for (const i of range(51, 101)) {
219
221
  expect(Optional.unwrap(q.dequeue())).toBe(i);
220
222
  }
221
- for (let i = 101; i <= 150; i++) {
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 (let i = 0; i < 10; i++) {
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 (let i = 1; i <= 50; i++) {
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
- objects.forEach((obj) => {
265
+ for (const obj of objects) {
264
266
  q.enqueue(obj);
265
- });
267
+ }
266
268
 
267
269
  // Remove first 5 objects
268
- for (let i = 0; i < 5; i++) {
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 (let i = 5; i < 10; i++) {
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 = castMutable(
120
- Arr.create<T | undefined, Uint32>(initialCapacity, undefined),
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 (let i = 0; i < 1000000; i++) {
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 = castMutable(
278
- Arr.create<T | undefined, Uint32>(newCapacity, undefined),
277
+ const newBuffer = Array.from<unknown, T | undefined>(
278
+ { length: newCapacity },
279
+ () => undefined,
279
280
  );
280
281
 
281
282
  // Copy existing elements
282
- for (let i = 0; i < this.#mut_size; i++) {
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 (let i = 0; i < 100000; i++) {
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 (let i = 0; i < n; i++) {
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 (let i = n - 1; i >= 0; i--) {
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.length).toBe(originalLength);
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())).toBe(undefined);
174
- expect(Optional.unwrap(stack.pop())).toBe(null);
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 (let i = 0; i < 1000; i++) {
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 1000 operations)
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 (let i = 0; i < 100; i++) {
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 (let i = 98; i >= 0; i -= 2) {
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
  }
@@ -1,3 +1,4 @@
1
+ // eslint-disable-next-line import/no-unassigned-import
1
2
  import 'ts-type-forge';
2
3
 
3
4
  export * from './index.mjs';
@@ -186,11 +186,7 @@ export function match<
186
186
  }
187
187
  case 3: {
188
188
  const [target, cases, defaultValue] = args;
189
- if (keyIsIn(target, cases)) {
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
- return isSome(optional)
455
- ? pipe(unwrap(optional)).map((value) =>
456
- predicate(value) ? some(value) : none,
457
- ).value
458
- : none;
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)).toBe(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))).toBe(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)).toBe(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))).toBe(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)).toBe(undefined);
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)).toBe(undefined);
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)).toBe(null);
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
- if (isErr(msg)) {
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.length).toBe(6); // string, 42, true, null, undefined, symbol
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]).toBe(null);
97
- expect(primitives[4]).toBe(undefined);
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.length).toBe(4);
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.length).toBe(4);
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
- if (isNotBoolean(value)) {
465
- if (isNotNumber(value)) {
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
 
@@ -15,7 +15,7 @@ describe('range', () => {
15
15
  expect(Array.from(range(0))).toStrictEqual([]);
16
16
  });
17
17
 
18
- test('range(0)', () => {
18
+ test('range(-1)', () => {
19
19
  // @ts-expect-error negative end is not allowed
20
20
  expect(Array.from(range(-1))).toStrictEqual([]);
21
21
  });
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