ts-data-forge 6.3.1 → 6.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/README.md +5 -3
  2. package/dist/array/impl/array-utils-element-access.d.mts +5 -5
  3. package/dist/array/impl/array-utils-element-access.mjs +4 -4
  4. package/dist/array/impl/array-utils-iterators.d.mts +1 -1
  5. package/dist/array/impl/array-utils-iterators.mjs +1 -1
  6. package/dist/array/impl/array-utils-modification.d.mts +4 -4
  7. package/dist/array/impl/array-utils-reducing-value.d.mts +5 -5
  8. package/dist/array/impl/array-utils-reducing-value.d.mts.map +1 -1
  9. package/dist/array/impl/array-utils-reducing-value.mjs +1 -0
  10. package/dist/array/impl/array-utils-reducing-value.mjs.map +1 -1
  11. package/dist/array/impl/array-utils-search.d.mts +8 -8
  12. package/dist/array/impl/array-utils-set-op.d.mts.map +1 -1
  13. package/dist/array/impl/array-utils-set-op.mjs +3 -1
  14. package/dist/array/impl/array-utils-set-op.mjs.map +1 -1
  15. package/dist/array/impl/array-utils-size.d.mts +1 -1
  16. package/dist/array/impl/array-utils-size.mjs +1 -1
  17. package/dist/array/impl/array-utils-slice-clamped.d.mts +1 -1
  18. package/dist/array/impl/array-utils-slicing.d.mts +3 -3
  19. package/dist/array/impl/array-utils-transformation.d.mts.map +1 -1
  20. package/dist/array/impl/array-utils-validation.d.mts +7 -7
  21. package/dist/array/impl/array-utils-validation.d.mts.map +1 -1
  22. package/dist/array/impl/array-utils-validation.mjs +22 -12
  23. package/dist/array/impl/array-utils-validation.mjs.map +1 -1
  24. package/dist/collections/imap.d.mts +19 -16
  25. package/dist/collections/imap.d.mts.map +1 -1
  26. package/dist/collections/imap.mjs +1 -1
  27. package/dist/collections/imap.mjs.map +1 -1
  28. package/dist/collections/iset-mapped.d.mts +2 -2
  29. package/dist/collections/iset-mapped.d.mts.map +1 -1
  30. package/dist/collections/iset-mapped.mjs.map +1 -1
  31. package/dist/collections/iset.d.mts +1 -1
  32. package/dist/collections/iset.d.mts.map +1 -1
  33. package/dist/collections/iset.mjs +1 -0
  34. package/dist/collections/iset.mjs.map +1 -1
  35. package/dist/entry-point.mjs +1 -0
  36. package/dist/entry-point.mjs.map +1 -1
  37. package/dist/functional/optional/impl/optional-is-optional.d.mts +1 -1
  38. package/dist/functional/optional/impl/optional-is-optional.d.mts.map +1 -1
  39. package/dist/functional/optional/impl/optional-is-optional.mjs +6 -5
  40. package/dist/functional/optional/impl/optional-is-optional.mjs.map +1 -1
  41. package/dist/functional/optional/impl/optional-some.d.mts.map +1 -1
  42. package/dist/functional/optional/impl/optional-some.mjs.map +1 -1
  43. package/dist/functional/optional/impl/optional-zip.d.mts +1 -1
  44. package/dist/functional/optional/impl/optional-zip.mjs +1 -1
  45. package/dist/functional/result/impl/result-err.d.mts.map +1 -1
  46. package/dist/functional/result/impl/result-err.mjs.map +1 -1
  47. package/dist/functional/result/impl/result-is-result.d.mts +1 -1
  48. package/dist/functional/result/impl/result-is-result.mjs +1 -1
  49. package/dist/functional/result/impl/result-ok.d.mts.map +1 -1
  50. package/dist/functional/result/impl/result-ok.mjs.map +1 -1
  51. package/dist/functional/result/impl/result-unwrap-err-throw.mjs +1 -0
  52. package/dist/functional/result/impl/result-unwrap-err-throw.mjs.map +1 -1
  53. package/dist/functional/result/impl/result-unwrap-throw.mjs +1 -0
  54. package/dist/functional/result/impl/result-unwrap-throw.mjs.map +1 -1
  55. package/dist/functional/ternary-result/impl/ternary-result-err.d.mts.map +1 -1
  56. package/dist/functional/ternary-result/impl/ternary-result-err.mjs.map +1 -1
  57. package/dist/functional/ternary-result/impl/ternary-result-is-ternary-result.d.mts +1 -1
  58. package/dist/functional/ternary-result/impl/ternary-result-is-ternary-result.mjs +1 -1
  59. package/dist/functional/ternary-result/impl/ternary-result-ok.d.mts.map +1 -1
  60. package/dist/functional/ternary-result/impl/ternary-result-ok.mjs.map +1 -1
  61. package/dist/functional/ternary-result/impl/ternary-result-unwrap-err-throw.mjs +1 -0
  62. package/dist/functional/ternary-result/impl/ternary-result-unwrap-err-throw.mjs.map +1 -1
  63. package/dist/functional/ternary-result/impl/ternary-result-unwrap-throw.mjs +1 -0
  64. package/dist/functional/ternary-result/impl/ternary-result-unwrap-throw.mjs.map +1 -1
  65. package/dist/functional/ternary-result/impl/ternary-result-unwrap-warn-throw.mjs +1 -0
  66. package/dist/functional/ternary-result/impl/ternary-result-unwrap-warn-throw.mjs.map +1 -1
  67. package/dist/functional/ternary-result/impl/ternary-result-warn.d.mts.map +1 -1
  68. package/dist/functional/ternary-result/impl/ternary-result-warn.mjs.map +1 -1
  69. package/dist/guard/has-key.d.mts +3 -1
  70. package/dist/guard/has-key.d.mts.map +1 -1
  71. package/dist/guard/has-key.mjs +6 -2
  72. package/dist/guard/has-key.mjs.map +1 -1
  73. package/dist/guard/is-non-null-object.d.mts.map +1 -1
  74. package/dist/guard/is-non-null-object.mjs +3 -1
  75. package/dist/guard/is-non-null-object.mjs.map +1 -1
  76. package/dist/guard/is-record.d.mts +2 -2
  77. package/dist/guard/is-record.mjs +2 -2
  78. package/dist/guard/is-type.d.mts +15 -15
  79. package/dist/guard/is-type.mjs +15 -15
  80. package/dist/guard/key-is-in.d.mts.map +1 -1
  81. package/dist/guard/key-is-in.mjs +3 -1
  82. package/dist/guard/key-is-in.mjs.map +1 -1
  83. package/dist/index.mjs +1 -0
  84. package/dist/index.mjs.map +1 -1
  85. package/dist/json/json.d.mts +3 -3
  86. package/dist/json/json.mjs +4 -3
  87. package/dist/json/json.mjs.map +1 -1
  88. package/dist/number/branded-types/non-zero-safe-int.mjs +2 -2
  89. package/dist/number/branded-types/positive-safe-int.mjs +1 -1
  90. package/dist/number/branded-types/safe-int.mjs +2 -2
  91. package/dist/number/branded-types/safe-uint.mjs +1 -1
  92. package/dist/number/num.mjs +1 -1
  93. package/dist/object/object.d.mts +8 -8
  94. package/dist/object/object.d.mts.map +1 -1
  95. package/dist/object/object.mjs +7 -6
  96. package/dist/object/object.mjs.map +1 -1
  97. package/dist/others/fast-deep-equal.d.mts +8 -0
  98. package/dist/others/fast-deep-equal.d.mts.map +1 -0
  99. package/dist/others/fast-deep-equal.mjs +72 -0
  100. package/dist/others/fast-deep-equal.mjs.map +1 -0
  101. package/dist/others/index.d.mts +1 -0
  102. package/dist/others/index.d.mts.map +1 -1
  103. package/dist/others/index.mjs +1 -0
  104. package/dist/others/index.mjs.map +1 -1
  105. package/dist/others/memoize-function.d.mts +3 -2
  106. package/dist/others/memoize-function.d.mts.map +1 -1
  107. package/dist/others/memoize-function.mjs +10 -39
  108. package/dist/others/memoize-function.mjs.map +1 -1
  109. package/package.json +22 -17
  110. package/src/array/impl/array-utils-creation.test.mts +13 -10
  111. package/src/array/impl/array-utils-element-access.mts +5 -5
  112. package/src/array/impl/array-utils-element-access.test.mts +5 -5
  113. package/src/array/impl/array-utils-iterators.mts +1 -1
  114. package/src/array/impl/array-utils-iterators.test.mts +6 -6
  115. package/src/array/impl/array-utils-modification.mts +4 -4
  116. package/src/array/impl/array-utils-modification.test.mts +12 -12
  117. package/src/array/impl/array-utils-overload-type-error.test.mts +1 -1
  118. package/src/array/impl/array-utils-reducing-value.mts +6 -5
  119. package/src/array/impl/array-utils-reducing-value.test.mts +9 -9
  120. package/src/array/impl/array-utils-search.mts +8 -8
  121. package/src/array/impl/array-utils-search.test.mts +35 -35
  122. package/src/array/impl/array-utils-set-op.mts +1 -0
  123. package/src/array/impl/array-utils-set-op.test.mts +2 -2
  124. package/src/array/impl/array-utils-size.mts +1 -1
  125. package/src/array/impl/array-utils-size.test.mts +1 -1
  126. package/src/array/impl/array-utils-slice-clamped.mts +1 -1
  127. package/src/array/impl/array-utils-slice-clamped.test.mts +5 -5
  128. package/src/array/impl/array-utils-slicing.mts +3 -3
  129. package/src/array/impl/array-utils-slicing.test.mts +5 -5
  130. package/src/array/impl/array-utils-transformation.mts +1 -1
  131. package/src/array/impl/array-utils-transformation.test.mts +53 -53
  132. package/src/array/impl/array-utils-validation.mts +18 -10
  133. package/src/array/impl/array-utils-validation.test.mts +34 -29
  134. package/src/array/impl/array.test.mts +1 -1
  135. package/src/collections/imap-mapped.test.mts +9 -9
  136. package/src/collections/imap.mts +20 -17
  137. package/src/collections/imap.test.mts +6 -6
  138. package/src/collections/iset-mapped.mts +7 -6
  139. package/src/collections/iset-mapped.test.mts +6 -6
  140. package/src/collections/iset.mts +6 -5
  141. package/src/collections/queue.test.mts +2 -1
  142. package/src/collections/stack.test.mts +3 -3
  143. package/src/functional/optional/impl/optional-is-optional.mts +6 -6
  144. package/src/functional/optional/impl/optional-some.mts +5 -4
  145. package/src/functional/optional/impl/optional-zip.mts +1 -1
  146. package/src/functional/result/impl/result-err.mts +5 -4
  147. package/src/functional/result/impl/result-is-result.mts +1 -1
  148. package/src/functional/result/impl/result-ok.mts +5 -4
  149. package/src/functional/result.test.mts +2 -2
  150. package/src/functional/ternary-result/impl/ternary-result-err.mts +5 -4
  151. package/src/functional/ternary-result/impl/ternary-result-is-ternary-result.mts +1 -1
  152. package/src/functional/ternary-result/impl/ternary-result-ok.mts +5 -4
  153. package/src/functional/ternary-result/impl/ternary-result-warn.mts +6 -5
  154. package/src/guard/has-key.mts +6 -2
  155. package/src/guard/is-error.test.mts +1 -1
  156. package/src/guard/is-non-empty-string.test.mts +1 -1
  157. package/src/guard/is-non-null-object.mts +1 -0
  158. package/src/guard/is-non-null-object.test.mts +4 -3
  159. package/src/guard/is-primitive.test.mts +1 -1
  160. package/src/guard/is-record.mts +2 -2
  161. package/src/guard/is-record.test.mts +2 -2
  162. package/src/guard/is-type.mts +15 -15
  163. package/src/guard/is-type.test.mts +2 -2
  164. package/src/guard/key-is-in.mts +3 -1
  165. package/src/json/json.mts +4 -3
  166. package/src/json/json.test.mts +20 -19
  167. package/src/number/branded-types/non-zero-safe-int.mts +2 -2
  168. package/src/number/branded-types/positive-safe-int.mts +1 -1
  169. package/src/number/branded-types/safe-int.mts +2 -2
  170. package/src/number/branded-types/safe-uint.mts +1 -1
  171. package/src/number/num.mts +1 -1
  172. package/src/object/object.mts +9 -8
  173. package/src/object/object.test.mts +12 -7
  174. package/src/others/cast-mutable.test.mts +3 -3
  175. package/src/others/cast-readonly.test.mts +8 -5
  176. package/src/others/fast-deep-equal.mts +98 -0
  177. package/src/others/fast-deep-equal.test.mts +769 -0
  178. package/src/others/index.mts +1 -0
  179. package/src/others/map-nullable.test.mts +8 -8
  180. package/src/others/memoize-function.mts +35 -17
  181. package/src/others/memoize-function.test.mts +45 -8
  182. package/src/others/unknown-to-string.test.mts +8 -8
