@jsopen/objects 2.1.1 → 2.2.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/README.md +18 -0
- package/merge.d.ts +2 -2
- package/merge.js +94 -63
- package/package.json +1 -1
- package/update-error-message.d.ts +1 -7
- package/update-error-message.js +0 -16
package/README.md
CHANGED
|
@@ -7,6 +7,24 @@
|
|
|
7
7
|
|
|
8
8
|
A 'swiss army knife' solution for working with javascript objects.
|
|
9
9
|
|
|
10
|
+
## Functions
|
|
11
|
+
|
|
12
|
+
### [merge](docs/merge.md)
|
|
13
|
+
Is a powerful, flexible tool for merging objects, arrays, and their nested properties.
|
|
14
|
+
|
|
15
|
+
### [clone / deepClone](docs/clone.md)
|
|
16
|
+
Easy ways to create shallow or deep copies of objects and arrays.
|
|
17
|
+
|
|
18
|
+
### [omit / omitUndefined / omitNull / omitNullish](docs/omit.md)
|
|
19
|
+
Easily exclude specific keys or nullish values from objects.
|
|
20
|
+
|
|
21
|
+
### [updateErrorMessage](docs/update-error-message.md)
|
|
22
|
+
Update an Error object's message while correctly refreshing the stack trace.
|
|
23
|
+
|
|
24
|
+
### [Utilities](docs/utils.md)
|
|
25
|
+
Various utility functions for object and type checking.
|
|
26
|
+
|
|
27
|
+
|
|
10
28
|
## Installation
|
|
11
29
|
|
|
12
30
|
`$ npm install @jsopen/objects`
|
package/merge.d.ts
CHANGED
|
@@ -18,8 +18,8 @@ export declare namespace merge {
|
|
|
18
18
|
/**
|
|
19
19
|
* Optional variable that determines the depth of an operation or inclusion behavior.
|
|
20
20
|
*
|
|
21
|
-
* - If set to `true`, it enables a deep operation for only
|
|
22
|
-
* - If set to `'full'`, it enables a deep operation for all objects, including classes, excluding built-in objects
|
|
21
|
+
* - If set to `true`, it enables a deep operation for only plain objects and arrays. Non-plain objects (class instances) are assigned by reference.
|
|
22
|
+
* - If set to `'full'`, it enables a deep operation for all objects, including classes, excluding built-in objects.
|
|
23
23
|
* - If assigned a `NodeCallback` function, it provides a custom callback mechanism for handling the operation.
|
|
24
24
|
*
|
|
25
25
|
* This variable can be used to define the level of depth or customization for a given process.
|
package/merge.js
CHANGED
|
@@ -12,20 +12,20 @@ export function merge(targetObject, sourceObject, options) {
|
|
|
12
12
|
Array.isArray(sourceObject))) {
|
|
13
13
|
throw new TypeError('"target" argument must be an object or array of objects');
|
|
14
14
|
}
|
|
15
|
-
const
|
|
16
|
-
const
|
|
15
|
+
const optsKeepExisting = !!options?.keepExisting;
|
|
16
|
+
const optsKeepExistingFn = typeof options?.keepExisting === 'function'
|
|
17
17
|
? options?.keepExisting
|
|
18
18
|
: undefined;
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
const
|
|
19
|
+
const optsFilterFn = options?.filter;
|
|
20
|
+
const optsIgnoreUndefined = options?.ignoreUndefined ?? true;
|
|
21
|
+
const optsIgnoreNulls = options?.ignoreNulls;
|
|
22
|
+
const optsDeep = options?.deep;
|
|
23
|
+
const optsDeepFull = optsDeep === 'full';
|
|
24
|
+
const optsDeepFn = typeof options?.deep === 'function' ? options?.deep : undefined;
|
|
25
|
+
const optsCopyDescriptors = options?.copyDescriptors;
|
|
26
|
+
const optsMergeArrays = !!options?.mergeArrays;
|
|
27
|
+
const optsMergeArraysUnique = options?.mergeArrays === 'unique';
|
|
28
|
+
const optsMergeArraysFn = typeof options?.mergeArrays === 'function'
|
|
29
29
|
? options?.mergeArrays
|
|
30
30
|
: undefined;
|
|
31
31
|
const _merge = (target, source, parentPath = '') => {
|
|
@@ -37,18 +37,25 @@ export function merge(targetObject, sourceObject, options) {
|
|
|
37
37
|
let key;
|
|
38
38
|
let descriptor;
|
|
39
39
|
let srcVal;
|
|
40
|
-
let
|
|
40
|
+
let trgVal;
|
|
41
|
+
let goDeep;
|
|
42
|
+
let srcIsPlainObject;
|
|
43
|
+
let srcIsArray;
|
|
44
|
+
let srcIsBuiltIn;
|
|
45
|
+
let trgIsArray;
|
|
46
|
+
let curPath;
|
|
47
|
+
let keepExisting;
|
|
41
48
|
if (isPlainObject(target))
|
|
42
49
|
Object.setPrototypeOf(target, Object.getPrototypeOf(source));
|
|
43
50
|
const ignoreFn = options?.ignoreSource;
|
|
44
|
-
let i
|
|
51
|
+
let i;
|
|
45
52
|
const len = keys.length;
|
|
46
53
|
for (i = 0; i < len; i++) {
|
|
47
54
|
key = keys[i];
|
|
48
55
|
/** Should not overwrite __proto__ and constructor properties */
|
|
49
56
|
if (key === '__proto__' || key === 'constructor')
|
|
50
57
|
continue;
|
|
51
|
-
if (
|
|
58
|
+
if (optsCopyDescriptors) {
|
|
52
59
|
descriptor = Object.getOwnPropertyDescriptor(source, key);
|
|
53
60
|
if (descriptor?.get || descriptor?.set) {
|
|
54
61
|
Object.defineProperty(target, key, descriptor);
|
|
@@ -56,6 +63,7 @@ export function merge(targetObject, sourceObject, options) {
|
|
|
56
63
|
}
|
|
57
64
|
}
|
|
58
65
|
srcVal = source[key];
|
|
66
|
+
/** Check if the property should be ignored */
|
|
59
67
|
if (ignoreFn?.(srcVal, {
|
|
60
68
|
key,
|
|
61
69
|
source,
|
|
@@ -64,76 +72,99 @@ export function merge(targetObject, sourceObject, options) {
|
|
|
64
72
|
})) {
|
|
65
73
|
continue;
|
|
66
74
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
target,
|
|
76
|
-
path: parentPath + (parentPath ? '.' : '') + String(key),
|
|
77
|
-
});
|
|
78
|
-
else
|
|
79
|
-
_goDeep = deepFull || isPlainObject(srcVal) || Array.isArray(srcVal);
|
|
80
|
-
}
|
|
81
|
-
if (!_goDeep && keepExisting && hasOwnProperty.call(target, key)) {
|
|
82
|
-
if (!keepExistingFn)
|
|
83
|
-
continue;
|
|
84
|
-
if (keepExistingFn(srcVal, {
|
|
75
|
+
srcIsPlainObject = isPlainObject(srcVal);
|
|
76
|
+
srcIsArray = Array.isArray(srcVal);
|
|
77
|
+
srcIsBuiltIn = isBuiltIn(srcVal) && !srcIsArray;
|
|
78
|
+
trgVal = target[key];
|
|
79
|
+
trgIsArray = Array.isArray(trgVal);
|
|
80
|
+
curPath = parentPath + (parentPath ? '.' : '') + String(key);
|
|
81
|
+
if (optsFilterFn &&
|
|
82
|
+
!optsFilterFn(srcVal, {
|
|
85
83
|
key,
|
|
86
84
|
source,
|
|
87
85
|
target,
|
|
88
|
-
path:
|
|
86
|
+
path: curPath,
|
|
89
87
|
})) {
|
|
90
|
-
|
|
91
|
-
}
|
|
88
|
+
continue;
|
|
92
89
|
}
|
|
93
|
-
if
|
|
94
|
-
|
|
90
|
+
/** Determine if we should go deeper into the object */
|
|
91
|
+
goDeep = !!(optsDeep &&
|
|
92
|
+
!srcIsBuiltIn &&
|
|
93
|
+
/** Source value should be an object */
|
|
94
|
+
typeof srcVal === 'object' &&
|
|
95
|
+
/** deep full or plain object */
|
|
96
|
+
(optsDeepFull || srcIsPlainObject || srcIsArray));
|
|
97
|
+
keepExisting =
|
|
98
|
+
optsKeepExisting &&
|
|
99
|
+
hasOwnProperty.call(target, key) &&
|
|
100
|
+
(!optsKeepExistingFn ||
|
|
101
|
+
optsKeepExistingFn(srcVal, {
|
|
102
|
+
key,
|
|
103
|
+
source,
|
|
104
|
+
target,
|
|
105
|
+
path: curPath,
|
|
106
|
+
}));
|
|
107
|
+
if (goDeep && optsDeepFn) {
|
|
108
|
+
goDeep = optsDeepFn(srcVal, {
|
|
95
109
|
key,
|
|
96
110
|
source,
|
|
97
111
|
target,
|
|
98
|
-
path:
|
|
99
|
-
})
|
|
100
|
-
continue;
|
|
112
|
+
path: curPath,
|
|
113
|
+
});
|
|
101
114
|
}
|
|
102
|
-
if (
|
|
115
|
+
if (optsIgnoreUndefined && srcVal === undefined) {
|
|
103
116
|
continue;
|
|
104
117
|
}
|
|
105
|
-
if (
|
|
118
|
+
if (optsIgnoreNulls && srcVal === null) {
|
|
106
119
|
continue;
|
|
107
120
|
}
|
|
108
|
-
if (
|
|
121
|
+
if (goDeep) {
|
|
122
|
+
// if (keepExisting) &&
|
|
109
123
|
/** Array */
|
|
110
|
-
if (
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
124
|
+
if (srcIsArray) {
|
|
125
|
+
/** If the target value is not an array, we do not need a deep merge operation */
|
|
126
|
+
if (!trgIsArray) {
|
|
127
|
+
if (keepExisting)
|
|
128
|
+
continue;
|
|
129
|
+
srcVal = _arrayClone(srcVal, curPath);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
srcVal = _arrayClone(srcVal, curPath);
|
|
133
|
+
if (optsMergeArrays &&
|
|
134
|
+
(!optsMergeArraysFn ||
|
|
135
|
+
optsMergeArraysFn?.(srcVal, {
|
|
136
|
+
key,
|
|
137
|
+
source,
|
|
138
|
+
target,
|
|
139
|
+
path: curPath,
|
|
140
|
+
}))) {
|
|
141
|
+
srcVal = [...trgVal, ...srcVal];
|
|
142
|
+
if (optsMergeArraysUnique)
|
|
143
|
+
target[key] = Array.from(new Set(srcVal));
|
|
144
|
+
else
|
|
145
|
+
target[key] = srcVal;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
if (optsMergeArraysUnique)
|
|
150
|
+
srcVal = Array.from(new Set(srcVal));
|
|
151
|
+
}
|
|
120
152
|
}
|
|
121
|
-
else
|
|
122
|
-
target[key] = [];
|
|
123
|
-
target[key].push(..._arrayClone(srcVal, parentPath + (parentPath ? '.' : '') + String(key)));
|
|
124
|
-
if (mergeArraysUnique)
|
|
125
|
-
target[key] = Array.from(new Set(target[key]));
|
|
126
|
-
continue;
|
|
127
153
|
}
|
|
128
154
|
else {
|
|
129
155
|
/** Object */
|
|
130
|
-
if (!isObject(target[key]))
|
|
156
|
+
if (!isObject(target[key])) {
|
|
157
|
+
if (keepExisting)
|
|
158
|
+
continue;
|
|
131
159
|
target[key] = {};
|
|
132
|
-
|
|
160
|
+
}
|
|
161
|
+
_merge(target[key], srcVal, curPath);
|
|
133
162
|
continue;
|
|
134
163
|
}
|
|
135
164
|
}
|
|
136
|
-
if (
|
|
165
|
+
if (keepExisting)
|
|
166
|
+
continue;
|
|
167
|
+
if (optsCopyDescriptors) {
|
|
137
168
|
descriptor = { ...Object.getOwnPropertyDescriptor(source, key) };
|
|
138
169
|
descriptor.value = srcVal;
|
|
139
170
|
Object.defineProperty(target, key, descriptor);
|
package/package.json
CHANGED
|
@@ -3,10 +3,4 @@
|
|
|
3
3
|
* @param err
|
|
4
4
|
* @param newMessage
|
|
5
5
|
*/
|
|
6
|
-
export declare function updateErrorMessage(err: Error, newMessage: string): Error
|
|
7
|
-
/**
|
|
8
|
-
* Updates the error message and stack trace at sametime.
|
|
9
|
-
* @param err
|
|
10
|
-
* @param newMessage
|
|
11
|
-
*/
|
|
12
|
-
export declare function updateErrorMessageFallback(err: Error, newMessage: string): Error;
|
|
6
|
+
export declare function updateErrorMessage(err: Error, newMessage: string): Error;
|
package/update-error-message.js
CHANGED
|
@@ -5,22 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export function updateErrorMessage(err, newMessage) {
|
|
7
7
|
err.message = String(newMessage);
|
|
8
|
-
/** V8 */
|
|
9
|
-
if (typeof Error.captureStackTrace === 'function') {
|
|
10
|
-
Error.captureStackTrace(err);
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
/** Other engines */
|
|
14
|
-
return updateErrorMessageFallback(err, newMessage);
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Updates the error message and stack trace at sametime.
|
|
18
|
-
* @param err
|
|
19
|
-
* @param newMessage
|
|
20
|
-
*/
|
|
21
|
-
export function updateErrorMessageFallback(err, newMessage) {
|
|
22
|
-
err.message = String(newMessage);
|
|
23
|
-
/** Other engines */
|
|
24
8
|
const stack = typeof err.stack === 'string' ? err.stack : null;
|
|
25
9
|
if (!stack)
|
|
26
10
|
return err;
|