merge-deeper-object 0.2.0 → 1.0.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/README.md CHANGED
@@ -1,32 +1,82 @@
1
1
  ## merge-deeper-object
2
- Combine the attributes of objects deeply.
3
2
 
4
- ## Install
3
+ A lightweight, zero-dependency utility for deep merging objects
4
+
5
+ ## Features
6
+
7
+ - **Deep merge object:** recursively merges nested objects
8
+ - **Array concatenation:** arrays are combined, not overwritten
9
+ - **Immutable:** returns a new object, never mutates the originals
10
+ - **Symbol support:** handles Symbol keys alongside string keys
11
+ - **Secure:** blocks prototype pollution
12
+ - **Dual format:** ships both CJS and ESM builds
13
+ - **Zero dependencies**
14
+
15
+ ## Installation
16
+
5
17
  ```
6
- npm install --save merge-deeper-object
18
+ npm install merge-deeper-object
7
19
  ```
8
20
 
9
- ## Running tests
10
21
  ```
11
- npm install
12
- npm run test
22
+ yarn add merge-deeper-object
23
+ ```
24
+
25
+ ```
26
+ pnpm add merge-deeper-object
13
27
  ```
14
28
 
15
29
  ## Usage
30
+
31
+ ### ESM
32
+
16
33
  ```javascript
17
- var mergeDeeper = require('merge-deeper-object')
34
+ import mergeDeeper from 'merge-deeper-object';
18
35
 
19
- var obj1 = { a: { b: { c: 1 } }, d: "d", e: { f: true } }
20
- var obj2 = { a: { g: "g" }, d: "dd", e: { f: false } }
36
+ const base = {
37
+ server: { port: 3000, host: 'localhost' },
38
+ features: ['auth']
39
+ };
21
40
 
22
- mergeDeeper(obj1, obj2)
41
+ const overrides = {
42
+ server: { port: 8080, ssl: true },
43
+ features: ['logging']
44
+ };
23
45
 
46
+ const config = mergeDeeper(base, overrides);
47
+ // {
48
+ // server: { port: 8080, host: 'localhost', ssl: true },
49
+ // features: ['auth', 'logging']
50
+ // }
51
+ ```
52
+
53
+ ### CJS
54
+
55
+ ```javascript
56
+ const mergeDeeper = require('merge-deeper-object');
24
57
 
25
- > { a: { b: { c: 1 }, g: "g" }, d: "dd", e: { f: false } }
58
+ const result = mergeDeeper({ a: 1 }, { b: 2 });
59
+ // { a: 1, b: 2 }
26
60
  ```
27
61
 