@@ -1,6 +1,7 @@
1
1
  export * from './cast-mutable.mjs';
2
2
  export * from './cast-readonly.mjs';
3
3
  export * from './debounce-function.mjs';
4
+ export * from './fast-deep-equal.mjs';
4
5
  export * from './if-then.mjs';
5
6
  export * from './map-nullable.mjs';
6
7
  export * from './memoize-function.mjs';
@@ -37,7 +37,7 @@ describe(mapNullable, () => {
37
37
  });
38
38
 
39
39
  test('should work with complex transformations', () => {
40
- const user = { name: 'Alice', age: 30 };
40
+ const user = { name: 'Alice', age: 30 } as const;
41
41
 
42
42
  const result = mapNullable(
43
43
  user,
@@ -48,13 +48,13 @@ describe(mapNullable, () => {
48
48
  });
49
49
 
50
50
  test('should work with nullable object properties', () => {
51
- const user: Readonly<{ name?: string }> = { name: 'Bob' };
51
+ const user: Readonly<{ name?: string }> = { name: 'Bob' } as const;
52
52
 
53
53
  const result = mapNullable(user.name, (name) => name.toUpperCase());
54
54
 
55
55
  expect(result).toBe('BOB');
56
56
 
57
- const userWithoutName: Readonly<{ name?: string }> = {};
57
+ const userWithoutName: Readonly<{ name?: string }> = {} as const;
58
58
 
59
59
  const resultEmpty = mapNullable(userWithoutName.name, (name) =>
60
60
  name.toUpperCase(),
@@ -102,7 +102,7 @@ describe(mapNullable, () => {
102
102
  (u: Readonly<{ name: string; age: number }>) => u.name,
103
103
  );
104
104
 
105
- const user = { name: 'Charlie', age: 25 };
105
+ const user = { name: 'Charlie', age: 25 } as const;
106
106
 
107
107
  const result1 = getName(user);
108
108
 
@@ -201,7 +201,7 @@ describe(mapNullable, () => {
201
201
  const data = {
202
202
  user: { profile: { name: 'Alice' } },
203
203
  settings: { theme: 'dark' },
204
- };
204
+ } as const;
205
205
 
206
206
  const result = mapNullable(data, (d) => d.user.profile.name);
207
207
 
@@ -277,7 +277,7 @@ describe(mapNullable, () => {
277
277
  email: 'john@example.com',
278
278
  },
279
279
  },
280
- };
280
+ } as const;
281
281
 
282
282
  const extractUserName = mapNullable(
283
283
  (r: ApiResponse) => r.data?.user?.name,
@@ -301,7 +301,7 @@ describe(mapNullable, () => {
301
301
  const formData: FormDataType = {
302
302
  email: 'test@example.com',
303
303
  age: '25',
304
- };
304
+ } as const;
305
305
 
306
306
  const extractAge = mapNullable((data: FormDataType) => data.age);
307
307
 
@@ -331,7 +331,7 @@ describe(mapNullable, () => {
331
331
  const incompleteFormData: FormDataType = {
332
332
  email: 'test@example.com',
333
333
  // age is missing
334
- };
334
+ } as const;
335
335
 
336
336
  const extractAge = mapNullable((data: FormDataType) => data.age);
337
337
 
@@ -21,33 +21,51 @@
21
21
  * key)
22
22
  * @param fn - The pure function to memoize
23
23
  * @param argsToCacheKey - Function that converts arguments to a unique cache
24
- * key
24
+ * key. Optional for zero-argument functions.
25
25
  * @returns A memoized version of the input function with the same signature
26
26
  *
27
27
  * @see https://en.wikipedia.org/wiki/Memoization
28
28
  */
29
- export const memoizeFunction = <
30
- const A extends readonly unknown[],
29
+ export function memoizeFunction<R>(fn: () => R): () => R;
30
+
31
+ export function memoizeFunction<
32
+ Arg0,
33
+ const RestArgs extends readonly unknown[],
34
+ R,
35
+ K extends Primitive,
36
+ >(
37
+ fn: (arg0: Arg0, ...args: RestArgs) => R,
38
+ argsToCacheKey: (arg0: Arg0, ...args: RestArgs) => K,
39
+ ): (arg0: Arg0, ...args: RestArgs) => R;
40
+
41
+ export function memoizeFunction<
42
+ const Args extends readonly unknown[],
31
43
  R,
32
44
  K extends Primitive,
33
45
  >(
34
- fn: (...args: A) => R,
35
- argsToCacheKey: (...args: A) => K,
36
- ): ((...args: A) => R) => {
37
- const mut_cache = new Map<K, R>();
46
+ fn: (...args: Args) => R,
47
+ argsToCacheKey?: (...args: Args) => K,
48
+ ): (...args: Args) => R {
49
+ type CacheEntry = Readonly<{ value: R }>;
38
50
 
39
- return (...args: A): R => {
40
- const key = argsToCacheKey(...args);
51
+ const mut_cache = new Map<K | symbol, CacheEntry>();
41
52
 
42
- if (mut_cache.has(key)) {
43
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
44
- return mut_cache.get(key)!;
45
- } else {
46
- const result = fn(...args);
53
+ const defaultKey = Symbol('memoize-default-key');
47
54
 
48
- mut_cache.set(key, result);
55
+ return (...args: Args): R => {
56
+ const key: K | symbol =
57
+ argsToCacheKey === undefined ? defaultKey : argsToCacheKey(...args);
49
58
 
50
- return result;
59
+ const cached = mut_cache.get(key);
60
+
61
+ if (cached !== undefined) {
62
+ return cached.value;
51
63
  }
64
+
65
+ const result = fn(...args);
66
+
67
+ mut_cache.set(key, { value: result });
68
+
69
+ return result;
52
70
  };
53
- };
71
+ }
@@ -65,11 +65,11 @@ describe(memoizeFunction, () => {
65
65
 
66
66
  const memoized = memoizeFunction(mockFn, (user) => user.id);
67
67
 
68
- const user1 = { id: 1, name: 'Alice' };
68
+ const user1 = { id: 1, name: 'Alice' } as const;
69
69
 
70
- const user2 = { id: 1, name: 'Bob' }; // Same id, different name
70
+ const user2 = { id: 1, name: 'Bob' } as const; // Same id, different name
71
71
 
72
- const user3 = { id: 2, name: 'Charlie' };
72
+ const user3 = { id: 2, name: 'Charlie' } as const;
73
73
 
74
74
  expect(memoized(user1)).toBe('Hello Alice');
75
75
 
@@ -148,6 +148,31 @@ describe(memoizeFunction, () => {
148
148
  expect(mockFn).toHaveBeenCalledTimes(2);
149
149
  });
150
150
 
151
+ test('should work with zero-argument functions without key mapper', () => {
152
+ const mockFn = vi.fn(() => Math.random());
153
+
154
+ const memoized = memoizeFunction(mockFn);
155
+
156
+ // First call
157
+ const result1 = memoized();
158
+
159
+ expect(mockFn).toHaveBeenCalledOnce();
160
+
161
+ // Second call - should use cache and return the same random value
162
+ const result2 = memoized();
163
+
164
+ expect(mockFn).toHaveBeenCalledOnce();
165
+
166
+ expect(result2).toBe(result1);
167
+
168
+ // Third call - still using cache
169
+ const result3 = memoized();
170
+
171
+ expect(mockFn).toHaveBeenCalledOnce();
172
+
173
+ expect(result3).toBe(result1);
174
+ });
175
+
151
176
  test('should maintain separate caches for different memoized functions', () => {
152
177
  const fn1 = vi.fn((x: number) => x * 2);
153
178
 
@@ -191,11 +216,23 @@ describe(memoizeFunction, () => {
191
216
  (args) => `${args.category}:${args.subcategory}:${args.id}`,
192
217
  );
193
218
 
194
- const args1 = { category: 'books', subcategory: 'fiction', id: 123 };
195
-
196
- const args2 = { category: 'books', subcategory: 'fiction', id: 123 };
197
-
198
- const args3 = { category: 'books', subcategory: 'fiction', id: 124 };
219
+ const args1 = {
220
+ category: 'books',
221
+ subcategory: 'fiction',
222
+ id: 123,
223
+ } as const;
224
+
225
+ const args2 = {
226
+ category: 'books',
227
+ subcategory: 'fiction',
228
+ id: 123,
229
+ } as const;
230
+
231
+ const args3 = {
232
+ category: 'books',
233
+ subcategory: 'fiction',
234
+ id: 124,
235
+ } as const;
199
236
 
200
237
  expect(memoized(args1)).toBe('books/fiction/123');
201
238
 
@@ -62,7 +62,7 @@ describe(unknownToString, () => {
62
62
  });
63
63
 
64
64
  test('(args) => ({ ret: args })', () => {
65
- const fn = (args: unknown): unknown => ({ ret: args });
65
+ const fn = (args: unknown): unknown => ({ ret: args }) as const;
66
66
 
67
67
  expect(unknownToString(fn)).toBe('(args) => ({ ret: args })');
68
68
 
@@ -72,7 +72,7 @@ describe(unknownToString, () => {
72
72
 
73
73
  describe('object', () => {
74
74
  test('object', () => {
75
- const obj = { a: { b: 1 } };
75
+ const obj = { a: { b: 1 } } as const;
76
76
 
77
77
  expect(unknownToString(obj)).toBe('{"a":{"b":1}}');
78
78
 
@@ -80,7 +80,7 @@ describe(unknownToString, () => {
80
80
  });
81
81
 
82
82
  test('object(prettyPrint=true)', () => {
83
- const obj = { a: { b: 1 } };
83
+ const obj = { a: { b: 1 } } as const;
84
84
 
85
85
  expect(unknownToString(obj, { prettyPrintObject: true })).toBe(
86
86
  dedent`
@@ -95,7 +95,7 @@ describe(unknownToString, () => {
95
95
 
96
96
  describe('array', () => {
97
97
  test('array of primitives', () => {
98
- const arr = [1, 2, 3, 'test', true];
98
+ const arr = [1, 2, 3, 'test', true] as const;
99
99
 
100
100
  expect(unknownToString(arr)).toBe('[1,2,3,"test",true]');
101
101
 
@@ -103,7 +103,7 @@ describe(unknownToString, () => {
103
103
  });
104
104
 
105
105
  test('array of objects', () => {
106
- const arr = [{ a: 1 }, { b: 2 }];
106
+ const arr = [{ a: 1 }, { b: 2 }] as const;
107
107
 
108
108
  expect(unknownToString(arr)).toBe('[{"a":1},{"b":2}]');
109
109
 
@@ -120,7 +120,7 @@ describe(unknownToString, () => {
120
120
  const nestedArray = [
121
121
  [1, 2],
122
122
  [3, 4],
123
- ];
123
+ ] as const;
124
124
 
125
125
  expect(unknownToString(nestedArray)).toBe('[[1,2],[3,4]]');
126
126
 
@@ -128,7 +128,7 @@ describe(unknownToString, () => {
128
128
  });
129
129
 
130
130
  test('array with prettyPrint', () => {
131
- const arr = [1, { a: 2 }, 3];
131
+ const arr = [1, { a: 2 }, 3] as const;
132
132
 
133
133
  expect(
134
134
  unknownToString(arr, {
@@ -288,7 +288,7 @@ describe(unknownToString, () => {
288
288
  // eslint-disable-next-line @typescript-eslint/only-throw-error
289
289
  throw 'custom failure';
290
290
  },
291
- };
291
+ } as const;
292
292
 
293
293
  expect(unknownToString(value)).toBe('[Circular or Non-serializable]');
294
294
  });