es-toolkit 1.14.0-dev.409 → 1.14.0-dev.410

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.
@@ -108,6 +108,7 @@ export { property } from './object/property.mjs';
108
108
  export { mapKeys } from './object/mapKeys.mjs';
109
109
  export { mapValues } from './object/mapValues.mjs';
110
110
  export { merge } from './object/merge.mjs';
111
+ export { mergeWith } from './object/mergeWith.mjs';
111
112
  export { isPlainObject } from './predicate/isPlainObject.mjs';
112
113
  export { isArray } from './predicate/isArray.mjs';
113
114
  export { isArguments } from './predicate/isArguments.mjs';
@@ -108,6 +108,7 @@ export { property } from './object/property.js';
108
108
  export { mapKeys } from './object/mapKeys.js';
109
109
  export { mapValues } from './object/mapValues.js';
110
110
  export { merge } from './object/merge.js';
111
+ export { mergeWith } from './object/mergeWith.js';
111
112
  export { isPlainObject } from './predicate/isPlainObject.js';
112
113
  export { isArray } from './predicate/isArray.js';
113
114
  export { isArguments } from './predicate/isArguments.js';
@@ -354,22 +354,24 @@ function cloneDeep(obj) {
354
354
  }
355
355
  }
356
356
 
357
- function merge(object, ...sources) {
357
+ function mergeWith(object, ...otherArgs) {
358
+ const sources = otherArgs.slice(0, -1);
359
+ const merge = otherArgs[otherArgs.length - 1];
358
360
  let result = object;
359
361
  for (let i = 0; i < sources.length; i++) {
360
362
  const source = sources[i];
361
- result = mergeDeep(object, source, new Map());
363
+ result = mergeWithDeep(object, source, merge, new Map());
362
364
  }
363
365
  return result;
364
366
  }
365
- function mergeDeep(object, source, stack) {
367
+ function mergeWithDeep(target, source, merge, stack) {
366
368
  if (source == null || typeof source !== 'object') {
367
- return object;
369
+ return target;
368
370
  }
369
371
  if (stack.has(source)) {
370
372
  return isObjectLike.clone(stack.get(source));
371
373
  }
372
- stack.set(source, object);
374
+ stack.set(source, target);
373
375
  if (Array.isArray(source)) {
374
376
  source = source.slice();
375
377
  for (let i = 0; i < source.length; i++) {
@@ -380,39 +382,47 @@ function mergeDeep(object, source, stack) {
380
382
  for (let i = 0; i < sourceKeys.length; i++) {
381
383
  const key = sourceKeys[i];
382
384
  let sourceValue = source[key];
383
- let objectValue = object[key];
385
+ let targetValue = target[key];
384
386
  if (isArguments(sourceValue)) {
385
387
  sourceValue = { ...sourceValue };
386
388
  }
387
- if (isArguments(objectValue)) {
388
- objectValue = { ...objectValue };
389
+ if (isArguments(targetValue)) {
390
+ targetValue = { ...targetValue };
389
391
  }
390
392
  if (typeof Buffer !== 'undefined' && Buffer.isBuffer(sourceValue)) {
391
393
  sourceValue = cloneDeep(sourceValue);
392
394
  }
393
395
  if (Array.isArray(sourceValue)) {
394
- objectValue = typeof objectValue === 'object' ? Array.from(objectValue ?? []) : [];
396
+ targetValue = typeof targetValue === 'object' ? Array.from(targetValue ?? []) : [];
395
397
  }
396
- if (Array.isArray(sourceValue)) {
397
- object[key] = mergeDeep(objectValue, sourceValue, stack);
398
+ const merged = merge(targetValue, sourceValue, key, target, source, stack);
399
+ if (merged != null) {
400
+ target[key] = merged;
401
+ }
402
+ else if (Array.isArray(sourceValue)) {
403
+ target[key] = mergeWithDeep(targetValue, sourceValue, merge, stack);
398
404
  }
399
- else if (isObjectLike.isObjectLike(objectValue) && isObjectLike.isObjectLike(sourceValue)) {
400
- object[key] = mergeDeep(objectValue, sourceValue, stack);
405
+ else if (isObjectLike.isObjectLike(targetValue) && isObjectLike.isObjectLike(sourceValue)) {
406
+ target[key] = mergeWithDeep(targetValue, sourceValue, merge, stack);
401
407
  }
402
- else if (objectValue == null && Array.isArray(sourceValue)) {
403
- object[key] = mergeDeep([], sourceValue, stack);
408
+ else if (targetValue == null && Array.isArray(sourceValue)) {
409
+ target[key] = mergeWithDeep([], sourceValue, merge, stack);
404
410
  }
405
- else if (objectValue == null && isPlainObject(sourceValue)) {
406
- object[key] = mergeDeep({}, sourceValue, stack);
411
+ else if (targetValue == null && isPlainObject(sourceValue)) {
412
+ target[key] = mergeWithDeep({}, sourceValue, merge, stack);
407
413
  }
408
- else if (objectValue == null && isTypedArray(sourceValue)) {
409
- object[key] = cloneDeep(sourceValue);
414
+ else if (targetValue == null && isTypedArray(sourceValue)) {
415
+ target[key] = cloneDeep(sourceValue);
410
416
  }
411
- else if (objectValue === undefined || sourceValue !== undefined) {
412
- object[key] = sourceValue;
417
+ else if (targetValue === undefined || sourceValue !== undefined) {
418
+ target[key] = sourceValue;
413
419
  }
414
420
  }
415
- return object;
421
+ return target;
422
+ }
423
+
424
+ function merge(object, ...sources) {
425
+ return mergeWith(object, ...sources, function_index.noop);
416
426
  }
417
427
 
418
428
  function isArray(value) {
@@ -692,6 +702,7 @@ exports.mapValues = mapValues;
692
702
  exports.matches = matches;
693
703
  exports.max = max;
694
704
  exports.merge = merge;
705
+ exports.mergeWith = mergeWith;
695
706
  exports.min = min;
696
707
  exports.padStart = padStart;
697
708
  exports.property = property;
@@ -109,6 +109,7 @@ export { property } from './object/property.mjs';
109
109
  export { mapKeys } from './object/mapKeys.mjs';
110
110
  export { mapValues } from './object/mapValues.mjs';
111
111
  export { merge } from './object/merge.mjs';
112
+ export { mergeWith } from './object/mergeWith.mjs';
112
113
  export { isPlainObject } from './predicate/isPlainObject.mjs';
113
114
  export { isArray } from './predicate/isArray.mjs';
114
115
  export { isArguments } from './predicate/isArguments.mjs';
@@ -1,69 +1,8 @@
1
- import { clone } from '../../object/clone.mjs';
2
- import { isArguments } from '../predicate/isArguments.mjs';
3
- import { isObjectLike } from '../predicate/isObjectLike.mjs';
4
- import { isPlainObject } from '../predicate/isPlainObject.mjs';
5
- import { isTypedArray } from '../predicate/isTypedArray.mjs';
6
- import { cloneDeep } from './cloneDeep.mjs';
1
+ import { noop } from '../../function/noop.mjs';
2
+ import { mergeWith } from './mergeWith.mjs';
7
3
 
8
4
  function merge(object, ...sources) {
9
- let result = object;
10
- for (let i = 0; i < sources.length; i++) {
11
- const source = sources[i];
12
- result = mergeDeep(object, source, new Map());
13
- }
14
- return result;
15
- }
16
- function mergeDeep(object, source, stack) {
17
- if (source == null || typeof source !== 'object') {
18
- return object;
19
- }
20
- if (stack.has(source)) {
21
- return clone(stack.get(source));
22
- }
23
- stack.set(source, object);
24
- if (Array.isArray(source)) {
25
- source = source.slice();
26
- for (let i = 0; i < source.length; i++) {
27
- source[i] = source[i] ?? undefined;
28
- }
29
- }
30
- const sourceKeys = Object.keys(source);
31
- for (let i = 0; i < sourceKeys.length; i++) {
32
- const key = sourceKeys[i];
33
- let sourceValue = source[key];
34
- let objectValue = object[key];
35
- if (isArguments(sourceValue)) {
36
- sourceValue = { ...sourceValue };
37
- }
38
- if (isArguments(objectValue)) {
39
- objectValue = { ...objectValue };
40
- }
41
- if (typeof Buffer !== 'undefined' && Buffer.isBuffer(sourceValue)) {
42
- sourceValue = cloneDeep(sourceValue);
43
- }
44
- if (Array.isArray(sourceValue)) {
45
- objectValue = typeof objectValue === 'object' ? Array.from(objectValue ?? []) : [];
46
- }
47
- if (Array.isArray(sourceValue)) {
48
- object[key] = mergeDeep(objectValue, sourceValue, stack);
49
- }
50
- else if (isObjectLike(objectValue) && isObjectLike(sourceValue)) {
51
- object[key] = mergeDeep(objectValue, sourceValue, stack);
52
- }
53
- else if (objectValue == null && Array.isArray(sourceValue)) {
54
- object[key] = mergeDeep([], sourceValue, stack);
55
- }
56
- else if (objectValue == null && isPlainObject(sourceValue)) {
57
- object[key] = mergeDeep({}, sourceValue, stack);
58
- }
59
- else if (objectValue == null && isTypedArray(sourceValue)) {
60
- object[key] = cloneDeep(sourceValue);
61
- }
62
- else if (objectValue === undefined || sourceValue !== undefined) {
63
- object[key] = sourceValue;
64
- }
65
- }
66
- return object;
5
+ return mergeWith(object, ...sources, noop);
67
6
  }
68
7
 
69
8
  export { merge };
@@ -0,0 +1,261 @@
1
+ /**
2
+ * Merges the properties of one or more source objects into the target object.
3
+ *
4
+ * This function performs a deep merge, recursively merging nested objects and arrays.
5
+ * If a property in the source object is an array or object and the corresponding property in the target object is also an array or object, they will be merged.
6
+ * If a property in the source object is `undefined`, it will not overwrite a defined property in the target object.
7
+ *
8
+ * You can provide a custom `merge` function to control how properties are merged. The `merge` function is called for each property that is being merged and receives the following arguments:
9
+ *
10
+ * - `targetValue`: The current value of the property in the target object.
11
+ * - `sourceValue`: The value of the property in the source object.
12
+ * - `key`: The key of the property being merged.
13
+ * - `target`: The target object.
14
+ * - `source`: The source object.
15
+ * - `stack`: A `Map` used to keep track of objects that have already been processed to handle circular references.
16
+ *
17
+ * The `merge` function should return the value to be set in the target object. If it returns `undefined`, a default deep merge will be applied for arrays and objects.
18
+ *
19
+ * The function can handle multiple source objects and will merge them all into the target object.
20
+ *
21
+ * @param {T} target - The target object into which the source object properties will be merged. This object is modified in place.
22
+ * @param {S} source - The first source object whose properties will be merged into the target object.
23
+ * @returns {T & S} The updated target object with properties from the source object(s) merged in.
24
+ *
25
+ * @template T - Type of the target object.
26
+ * @template S - Type of the first source object.
27
+ *
28
+ * @example
29
+ * const target = { a: 1, b: 2 };
30
+ * const source = { b: 3, c: 4 };
31
+ *
32
+ * mergeWith(target, source, (targetValue, sourceValue) => {
33
+ * if (typeof targetValue === 'number' && typeof sourceValue === 'number') {
34
+ * return targetValue + sourceValue;
35
+ * }
36
+ * });
37
+ * // Returns { a: 1, b: 5, c: 4 }
38
+ * @example
39
+ * const target = { a: [1], b: [2] };
40
+ * const source = { a: [3], b: [4] };
41
+ *
42
+ * const result = mergeWith(target, source, (objValue, srcValue) => {
43
+ * if (Array.isArray(objValue)) {
44
+ * return objValue.concat(srcValue);
45
+ * }
46
+ * });
47
+ *
48
+ * expect(result).toEqual({ a: [1, 3], b: [2, 4] });
49
+ */
50
+ declare function mergeWith<T, S>(target: T, source: S, merge: (targetValue: any, sourceValue: any, key: string, target: T, source: S, stack: Map<any, any>) => any): T & S;
51
+ /**
52
+ * Merges the properties of one or more source objects into the target object.
53
+ *
54
+ * This function performs a deep merge, recursively merging nested objects and arrays.
55
+ * If a property in the source object is an array or object and the corresponding property in the target object is also an array or object, they will be merged.
56
+ * If a property in the source object is `undefined`, it will not overwrite a defined property in the target object.
57
+ *
58
+ * You can provide a custom `merge` function to control how properties are merged. The `merge` function is called for each property that is being merged and receives the following arguments:
59
+ *
60
+ * - `targetValue`: The current value of the property in the target object.
61
+ * - `sourceValue`: The value of the property in the source object.
62
+ * - `key`: The key of the property being merged.
63
+ * - `target`: The target object.
64
+ * - `source`: The source object.
65
+ * - `stack`: A `Map` used to keep track of objects that have already been processed to handle circular references.
66
+ *
67
+ * The `merge` function should return the value to be set in the target object. If it returns `undefined`, a default deep merge will be applied for arrays and objects.
68
+ *
69
+ * The function can handle multiple source objects and will merge them all into the target object.
70
+ *
71
+ * @param {O} object - The target object into which the source object properties will be merged. This object is modified in place.
72
+ * @param {S1} source1 - The first source object to be merged into the target object.
73
+ * @param {S2} source2 - The second source object to be merged into the target object.
74
+ * @returns {O & S1 & S2} The updated target object with properties from the source objects merged in.
75
+ *
76
+ * @template O - Type of the target object.
77
+ * @template S1 - Type of the first source object.
78
+ * @template S2 - Type of the second source object.
79
+ *
80
+ * @example
81
+ * const target = { a: 1, b: 2 };
82
+ * const source = { b: 3, c: 4 };
83
+ *
84
+ * mergeWith(target, source, (targetValue, sourceValue) => {
85
+ * if (typeof targetValue === 'number' && typeof sourceValue === 'number') {
86
+ * return targetValue + sourceValue;
87
+ * }
88
+ * });
89
+ * // Returns { a: 1, b: 5, c: 4 }
90
+ * @example
91
+ * const target = { a: [1], b: [2] };
92
+ * const source = { a: [3], b: [4] };
93
+ *
94
+ * const result = mergeWith(target, source, (objValue, srcValue) => {
95
+ * if (Array.isArray(objValue)) {
96
+ * return objValue.concat(srcValue);
97
+ * }
98
+ * });
99
+ *
100
+ * expect(result).toEqual({ a: [1, 3], b: [2, 4] });
101
+ */
102
+ declare function mergeWith<O, S1, S2>(object: O, source1: S1, source2: S2, merge: (targetValue: any, sourceValue: any, key: string, target: any, source: any, stack: Map<any, any>) => any): O & S1 & S2;
103
+ /**
104
+ * Merges the properties of one or more source objects into the target object.
105
+ *
106
+ * This function performs a deep merge, recursively merging nested objects and arrays.
107
+ * If a property in the source object is an array or object and the corresponding property in the target object is also an array or object, they will be merged.
108
+ * If a property in the source object is `undefined`, it will not overwrite a defined property in the target object.
109
+ *
110
+ * You can provide a custom `merge` function to control how properties are merged. The `merge` function is called for each property that is being merged and receives the following arguments:
111
+ *
112
+ * - `targetValue`: The current value of the property in the target object.
113
+ * - `sourceValue`: The value of the property in the source object.
114
+ * - `key`: The key of the property being merged.
115
+ * - `target`: The target object.
116
+ * - `source`: The source object.
117
+ * - `stack`: A `Map` used to keep track of objects that have already been processed to handle circular references.
118
+ *
119
+ * The `merge` function should return the value to be set in the target object. If it returns `undefined`, a default deep merge will be applied for arrays and objects.
120
+ *
121
+ * The function can handle multiple source objects and will merge them all into the target object.
122
+ *
123
+ * @param {O} object - The target object into which the source object properties will be merged. This object is modified in place.
124
+ * @param {S1} source1 - The first source object whose properties will be merged into the target object.
125
+ * @param {S2} source2 - The second source object whose properties will be merged into the target object.
126
+ * @param {S3} source3 - The third source object whose properties will be merged into the target object.
127
+ * @returns {O & S1 & S2 & S3} The updated target object with properties from the source object(s) merged in.
128
+ *
129
+ * @template O - Type of the target object.
130
+ * @template S1 - Type of the first source object.
131
+ * @template S2 - Type of the second source object.
132
+ * @template S3 - Type of the third source object.
133
+ *
134
+ * @example
135
+ * const target = { a: 1, b: 2 };
136
+ * const source = { b: 3, c: 4 };
137
+ *
138
+ * mergeWith(target, source, (targetValue, sourceValue) => {
139
+ * if (typeof targetValue === 'number' && typeof sourceValue === 'number') {
140
+ * return targetValue + sourceValue;
141
+ * }
142
+ * });
143
+ * // Returns { a: 1, b: 5, c: 4 }
144
+ * @example
145
+ * const target = { a: [1], b: [2] };
146
+ * const source = { a: [3], b: [4] };
147
+ *
148
+ * const result = mergeWith(target, source, (objValue, srcValue) => {
149
+ * if (Array.isArray(objValue)) {
150
+ * return objValue.concat(srcValue);
151
+ * }
152
+ * });
153
+ *
154
+ * expect(result).toEqual({ a: [1, 3], b: [2, 4] });
155
+ */
156
+ declare function mergeWith<O, S1, S2, S3>(object: O, source1: S1, source2: S2, source3: S3, merge: (targetValue: any, sourceValue: any, key: string, target: any, source: any, stack: Map<any, any>) => any): O & S1 & S2 & S3;
157
+ /**
158
+ * Merges the properties of one or more source objects into the target object.
159
+ *
160
+ * This function performs a deep merge, recursively merging nested objects and arrays.
161
+ * If a property in the source object is an array or object and the corresponding property in the target object is also an array or object, they will be merged.
162
+ * If a property in the source object is `undefined`, it will not overwrite a defined property in the target object.
163
+ *
164
+ * You can provide a custom `merge` function to control how properties are merged. The `merge` function is called for each property that is being merged and receives the following arguments:
165
+ *
166
+ * - `targetValue`: The current value of the property in the target object.
167
+ * - `sourceValue`: The value of the property in the source object.
168
+ * - `key`: The key of the property being merged.
169
+ * - `target`: The target object.
170
+ * - `source`: The source object.
171
+ * - `stack`: A `Map` used to keep track of objects that have already been processed to handle circular references.
172
+ *
173
+ * The `merge` function should return the value to be set in the target object. If it returns `undefined`, a default deep merge will be applied for arrays and objects.
174
+ *
175
+ * The function can handle multiple source objects and will merge them all into the target object.
176
+ *
177
+ * @param {O} object - The target object into which the source object properties will be merged. This object is modified in place.
178
+ * @param {S1} source1 - The first source object whose properties will be merged into the target object.
179
+ * @param {S2} source2 - The second source object whose properties will be merged into the target object.
180
+ * @param {S3} source3 - The third source object whose properties will be merged into the target object.
181
+ * @param {S4} source4 - The fourth source object whose properties will be merged into the target object.
182
+ * @returns {O & S1 & S2 & S3 & S4} The updated target object with properties from the source object(s) merged in.
183
+ *
184
+ * @template O - Type of the target object.
185
+ * @template S1 - Type of the first source object.
186
+ * @template S2 - Type of the second source object.
187
+ * @template S3 - Type of the third source object.
188
+ * @template S4 - Type of the fourth source object.
189
+ *
190
+ * @example
191
+ * const target = { a: 1, b: 2 };
192
+ * const source = { b: 3, c: 4 };
193
+ *
194
+ * mergeWith(target, source, (targetValue, sourceValue) => {
195
+ * if (typeof targetValue === 'number' && typeof sourceValue === 'number') {
196
+ * return targetValue + sourceValue;
197
+ * }
198
+ * });
199
+ * // Returns { a: 1, b: 5, c: 4 }
200
+ * @example
201
+ * const target = { a: [1], b: [2] };
202
+ * const source = { a: [3], b: [4] };
203
+ *
204
+ * const result = mergeWith(target, source, (objValue, srcValue) => {
205
+ * if (Array.isArray(objValue)) {
206
+ * return objValue.concat(srcValue);
207
+ * }
208
+ * });
209
+ *
210
+ * expect(result).toEqual({ a: [1, 3], b: [2, 4] });
211
+ */
212
+ declare function mergeWith<O, S1, S2, S3, S4>(object: O, source1: S1, source2: S2, source3: S3, source4: S4, merge: (targetValue: any, sourceValue: any, key: string, target: any, source: any, stack: Map<any, any>) => any): O & S1 & S2 & S3;
213
+ /**
214
+ * Merges the properties of one or more source objects into the target object.
215
+ *
216
+ * This function performs a deep merge, recursively merging nested objects and arrays.
217
+ * If a property in the source object is an array or object and the corresponding property in the target object is also an array or object, they will be merged.
218
+ * If a property in the source object is `undefined`, it will not overwrite a defined property in the target object.
219
+ *
220
+ * You can provide a custom `merge` function to control how properties are merged. The `merge` function is called for each property that is being merged and receives the following arguments:
221
+ *
222
+ * - `targetValue`: The current value of the property in the target object.
223
+ * - `sourceValue`: The value of the property in the source object.
224
+ * - `key`: The key of the property being merged.
225
+ * - `target`: The target object.
226
+ * - `source`: The source object.
227
+ * - `stack`: A `Map` used to keep track of objects that have already been processed to handle circular references.
228
+ *
229
+ * The `merge` function should return the value to be set in the target object. If it returns `undefined`, a default deep merge will be applied for arrays and objects.
230
+ *
231
+ * The function can handle multiple source objects and will merge them all into the target object.
232
+ *
233
+ * @param {any} any - The target object into which the source object properties will be merged. This object is modified in place.
234
+ * @param {any[]} sources - The source objects whose properties will be merged into the target object.
235
+ * @returns {any} The updated target object with properties from the source object(s) merged in.
236
+ *
237
+ * @example
238
+ * const target = { a: 1, b: 2 };
239
+ * const source = { b: 3, c: 4 };
240
+ *
241
+ * mergeWith(target, source, (targetValue, sourceValue) => {
242
+ * if (typeof targetValue === 'number' && typeof sourceValue === 'number') {
243
+ * return targetValue + sourceValue;
244
+ * }
245
+ * });
246
+ * // Returns { a: 1, b: 5, c: 4 }
247
+ * @example
248
+ * const target = { a: [1], b: [2] };
249
+ * const source = { a: [3], b: [4] };
250
+ *
251
+ * const result = mergeWith(target, source, (objValue, srcValue) => {
252
+ * if (Array.isArray(objValue)) {
253
+ * return objValue.concat(srcValue);
254
+ * }
255
+ * });
256
+ *
257
+ * expect(result).toEqual({ a: [1, 3], b: [2, 4] });
258
+ */
259
+ declare function mergeWith(object: any, ...otherArgs: any[]): any;
260
+
261
+ export { mergeWith };