@oscarpalmer/atoms 0.185.0 → 0.186.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 (94) hide show
  1. package/dist/array/difference.d.mts +29 -0
  2. package/dist/array/exists.d.mts +35 -0
  3. package/dist/array/filter.d.mts +72 -2
  4. package/dist/array/find.d.mts +70 -0
  5. package/dist/array/first.d.mts +77 -2
  6. package/dist/array/flatten.d.mts +6 -0
  7. package/dist/array/flatten.mjs +6 -0
  8. package/dist/array/from.d.mts +36 -0
  9. package/dist/array/get.d.mts +21 -13
  10. package/dist/array/group-by.d.mts +142 -0
  11. package/dist/array/insert.d.mts +16 -0
  12. package/dist/array/intersection.d.mts +29 -0
  13. package/dist/array/last.d.mts +75 -2
  14. package/dist/array/match.d.mts +161 -32
  15. package/dist/array/move.d.mts +78 -8
  16. package/dist/array/move.mjs +10 -0
  17. package/dist/array/partition.d.mts +35 -0
  18. package/dist/array/push.d.mts +8 -0
  19. package/dist/array/push.mjs +8 -0
  20. package/dist/array/reverse.d.mts +1 -0
  21. package/dist/array/reverse.mjs +1 -0
  22. package/dist/array/select.d.mts +94 -8
  23. package/dist/array/single.d.mts +29 -0
  24. package/dist/array/slice.d.mts +106 -16
  25. package/dist/array/sort.d.mts +21 -0
  26. package/dist/array/splice.d.mts +48 -0
  27. package/dist/array/splice.mjs +2 -1
  28. package/dist/array/swap.d.mts +113 -8
  29. package/dist/array/swap.mjs +1 -0
  30. package/dist/array/to-map.d.mts +124 -0
  31. package/dist/array/to-record.d.mts +124 -0
  32. package/dist/array/to-set.d.mts +24 -0
  33. package/dist/array/toggle.d.mts +38 -3
  34. package/dist/array/union.d.mts +29 -0
  35. package/dist/array/unique.d.mts +24 -0
  36. package/dist/array/update.d.mts +38 -3
  37. package/dist/index.d.mts +1892 -135
  38. package/dist/index.mjs +64 -18
  39. package/dist/internal/array/chunk.d.mts +6 -0
  40. package/dist/internal/array/chunk.mjs +6 -0
  41. package/dist/internal/array/compact.d.mts +12 -0
  42. package/dist/internal/array/index-of.d.mts +70 -0
  43. package/dist/internal/math/aggregate.d.mts +29 -0
  44. package/dist/internal/value/get.d.mts +25 -3
  45. package/dist/internal/value/has.d.mts +4 -4
  46. package/dist/models.d.mts +14 -1
  47. package/dist/value/collection.d.mts +1 -1
  48. package/dist/value/merge.d.mts +28 -25
  49. package/dist/value/merge.mjs +29 -18
  50. package/dist/value/transform.d.mts +1 -1
  51. package/dist/value/unsmush.d.mts +1 -5
  52. package/package.json +5 -5
  53. package/src/array/difference.ts +29 -0
  54. package/src/array/exists.ts +35 -0
  55. package/src/array/filter.ts +72 -2
  56. package/src/array/find.ts +70 -0
  57. package/src/array/first.ts +77 -3
  58. package/src/array/flatten.ts +6 -0
  59. package/src/array/from.ts +36 -0
  60. package/src/array/get.ts +21 -15
  61. package/src/array/group-by.ts +142 -0
  62. package/src/array/insert.ts +16 -2
  63. package/src/array/intersection.ts +29 -0
  64. package/src/array/last.ts +75 -2
  65. package/src/array/match.ts +171 -42
  66. package/src/array/move.ts +82 -12
  67. package/src/array/partition.ts +35 -0
  68. package/src/array/push.ts +8 -2
  69. package/src/array/reverse.ts +1 -0
  70. package/src/array/select.ts +94 -13
  71. package/src/array/single.ts +29 -0
  72. package/src/array/slice.ts +114 -24
  73. package/src/array/sort.ts +21 -0
  74. package/src/array/splice.ts +52 -4
  75. package/src/array/swap.ts +117 -12
  76. package/src/array/to-map.ts +124 -0
  77. package/src/array/to-record.ts +124 -0
  78. package/src/array/to-set.ts +24 -0
  79. package/src/array/toggle.ts +38 -3
  80. package/src/array/union.ts +29 -0
  81. package/src/array/unique.ts +24 -0
  82. package/src/array/update.ts +38 -3
  83. package/src/internal/array/chunk.ts +6 -0
  84. package/src/internal/array/compact.ts +12 -0
  85. package/src/internal/array/index-of.ts +70 -0
  86. package/src/internal/math/aggregate.ts +29 -0
  87. package/src/internal/string.ts +0 -2
  88. package/src/internal/value/get.ts +25 -3
  89. package/src/internal/value/has.ts +4 -4
  90. package/src/models.ts +18 -0
  91. package/src/value/collection.ts +1 -1
  92. package/src/value/merge.ts +88 -66
  93. package/src/value/transform.ts +1 -1
  94. package/src/value/unsmush.ts +1 -10
