@jsopen/objects 1.3.0 → 1.4.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 CHANGED
@@ -1,6 +1,6 @@
1
- # v1.3.0
2
- [2024-11-22]
1
+ # v1.4.1
2
+ [2024-11-23]
3
3
 
4
4
  ### Changes
5
5
 
6
- * feat: Added ability to merge non plain objects ([`3d32279`](https://github.com/panates/jsopen-objects/commit/3d3227998dbd8b345c24f4d7a0d9ab9bc3cd7b52))
6
+ * refactor: Optimized generated merge script ([`600e29d`](https://github.com/panates/jsopen-objects/commit/600e29db05ed0d6712d8f9623d632537efe756c4))
package/cjs/merge.js CHANGED
@@ -13,7 +13,7 @@ function merge(target, source, options) {
13
13
  throw new TypeError('"target" argument must be an object');
14
14
  }
15
15
  const fn = getMergeFunction(options);
16
- return fn(target, source, '', options, fn, type_guards_js_1.isBuiltIn, is_object_js_1.isObject, is_object_js_1.isPlainObject, arrayClone);
16
+ return fn(target, source, '', options, fn, is_object_js_1.isObject, is_object_js_1.isPlainObject, arrayClone);
17
17
  }
18
18
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
19
19
  const functionCache = new Map();
@@ -32,9 +32,11 @@ function getMergeFunction(options) {
32
32
  ? 'n'
33
33
  : typeof option === 'function'
34
34
  ? 'f'
35
- : option
36
- ? '1'
37
- : '0')
35
+ : typeof option === 'string'
36
+ ? option
37
+ : option
38
+ ? '1'
39
+ : '0')
38
40
  .join();
39
41
  let fn = functionCache.get(cacheKey);
40
42
  if (!fn) {
@@ -44,21 +46,10 @@ function getMergeFunction(options) {
44
46
  return fn;
45
47
  }
46
48
  function buildMerge(options) {
47
- const args = [
48
- 'target',
49
- 'source',
50
- 'curPath',
51
- 'options',
52
- 'mergeFunction',
53
- 'isBuiltIn',
54
- 'isObject',
55
- 'isPlainObject',
56
- 'arrayClone',
57
- ];
58
49
  const scriptL0 = [
59
50
  `
60
- const _merge = (_trgVal, _srcVal, _curPath) =>
61
- mergeFunction(_trgVal, _srcVal, _curPath, options, mergeFunction, isBuiltIn, isObject, isPlainObject, arrayClone);
51
+ const { options, merge, isObject, isPlainObject, deepTest, arrayClone } = context;
52
+ const hasOwnProperty = Object.prototype.hasOwnProperty;
62
53
  const keys = Object.getOwnPropertyNames(source);
63
54
  keys.push(...Object.getOwnPropertySymbols(source));
64
55
  let key;
@@ -67,7 +58,19 @@ let srcVal;
67
58
  let trgVal;
68
59
  `,
69
60
  ];
61
+ // noinspection JSUnusedGlobalSymbols
62
+ const context = {
63
+ options,
64
+ deepTest: is_object_js_1.isPlainObject,
65
+ isPlainObject: is_object_js_1.isPlainObject,
66
+ isObject: is_object_js_1.isObject,
67
+ arrayClone,
68
+ merge: null,
69
+ };
70
70
  if (options?.deep) {
71
+ if (options.deep === 'full') {
72
+ context.deepTest = v => typeof v === 'object' && !(0, type_guards_js_1.isBuiltIn)(v);
73
+ }
71
74
  scriptL0.push(`let subPath;`, `let _isArray;`);
72
75
  if (typeof options?.deep === 'function') {
73
76
  scriptL0.push(`const deepCallback = options.deep;`);
@@ -109,14 +112,11 @@ if (!filterCallback(key, source, target, curPath)) {
109
112
  if (typeof options?.ignore === 'function') {
110
113
  scriptL1For.push(`
111
114
  if (
112
- Object.prototype.hasOwnProperty.call(target, key) &&
115
+ hasOwnProperty.call(target, key) &&
113
116
  ignoreCallback(key, source, target, curPath)
114
117
  ) continue;
115
118
  `);
116
119
  }
117
- // scriptL1For.push(
118
- // `descriptor = { ...Object.getOwnPropertyDescriptor(source, key) };`,
119
- // );
120
120
  /** ************* copyDescriptors *****************/
121
121
  if (options?.copyDescriptors) {
122
122
  let scriptL2Descriptors = scriptL1For;
@@ -156,11 +156,11 @@ if (
156
156
  if (deepArray) {
157
157
  scriptL1For.push(`
158
158
  _isArray = Array.isArray(srcVal);
159
- if (_isArray || (typeof srcVal === 'object' && !isBuiltIn(srcVal))) {`);
159
+ if (typeof key !== 'symbol' && (_isArray || deepTest(srcVal))) {`);
160
160
  }
161
161
  else {
162
162
  scriptL1For.push(`
163
- if (typeof srcVal === 'object' && !isBuiltIn(srcVal)) {
163
+ if (typeof key !== 'symbol' && deepTest(srcVal)) {
164
164
  subPath = curPath + (curPath ? '.' : '') + key;`);
165
165
  }
166
166
  scriptL1For.push(`subPath = curPath + (curPath ? '.' : '') + key;`);
@@ -194,7 +194,7 @@ if (moveArraysCallback(key, subPath, target, source)) {
194
194
  scriptL4IsArray.push('}');
195
195
  }
196
196
  scriptL5CloneArrays.push(`
197
- descriptor.value = arrayClone(srcVal, _merge, subPath);
197
+ descriptor.value = arrayClone(srcVal, merge, subPath);
198
198
  Object.defineProperty(target, key, descriptor);
199
199
  continue;
200
200
  `);
@@ -206,7 +206,7 @@ if (!isObject(trgVal)) {
206
206
  descriptor.value = trgVal = {};
207
207
  Object.defineProperty(target, key, descriptor);
208
208
  }
209
- _merge(trgVal, srcVal, subPath, options);
209
+ merge(trgVal, srcVal, subPath, options);
210
210
  continue;`);
211
211
  }
212
212
  /** ************* finalize *****************/
@@ -216,7 +216,9 @@ Object.defineProperty(target, key, descriptor);`);
216
216
  scriptL0.push('return target;');
217
217
  const script = _flattenText(scriptL0);
218
218
  // eslint-disable-next-line @typescript-eslint/no-implied-eval,prefer-const
219
- return Function(...args, script);
219
+ const fn = Function('target', 'source', 'curPath', 'context', script);
220
+ context.merge = (target, source, curPath) => fn(target, source, curPath, context);
221
+ return context.merge;
220
222
  }
221
223
  function arrayClone(arr, _merge, curPath) {
222
224
  return arr.map((x) => {
package/esm/merge.js CHANGED
@@ -9,7 +9,7 @@ export function merge(target, source, options) {
9
9
  throw new TypeError('"target" argument must be an object');
10
10
  }
11
11
  const fn = getMergeFunction(options);
12
- return fn(target, source, '', options, fn, isBuiltIn, isObject, isPlainObject, arrayClone);
12
+ return fn(target, source, '', options, fn, isObject, isPlainObject, arrayClone);
13
13
  }
14
14
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
15
15
  const functionCache = new Map();
@@ -28,9 +28,11 @@ export function getMergeFunction(options) {
28
28
  ? 'n'
29
29
  : typeof option === 'function'
30
30
  ? 'f'
31
- : option
32
- ? '1'
33
- : '0')
31
+ : typeof option === 'string'
32
+ ? option
33
+ : option
34
+ ? '1'
35
+ : '0')
34
36
  .join();
35
37
  let fn = functionCache.get(cacheKey);
36
38
  if (!fn) {
@@ -40,21 +42,10 @@ export function getMergeFunction(options) {
40
42
  return fn;
41
43
  }
42
44
  function buildMerge(options) {
43
- const args = [
44
- 'target',
45
- 'source',
46
- 'curPath',
47
- 'options',
48
- 'mergeFunction',
49
- 'isBuiltIn',
50
- 'isObject',
51
- 'isPlainObject',
52
- 'arrayClone',
53
- ];
54
45
  const scriptL0 = [
55
46
  `
56
- const _merge = (_trgVal, _srcVal, _curPath) =>
57
- mergeFunction(_trgVal, _srcVal, _curPath, options, mergeFunction, isBuiltIn, isObject, isPlainObject, arrayClone);
47
+ const { options, merge, isObject, isPlainObject, deepTest, arrayClone } = context;
48
+ const hasOwnProperty = Object.prototype.hasOwnProperty;
58
49
  const keys = Object.getOwnPropertyNames(source);
59
50
  keys.push(...Object.getOwnPropertySymbols(source));
60
51
  let key;
@@ -63,7 +54,19 @@ let srcVal;
63
54
  let trgVal;
64
55
  `,
65
56
  ];
57
+ // noinspection JSUnusedGlobalSymbols
58
+ const context = {
59
+ options,
60
+ deepTest: isPlainObject,
61
+ isPlainObject,
62
+ isObject,
63
+ arrayClone,
64
+ merge: null,
65
+ };
66
66
  if (options?.deep) {
67
+ if (options.deep === 'full') {
68
+ context.deepTest = v => typeof v === 'object' && !isBuiltIn(v);
69
+ }
67
70
  scriptL0.push(`let subPath;`, `let _isArray;`);
68
71
  if (typeof options?.deep === 'function') {
69
72
  scriptL0.push(`const deepCallback = options.deep;`);
@@ -105,14 +108,11 @@ if (!filterCallback(key, source, target, curPath)) {
105
108
  if (typeof options?.ignore === 'function') {
106
109
  scriptL1For.push(`
107
110
  if (
108
- Object.prototype.hasOwnProperty.call(target, key) &&
111
+ hasOwnProperty.call(target, key) &&
109
112
  ignoreCallback(key, source, target, curPath)
110
113
  ) continue;
111
114
  `);
112
115
  }
113
- // scriptL1For.push(
114
- // `descriptor = { ...Object.getOwnPropertyDescriptor(source, key) };`,
115
- // );
116
116
  /** ************* copyDescriptors *****************/
117
117
  if (options?.copyDescriptors) {
118
118
  let scriptL2Descriptors = scriptL1For;
@@ -152,11 +152,11 @@ if (
152
152
  if (deepArray) {
153
153
  scriptL1For.push(`
154
154
  _isArray = Array.isArray(srcVal);
155
- if (_isArray || (typeof srcVal === 'object' && !isBuiltIn(srcVal))) {`);
155
+ if (typeof key !== 'symbol' && (_isArray || deepTest(srcVal))) {`);
156
156
  }
157
157
  else {
158
158
  scriptL1For.push(`
159
- if (typeof srcVal === 'object' && !isBuiltIn(srcVal)) {
159
+ if (typeof key !== 'symbol' && deepTest(srcVal)) {
160
160
  subPath = curPath + (curPath ? '.' : '') + key;`);
161
161
  }
162
162
  scriptL1For.push(`subPath = curPath + (curPath ? '.' : '') + key;`);
@@ -190,7 +190,7 @@ if (moveArraysCallback(key, subPath, target, source)) {
190
190
  scriptL4IsArray.push('}');
191
191
  }
192
192
  scriptL5CloneArrays.push(`
193
- descriptor.value = arrayClone(srcVal, _merge, subPath);
193
+ descriptor.value = arrayClone(srcVal, merge, subPath);
194
194
  Object.defineProperty(target, key, descriptor);
195
195
  continue;
196
196
  `);
@@ -202,7 +202,7 @@ if (!isObject(trgVal)) {
202
202
  descriptor.value = trgVal = {};
203
203
  Object.defineProperty(target, key, descriptor);
204
204
  }
205
- _merge(trgVal, srcVal, subPath, options);
205
+ merge(trgVal, srcVal, subPath, options);
206
206
  continue;`);
207
207
  }
208
208
  /** ************* finalize *****************/
@@ -212,7 +212,9 @@ Object.defineProperty(target, key, descriptor);`);
212
212
  scriptL0.push('return target;');
213
213
  const script = _flattenText(scriptL0);
214
214
  // eslint-disable-next-line @typescript-eslint/no-implied-eval,prefer-const
215
- return Function(...args, script);
215
+ const fn = Function('target', 'source', 'curPath', 'context', script);
216
+ context.merge = (target, source, curPath) => fn(target, source, curPath, context);
217
+ return context.merge;
216
218
  }
217
219
  function arrayClone(arr, _merge, curPath) {
218
220
  return arr.map((x) => {
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.3.0",
4
+ "version": "1.4.1",
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;