28
- ## Author
29
- [Ilyass Mabrouk](https://github.com/work-state)
62
+ ## Testing
63
+
64
+ ```
65
+ git clone git@github.com:work-state/merge-deeper-object.git
66
+ cd merge-deeper-object
67
+ npm install
68
+ npm test
69
+ ```
70
+
71
+ ## Compatibility
72
+
73
+ - **Node.js** >= 14
74
+ - **Browsers:** all modern browsers (ES2015+). If you need to support older browsers, configure yout bundler (Babel, SWC) to transpile `node_modules/merge-deeper-object`
30
75
 
31
76
  ## License
77
+
32
78
  [MIT](https://github.com/work-state/merge-deeper-object/blob/master/LICENSE.md)
79
+
80
+ ## Author
81
+
82
+ [Ilyass Mabrouk](https://github.com/work-state)
package/dist/index.cjs ADDED
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+
3
+ const UNSAFE_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
4
+
5
+ function isSafe(key) {
6
+ return typeof key === 'symbol' || !UNSAFE_KEYS.has(key);
7
+ }
8
+
9
+ function isPlainObject(value) {
10
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
11
+ }
12
+
13
+ function mergeDeeper(target, source) {
14
+ if (!isPlainObject(source)) return target;
15
+
16
+ const result = { ...target };
17
+
18
+ for (const key of [
19
+ ...Object.keys(source),
20
+ ...Object.getOwnPropertySymbols(source)
21
+ ]) {
22
+ if (!isSafe(key)) continue;
23
+
24
+ const srcVal = source[key];
25
+ const targetVal = result[key];
26
+
27
+ if (Array.isArray(srcVal) && Array.isArray(targetVal)) {
28
+ result[key] = [...targetVal, ...srcVal];
29
+ } else if (isPlainObject(srcVal) && isPlainObject(targetVal)) {
30
+ result[key] = mergeDeeper(targetVal, srcVal);
31
+ } else {
32
+ result[key] = srcVal;
33
+ }
34
+ }
35
+
36
+ return result;
37
+ }
38
+
39
+ module.exports = mergeDeeper;
package/dist/index.mjs ADDED
@@ -0,0 +1,37 @@
1
+ const UNSAFE_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
2
+
3
+ function isSafe(key) {
4
+ return typeof key === 'symbol' || !UNSAFE_KEYS.has(key);
5
+ }
6
+
7
+ function isPlainObject(value) {
8
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
9
+ }
10
+
11
+ function mergeDeeper(target, source) {
12
+ if (!isPlainObject(source)) return target;
13
+
14
+ const result = { ...target };
15
+
16
+ for (const key of [
17
+ ...Object.keys(source),
18
+ ...Object.getOwnPropertySymbols(source)
19
+ ]) {
20
+ if (!isSafe(key)) continue;
21
+
22
+ const srcVal = source[key];
23
+ const targetVal = result[key];
24
+
25
+ if (Array.isArray(srcVal) && Array.isArray(targetVal)) {
26
+ result[key] = [...targetVal, ...srcVal];
27
+ } else if (isPlainObject(srcVal) && isPlainObject(targetVal)) {
28
+ result[key] = mergeDeeper(targetVal, srcVal);
29
+ } else {
30
+ result[key] = srcVal;
31
+ }
32
+ }
33
+
34
+ return result;
35
+ }
36
+
37
+ export { mergeDeeper as default };
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
- "version": "0.2.0",
2
+ "version": "1.0.0",
3
3
  "author": "Ilyass Mabrouk",
4
4
  "license": "MIT",
5
5
  "name": "merge-deeper-object",
6
- "description": "Deep merge properties of objects.",
6
+ "description": "Deep merge utility for nested objects.",
7
7
  "homepage": "https://github.com/work-state/merge-deeper-object",
8
8
  "repository": {
9
9
  "type": "git",
@@ -12,14 +12,19 @@
12
12
  "bugs": {
13
13
  "url": "https://github.com/work-state/merge-deeper-object/issues"
14
14
  },
15
- "main": "index.js",
16
- "files": [
17
- "index.d.ts",
18
- "index.js"
19
- ],
20
- "types": "index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "import": "./dist/index.mjs",
18
+ "require": "./dist/index.cjs"
19
+ }
20
+ },
21
+ "main": "dist/index.cjs",
22
+ "module": "dist/index.mjs",
23
+ "files": ["dist"],
21
24
  "scripts": {
22
- "test": "mocha"
25
+ "test": "vitest run",
26
+ "build": "rollup -c",
27
+ "prepublishOnly": "npm run build && npm run test"
23
28
  },
24
29
  "keywords": [
25
30
  "object",
@@ -37,7 +42,8 @@
37
42
  "properties",
38
43
  "property",
39
44
  "entries",
40
- "entry"
45
+ "entry",
46
+ "recursive"
41
47
  ],
42
48
  "verb": {
43
49
  "tasks": [
@@ -51,10 +57,10 @@
51
57
  }
52
58
  },
53
59
  "devDependencies": {
54
- "chai": "^4.3.7",
55
- "mocha": "^10.2.0"
60
+ "rollup": "^4.59.0",
61
+ "vitest": "^4.1.0"
56
62
  },
57
- "directories": {
58
- "test": "test"
63
+ "engines": {
64
+ "node": ">=14"
59
65
  }
60
66
  }
package/index.d.ts DELETED
@@ -1,2 +0,0 @@
1
- declare function _exports(object: Record<any, any>, merge: Record<any, any>): Record<any, any>;
2
- export = _exports;
package/index.js DELETED
@@ -1,18 +0,0 @@
1
- module.exports = function mergeDeeper(object, merge) {
2
- if (!merge || typeof merge === "string") merge = {};
3
- [...Object.keys(merge), ...Object.getOwnPropertySymbols(merge)].map((key) => {
4
- if (Array.isArray(merge[key]) && Array.isArray(object[key])) {
5
- object[key] = [...object[key], ...merge[key]];
6
- } else {
7
- if (
8
- key in object &&
9
- (typeof merge[key] && typeof object[key]) === "object"
10
- ) {
11
- mergeDeeper(object[key], merge[key]);
12
- } else {
13
- object[key] = merge[key];
14
- }
15
- }
16
- });
17
- return object;
18
- };