@@ -5,10 +5,20 @@ import type {PlainObject} from '../../models';
5
5
 
6
6
  /**
7
7
  * Get the index of the first matching item by callback
8
+ *
8
9
  * @param array Array to search in
9
10
  * @param callback Callback to get an item's value
10
11
  * @param value Value to match against
11
12
  * @returns Index of the first matching item, or `-1` if no match is found
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * indexOf(
17
+ * [{id: 1}, {id: 2}, {id: 3}],
18
+ * item => item.id,
19
+ * 2,
20
+ * ); // => 1
21
+ * ```
12
22
  */
13
23
  export function indexOf<
14
24
  Item,
@@ -17,10 +27,20 @@ export function indexOf<
17
27
 
18
28
  /**
19
29
  * Get the index of the first matching item by key
30
+ *
20
31
  * @param array Array to search in
21
32
  * @param key Key to match items by
22
33
  * @param value Value to match against
23
34
  * @returns Index of the first matching item, or `-1` if no match is found
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * indexOf(
39
+ * [{id: 1}, {id: 2}, {id: 3}],
40
+ * 'id',
41
+ * 2,
42
+ * ); // => 1
43
+ * ```
24
44
  */
25
45
  export function indexOf<Item extends PlainObject, ItemKey extends keyof Item>(
26
46
  array: Item[],
@@ -30,9 +50,18 @@ export function indexOf<Item extends PlainObject, ItemKey extends keyof Item>(
30
50
 
31
51
  /**
32
52
  * Get the index of the first item matching the filter
53
+ *
33
54
  * @param array Array to search in
34
55
  * @param filter Filter callback to match items
35
56
  * @returns Index of the first matching item, or `-1` if no match is found
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * indexOf(
61
+ * [{id: 1}, {id: 2}, {id: 3}],
62
+ * item => item.id === 2,
63
+ * ); // => 1
64
+ * ```
36
65
  */
37
66
  export function indexOf<Item>(
38
67
  array: Item[],
@@ -41,9 +70,15 @@ export function indexOf<Item>(
41
70
 
42
71
  /**
43
72
  * Get the index of the first item matching the given item
73
+ *
44
74
  * @param array Array to search in
45
75
  * @param item Item to match against
46
76
  * @returns Index of the first matching item, or `-1` if no match is found
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * indexOf([1, 2, 3, 4, 5], 3); // => 2
81
+ * ```
47
82
  */
48
83
  export function indexOf<Item>(array: Item[], item: Item): number;
49
84
 
@@ -57,10 +92,20 @@ indexOf.last = lastIndexOf;
57
92
  * Get the index of the last matching item by callback
58
93
  *
59
94
  * Available as `lastIndexOf` and `indexOf.last`
95
+ *
60
96
  * @param array Array to search in
61
97
  * @param callback Callback to get an item's value
62
98
  * @param value Value to match against
63
99
  * @returns Index of the last matching item, or `-1` if no match is found
100
+ *
101
+ * @example
102
+ * ```typescript
103
+ * lastIndexOf(
104
+ * [{id: 1}, {id: 2}, {id: 3}, {id: 2}],
105
+ * item => item.id,
106
+ * 2,
107
+ * ); // => 3
108
+ * ```
64
109
  */
65
110
  export function lastIndexOf<
66
111
  Item,
@@ -71,10 +116,20 @@ export function lastIndexOf<
71
116
  * Get the index of the last matching item by key
72
117
  *
73
118
  * Available as `lastIndexOf` and `indexOf.last`
119
+ *
74
120
  * @param array Array to search in
75
121
  * @param key Key to match items by
76
122
  * @param value Value to match against
77
123
  * @returns Index of the last matching item, or `-1` if no match is found
124
+ *
125
+ * @example
126
+ * ```typescript
127
+ * lastIndexOf(
128
+ * [{id: 1}, {id: 2}, {id: 3}, {id: 2}],
129
+ * 'id',
130
+ * 2,
131
+ * ); // => 3
132
+ * ```
78
133
  */
79
134
  export function lastIndexOf<Item extends PlainObject, ItemKey extends keyof Item>(
80
135
  array: Item[],
@@ -86,9 +141,18 @@ export function lastIndexOf<Item extends PlainObject, ItemKey extends keyof Item
86
141
  * Get the index of the last item matching the filter
87
142
  *
88
143
  * Available as `lastIndexOf` and `indexOf.last`
144
+ *
89
145
  * @param array Array to search in
90
146
  * @param filter Filter callback to match items
91
147
  * @returns Index of the last matching item, or `-1` if no match is found
148
+ *
149
+ * @example
150
+ * ```typescript
151
+ * lastIndexOf(
152
+ * [{id: 1}, {id: 2}, {id: 3}, {id: 2}],
153
+ * item => item.id === 2,
154
+ * ); // => 3
155
+ * ```
92
156
  */
93
157
  export function lastIndexOf<Item>(
94
158
  array: Item[],
@@ -99,9 +163,15 @@ export function lastIndexOf<Item>(
99
163
  * Get the index of the last item matching the given item
100
164
  *
101
165
  * Available as `lastIndexOf` and `indexOf.last`
166
+ *
102
167
  * @param array Array to search in
103
168
  * @param item Item to match against
104
169
  * @returns Index of the last matching item, or `-1` if no match is found
170
+ *
171
+ * @example
172
+ * ```typescript
173
+ * lastIndexOf([1, 2, 3, 2, 1], 2); // => 3
174
+ * ```
105
175
  */
106
176
  export function lastIndexOf<Item>(array: Item[], item: Item): number;
107
177
 
@@ -66,6 +66,17 @@ export function getAggregateCallback(key: unknown): Function | undefined {
66
66
 
67
67
  /**
68
68
  * Get the maximum value from a list of items
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * max(
73
+ * [{id: 1, value: 10}, {id: 2, value: 20}],
74
+ * item => item.value,
75
+ * ); // 20
76
+ *
77
+ * max([], item => item.value); // Number.NaN
78
+ * ```
79
+ *
69
80
  * @param items List of items
70
81
  * @param callback Callback to get an item's value
71
82
  * @returns Maximum value, or `NaN` if no maximum can be found
@@ -77,6 +88,17 @@ export function max<Item>(
77
88
 
78
89
  /**
79
90
  * Get the maximum value from a list of items
91
+ *
92
+ * @example
93
+ * ```typescript
94
+ * max(
95
+ * [{id: 1, value: 10}, {id: 2, value: 20}],
96
+ * 'value',
97
+ * ); // 20
98
+ *
99
+ * max([], 'value'); // Number.NaN
100
+ * ```
101
+ *
80
102
  * @param items List of items
81
103
  * @param key Key to use for value
82
104
  * @returns Maximum value, or `NaN` if no maximum can be found
@@ -88,6 +110,13 @@ export function max<Item extends PlainObject, ItemKey extends keyof NumericalVal
88
110
 
89
111
  /**
90
112
  * Get the maximum value from a list of numbers
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * max([10, 20]); // 20
117
+ * max([]); // Number.NaN
118
+ * ```
119
+ *
91
120
  * @param values List of numbers
92
121
  * @returns Maximum value, or `NaN` if no maximum can be found
93
122
  */
@@ -19,11 +19,9 @@ export function getString(value: unknown): string {
19
19
  }
20
20
 
21
21
  if (typeof value !== 'object') {
22
- // oxlint-disable-next-line typescript/no-base-to-string: the whole point of this function is to get a string representation of any value, so calling `String` on it is fine
23
22
  return String(value);
24
23
  }
25
24
 
26
- // oxlint-disable-next-line typescript/no-base-to-string: ditto
27
25
  const asString = String(value.valueOf?.() ?? value);
28
26
 
29
27
  return asString.startsWith('[object ') ? JSON.stringify(value) : asString;
@@ -6,8 +6,19 @@ import {getNestedValue} from './misc';
6
6
 
7
7
  /**
8
8
  * Get the value from an object using a known path
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const data = {foo: {bar: {baz: 42}}};
13
+ *
14
+ * getValue(data, 'foo'); // {bar: {baz: 42}}
15
+ * getValue(data, 'foo.bar'); // {baz: 42}
16
+ * getValue(data, 'foo.bar.baz'); // 42
17
+ * getValue(data, 'foo.nope'); // undefined
18
+ * ```
19
+ *
9
20
  * @param data Object to get value from
10
- * @param path Path for value, e.g., `foo.bar.baz`
21
+ * @param path Path for value
11
22
  * @returns Found value, or `undefined`
12
23
  */
13
24
  export function getValue<Data extends PlainObject, Path extends NestedKeys<Data>>(
@@ -17,9 +28,20 @@ export function getValue<Data extends PlainObject, Path extends NestedKeys<Data>
17
28
 
18
29
  /**
19
30
  * Get the value from an object using an unknown path
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * const data = {foo: {bar: {baz: 42}}};
35
+ *
36
+ * getValue(data, 'foo'); // {bar: {baz: 42}}
37
+ * getValue(data, 'foo.bar'); // {baz: 42}
38
+ * getValue(data, 'Foo.Bar.Baz', true); // 42
39
+ * getValue(data, 'foo.nope'); // undefined
40
+ * ```
41
+ *
20
42
  * @param data Object to get value from
21
- * @param path Path for value, e.g., `foo.bar.baz`
22
- * @param ignoreCase If `true`, the path matching is case-insensitive
43
+ * @param path Path for value
44
+ * @param ignoreCase If `true`, path matching is case-insensitive
23
45
  * @returns Found value, or `undefined`
24
46
  */
25
47
  export function getValue<Data extends PlainObject>(
@@ -8,7 +8,7 @@ import {getNestedValue} from './misc';
8
8
  * Check if a nested property is defined in an object
9
9
  * @param data Object to check in
10
10
  * @param path Path for property
11
- * @return `true` if the property exists, `false` otherwise
11
+ * @returns `true` if the property exists, `false` otherwise
12
12
  */
13
13
  export function hasValue<Data extends PlainObject, Path extends NestedKeys<Data>>(
14
14
  data: Data,
@@ -20,7 +20,7 @@ export function hasValue<Data extends PlainObject, Path extends NestedKeys<Data>
20
20
  * @param data Object to check in
21
21
  * @param path Path for property
22
22
  * @param ignoreCase If `true`, the path matching is case-insensitive
23
- * @return `true` if the property exists, `false` otherwise
23
+ * @returns `true` if the property exists, `false` otherwise
24
24
  */
25
25
  export function hasValue<Data extends PlainObject>(
26
26
  data: Data,
@@ -41,7 +41,7 @@ hasValue.get = hasValueResult;
41
41
  * @param data Object to check in
42
42
  * @param path Path for property
43
43
  * @param ignoreCase If `true`, the path matching is case-insensitive
44
- * @return Result object
44
+ * @returns Result object
45
45
  */
46
46
  export function hasValueResult<Data extends PlainObject, Path extends NestedKeys<Data>>(
47
47
  data: Data,
@@ -56,7 +56,7 @@ export function hasValueResult<Data extends PlainObject, Path extends NestedKeys
56
56
  * @param data Object to check in
57
57
  * @param path Path for property
58
58
  * @param ignoreCase If `true`, the path matching is case-insensitive
59
- * @return Result object
59
+ * @returns Result object
60
60
  */
61
61
  export function hasValueResult<Data extends PlainObject>(
62
62
  data: Data,
package/src/models.ts CHANGED
@@ -260,4 +260,22 @@ export type TypedArray =
260
260
  | BigInt64Array
261
261
  | BigUint64Array;
262
262
 
263
+ /**
264
+ * Converts a union type to an intersection type
265
+ *
266
+ * @example
267
+ * ```typescript
268
+ * type A = {a: string};
269
+ * type B = {b: number};
270
+ * type C = UnionToIntersection<A | B>; // {a: string} & {b: number}
271
+ * ```
272
+ *
273
+ * Thanks, type-fest!
274
+ */
275
+ export type UnionToIntersection<Union> = (
276
+ Union extends unknown ? (distributedUnion: Union) => void : never
277
+ ) extends (mergedIntersection: infer Intersection) => void
278
+ ? Intersection & Union
279
+ : never;
280
+
263
281
  // #endregion
@@ -13,7 +13,7 @@ export function inMap<Value>(map: Map<unknown, Value>, value: Value): boolean;
13
13
  * @param map Map to check in
14
14
  * @param value Value to check for
15
15
  * @param key To return the key for the value
16
- * @return The key for the value if it exists, otherwise `undefined`
16
+ * @returns The key for the value if it exists, otherwise `undefined`
17
17
  */
18
18
  export function inMap<Key, Value>(map: Map<Key, Value>, value: Value, key: true): Key;
19
19
 
@@ -1,6 +1,5 @@
1
1
  import {isArrayOrPlainObject} from '../internal/is';
2
- import {join} from '../internal/string';
3
- import type {ArrayOrPlainObject, NestedPartial, PlainObject} from '../models';
2
+ import type {ArrayOrPlainObject, NestedPartial, PlainObject, UnionToIntersection} from '../models';
4
3
 
5
4
  // #region Types
6
5
 
@@ -9,16 +8,19 @@ import type {ArrayOrPlainObject, NestedPartial, PlainObject} from '../models';
9
8
  */
10
9
  export type AssignOptions = Omit<MergeOptions, 'assignValues'>;
11
10
 
12
- /**
13
- * Assign values from multiple arrays or objects to the first one
14
- * @param to Value to assign to
15
- * @param from Values to assign
16
- * @returns Assigned value
17
- */
18
- export type Assigner<Model extends ArrayOrPlainObject = ArrayOrPlainObject> = (
19
- to: NestedPartial<Model>,
20
- from: NestedPartial<Model>[],
21
- ) => Model;
11
+ export type Assigner = {
12
+ /**
13
+ * Assign values from one or more objects to the first one
14
+ *
15
+ * @param to Value to assign to
16
+ * @param from Values to assign
17
+ * @returns Assigned value
18
+ */
19
+ <To extends PlainObject, From extends PlainObject[]>(
20
+ to: To,
21
+ from: [...From],
22
+ ): To & UnionToIntersection<From[number]>;
23
+ };
22
24
 
23
25
  /**
24
26
  * Options for merging values
@@ -54,14 +56,17 @@ export type MergeOptions = {
54
56
  skipNullableInArrays?: boolean;
55
57
  };
56
58
 
57
- /**
58
- * Merge multiple arrays or objects into a single one
59
- * @param values Values to merge
60
- * @returns Merged value
61
- */
62
- export type Merger<Model extends ArrayOrPlainObject = ArrayOrPlainObject> = (
63
- values: NestedPartial<Model>[],
64
- ) => Model;
59
+ export type Merger = {
60
+ /**
61
+ * Merge multiple arrays or objects into a single one
62
+ *
63
+ * @param values Values to merge
64
+ * @returns Merged value
65
+ */
66
+ <Values extends ArrayOrPlainObject[]>(
67
+ values: NestedPartial<Values[number]>[],
68
+ ): UnionToIntersection<Values[number]>;
69
+ };
65
70
 
66
71
  type Options = {
67
72
  assignValues: boolean;
@@ -77,22 +82,23 @@ type ReplaceableObjectsCallback = (name: string) => boolean;
77
82
  // #region Functions
78
83
 
79
84
  /**
80
- * Assign values from multiple arrays or objects to the first one
85
+ * Assign values from one or more objects to the first one
86
+ *
81
87
  * @param to Value to assign to
82
88
  * @param from Values to assign
83
89
  * @param options Assigning options
84
90
  * @returns Assigned value
85
91
  */
86
- export function assign<Model extends ArrayOrPlainObject>(
87
- to: NestedPartial<Model>,
88
- from: NestedPartial<Model>[],
92
+ export function assign<To extends PlainObject, From extends PlainObject[]>(
93
+ to: To,
94
+ from: [...From],
89
95
  options?: AssignOptions,
90
- ): Model {
96
+ ): To & UnionToIntersection<From[number]> {
91
97
  const actual = getMergeOptions(options);
92
98
 
93
99
  actual.assignValues = true;
94
100
 
95
- return mergeValues([to, ...from], actual, true) as Model;
101
+ return mergeValues([to, ...from], actual) as To & UnionToIntersection<From[number]>;
96
102
  }
97
103
 
98
104
  assign.initialize = initializeAssigner;
@@ -129,69 +135,50 @@ function getReplaceableObjects(value: unknown): ReplaceableObjectsCallback | und
129
135
  }
130
136
  }
131
137
 
132
- function handleMerge(values: ArrayOrPlainObject[], options: Options): ArrayOrPlainObject {
133
- return !Array.isArray(values) || values.length === 0 ? {} : mergeValues(values, options, true);
134
- }
135
-
136
138
  /**
137
139
  * Create an assigner with predefined options
138
140
  *
139
141
  * Available as `initializeAssigner` and `assign.initialize`
142
+ *
140
143
  * @param options Assigning options
141
144
  * @returns Assigner function
142
145
  */
143
- export function initializeAssigner<Model extends ArrayOrPlainObject>(
144
- options?: AssignOptions,
145
- ): Assigner<Model> {
146
+ export function initializeAssigner(options?: AssignOptions): Assigner {
146
147
  const actual = getMergeOptions(options);
147
148
 
148
149
  actual.assignValues = true;
149
150
 
150
- return ((to: ArrayOrPlainObject, from: NestedPartial<ArrayOrPlainObject>[]): ArrayOrPlainObject =>
151
- mergeValues([to, ...from], actual, true)) as Assigner<Model>;
151
+ return ((to: PlainObject, from: PlainObject[]): PlainObject =>
152
+ mergeValues([to, ...from], actual) as PlainObject) as Assigner;
152
153
  }
153
154
 
154
155
  /**
155
156
  * Create a merger with predefined options
156
157
  *
157
158
  * Available as `initializeMerger` and `merge.initialize`
159
+ *
158
160
  * @param options Merging options
159
161
  * @returns Merger function
160
162
  */
161
163
  export function initializeMerger(options?: MergeOptions): Merger {
162
164
  const actual = getMergeOptions(options);
163
165
 
164
- return <Model extends ArrayOrPlainObject>(values: NestedPartial<Model>[]): Model =>
165
- handleMerge(values, actual) as Model;
166
+ return ((values: NestedPartial<ArrayOrPlainObject>[]): ArrayOrPlainObject =>
167
+ mergeValues(values, actual)) as Merger;
166
168
  }
167
169
 
168
170
  /**
169
171
  * Merge multiple arrays or objects into a single one
172
+ *
170
173
  * @param values Values to merge
171
174
  * @param options Merging options
172
175
  * @returns Merged value
173
176
  */
174
- export function merge<Model extends ArrayOrPlainObject>(
175
- values: NestedPartial<Model>[],
176
- options?: MergeOptions,
177
- ): Model;
178
-
179
- /**
180
- * Merge multiple arrays or objects into a single one
181
- * @param values Values to merge
182
- * @param options Merging options
183
- * @returns Merged value
184
- */
185
- export function merge(
186
- values: NestedPartial<ArrayOrPlainObject>[],
177
+ export function merge<Values extends ArrayOrPlainObject[]>(
178
+ values: [...Values],
187
179
  options?: MergeOptions,
188
- ): ArrayOrPlainObject;
189
-
190
- export function merge(
191
- values: NestedPartial<ArrayOrPlainObject>[],
192
- options?: MergeOptions,
193
- ): ArrayOrPlainObject {
194
- return handleMerge(values, getMergeOptions(options));
180
+ ): UnionToIntersection<Values[number]> {
181
+ return mergeValues(values, getMergeOptions(options)) as UnionToIntersection<Values[number]>;
195
182
  }
196
183
 
197
184
  merge.initialize = initializeMerger;
@@ -199,20 +186,23 @@ merge.initialize = initializeMerger;
199
186
  function mergeObjects(
200
187
  values: ArrayOrPlainObject[],
201
188
  options: Options,
189
+ destination?: ArrayOrPlainObject,
202
190
  prefix?: string,
203
191
  ): ArrayOrPlainObject {
204
192
  const {length} = values;
205
- const isArray = values.every(Array.isArray);
206
- const merged = (options.assignValues ? values[0] : isArray ? [] : {}) as PlainObject;
207
193
 
208
- for (let outerIndex = 0; outerIndex < length; outerIndex += 1) {
194
+ const isArray = Array.isArray(destination ?? values[0]);
195
+ const merged = (destination ?? (isArray ? [] : {})) as PlainObject;
196
+
197
+ const offset = destination == null ? 0 : 1;
198
+
199
+ for (let outerIndex = offset; outerIndex < length; outerIndex += 1) {
209
200
  const item = values[outerIndex] as PlainObject;
210
201
  const keys = Object.keys(item);
211
202
  const size = keys.length;
212
203
 
213
204
  for (let innerIndex = 0; innerIndex < size; innerIndex += 1) {
214
205
  const key = keys[innerIndex];
215
- const full = join([prefix, key], '.');
216
206
 
217
207
  const next = item[key];
218
208
  const previous = merged[key];
@@ -221,12 +211,20 @@ function mergeObjects(
221
211
  continue;
222
212
  }
223
213
 
214
+ const full =
215
+ options.replaceableObjects == null ? undefined : prefix == null ? key : `${prefix}.${key}`;
216
+
224
217
  if (
225
218
  isArrayOrPlainObject(next) &&
226
219
  isArrayOrPlainObject(previous) &&
227
- !(options.replaceableObjects?.(full) ?? false)
220
+ !(options.replaceableObjects?.(full!) ?? false)
228
221
  ) {
229
- merged[key] = mergeValues([previous, next], options, false, full);
222
+ merged[key] = mergeObjects(
223
+ [previous, next],
224
+ options,
225
+ (destination == null ? undefined : merged[key]) as ArrayOrPlainObject,
226
+ full,
227
+ );
230
228
  } else {
231
229
  merged[key] = next;
232
230
  }
@@ -239,12 +237,36 @@ function mergeObjects(
239
237
  function mergeValues(
240
238
  values: ArrayOrPlainObject[],
241
239
  options: Options,
242
- validate: boolean,
243
240
  prefix?: string,
244
241
  ): ArrayOrPlainObject {
245
- const actual = validate ? values.filter(isArrayOrPlainObject) : values;
242
+ if (!Array.isArray(values)) {
243
+ return {};
244
+ }
245
+
246
+ const actual = values.filter(isArrayOrPlainObject);
247
+
248
+ if (actual.length === 0) {
249
+ return {};
250
+ }
251
+
252
+ if (
253
+ options.assignValues &&
254
+ actual.length === 2 &&
255
+ !Array.isArray(actual[0]) &&
256
+ Object.keys(actual[0]).length === 0
257
+ ) {
258
+ return Object.assign(actual[0], actual[1]);
259
+ }
260
+
261
+ if (actual.length > 1) {
262
+ return mergeObjects(actual, options, options.assignValues ? actual[0] : undefined, prefix);
263
+ }
246
264
 
247
- return actual.length > 1 ? mergeObjects(actual, options, prefix) : (actual[0] ?? {});
265
+ return options.assignValues
266
+ ? actual[0]
267
+ : Array.isArray(actual[0])
268
+ ? actual[0].slice()
269
+ : {...actual[0]};
248
270
  }
249
271
 
250
272
  // #endregion
@@ -75,7 +75,7 @@ export function initializeTransformer<Value extends PlainObject>(
75
75
  *
76
76
  * Available as `initializeTransformer` and `transform.initialize`
77
77
  * @param transformers Keyed transformer functions
78
- * @return Transformer
78
+ * @returns Transformer
79
79
  */
80
80
  export function initializeTransformer<Value extends PlainObject>(
81
81
  transformers: TransformCallbacks<Value>,
@@ -1,6 +1,6 @@
1
1
  import {isArrayOrPlainObject} from '../internal/is';
2
2
  import {setValue} from '../internal/value/set';
3
- import type {PlainObject, Simplify} from '../models';
3
+ import type {PlainObject, Simplify, UnionToIntersection} from '../models';
4
4
 
5
5
  // #region Types
6
6
 
@@ -16,15 +16,6 @@ type OrderedKey = {
16
16
  value: string;
17
17
  };
18
18
 
19
- /**
20
- * Thanks, type-fest!
21
- */
22
- type UnionToIntersection<Union> = (
23
- Union extends unknown ? (distributedUnion: Union) => void : never
24
- ) extends (mergedIntersection: infer Intersection) => void
25
- ? Intersection & Union
26
- : never;
27
-
28
19
  /**
29
20
  * An unsmushed object, with all dot notation keys turned into nested keys
30
21
  */