@jsopen/objects 1.2.0 → 1.4.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.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
- # v1.2.0
2
- [2024-11-21]
1
+ # v1.4.0
2
+ [2024-11-22]
3
3
 
4
4
  ### Changes
5
5
 
6
- * feat: Added isConstructor, isIterable and isAsyncIterable type guards ([`b2251c1`](https://github.com/panates/jsopen-objects/commit/b2251c1a780a632d7eaf8bd8e7f3205f73c43c52))
6
+ * feat: Added "full" option to "deep" config ([`3d2a51a`](https://github.com/panates/jsopen-objects/commit/3d2a51adff14d2ac67f3ec0c8760ae167febc4d7))
package/cjs/merge.js CHANGED
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.merge = merge;
4
4
  exports.getMergeFunction = getMergeFunction;
5
5
  const is_object_js_1 = require("./is-object.js");
6
+ const type_guards_js_1 = require("./type-guards.js");
6
7
  function merge(target, source, options) {
7
8
  if (!((0, is_object_js_1.isObject)(target) || typeof target === 'function')) {
8
9
  throw new TypeError('"target" argument must be an object');
@@ -12,7 +13,7 @@ function merge(target, source, options) {
12
13
  throw new TypeError('"target" argument must be an object');
13
14
  }
14
15
  const fn = getMergeFunction(options);
15
- return fn(target, source, '', options, fn, is_object_js_1.isPlainObject, is_object_js_1.isObject, arrayClone);
16
+ return fn(target, source, '', options, fn, type_guards_js_1.isBuiltIn, is_object_js_1.isObject, is_object_js_1.isPlainObject, arrayClone);
16
17
  }
17
18
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
18
19
  const functionCache = new Map();
@@ -31,9 +32,11 @@ function getMergeFunction(options) {
31
32
  ? 'n'
32
33
  : typeof option === 'function'
33
34
  ? 'f'
34
- : option
35
- ? '1'
36
- : '0')
35
+ : typeof option === 'string'
36
+ ? option
37
+ : option
38
+ ? '1'
39
+ : '0')
37
40
  .join();
38
41
  let fn = functionCache.get(cacheKey);
39
42
  if (!fn) {
@@ -49,14 +52,15 @@ function buildMerge(options) {
49
52
  'curPath',
50
53
  'options',
51
54
  'mergeFunction',
52
- 'isPlainObject',
55
+ 'isBuiltIn',
53
56
  'isObject',
57
+ 'isPlainObject',
54
58
  'arrayClone',
55
59
  ];
56
60
  const scriptL0 = [
57
61
  `
58
62
  const _merge = (_trgVal, _srcVal, _curPath) =>
59
- mergeFunction(_trgVal, _srcVal, _curPath, options, mergeFunction, isPlainObject, isObject, arrayClone);
63
+ mergeFunction(_trgVal, _srcVal, _curPath, options, mergeFunction, isBuiltIn, isObject, isPlainObject, arrayClone);
60
64
  const keys = Object.getOwnPropertyNames(source);
61
65
  keys.push(...Object.getOwnPropertySymbols(source));
62
66
  let key;
@@ -66,7 +70,7 @@ let trgVal;
66
70
  `,
67
71
  ];
68
72
  if (options?.deep) {
69
- scriptL0.push(`let subPath;`, `let _isPlain;`, `let _isArray;`);
73
+ scriptL0.push(`let subPath;`, `let _isArray;`);
70
74
  if (typeof options?.deep === 'function') {
71
75
  scriptL0.push(`const deepCallback = options.deep;`);
72
76
  }
@@ -84,6 +88,7 @@ let trgVal;
84
88
  scriptL0.push(`const moveArraysCallback = options.moveArrays;`);
85
89
  }
86
90
  scriptL0.push(`
91
+ if (isPlainObject(target)) Object.setPrototypeOf(target, Object.getPrototypeOf(source));
87
92
  let i = 0;
88
93
  const len = keys.length;
89
94
  for (i = 0; i < len; i++) {
@@ -133,7 +138,7 @@ if (
133
138
  srcVal = source[key];`);
134
139
  }
135
140
  else {
136
- scriptL1For.push(`descriptor = {enumerable: true, configurable: true, writable: true}`, `srcVal = source[key];`);
141
+ scriptL1For.push(`descriptor = {enumerable: true, configurable: true, writable: true}`, `srcVal = source[key];`);
137
142
  }
138
143
  /** ************* keepExisting *****************/
139
144
  if (options?.keepExisting) {
@@ -147,36 +152,35 @@ if (
147
152
  if (options?.ignoreNulls) {
148
153
  scriptL1For.push(`if (srcVal === null) continue;`);
149
154
  }
155
+ const deepArray = !options?.moveArrays || typeof options?.moveArrays === 'function';
150
156
  /** ************* deep *****************/
151
157
  if (options?.deep) {
152
- scriptL1For.push(`
153
- _isPlain = isPlainObject(srcVal);
158
+ const deepCondition = options.deep === 'full'
159
+ ? `typeof srcVal === 'object' && !isBuiltIn(srcVal)`
160
+ : `isPlainObject(srcVal)`;
161
+ if (deepArray) {
162
+ scriptL1For.push(`
154
163
  _isArray = Array.isArray(srcVal);
155
- if (_isPlain || _isArray) {`);
164
+ if (typeof key !== 'symbol' && (_isArray || (${deepCondition}))) {`);
165
+ }
166
+ else {
167
+ scriptL1For.push(`
168
+ if (typeof key !== 'symbol' && ${deepCondition}) {
169
+ subPath = curPath + (curPath ? '.' : '') + key;`);
170
+ }
171
+ scriptL1For.push(`subPath = curPath + (curPath ? '.' : '') + key;`);
156
172
  const scriptL2Deep = [];
157
173
  scriptL1For.push(scriptL2Deep);
158
174
  scriptL1For.push('}');
159
175
  let scriptL3Deep = scriptL2Deep;
160
176
  if (typeof options?.deep === 'function') {
161
177
  scriptL2Deep.push(`
162
- subPath = curPath + (curPath ? '.' : '') + key;
163
178
  if (deepCallback(key, subPath, target, source)) {`);
164
179
  scriptL3Deep = [];
165
180
  scriptL2Deep.push(scriptL3Deep);
166
181
  scriptL2Deep.push('}');
167
182
  }
168
- /** ************* _isPlain *****************/
169
- scriptL3Deep.push(`
170
- if (_isPlain) {
171
- trgVal = target[key];
172
- if (!isObject(trgVal)) {
173
- descriptor.value = trgVal = {};
174
- Object.defineProperty(target, key, descriptor);
175
- }
176
- _merge(trgVal, srcVal, subPath, options);
177
- continue;
178
- }`);
179
- /** ************* moveArrays *****************/
183
+ /** ************* Array *****************/
180
184
  if (!options?.moveArrays || typeof options?.moveArrays === 'function') {
181
185
  scriptL3Deep.push(`if (_isArray) {`);
182
186
  const scriptL4IsArray = [];
@@ -184,7 +188,12 @@ if (_isPlain) {
184
188
  scriptL3Deep.push('}');
185
189
  let scriptL5CloneArrays = scriptL4IsArray;
186
190
  if (typeof options?.moveArrays === 'function') {
187
- scriptL4IsArray.push(`if (!moveArraysCallback(key, subPath, target, source)) {`);
191
+ scriptL4IsArray.push(`
192
+ if (moveArraysCallback(key, subPath, target, source)) {
193
+ descriptor.value = srcVal;
194
+ Object.defineProperty(target, key, descriptor);
195
+ continue;
196
+ } else {`);
188
197
  scriptL5CloneArrays = [];
189
198
  scriptL4IsArray.push(scriptL5CloneArrays);
190
199
  scriptL4IsArray.push('}');
@@ -195,6 +204,15 @@ Object.defineProperty(target, key, descriptor);
195
204
  continue;
196
205
  `);
197
206
  }
207
+ /** ************* object *****************/
208
+ scriptL3Deep.push(`
209
+ trgVal = target[key];
210
+ if (!isObject(trgVal)) {
211
+ descriptor.value = trgVal = {};
212
+ Object.defineProperty(target, key, descriptor);
213
+ }
214
+ _merge(trgVal, srcVal, subPath, options);
215
+ continue;`);
198
216
  }
199
217
  /** ************* finalize *****************/
200
218
  scriptL1For.push(`
@@ -209,7 +227,7 @@ function arrayClone(arr, _merge, curPath) {
209
227
  return arr.map((x) => {
210
228
  if (Array.isArray(x))
211
229
  return arrayClone(x, _merge, curPath);
212
- if ((0, is_object_js_1.isPlainObject)(x))
230
+ if (typeof x === 'object' && !(0, type_guards_js_1.isBuiltIn)(x))
213
231
  return _merge({}, x, curPath);
214
232
  return x;
215
233
  });
package/esm/merge.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { isObject, isPlainObject } from './is-object.js';
2
+ import { isBuiltIn } from './type-guards.js';
2
3
  export function merge(target, source, options) {
3
4
  if (!(isObject(target) || typeof target === 'function')) {
4
5
  throw new TypeError('"target" argument must be an object');
@@ -8,7 +9,7 @@ export function merge(target, source, options) {
8
9
  throw new TypeError('"target" argument must be an object');
9
10
  }
10
11
  const fn = getMergeFunction(options);
11
- return fn(target, source, '', options, fn, isPlainObject, isObject, arrayClone);
12
+ return fn(target, source, '', options, fn, isBuiltIn, isObject, isPlainObject, arrayClone);
12
13
  }
13
14
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
14
15
  const functionCache = new Map();
@@ -27,9 +28,11 @@ export function getMergeFunction(options) {
27
28
  ? 'n'
28
29
  : typeof option === 'function'
29
30
  ? 'f'
30
- : option
31
- ? '1'
32
- : '0')
31
+ : typeof option === 'string'
32
+ ? option
33
+ : option
34
+ ? '1'
35
+ : '0')
33
36
  .join();
34
37
  let fn = functionCache.get(cacheKey);
35
38
  if (!fn) {
@@ -45,14 +48,15 @@ function buildMerge(options) {
45
48
  'curPath',
46
49
  'options',
47
50
  'mergeFunction',
48
- 'isPlainObject',
51
+ 'isBuiltIn',
49
52
  'isObject',
53
+ 'isPlainObject',
50
54
  'arrayClone',
51
55
  ];
52
56
  const scriptL0 = [
53
57
  `
54
58
  const _merge = (_trgVal, _srcVal, _curPath) =>
55
- mergeFunction(_trgVal, _srcVal, _curPath, options, mergeFunction, isPlainObject, isObject, arrayClone);
59
+ mergeFunction(_trgVal, _srcVal, _curPath, options, mergeFunction, isBuiltIn, isObject, isPlainObject, arrayClone);
56
60
  const keys = Object.getOwnPropertyNames(source);
57
61
  keys.push(...Object.getOwnPropertySymbols(source));
58
62
  let key;
@@ -62,7 +66,7 @@ let trgVal;
62
66
  `,
63
67
  ];
64
68
  if (options?.deep) {
65
- scriptL0.push(`let subPath;`, `let _isPlain;`, `let _isArray;`);
69
+ scriptL0.push(`let subPath;`, `let _isArray;`);
66
70
  if (typeof options?.deep === 'function') {
67
71
  scriptL0.push(`const deepCallback = options.deep;`);
68
72
  }
@@ -80,6 +84,7 @@ let trgVal;
80
84
  scriptL0.push(`const moveArraysCallback = options.moveArrays;`);
81
85
  }
82
86
  scriptL0.push(`
87
+ if (isPlainObject(target)) Object.setPrototypeOf(target, Object.getPrototypeOf(source));
83
88
  let i = 0;
84
89
  const len = keys.length;
85
90
  for (i = 0; i < len; i++) {
@@ -129,7 +134,7 @@ if (
129
134
  srcVal = source[key];`);
130
135
  }
131
136
  else {
132
- scriptL1For.push(`descriptor = {enumerable: true, configurable: true, writable: true}`, `srcVal = source[key];`);
137
+ scriptL1For.push(`descriptor = {enumerable: true, configurable: true, writable: true}`, `srcVal = source[key];`);
133
138
  }
134
139
  /** ************* keepExisting *****************/
135
140
  if (options?.keepExisting) {
@@ -143,36 +148,35 @@ if (
143
148
  if (options?.ignoreNulls) {
144
149
  scriptL1For.push(`if (srcVal === null) continue;`);
145
150
  }
151
+ const deepArray = !options?.moveArrays || typeof options?.moveArrays === 'function';
146
152
  /** ************* deep *****************/
147
153
  if (options?.deep) {
148
- scriptL1For.push(`
149
- _isPlain = isPlainObject(srcVal);
154
+ const deepCondition = options.deep === 'full'
155
+ ? `typeof srcVal === 'object' && !isBuiltIn(srcVal)`
156
+ : `isPlainObject(srcVal)`;
157
+ if (deepArray) {
158
+ scriptL1For.push(`
150
159
  _isArray = Array.isArray(srcVal);
151
- if (_isPlain || _isArray) {`);
160
+ if (typeof key !== 'symbol' && (_isArray || (${deepCondition}))) {`);
161
+ }
162
+ else {
163
+ scriptL1For.push(`
164
+ if (typeof key !== 'symbol' && ${deepCondition}) {
165
+ subPath = curPath + (curPath ? '.' : '') + key;`);
166
+ }
167
+ scriptL1For.push(`subPath = curPath + (curPath ? '.' : '') + key;`);
152
168
  const scriptL2Deep = [];
153
169
  scriptL1For.push(scriptL2Deep);
154
170
  scriptL1For.push('}');
155
171
  let scriptL3Deep = scriptL2Deep;
156
172
  if (typeof options?.deep === 'function') {
157
173
  scriptL2Deep.push(`
158
- subPath = curPath + (curPath ? '.' : '') + key;
159
174
  if (deepCallback(key, subPath, target, source)) {`);
160
175
  scriptL3Deep = [];
161
176
  scriptL2Deep.push(scriptL3Deep);
162
177
  scriptL2Deep.push('}');
163
178
  }
164
- /** ************* _isPlain *****************/
165
- scriptL3Deep.push(`
166
- if (_isPlain) {
167
- trgVal = target[key];
168
- if (!isObject(trgVal)) {
169
- descriptor.value = trgVal = {};
170
- Object.defineProperty(target, key, descriptor);
171
- }
172
- _merge(trgVal, srcVal, subPath, options);
173
- continue;
174
- }`);
175
- /** ************* moveArrays *****************/
179
+ /** ************* Array *****************/
176
180
  if (!options?.moveArrays || typeof options?.moveArrays === 'function') {
177
181
  scriptL3Deep.push(`if (_isArray) {`);
178
182
  const scriptL4IsArray = [];
@@ -180,7 +184,12 @@ if (_isPlain) {
180
184
  scriptL3Deep.push('}');
181
185
  let scriptL5CloneArrays = scriptL4IsArray;
182
186
  if (typeof options?.moveArrays === 'function') {
183
- scriptL4IsArray.push(`if (!moveArraysCallback(key, subPath, target, source)) {`);
187
+ scriptL4IsArray.push(`
188
+ if (moveArraysCallback(key, subPath, target, source)) {
189
+ descriptor.value = srcVal;
190
+ Object.defineProperty(target, key, descriptor);
191
+ continue;
192
+ } else {`);
184
193
  scriptL5CloneArrays = [];
185
194
  scriptL4IsArray.push(scriptL5CloneArrays);
186
195
  scriptL4IsArray.push('}');
@@ -191,6 +200,15 @@ Object.defineProperty(target, key, descriptor);
191
200
  continue;
192
201
  `);
193
202
  }
203
+ /** ************* object *****************/
204
+ scriptL3Deep.push(`
205
+ trgVal = target[key];
206
+ if (!isObject(trgVal)) {
207
+ descriptor.value = trgVal = {};
208
+ Object.defineProperty(target, key, descriptor);
209
+ }
210
+ _merge(trgVal, srcVal, subPath, options);
211
+ continue;`);
194
212
  }
195
213
  /** ************* finalize *****************/
196
214
  scriptL1For.push(`
@@ -205,7 +223,7 @@ function arrayClone(arr, _merge, curPath) {
205
223
  return arr.map((x) => {
206
224
  if (Array.isArray(x))
207
225
  return arrayClone(x, _merge, curPath);
208
- if (isPlainObject(x))
226
+ if (typeof x === 'object' && !isBuiltIn(x))
209
227
  return _merge({}, x, curPath);
210
228
  return x;
211
229
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jsopen/objects",
3
3
  "description": "Helper utilities for working with JavaScript objects and arrays",
4
- "version": "1.2.0",
4
+ "version": "1.4.0",
5
5
  "author": "Panates",
6
6
  "license": "MIT",
7
7
  "dependencies": {
package/types/merge.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export declare namespace merge {
2
2
  type NodeCallback = (key: string | symbol, source: any, target: any, path: string) => boolean;
3
3
  interface Options {
4
- deep?: boolean | NodeCallback;
4
+ deep?: boolean | 'full' | NodeCallback;
5
5
  /**
6
6
  */
7
7
  moveArrays?: boolean | NodeCallback;