@jsopen/objects 1.6.3 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -3
- package/cjs/merge.js +152 -230
- package/cjs/omit.js +1 -1
- package/cjs/tsconfig-build-cjs.tsbuildinfo +1 -1
- package/esm/merge.js +152 -229
- package/esm/omit.js +1 -1
- package/esm/tsconfig-build-esm.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/types/merge.d.ts +60 -14
package/CHANGELOG.md
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
## Changelog
|
|
2
2
|
|
|
3
|
-
### [
|
|
3
|
+
### [v2.0.1](https://github.com/panates/jsopen-objects/compare/v2.0.0...v2.0.1) -
|
|
4
4
|
|
|
5
|
-
####
|
|
5
|
+
#### 🛠 Refactoring and Updates
|
|
6
6
|
|
|
7
|
-
-
|
|
7
|
+
- refactor: Made default "symbolKeys" option to true @Eray Hanoğlu
|
|
8
|
+
|
|
9
|
+
#### 💬 General Changes
|
|
10
|
+
|
|
11
|
+
- dev: Coveralls parallel @Eray Hanoğlu
|
|
12
|
+
- dev: Coveralls parallel @Eray Hanoğlu
|
package/cjs/merge.js
CHANGED
|
@@ -1,241 +1,163 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.merge = merge;
|
|
4
|
-
exports.getMergeFunction = getMergeFunction;
|
|
5
4
|
const is_object_js_1 = require("./is-object.js");
|
|
6
5
|
const type_guards_js_1 = require("./type-guards.js");
|
|
7
|
-
function merge(target, source, options) {
|
|
8
|
-
if (!((0, is_object_js_1.isObject)(target) || typeof target === 'function')) {
|
|
9
|
-
throw new TypeError('"target" argument must be an object');
|
|
10
|
-
}
|
|
11
|
-
source = source || {};
|
|
12
|
-
if (!((0, is_object_js_1.isObject)(source) || typeof target === 'function')) {
|
|
13
|
-
throw new TypeError('"target" argument must be an object');
|
|
14
|
-
}
|
|
15
|
-
const fn = getMergeFunction(options);
|
|
16
|
-
return fn(target, source, options, '');
|
|
17
|
-
}
|
|
18
|
-
const functionCache = new Map();
|
|
19
|
-
function getMergeFunction(options) {
|
|
20
|
-
const cacheKey = [
|
|
21
|
-
options?.deep,
|
|
22
|
-
options?.moveArrays,
|
|
23
|
-
options?.keepExisting,
|
|
24
|
-
options?.copyDescriptors,
|
|
25
|
-
options?.ignore,
|
|
26
|
-
options?.ignoreUndefined,
|
|
27
|
-
options?.ignoreNulls,
|
|
28
|
-
options?.filter,
|
|
29
|
-
]
|
|
30
|
-
.map(option => option == null
|
|
31
|
-
? 'n'
|
|
32
|
-
: typeof option === 'function'
|
|
33
|
-
? 'f'
|
|
34
|
-
: typeof option === 'string'
|
|
35
|
-
? option
|
|
36
|
-
: option
|
|
37
|
-
? '1'
|
|
38
|
-
: '0')
|
|
39
|
-
.join();
|
|
40
|
-
let fn = functionCache.get(cacheKey);
|
|
41
|
-
if (!fn) {
|
|
42
|
-
fn = buildMerge(options);
|
|
43
|
-
functionCache.set(cacheKey, fn);
|
|
44
|
-
}
|
|
45
|
-
return fn;
|
|
46
|
-
}
|
|
47
|
-
function buildMerge(options) {
|
|
48
|
-
const scriptL0 = [
|
|
49
|
-
`
|
|
50
|
-
const { merge, isObject, isPlainObject, deepTest, arrayClone } = context;
|
|
51
6
|
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
let descriptor;
|
|
56
|
-
let srcVal;
|
|
57
|
-
let trgVal;
|
|
58
|
-
`,
|
|
59
|
-
];
|
|
60
|
-
// noinspection JSUnusedGlobalSymbols
|
|
61
|
-
const context = {
|
|
62
|
-
deepTest: is_object_js_1.isPlainObject,
|
|
63
|
-
isPlainObject: is_object_js_1.isPlainObject,
|
|
64
|
-
isObject: is_object_js_1.isObject,
|
|
65
|
-
arrayClone,
|
|
66
|
-
merge: null,
|
|
67
|
-
};
|
|
68
|
-
if (options?.deep) {
|
|
69
|
-
if (options.deep === 'full') {
|
|
70
|
-
context.deepTest = v => v && typeof v === 'object' && !(0, type_guards_js_1.isBuiltIn)(v);
|
|
71
|
-
}
|
|
72
|
-
scriptL0.push(`let subPath;`, `let _isArray;`);
|
|
73
|
-
if (typeof options?.deep === 'function') {
|
|
74
|
-
scriptL0.push(`const deepCallback = options.deep;`);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
if (typeof options?.ignore === 'function') {
|
|
78
|
-
scriptL0.push('const ignoreCallback = options.ignore;');
|
|
79
|
-
}
|
|
80
|
-
if (typeof options?.filter === 'function') {
|
|
81
|
-
scriptL0.push('const filterCallback = options.filter;');
|
|
82
|
-
}
|
|
83
|
-
if (typeof options?.copyDescriptors === 'function') {
|
|
84
|
-
scriptL0.push(`const copyDescriptorsCallback = options.copyDescriptors;`);
|
|
85
|
-
}
|
|
86
|
-
if (typeof options?.moveArrays === 'function') {
|
|
87
|
-
scriptL0.push(`const moveArraysCallback = options.moveArrays;`);
|
|
88
|
-
}
|
|
89
|
-
scriptL0.push(`
|
|
90
|
-
if (isPlainObject(target)) Object.setPrototypeOf(target, Object.getPrototypeOf(source));
|
|
91
|
-
let i = 0;
|
|
92
|
-
const len = keys.length;
|
|
93
|
-
for (i = 0; i < len; i++) {
|
|
94
|
-
key = keys[i];
|
|
95
|
-
/** Should not overwrite __proto__ and constructor properties */
|
|
96
|
-
if (key === '__proto__' || key === 'constructor') continue;
|
|
97
|
-
`);
|
|
98
|
-
const scriptL1For = [];
|
|
99
|
-
scriptL0.push(scriptL1For);
|
|
100
|
-
scriptL0.push('}');
|
|
101
|
-
/** ************* filter *****************/
|
|
102
|
-
if (options?.filter) {
|
|
103
|
-
scriptL1For.push(`
|
|
104
|
-
if (!filterCallback(key, source, target, curPath)) {
|
|
105
|
-
delete target[key];
|
|
106
|
-
continue;
|
|
107
|
-
}`);
|
|
108
|
-
}
|
|
109
|
-
/** ************* ignore *****************/
|
|
110
|
-
if (typeof options?.ignore === 'function') {
|
|
111
|
-
scriptL1For.push(`
|
|
112
|
-
if (
|
|
113
|
-
hasOwnProperty.call(target, key) &&
|
|
114
|
-
ignoreCallback(key, source, target, curPath)
|
|
115
|
-
) continue;
|
|
116
|
-
`);
|
|
117
|
-
}
|
|
118
|
-
/** ************* copyDescriptors *****************/
|
|
119
|
-
if (options?.copyDescriptors) {
|
|
120
|
-
let scriptL2Descriptors = scriptL1For;
|
|
121
|
-
if (typeof options?.copyDescriptors === 'function') {
|
|
122
|
-
scriptL1For.push('if (copyDescriptorsCallback(key, source, target, curPath)) {');
|
|
123
|
-
scriptL2Descriptors = [];
|
|
124
|
-
scriptL1For.push(scriptL2Descriptors);
|
|
125
|
-
scriptL1For.push(`} else`);
|
|
126
|
-
scriptL1For.push(` descriptor = {enumerable: true, configurable: true, writable: true}`);
|
|
127
|
-
}
|
|
128
|
-
scriptL2Descriptors.push(`
|
|
129
|
-
descriptor = { ...Object.getOwnPropertyDescriptor(source, key) }
|
|
130
|
-
if ((descriptor.get || descriptor.set)) {
|
|
131
|
-
Object.defineProperty(target, key, descriptor);
|
|
132
|
-
continue;
|
|
133
|
-
}
|
|
134
|
-
srcVal = source[key];`);
|
|
135
|
-
}
|
|
136
|
-
else {
|
|
137
|
-
scriptL1For.push(`descriptor = {enumerable: true, configurable: true, writable: true}`, `srcVal = source[key];`);
|
|
138
|
-
}
|
|
139
|
-
/** ************* keepExisting *****************/
|
|
140
|
-
if (options?.keepExisting) {
|
|
141
|
-
scriptL1For.push(`if (hasOwnProperty.call(target, key)) continue;`);
|
|
142
|
-
}
|
|
143
|
-
/** ************* ignoreUndefined *****************/
|
|
144
|
-
if (options?.ignoreUndefined ?? true) {
|
|
145
|
-
scriptL1For.push(`if (srcVal === undefined) continue;`);
|
|
146
|
-
}
|
|
147
|
-
/** ************* ignoreNulls *****************/
|
|
148
|
-
if (options?.ignoreNulls) {
|
|
149
|
-
scriptL1For.push(`if (srcVal === null) continue;`);
|
|
7
|
+
function merge(targetObject, sourceObject, options) {
|
|
8
|
+
if (!((0, is_object_js_1.isObject)(targetObject) || typeof targetObject === 'function')) {
|
|
9
|
+
throw new TypeError('"target" argument must be an object');
|
|
150
10
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if (
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
11
|
+
if (sourceObject == null)
|
|
12
|
+
return targetObject;
|
|
13
|
+
if (!((0, is_object_js_1.isObject)(sourceObject) ||
|
|
14
|
+
typeof sourceObject === 'function' ||
|
|
15
|
+
Array.isArray(sourceObject))) {
|
|
16
|
+
throw new TypeError('"target" argument must be an object or array of objects');
|
|
17
|
+
}
|
|
18
|
+
const keepExisting = options?.keepExisting;
|
|
19
|
+
const keepExistingFn = typeof options?.keepExisting === 'function'
|
|
20
|
+
? options?.keepExisting
|
|
21
|
+
: undefined;
|
|
22
|
+
const filterFn = options?.filter;
|
|
23
|
+
const ignoreUndefined = options?.ignoreUndefined ?? true;
|
|
24
|
+
const ignoreNulls = options?.ignoreNulls;
|
|
25
|
+
const deep = options?.deep;
|
|
26
|
+
const deepFull = deep === 'full';
|
|
27
|
+
const deepFn = typeof options?.deep === 'function' ? options?.deep : undefined;
|
|
28
|
+
const copyDescriptors = options?.copyDescriptors;
|
|
29
|
+
const mergeArrays = options?.mergeArrays;
|
|
30
|
+
const mergeArraysUnique = options?.mergeArrays === 'unique';
|
|
31
|
+
const mergeArraysFn = typeof options?.mergeArrays === 'function'
|
|
32
|
+
? options?.mergeArrays
|
|
33
|
+
: undefined;
|
|
34
|
+
const _merge = (target, source, parentPath = '') => {
|
|
35
|
+
if (!(0, is_object_js_1.isObject)(source))
|
|
36
|
+
return;
|
|
37
|
+
const keys = Object.getOwnPropertyNames(source);
|
|
38
|
+
if (options?.symbolKeys ?? true)
|
|
39
|
+
keys.push(...Object.getOwnPropertySymbols(source));
|
|
40
|
+
let key;
|
|
41
|
+
let descriptor;
|
|
42
|
+
let srcVal;
|
|
43
|
+
let _goDeep = false;
|
|
44
|
+
if ((0, is_object_js_1.isPlainObject)(target))
|
|
45
|
+
Object.setPrototypeOf(target, Object.getPrototypeOf(source));
|
|
46
|
+
const ignoreFn = options?.ignoreSource;
|
|
47
|
+
let i = 0;
|
|
48
|
+
const len = keys.length;
|
|
49
|
+
for (i = 0; i < len; i++) {
|
|
50
|
+
key = keys[i];
|
|
51
|
+
/** Should not overwrite __proto__ and constructor properties */
|
|
52
|
+
if (key === '__proto__' || key === 'constructor')
|
|
53
|
+
continue;
|
|
54
|
+
if (copyDescriptors) {
|
|
55
|
+
descriptor = Object.getOwnPropertyDescriptor(source, key);
|
|
56
|
+
if (descriptor?.get || descriptor?.set) {
|
|
57
|
+
Object.defineProperty(target, key, descriptor);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
srcVal = source[key];
|
|
62
|
+
if (ignoreFn?.(srcVal, {
|
|
63
|
+
key,
|
|
64
|
+
source,
|
|
65
|
+
target,
|
|
66
|
+
path: parentPath + (parentPath ? '.' : '') + String(key),
|
|
67
|
+
})) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (keepExisting && hasOwnProperty.call(target, key)) {
|
|
71
|
+
if (!keepExistingFn)
|
|
72
|
+
continue;
|
|
73
|
+
if (keepExistingFn(srcVal, {
|
|
74
|
+
key,
|
|
75
|
+
source,
|
|
76
|
+
target,
|
|
77
|
+
path: parentPath + (parentPath ? '.' : '') + String(key),
|
|
78
|
+
})) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (filterFn &&
|
|
83
|
+
!filterFn(srcVal, {
|
|
84
|
+
key,
|
|
85
|
+
source,
|
|
86
|
+
target,
|
|
87
|
+
path: parentPath + (parentPath ? '.' : '') + String(key),
|
|
88
|
+
})) {
|
|
89
|
+
continue;
|
|
193
90
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
91
|
+
if (ignoreUndefined && srcVal === undefined) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (ignoreNulls && srcVal === null) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (deep &&
|
|
98
|
+
typeof srcVal === 'object' &&
|
|
99
|
+
(!(0, type_guards_js_1.isBuiltIn)(srcVal) || Array.isArray(srcVal))) {
|
|
100
|
+
_goDeep =
|
|
101
|
+
(deepFn &&
|
|
102
|
+
deepFn(srcVal, {
|
|
103
|
+
key,
|
|
104
|
+
source,
|
|
105
|
+
target,
|
|
106
|
+
path: parentPath + (parentPath ? '.' : '') + String(key),
|
|
107
|
+
})) ||
|
|
108
|
+
(!deepFn &&
|
|
109
|
+
(deepFull || (0, is_object_js_1.isPlainObject)(srcVal) || Array.isArray(srcVal)));
|
|
110
|
+
if (_goDeep) {
|
|
111
|
+
/** Array */
|
|
112
|
+
if (Array.isArray(srcVal)) {
|
|
113
|
+
if (Array.isArray(target[key]) &&
|
|
114
|
+
(mergeArrays ||
|
|
115
|
+
mergeArraysFn?.(srcVal, {
|
|
116
|
+
key,
|
|
117
|
+
source,
|
|
118
|
+
target,
|
|
119
|
+
path: parentPath + (parentPath ? '.' : '') + String(key),
|
|
120
|
+
}))) {
|
|
121
|
+
target[key] = _arrayClone(target[key], parentPath + (parentPath ? '.' : '') + String(key));
|
|
122
|
+
}
|
|
123
|
+
else
|
|
124
|
+
target[key] = [];
|
|
125
|
+
target[key].push(..._arrayClone(srcVal, parentPath + (parentPath ? '.' : '') + String(key)));
|
|
126
|
+
if (mergeArraysUnique)
|
|
127
|
+
target[key] = Array.from(new Set(target[key]));
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
/** Object */
|
|
132
|
+
if (!(0, is_object_js_1.isObject)(target[key]))
|
|
133
|
+
target[key] = {};
|
|
134
|
+
_merge(target[key], srcVal, parentPath + (parentPath ? '.' : '') + String(key));
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (copyDescriptors) {
|
|
140
|
+
descriptor = { ...Object.getOwnPropertyDescriptor(source, key) };
|
|
141
|
+
descriptor.value = srcVal;
|
|
142
|
+
Object.defineProperty(target, key, descriptor);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
target[key] = srcVal;
|
|
199
146
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
147
|
+
return target;
|
|
148
|
+
};
|
|
149
|
+
const _arrayClone = (arr, curPath) => {
|
|
150
|
+
return arr.map((x, index) => {
|
|
151
|
+
if (Array.isArray(x))
|
|
152
|
+
return _arrayClone(x, curPath + '[' + index + ']');
|
|
153
|
+
if (typeof x === 'object' && !(0, type_guards_js_1.isBuiltIn)(x))
|
|
154
|
+
return _merge({}, x, curPath + '[' + index + ']');
|
|
155
|
+
return x;
|
|
156
|
+
});
|
|
157
|
+
};
|
|
158
|
+
const sources = Array.isArray(sourceObject) ? sourceObject : [sourceObject];
|
|
159
|
+
for (const src of sources) {
|
|
160
|
+
_merge(targetObject, src);
|
|
209
161
|
}
|
|
210
|
-
|
|
211
|
-
scriptL1For.push(`
|
|
212
|
-
descriptor.value = srcVal;
|
|
213
|
-
Object.defineProperty(target, key, descriptor);`);
|
|
214
|
-
scriptL0.push('return target;');
|
|
215
|
-
const script = _flattenText(scriptL0);
|
|
216
|
-
const fn = Function('target', 'source', 'options', 'curPath', 'context', script);
|
|
217
|
-
context.merge = (target, source, opts, curPath) => fn(target, source, opts, curPath, context);
|
|
218
|
-
return context.merge;
|
|
219
|
-
}
|
|
220
|
-
function arrayClone(arr, options, _merge, curPath) {
|
|
221
|
-
return arr.map((x) => {
|
|
222
|
-
if (Array.isArray(x))
|
|
223
|
-
return arrayClone(x, options, _merge, curPath);
|
|
224
|
-
if (typeof x === 'object' && !(0, type_guards_js_1.isBuiltIn)(x))
|
|
225
|
-
return _merge({}, x, options, curPath);
|
|
226
|
-
return x;
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
|
-
function _flattenText(arr, level = 0) {
|
|
230
|
-
const indent = ' '.repeat(level);
|
|
231
|
-
return arr
|
|
232
|
-
.map(v => {
|
|
233
|
-
if (Array.isArray(v))
|
|
234
|
-
return _flattenText(v, level + 1);
|
|
235
|
-
return (indent +
|
|
236
|
-
String(v)
|
|
237
|
-
.trim()
|
|
238
|
-
.replace(/\n/g, '\n' + indent));
|
|
239
|
-
})
|
|
240
|
-
.join('\n');
|
|
162
|
+
return targetObject;
|
|
241
163
|
}
|
package/cjs/omit.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../../src/clone.ts","../../src/index.ts","../../src/is-object.ts","../../src/merge.ts","../../src/omit.ts","../../src/type-guards.ts"],"version":"5.
|
|
1
|
+
{"root":["../../src/clone.ts","../../src/index.ts","../../src/is-object.ts","../../src/merge.ts","../../src/omit.ts","../../src/type-guards.ts"],"version":"5.9.2"}
|
package/esm/merge.js
CHANGED
|
@@ -1,237 +1,160 @@
|
|
|
1
1
|
import { isObject, isPlainObject } from './is-object.js';
|
|
2
2
|
import { isBuiltIn } from './type-guards.js';
|
|
3
|
-
export function merge(target, source, options) {
|
|
4
|
-
if (!(isObject(target) || typeof target === 'function')) {
|
|
5
|
-
throw new TypeError('"target" argument must be an object');
|
|
6
|
-
}
|
|
7
|
-
source = source || {};
|
|
8
|
-
if (!(isObject(source) || typeof target === 'function')) {
|
|
9
|
-
throw new TypeError('"target" argument must be an object');
|
|
10
|
-
}
|
|
11
|
-
const fn = getMergeFunction(options);
|
|
12
|
-
return fn(target, source, options, '');
|
|
13
|
-
}
|
|
14
|
-
const functionCache = new Map();
|
|
15
|
-
export function getMergeFunction(options) {
|
|
16
|
-
const cacheKey = [
|
|
17
|
-
options?.deep,
|
|
18
|
-
options?.moveArrays,
|
|
19
|
-
options?.keepExisting,
|
|
20
|
-
options?.copyDescriptors,
|
|
21
|
-
options?.ignore,
|
|
22
|
-
options?.ignoreUndefined,
|
|
23
|
-
options?.ignoreNulls,
|
|
24
|
-
options?.filter,
|
|
25
|
-
]
|
|
26
|
-
.map(option => option == null
|
|
27
|
-
? 'n'
|
|
28
|
-
: typeof option === 'function'
|
|
29
|
-
? 'f'
|
|
30
|
-
: typeof option === 'string'
|
|
31
|
-
? option
|
|
32
|
-
: option
|
|
33
|
-
? '1'
|
|
34
|
-
: '0')
|
|
35
|
-
.join();
|
|
36
|
-
let fn = functionCache.get(cacheKey);
|
|
37
|
-
if (!fn) {
|
|
38
|
-
fn = buildMerge(options);
|
|
39
|
-
functionCache.set(cacheKey, fn);
|
|
40
|
-
}
|
|
41
|
-
return fn;
|
|
42
|
-
}
|
|
43
|
-
function buildMerge(options) {
|
|
44
|
-
const scriptL0 = [
|
|
45
|
-
`
|
|
46
|
-
const { merge, isObject, isPlainObject, deepTest, arrayClone } = context;
|
|
47
3
|
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
let descriptor;
|
|
52
|
-
let srcVal;
|
|
53
|
-
let trgVal;
|
|
54
|
-
`,
|
|
55
|
-
];
|
|
56
|
-
// noinspection JSUnusedGlobalSymbols
|
|
57
|
-
const context = {
|
|
58
|
-
deepTest: isPlainObject,
|
|
59
|
-
isPlainObject,
|
|
60
|
-
isObject,
|
|
61
|
-
arrayClone,
|
|
62
|
-
merge: null,
|
|
63
|
-
};
|
|
64
|
-
if (options?.deep) {
|
|
65
|
-
if (options.deep === 'full') {
|
|
66
|
-
context.deepTest = v => v && typeof v === 'object' && !isBuiltIn(v);
|
|
67
|
-
}
|
|
68
|
-
scriptL0.push(`let subPath;`, `let _isArray;`);
|
|
69
|
-
if (typeof options?.deep === 'function') {
|
|
70
|
-
scriptL0.push(`const deepCallback = options.deep;`);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
if (typeof options?.ignore === 'function') {
|
|
74
|
-
scriptL0.push('const ignoreCallback = options.ignore;');
|
|
75
|
-
}
|
|
76
|
-
if (typeof options?.filter === 'function') {
|
|
77
|
-
scriptL0.push('const filterCallback = options.filter;');
|
|
78
|
-
}
|
|
79
|
-
if (typeof options?.copyDescriptors === 'function') {
|
|
80
|
-
scriptL0.push(`const copyDescriptorsCallback = options.copyDescriptors;`);
|
|
81
|
-
}
|
|
82
|
-
if (typeof options?.moveArrays === 'function') {
|
|
83
|
-
scriptL0.push(`const moveArraysCallback = options.moveArrays;`);
|
|
84
|
-
}
|
|
85
|
-
scriptL0.push(`
|
|
86
|
-
if (isPlainObject(target)) Object.setPrototypeOf(target, Object.getPrototypeOf(source));
|
|
87
|
-
let i = 0;
|
|
88
|
-
const len = keys.length;
|
|
89
|
-
for (i = 0; i < len; i++) {
|
|
90
|
-
key = keys[i];
|
|
91
|
-
/** Should not overwrite __proto__ and constructor properties */
|
|
92
|
-
if (key === '__proto__' || key === 'constructor') continue;
|
|
93
|
-
`);
|
|
94
|
-
const scriptL1For = [];
|
|
95
|
-
scriptL0.push(scriptL1For);
|
|
96
|
-
scriptL0.push('}');
|
|
97
|
-
/** ************* filter *****************/
|
|
98
|
-
if (options?.filter) {
|
|
99
|
-
scriptL1For.push(`
|
|
100
|
-
if (!filterCallback(key, source, target, curPath)) {
|
|
101
|
-
delete target[key];
|
|
102
|
-
continue;
|
|
103
|
-
}`);
|
|
104
|
-
}
|
|
105
|
-
/** ************* ignore *****************/
|
|
106
|
-
if (typeof options?.ignore === 'function') {
|
|
107
|
-
scriptL1For.push(`
|
|
108
|
-
if (
|
|
109
|
-
hasOwnProperty.call(target, key) &&
|
|
110
|
-
ignoreCallback(key, source, target, curPath)
|
|
111
|
-
) continue;
|
|
112
|
-
`);
|
|
113
|
-
}
|
|
114
|
-
/** ************* copyDescriptors *****************/
|
|
115
|
-
if (options?.copyDescriptors) {
|
|
116
|
-
let scriptL2Descriptors = scriptL1For;
|
|
117
|
-
if (typeof options?.copyDescriptors === 'function') {
|
|
118
|
-
scriptL1For.push('if (copyDescriptorsCallback(key, source, target, curPath)) {');
|
|
119
|
-
scriptL2Descriptors = [];
|
|
120
|
-
scriptL1For.push(scriptL2Descriptors);
|
|
121
|
-
scriptL1For.push(`} else`);
|
|
122
|
-
scriptL1For.push(` descriptor = {enumerable: true, configurable: true, writable: true}`);
|
|
123
|
-
}
|
|
124
|
-
scriptL2Descriptors.push(`
|
|
125
|
-
descriptor = { ...Object.getOwnPropertyDescriptor(source, key) }
|
|
126
|
-
if ((descriptor.get || descriptor.set)) {
|
|
127
|
-
Object.defineProperty(target, key, descriptor);
|
|
128
|
-
continue;
|
|
129
|
-
}
|
|
130
|
-
srcVal = source[key];`);
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
133
|
-
scriptL1For.push(`descriptor = {enumerable: true, configurable: true, writable: true}`, `srcVal = source[key];`);
|
|
134
|
-
}
|
|
135
|
-
/** ************* keepExisting *****************/
|
|
136
|
-
if (options?.keepExisting) {
|
|
137
|
-
scriptL1For.push(`if (hasOwnProperty.call(target, key)) continue;`);
|
|
138
|
-
}
|
|
139
|
-
/** ************* ignoreUndefined *****************/
|
|
140
|
-
if (options?.ignoreUndefined ?? true) {
|
|
141
|
-
scriptL1For.push(`if (srcVal === undefined) continue;`);
|
|
142
|
-
}
|
|
143
|
-
/** ************* ignoreNulls *****************/
|
|
144
|
-
if (options?.ignoreNulls) {
|
|
145
|
-
scriptL1For.push(`if (srcVal === null) continue;`);
|
|
4
|
+
export function merge(targetObject, sourceObject, options) {
|
|
5
|
+
if (!(isObject(targetObject) || typeof targetObject === 'function')) {
|
|
6
|
+
throw new TypeError('"target" argument must be an object');
|
|
146
7
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
8
|
+
if (sourceObject == null)
|
|
9
|
+
return targetObject;
|
|
10
|
+
if (!(isObject(sourceObject) ||
|
|
11
|
+
typeof sourceObject === 'function' ||
|
|
12
|
+
Array.isArray(sourceObject))) {
|
|
13
|
+
throw new TypeError('"target" argument must be an object or array of objects');
|
|
14
|
+
}
|
|
15
|
+
const keepExisting = options?.keepExisting;
|
|
16
|
+
const keepExistingFn = typeof options?.keepExisting === 'function'
|
|
17
|
+
? options?.keepExisting
|
|
18
|
+
: undefined;
|
|
19
|
+
const filterFn = options?.filter;
|
|
20
|
+
const ignoreUndefined = options?.ignoreUndefined ?? true;
|
|
21
|
+
const ignoreNulls = options?.ignoreNulls;
|
|
22
|
+
const deep = options?.deep;
|
|
23
|
+
const deepFull = deep === 'full';
|
|
24
|
+
const deepFn = typeof options?.deep === 'function' ? options?.deep : undefined;
|
|
25
|
+
const copyDescriptors = options?.copyDescriptors;
|
|
26
|
+
const mergeArrays = options?.mergeArrays;
|
|
27
|
+
const mergeArraysUnique = options?.mergeArrays === 'unique';
|
|
28
|
+
const mergeArraysFn = typeof options?.mergeArrays === 'function'
|
|
29
|
+
? options?.mergeArrays
|
|
30
|
+
: undefined;
|
|
31
|
+
const _merge = (target, source, parentPath = '') => {
|
|
32
|
+
if (!isObject(source))
|
|
33
|
+
return;
|
|
34
|
+
const keys = Object.getOwnPropertyNames(source);
|
|
35
|
+
if (options?.symbolKeys ?? true)
|
|
36
|
+
keys.push(...Object.getOwnPropertySymbols(source));
|
|
37
|
+
let key;
|
|
38
|
+
let descriptor;
|
|
39
|
+
let srcVal;
|
|
40
|
+
let _goDeep = false;
|
|
41
|
+
if (isPlainObject(target))
|
|
42
|
+
Object.setPrototypeOf(target, Object.getPrototypeOf(source));
|
|
43
|
+
const ignoreFn = options?.ignoreSource;
|
|
44
|
+
let i = 0;
|
|
45
|
+
const len = keys.length;
|
|
46
|
+
for (i = 0; i < len; i++) {
|
|
47
|
+
key = keys[i];
|
|
48
|
+
/** Should not overwrite __proto__ and constructor properties */
|
|
49
|
+
if (key === '__proto__' || key === 'constructor')
|
|
50
|
+
continue;
|
|
51
|
+
if (copyDescriptors) {
|
|
52
|
+
descriptor = Object.getOwnPropertyDescriptor(source, key);
|
|
53
|
+
if (descriptor?.get || descriptor?.set) {
|
|
54
|
+
Object.defineProperty(target, key, descriptor);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
srcVal = source[key];
|
|
59
|
+
if (ignoreFn?.(srcVal, {
|
|
60
|
+
key,
|
|
61
|
+
source,
|
|
62
|
+
target,
|
|
63
|
+
path: parentPath + (parentPath ? '.' : '') + String(key),
|
|
64
|
+
})) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (keepExisting && hasOwnProperty.call(target, key)) {
|
|
68
|
+
if (!keepExistingFn)
|
|
69
|
+
continue;
|
|
70
|
+
if (keepExistingFn(srcVal, {
|
|
71
|
+
key,
|
|
72
|
+
source,
|
|
73
|
+
target,
|
|
74
|
+
path: parentPath + (parentPath ? '.' : '') + String(key),
|
|
75
|
+
})) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (filterFn &&
|
|
80
|
+
!filterFn(srcVal, {
|
|
81
|
+
key,
|
|
82
|
+
source,
|
|
83
|
+
target,
|
|
84
|
+
path: parentPath + (parentPath ? '.' : '') + String(key),
|
|
85
|
+
})) {
|
|
86
|
+
continue;
|
|
189
87
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
88
|
+
if (ignoreUndefined && srcVal === undefined) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (ignoreNulls && srcVal === null) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (deep &&
|
|
95
|
+
typeof srcVal === 'object' &&
|
|
96
|
+
(!isBuiltIn(srcVal) || Array.isArray(srcVal))) {
|
|
97
|
+
_goDeep =
|
|
98
|
+
(deepFn &&
|
|
99
|
+
deepFn(srcVal, {
|
|
100
|
+
key,
|
|
101
|
+
source,
|
|
102
|
+
target,
|
|
103
|
+
path: parentPath + (parentPath ? '.' : '') + String(key),
|
|
104
|
+
})) ||
|
|
105
|
+
(!deepFn &&
|
|
106
|
+
(deepFull || isPlainObject(srcVal) || Array.isArray(srcVal)));
|
|
107
|
+
if (_goDeep) {
|
|
108
|
+
/** Array */
|
|
109
|
+
if (Array.isArray(srcVal)) {
|
|
110
|
+
if (Array.isArray(target[key]) &&
|
|
111
|
+
(mergeArrays ||
|
|
112
|
+
mergeArraysFn?.(srcVal, {
|
|
113
|
+
key,
|
|
114
|
+
source,
|
|
115
|
+
target,
|
|
116
|
+
path: parentPath + (parentPath ? '.' : '') + String(key),
|
|
117
|
+
}))) {
|
|
118
|
+
target[key] = _arrayClone(target[key], parentPath + (parentPath ? '.' : '') + String(key));
|
|
119
|
+
}
|
|
120
|
+
else
|
|
121
|
+
target[key] = [];
|
|
122
|
+
target[key].push(..._arrayClone(srcVal, parentPath + (parentPath ? '.' : '') + String(key)));
|
|
123
|
+
if (mergeArraysUnique)
|
|
124
|
+
target[key] = Array.from(new Set(target[key]));
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
/** Object */
|
|
129
|
+
if (!isObject(target[key]))
|
|
130
|
+
target[key] = {};
|
|
131
|
+
_merge(target[key], srcVal, parentPath + (parentPath ? '.' : '') + String(key));
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (copyDescriptors) {
|
|
137
|
+
descriptor = { ...Object.getOwnPropertyDescriptor(source, key) };
|
|
138
|
+
descriptor.value = srcVal;
|
|
139
|
+
Object.defineProperty(target, key, descriptor);
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
target[key] = srcVal;
|
|
195
143
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
144
|
+
return target;
|
|
145
|
+
};
|
|
146
|
+
const _arrayClone = (arr, curPath) => {
|
|
147
|
+
return arr.map((x, index) => {
|
|
148
|
+
if (Array.isArray(x))
|
|
149
|
+
return _arrayClone(x, curPath + '[' + index + ']');
|
|
150
|
+
if (typeof x === 'object' && !isBuiltIn(x))
|
|
151
|
+
return _merge({}, x, curPath + '[' + index + ']');
|
|
152
|
+
return x;
|
|
153
|
+
});
|
|
154
|
+
};
|
|
155
|
+
const sources = Array.isArray(sourceObject) ? sourceObject : [sourceObject];
|
|
156
|
+
for (const src of sources) {
|
|
157
|
+
_merge(targetObject, src);
|
|
205
158
|
}
|
|
206
|
-
|
|
207
|
-
scriptL1For.push(`
|
|
208
|
-
descriptor.value = srcVal;
|
|
209
|
-
Object.defineProperty(target, key, descriptor);`);
|
|
210
|
-
scriptL0.push('return target;');
|
|
211
|
-
const script = _flattenText(scriptL0);
|
|
212
|
-
const fn = Function('target', 'source', 'options', 'curPath', 'context', script);
|
|
213
|
-
context.merge = (target, source, opts, curPath) => fn(target, source, opts, curPath, context);
|
|
214
|
-
return context.merge;
|
|
215
|
-
}
|
|
216
|
-
function arrayClone(arr, options, _merge, curPath) {
|
|
217
|
-
return arr.map((x) => {
|
|
218
|
-
if (Array.isArray(x))
|
|
219
|
-
return arrayClone(x, options, _merge, curPath);
|
|
220
|
-
if (typeof x === 'object' && !isBuiltIn(x))
|
|
221
|
-
return _merge({}, x, options, curPath);
|
|
222
|
-
return x;
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
function _flattenText(arr, level = 0) {
|
|
226
|
-
const indent = ' '.repeat(level);
|
|
227
|
-
return arr
|
|
228
|
-
.map(v => {
|
|
229
|
-
if (Array.isArray(v))
|
|
230
|
-
return _flattenText(v, level + 1);
|
|
231
|
-
return (indent +
|
|
232
|
-
String(v)
|
|
233
|
-
.trim()
|
|
234
|
-
.replace(/\n/g, '\n' + indent));
|
|
235
|
-
})
|
|
236
|
-
.join('\n');
|
|
159
|
+
return targetObject;
|
|
237
160
|
}
|
package/esm/omit.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../../src/clone.ts","../../src/index.ts","../../src/is-object.ts","../../src/merge.ts","../../src/omit.ts","../../src/type-guards.ts"],"version":"5.
|
|
1
|
+
{"root":["../../src/clone.ts","../../src/index.ts","../../src/is-object.ts","../../src/merge.ts","../../src/omit.ts","../../src/type-guards.ts"],"version":"5.9.2"}
|
package/package.json
CHANGED
package/types/merge.d.ts
CHANGED
|
@@ -1,26 +1,72 @@
|
|
|
1
1
|
export declare function merge<A, B>(target: A, source: B, options?: merge.Options): A & B;
|
|
2
|
-
export declare function
|
|
2
|
+
export declare function merge<A, B, C>(target: A, source: [B, C], options?: merge.Options): A & B & C;
|
|
3
|
+
export declare function merge<A, B, C, D>(target: A, source: [B, C, D], options?: merge.Options): A & B & C & D;
|
|
4
|
+
export declare function merge<A, B, C, D, E>(target: A, source: [B, C, D, E], options?: merge.Options): A & B & C & D & E;
|
|
5
|
+
export declare function merge<A, B, C, D, F>(target: A, source: [B, C, D, F], options?: merge.Options): A & B & C & D & F;
|
|
6
|
+
/**
|
|
7
|
+
* @namespace
|
|
8
|
+
*/
|
|
3
9
|
export declare namespace merge {
|
|
4
|
-
type
|
|
10
|
+
type CallbackFn = (value: any, ctx: CallbackContext) => boolean;
|
|
11
|
+
interface CallbackContext {
|
|
12
|
+
source: any;
|
|
13
|
+
target: any;
|
|
14
|
+
key: string | symbol | number;
|
|
15
|
+
path: string;
|
|
16
|
+
}
|
|
5
17
|
interface Options {
|
|
6
|
-
deep?: boolean | 'full' | NodeCallback;
|
|
7
18
|
/**
|
|
19
|
+
* Optional variable that determines the depth of an operation or inclusion behavior.
|
|
20
|
+
*
|
|
21
|
+
* - If set to `true`, it enables a deep operation for only native js objects, excluding classes.
|
|
22
|
+
* - If set to `'full'`, it enables a deep operation for all objects, including classes, excluding built-in objects
|
|
23
|
+
* - If assigned a `NodeCallback` function, it provides a custom callback mechanism for handling the operation.
|
|
24
|
+
*
|
|
25
|
+
* This variable can be used to define the level of depth or customization for a given process.
|
|
26
|
+
* @default false
|
|
8
27
|
*/
|
|
9
|
-
|
|
28
|
+
deep?: boolean | 'full' | CallbackFn;
|
|
10
29
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
30
|
+
* Indicates whether symbol keys should be included.
|
|
31
|
+
* If set to `true`, properties with symbol keys will be considered.
|
|
32
|
+
* If `false` or `undefined`, symbol keys will be ignored.
|
|
33
|
+
* @default true
|
|
13
34
|
*/
|
|
14
|
-
|
|
35
|
+
symbolKeys?: boolean;
|
|
15
36
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
37
|
+
* Specifies the behavior for merging arrays during a particular operation.
|
|
38
|
+
*
|
|
39
|
+
* When set to `true`, all array elements will be deeply merged, preserving all duplicates.
|
|
40
|
+
* When set to `'unique'`, only unique elements will be preserved in the merged array.
|
|
41
|
+
* If a callback function (`CallbackFn`) is provided, it determines the custom merging logic for the arrays.
|
|
18
42
|
*/
|
|
19
|
-
|
|
43
|
+
mergeArrays?: boolean | 'unique' | CallbackFn;
|
|
20
44
|
/**
|
|
21
|
-
*
|
|
45
|
+
* Determines whether to retain pre-existing values.
|
|
46
|
+
* If set to `true`, existing entities are preserved without modification.
|
|
47
|
+
* If set to `false`, existing entities may be replaced or overridden by new ones.
|
|
48
|
+
* Alternatively, can be assigned a callback function (`CallbackFn`) that dynamically resolves whether to keep existing entities based on custom logic.
|
|
22
49
|
*/
|
|
23
|
-
|
|
50
|
+
keepExisting?: boolean | CallbackFn;
|
|
51
|
+
/**
|
|
52
|
+
* A boolean flag that determines whether property descriptors
|
|
53
|
+
* should be copied when transferring properties from one object
|
|
54
|
+
* to another.
|
|
55
|
+
*
|
|
56
|
+
* If set to true, both the value and descriptor metadata
|
|
57
|
+
* (e.g., writable, configurable, enumerable) of a property
|
|
58
|
+
* will be copied. If set to false or undefined, only the
|
|
59
|
+
* property values will be copied, without preserving descriptor
|
|
60
|
+
* details.
|
|
61
|
+
*
|
|
62
|
+
* This is typically used when needing to retain detailed control
|
|
63
|
+
* over property attributes during object manipulation.
|
|
64
|
+
*/
|
|
65
|
+
copyDescriptors?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Ignores the source field if callback returns true
|
|
68
|
+
*/
|
|
69
|
+
ignoreSource?: CallbackFn;
|
|
24
70
|
/**
|
|
25
71
|
* Ignore fields which values are "undefined"
|
|
26
72
|
* @default true
|
|
@@ -32,8 +78,8 @@ export declare namespace merge {
|
|
|
32
78
|
*/
|
|
33
79
|
ignoreNulls?: boolean;
|
|
34
80
|
/**
|
|
35
|
-
*
|
|
81
|
+
* Ignores both target and source field if callback returns true
|
|
36
82
|
*/
|
|
37
|
-
filter?:
|
|
83
|
+
filter?: CallbackFn;
|
|
38
84
|
}
|
|
39
85
|
}
|