@cleverbrush/deep 4.4.2 → 4.5.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 +57 -3
- package/dist/data.d.ts +3 -0
- package/dist/deepClone.d.ts +9 -0
- package/dist/deepEqual.d.ts +5 -12
- package/dist/deepExtend.d.ts +9 -3
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|

|
|
7
7
|
<!-- coverage-badge-end -->
|
|
8
8
|
|
|
9
|
-
A library for deep operations on JavaScript objects —
|
|
9
|
+
A library for deep operations on JavaScript objects — cloning, equality, merging, and flattening.
|
|
10
10
|
|
|
11
11
|
## Installation
|
|
12
12
|
|
|
@@ -17,14 +17,55 @@ npm install @cleverbrush/deep
|
|
|
17
17
|
## Usage
|
|
18
18
|
|
|
19
19
|
```typescript
|
|
20
|
-
import { deepEqual, deepExtend, deepFlatten } from '@cleverbrush/deep';
|
|
20
|
+
import { deepClone, deepEqual, deepExtend, deepFlatten } from '@cleverbrush/deep';
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
## API
|
|
24
24
|
|
|
25
|
+
### `deepClone<T>(value: T): T`
|
|
26
|
+
|
|
27
|
+
Creates an isolated copy of plain data while preserving its TypeScript type.
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { deepClone } from '@cleverbrush/deep';
|
|
31
|
+
|
|
32
|
+
const input = { tags: ['a'], savedAt: new Date(1) };
|
|
33
|
+
const snapshot = deepClone(input);
|
|
34
|
+
input.tags.push('b');
|
|
35
|
+
input.savedAt.setTime(2);
|
|
36
|
+
// snapshot is still { tags: ['a'], savedAt: new Date(1) }
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
| Value | `deepClone` | `deepEqual` |
|
|
40
|
+
| --- | --- | --- |
|
|
41
|
+
| Primitives, functions | Returned unchanged | `Object.is` |
|
|
42
|
+
| Plain objects (including null prototypes) | Recursively cloned; prototype preserved | Enumerable own properties compared structurally; null and ordinary prototypes may compare equal |
|
|
43
|
+
| Arrays | Recursively cloned; length and holes preserved | Length, holes, elements and enumerable extra properties compared |
|
|
44
|
+
| Dates | Cloned by timestamp, including invalid dates | Timestamps compared with `Object.is`; two invalid dates compare equal |
|
|
45
|
+
| Files, Maps, Sets, typed arrays, custom instances and other objects | Returned by reference | Identity only |
|
|
46
|
+
|
|
47
|
+
Cloning preserves cycles and repeated references, including shared Dates. Own
|
|
48
|
+
enumerable string and symbol properties are copied as writable data properties.
|
|
49
|
+
Getters are read once per copied property; accessor descriptors, non-enumerable
|
|
50
|
+
properties and frozen/sealed state are not preserved. Date timestamps and array
|
|
51
|
+
length are copied explicitly. Special keys such as `__proto__` are defined as own
|
|
52
|
+
properties without invoking inherited setters. This is a data snapshot utility,
|
|
53
|
+
not a clone of arbitrary object internals or a replacement for serialization.
|
|
54
|
+
|
|
25
55
|
### `deepEqual(a, b, options?)`
|
|
26
56
|
|
|
27
|
-
Recursively compares
|
|
57
|
+
Recursively compares supported data values according to the table above. It handles
|
|
58
|
+
nulls and cycles, and does not require identical reference-sharing topology: one
|
|
59
|
+
shared child can compare equal to two separate, structurally equal children. Object
|
|
60
|
+
key order does not matter; symbol keys participate by identity. Dates compare only
|
|
61
|
+
their timestamps, not extra properties. Other opaque objects are never traversed.
|
|
62
|
+
|
|
63
|
+
Primitives follow `Object.is`: `NaN` equals `NaN`, but `0` differs from `-0`.
|
|
64
|
+
Array holes differ from explicit `undefined`. With `disregardArrayOrder`, each
|
|
65
|
+
element must match one unused element on the other side, preserving duplicate and
|
|
66
|
+
hole counts. Named/symbol array properties still compare by key. Inputs are not
|
|
67
|
+
sorted or mutated, and hash collisions cannot decide equality. Unordered matching
|
|
68
|
+
can require quadratic comparisons; prefer ordered equality for large arrays.
|
|
28
69
|
|
|
29
70
|
**Parameters:**
|
|
30
71
|
|
|
@@ -49,8 +90,21 @@ deepEqual({ a: { b: 1, c: 2 } }, { a: { b: 1 } });
|
|
|
49
90
|
// Array order can be ignored
|
|
50
91
|
deepEqual([1, 2, 3], [3, 1, 2], { disregardArrayOrder: true });
|
|
51
92
|
// => true
|
|
93
|
+
|
|
94
|
+
deepEqual([1, 1, 2], [1, 2, 2], { disregardArrayOrder: true });
|
|
95
|
+
// => false (duplicate counts differ)
|
|
96
|
+
|
|
97
|
+
deepEqual(new Map(), new Map());
|
|
98
|
+
// => false (opaque objects compare by identity)
|
|
52
99
|
```
|
|
53
100
|
|
|
101
|
+
**Breaking comparison corrections:** previous versions could throw for object/null
|
|
102
|
+
pairs, consider Dates equal to unrelated objects, compare distinct opaque objects
|
|
103
|
+
by enumerable shape, and reject equivalent cycles or repeated references. Signed
|
|
104
|
+
zero, invalid Dates, symbol keys and sparse arrays now follow the rules above.
|
|
105
|
+
Audit consumers relying on those outcomes. To compare Maps/Sets/custom instances
|
|
106
|
+
by content, explicitly project their relevant state into plain data first.
|
|
107
|
+
|
|
54
108
|
### `deepExtend(...objects)`
|
|
55
109
|
|
|
56
110
|
Deeply merges multiple objects. Works like `Object.assign`, but recursively merges nested objects instead of overwriting them. All arguments must be non-null objects.
|
package/dist/data.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copies plain objects, arrays and Dates, preserving cycles, shared references,
|
|
3
|
+
* sparse arrays and null prototypes. Other values (including class instances,
|
|
4
|
+
* Files, Maps and Sets) retain their identity.
|
|
5
|
+
*
|
|
6
|
+
* Enumerable own string/symbol properties are read and copied as writable data
|
|
7
|
+
* properties; accessors, non-enumerable properties and descriptors are not cloned.
|
|
8
|
+
*/
|
|
9
|
+
export declare function deepClone<T>(value: T): T;
|
package/dist/deepEqual.d.ts
CHANGED
|
@@ -1,17 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* @param p1 first object
|
|
7
|
-
* @param p2 second object
|
|
8
|
-
* @param options additional options
|
|
9
|
-
* @returns {boolean} `true` if the objects are equal, `false` otherwise
|
|
2
|
+
* Structurally compares plain objects and arrays (including cycles). Dates
|
|
3
|
+
* compare by timestamp; primitives and opaque objects use Object.is semantics.
|
|
4
|
+
* Only enumerable own string/symbol properties participate in structural
|
|
5
|
+
* comparisons. Shared-reference topology does not affect equality.
|
|
10
6
|
*/
|
|
11
7
|
export declare const deepEqual: (p1: any, p2: any, options?: {
|
|
12
|
-
/**
|
|
13
|
-
* if true, the order of the elements in the array will be disregarded
|
|
14
|
-
* e.g. [1, 2] and [2, 1] will be considered equal
|
|
15
|
-
*/
|
|
8
|
+
/** Ignore array element order, but preserve duplicate and hole counts. */
|
|
16
9
|
disregardArrayOrder?: boolean;
|
|
17
10
|
}) => boolean;
|
package/dist/deepExtend.d.ts
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
type UnsafeMergeKey = '__proto__' | 'constructor' | 'prototype';
|
|
2
2
|
type SafeMergeProps<T> = Omit<T, UnsafeMergeKey>;
|
|
3
3
|
type SafeProp<T, K extends PropertyKey> = K extends keyof SafeMergeProps<T> ? SafeMergeProps<T>[K] : never;
|
|
4
|
+
type DeepSafeMergeValue<T> = T extends readonly unknown[] ? {
|
|
5
|
+
[K in keyof T]: DeepSafeMergeValue<T[K]>;
|
|
6
|
+
} : T extends Record<string, unknown> ? DeepSafeMergeProps<T> : T;
|
|
7
|
+
type DeepSafeMergeProps<T> = {
|
|
8
|
+
[K in keyof SafeMergeProps<T>]: DeepSafeMergeValue<SafeProp<T, K>>;
|
|
9
|
+
};
|
|
4
10
|
/** Properties that exist in both `T1` and `T2`, typed as `T2`'s version. */
|
|
5
11
|
export type CommonProps<T1, T2> = {
|
|
6
12
|
[k in keyof SafeMergeProps<T1> & keyof SafeMergeProps<T2>]: SafeProp<T1, k> extends never ? never : SafeProp<T2, k> extends never ? never : SafeProp<T2, k>;
|
|
7
13
|
};
|
|
8
14
|
/** Properties present in `T1` but not in `T2`. */
|
|
9
|
-
export type PropsInFirstOnly<T1, T2> = Omit<
|
|
15
|
+
export type PropsInFirstOnly<T1, T2> = Omit<DeepSafeMergeProps<T1>, keyof SafeMergeProps<T2>>;
|
|
10
16
|
/** Recursively merges two object types. Matching keys are merged; unique keys are kept. */
|
|
11
17
|
export type MergeTwo<T1, T2> = PropsInFirstOnly<T1, T2> & PropsInFirstOnly<T2, T1> & {
|
|
12
|
-
[k in keyof CommonProps<T1, T2>]: SafeProp<T1, k> extends Record<string, unknown> ? SafeProp<T2, k> extends Record<string, unknown> ? MergeTwo<SafeProp<T1, k>, SafeProp<T2, k>> : SafeProp<T2, k
|
|
18
|
+
[k in keyof CommonProps<T1, T2>]: SafeProp<T1, k> extends Record<string, unknown> ? SafeProp<T2, k> extends Record<string, unknown> ? MergeTwo<SafeProp<T1, k>, SafeProp<T2, k>> : DeepSafeMergeValue<SafeProp<T2, k>> : DeepSafeMergeValue<SafeProp<T2, k>>;
|
|
13
19
|
};
|
|
14
20
|
/** Recursively merges a tuple of object types from left to right. */
|
|
15
|
-
export type Merge<T extends unknown[]> = T['length'] extends 3 ? MergeTwo<T[0], MergeTwo<T[1], T[2]>> : T['length'] extends 2 ? MergeTwo<T[0], T[1]> : T['length'] extends 1 ?
|
|
21
|
+
export type Merge<T extends unknown[]> = T['length'] extends 3 ? MergeTwo<T[0], MergeTwo<T[1], T[2]>> : T['length'] extends 2 ? MergeTwo<T[0], T[1]> : T['length'] extends 1 ? DeepSafeMergeProps<T[0]> : T extends [...infer K, infer PL, infer L] ? Merge<[Merge<[...K]>, MergeTwo<PL, L>]> : never;
|
|
16
22
|
/**
|
|
17
23
|
* Deep-merges multiple objects into one. Later values override earlier ones;
|
|
18
24
|
* nested objects are merged recursively rather than replaced.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
+
import { deepClone } from './deepClone.js';
|
|
1
2
|
import { deepEqual } from './deepEqual.js';
|
|
2
3
|
import { deepExtend, type Merge, type MergeTwo } from './deepExtend.js';
|
|
3
4
|
import { deepFlatten } from './deepFlatten.js';
|
|
4
|
-
export { deepEqual, deepExtend, deepFlatten, type Merge, type MergeTwo };
|
|
5
|
+
export { deepClone, deepEqual, deepExtend, deepFlatten, type Merge, type MergeTwo };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
function g(e){if(e===null||typeof e!="object")return!1;let n=Object.getPrototypeOf(e);return n===null||n===Object.prototype}function T(e){return Reflect.ownKeys(e).filter(n=>Object.prototype.propertyIsEnumerable.call(e,n))}function O(e){let n=new WeakMap;function i(r){if(!Array.isArray(r)&&!(r instanceof Date)&&!g(r))return r;if(n.has(r))return n.get(r);let c=Array.isArray(r)?new Array(r.length):r instanceof Date?new Date(r.getTime()):Object.create(Object.getPrototypeOf(r));n.set(r,c);for(let f of T(r))Object.defineProperty(c,f,{value:i(Reflect.get(r,f)),enumerable:!0,configurable:!0,writable:!0});return c}return i(e)}function b(e){if(typeof e!="string")return!1;let n=Number(e);return Number.isInteger(n)&&n>=0&&n<2**32-1&&String(n)===e}var S=(e,n,i)=>{let r=new WeakMap;function c(o,t,a,p){let l=new Set(p);return a.length===p.length&&a.every(u=>l.has(u)&&s(Reflect.get(o,u),Reflect.get(t,u)))}function f(o,t,a,p){let l=a.filter(b),u=p.filter(b);if(l.length!==u.length||!c(o,t,a.filter(y=>!b(y)),p.filter(y=>!b(y))))return!1;let P=new Set(u);for(let y of l){let M=Reflect.get(o,y),m=Array.from(P).find(j=>s(M,Reflect.get(t,j)));if(m===void 0)return!1;P.delete(m)}return!0}function s(o,t){if(Object.is(o,t))return!0;if(o instanceof Date||t instanceof Date)return o instanceof Date&&t instanceof Date&&Object.is(o.getTime(),t.getTime());if(Array.isArray(o)){if(!Array.isArray(t)||o.length!==t.length)return!1}else if(!g(o)||!g(t))return!1;let a=r.get(o);if(a?.has(t))return!0;a||(a=new Set,r.set(o,a)),a.add(t);try{let p=T(o),l=T(t);return Array.isArray(o)&&i?.disregardArrayOrder?f(o,t,p,l):c(o,t,p,l)}finally{a.delete(t)}}return s(e,n)};var k=((...e)=>{if(e.length===0)throw new Error("no arguments");if(typeof e[0]!="object"||e[0]===null)throw new Error("not a non-null object");let n={},i=(r,c,f)=>{let s=Object.keys(c);for(let o=0;o<s.length;o++){let t=s[o];if(x(t))continue;let a=c[t];if(!w(a)){d(r,t,a);continue}if(f.has(a)){d(r,t,f.get(a));continue}let p=Object.hasOwn(r,t)?r[t]:void 0,l=w(p)?p:A(a);f.set(a,l),i(l,a,f),d(r,t,l)}};for(let r=0;r<e.length;r++){let c=e[r];if(typeof c=="object"&&c!==null){let f=new WeakMap;f.set(c,n),i(n,c,f)}else throw new Error("not a non-null object")}return n});function x(e){return e==="__proto__"||e==="constructor"||e==="prototype"}function w(e){if(typeof e!="object"||e===null)return!1;if(Array.isArray(e))return!0;let n=Object.getPrototypeOf(e);return n===Object.prototype||n===null}function A(e){return Array.isArray(e)?[]:Object.getPrototypeOf(e)===null?Object.create(null):{}}function d(e,n,i){Object.defineProperty(e,n,{configurable:!0,enumerable:!0,value:i,writable:!0})}function h(e,n="."){let i=s=>typeof s=="object"&&s!==null&&!Array.isArray(s)&&Object.getPrototypeOf(s)===Object.prototype;if(!i(e))throw new Error("cannot flatten this object");let r=[],c={},f=(s,o="")=>{if(r.find(t=>t===s))throw new Error("circular reference detected");r.push(s),Object.keys(s).forEach(t=>{if(!i(s[t])){c[o?`${o}${n}${t}`:t]=s[t];return}f(s[t],o?`${o}${n}${t}`:t)}),r.pop()};return f(e),c}export{O as deepClone,S as deepEqual,k as deepExtend,h as deepFlatten};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hashObject.ts","../src/deepEqual.ts","../src/deepExtend.ts","../src/deepFlatten.ts"],"sourcesContent":["const stringHash = (string: string, noType?: boolean) => {\n let hashString = string;\n if (!noType) {\n hashString = `string${string}`;\n }\n let hash = 0;\n for (let i = 0; i < hashString.length; i++) {\n const character = hashString.charCodeAt(i);\n hash = (hash << 5) - hash + character;\n hash = hash & hash; // Convert to 32bit integer\n }\n return hash;\n};\n\nfunction objectHash(\n obj: Record<string, any>,\n exclude: any[]\n): number | undefined {\n if (exclude.indexOf(obj) > -1) {\n return undefined;\n }\n let hash = '';\n const keys = Object.keys(obj).sort();\n for (let index = 0; index < keys.length; index += 1) {\n const key = keys[index];\n const keyHash = hashFunc(key);\n const attrHash = hashFunc(obj[key], exclude);\n exclude.push(obj[key]);\n hash += stringHash(`object${keyHash}${attrHash}`, true);\n }\n return stringHash(hash, true);\n}\n\n/**\n * Computes a 32-bit numeric hash for any value.\n *\n * Objects are hashed by recursively hashing their sorted keys and values;\n * circular references are detected via an internal exclusion list.\n *\n * @param unkType - The value to hash (object, string, number, etc.).\n * @param exclude - Internal array used for circular-reference detection.\n * @returns A 32-bit integer hash code.\n */\nexport function HashObject(unkType: any, exclude?: any[]): number {\n let ex = exclude;\n if (ex === undefined) {\n ex = [];\n }\n // biome-ignore lint/suspicious/noGlobalIsNan: intentional coercion — isNaN returns true for non-numeric types like objects\n if (!isNaN(unkType) && typeof unkType !== 'string') {\n return unkType;\n }\n switch (typeof unkType) {\n case 'object':\n return objectHash(unkType, ex) as number;\n default:\n return stringHash(String(unkType)) as number;\n }\n}\n\nconst hashFunc = HashObject;\n","import { HashObject } from './hashObject.js';\n\nconst isBothNaN = (v1: any, v2: any) => Number.isNaN(v1) && Number.isNaN(v2);\n\n/**\n * Compares two objects and returns true if they\n * have the same structure and values. Can work\n * with arrays and objects, nested objects,\n * recursive objects, dates, etc.\n * @param p1 first object\n * @param p2 second object\n * @param options additional options\n * @returns {boolean} `true` if the objects are equal, `false` otherwise\n */\nexport const deepEqual = (\n p1: any,\n p2: any,\n options?: {\n /**\n * if true, the order of the elements in the array will be disregarded\n * e.g. [1, 2] and [2, 1] will be considered equal\n */\n disregardArrayOrder?: boolean;\n }\n): boolean => {\n const cache = new Map();\n\n const compare = (...args: any[]) => {\n const arraysAreIdentical = (a1: any, a2: any) => {\n if (a1.length !== a2.length) return false;\n if (a1.length === 0 && a2.length === 0) return true;\n\n const c1 = options?.disregardArrayOrder\n ? a1\n .map((t: any) => t)\n .sort((l: any, r: any) => {\n const hash1 = HashObject(l);\n const hash2 = HashObject(r);\n return hash1 < hash2 ? 1 : -1;\n })\n : a1.map((t: any) => t);\n const c2 = options?.disregardArrayOrder\n ? a2\n .map((t: any) => t)\n .sort((l: any, r: any) => {\n const hash1 = HashObject(l);\n const hash2 = HashObject(r);\n return hash1 < hash2 ? 1 : -1;\n })\n : a2.map((t: any) => t);\n\n for (let i = 0; i < c1.length; i++) {\n if (!compare(c1[i], c2[i])) return false;\n }\n return true;\n };\n\n if (args.length !== 2) return false;\n const [o1, o2] = args;\n if (o1 === o2) return true;\n if (typeof o1 !== typeof o2) return false;\n if (isBothNaN(o1, o2)) return true;\n\n if (\n (Array.isArray(o1) && !Array.isArray(o2)) ||\n (!Array.isArray(o1) && Array.isArray(o2))\n ) {\n return false;\n }\n if (Array.isArray(o1) && Array.isArray(o2)) {\n return arraysAreIdentical(o1, o2);\n }\n\n if (typeof o1 === 'object' && o1 !== null) {\n if (cache.get(o1) === true) {\n return false;\n }\n\n cache.set(o1, true);\n\n if (o1 instanceof Date && o2 instanceof Date) {\n return (\n // biome-ignore lint/suspicious/noGlobalIsNan: isNaN coerces Date to number, which is the intended behavior here\n !isNaN(o1 as any) &&\n // biome-ignore lint/suspicious/noGlobalIsNan: isNaN coerces Date to number, which is the intended behavior here\n !isNaN(o2 as any) &&\n o1.getTime() === o2.getTime()\n );\n }\n\n const keys1 = Object.keys(o1);\n const keys2 = Object.keys(o2);\n if (keys1.length !== keys2.length) return false;\n\n keys1.sort();\n keys2.sort();\n for (let i = 0; i < keys1.length; i++) {\n if (keys1[i] !== keys2[i]) {\n return false;\n }\n\n const v1 = o1[keys1[i]];\n const v2 = o2[keys1[i]];\n if (!compare(v1, v2)) return false;\n }\n return true;\n }\n\n return false;\n };\n\n return compare(p1, p2);\n};\n","type UnsafeMergeKey = '__proto__' | 'constructor' | 'prototype';\n\ntype SafeMergeProps<T> = Omit<T, UnsafeMergeKey>;\n\ntype SafeProp<T, K extends PropertyKey> = K extends keyof SafeMergeProps<T>\n ? SafeMergeProps<T>[K]\n : never;\n\n/** Properties that exist in both `T1` and `T2`, typed as `T2`'s version. */\nexport type CommonProps<T1, T2> = {\n [k in keyof SafeMergeProps<T1> & keyof SafeMergeProps<T2>]: SafeProp<\n T1,\n k\n > extends never\n ? never\n : SafeProp<T2, k> extends never\n ? never\n : SafeProp<T2, k>;\n};\n\n/** Properties present in `T1` but not in `T2`. */\nexport type PropsInFirstOnly<T1, T2> = Omit<\n SafeMergeProps<T1>,\n keyof SafeMergeProps<T2>\n>;\n\n/** Recursively merges two object types. Matching keys are merged; unique keys are kept. */\nexport type MergeTwo<T1, T2> = PropsInFirstOnly<T1, T2> &\n PropsInFirstOnly<T2, T1> & {\n [k in keyof CommonProps<T1, T2>]: SafeProp<T1, k> extends Record<\n string,\n unknown\n >\n ? SafeProp<T2, k> extends Record<string, unknown>\n ? MergeTwo<SafeProp<T1, k>, SafeProp<T2, k>>\n : SafeProp<T2, k>\n : SafeProp<T2, k>;\n };\n\n/** Recursively merges a tuple of object types from left to right. */\nexport type Merge<T extends unknown[]> = T['length'] extends 3\n ? MergeTwo<T[0], MergeTwo<T[1], T[2]>>\n : T['length'] extends 2\n ? MergeTwo<T[0], T[1]>\n : T['length'] extends 1\n ? SafeMergeProps<T[0]>\n : T extends [...infer K, infer PL, infer L]\n ? Merge<[Merge<[...K]>, MergeTwo<PL, L>]>\n : never;\n\n/**\n * Deep-merges multiple objects into one. Later values override earlier ones;\n * nested objects are merged recursively rather than replaced.\n * Prototype-polluting keys (`__proto__`, `constructor`, and `prototype`) are\n * ignored.\n *\n * @example\n * ```ts\n * const a = { x: 1, nested: { a: true } };\n * const b = { y: 2, nested: { b: false } };\n * const result = deepExtend(a, b);\n * // { x: 1, y: 2, nested: { a: true, b: false } }\n * ```\n *\n * @param args - Two or more non-null objects to merge.\n * @returns A new object containing the deep-merged result.\n * @throws If no arguments are provided or any argument is not a non-null object.\n */\nexport const deepExtend = ((...rest) => {\n if (rest.length === 0) throw new Error('no arguments');\n if (typeof rest[0] !== 'object' || rest[0] === null)\n throw new Error('not a non-null object');\n\n const result = {};\n\n const extendObject = (o1: any, o2: any) => {\n const keys = Object.keys(o2);\n\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i];\n if (isUnsafeMergeKey(key)) continue;\n\n if (\n !Object.hasOwn(o1, key) ||\n !(\n typeof o1[key] === 'object' &&\n o1[key] !== null &&\n typeof o2[key] === 'object'\n )\n ) {\n o1[key] = o2[key];\n } else {\n if (o1[key] == null || o2[key] == null) {\n o1[key] = o2[key];\n } else {\n extendObject(o1[key], o2[key]);\n }\n }\n }\n };\n\n for (let i = 0; i < rest.length; i++) {\n if (typeof rest[i] === 'object' && rest[i] !== null && rest[i]) {\n extendObject(result, rest[i]);\n } else {\n throw new Error('not a non-null object');\n }\n }\n\n return result;\n}) as <T extends unknown[]>(...args: T) => Merge<T>;\n\nfunction isUnsafeMergeKey(key: string): boolean {\n return key === '__proto__' || key === 'constructor' || key === 'prototype';\n}\n","/**\n * Flattens an object to a single level, with the nested keys separated by a `delimiter`.\n * @example\n * ```ts\n * deepFlatten({ a: { b: 1, c: 2 } });\n * // => { 'a.b': 1, 'a.c': 2 }\n *\n * deepFlatten({ a: { b: 1, c: 2 } }, '/');\n * // => { 'a/b': 1, 'a/c': 2 }\n *\n * deepFlatten({ a: { b: 1, c: { d: 'some val' } }, d: 3 });\n * // => { 'a.b': 1, 'a.c.d': 'some val', d: 3 }\n *\n * ```\n * @param {string} [delimiter]\n */\nexport function deepFlatten(\n obj: Record<string, any>,\n delimiter = '.'\n): Record<string, any> {\n const shouldFlatten = (obj: any) =>\n typeof obj === 'object' &&\n obj !== null &&\n !Array.isArray(obj) &&\n Object.getPrototypeOf(obj) === Object.prototype;\n\n if (!shouldFlatten(obj)) throw new Error('cannot flatten this object');\n\n const stack: any[] = [];\n\n const result: Record<string, any> = {};\n\n const deepFlattenHelper = (obj: any, prefix = '') => {\n if (stack.find(o => o === obj))\n throw new Error('circular reference detected');\n\n stack.push(obj);\n\n Object.keys(obj).forEach(key => {\n if (!shouldFlatten(obj[key])) {\n result[prefix ? `${prefix}${delimiter}${key}` : key] = obj[key];\n return;\n }\n deepFlattenHelper(\n obj[key],\n prefix ? `${prefix}${delimiter}${key}` : key\n );\n });\n\n stack.pop();\n };\n\n deepFlattenHelper(obj);\n\n return result;\n}\n"],"mappings":"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","names":["stringHash","string","noType","hashString","hash","i","character","objectHash","obj","exclude","keys","index","key","keyHash","hashFunc","attrHash","HashObject","unkType","ex","isBothNaN","v1","v2","deepEqual","p1","p2","options","cache","compare","args","arraysAreIdentical","a1","a2","c1","t","l","r","hash1","HashObject","hash2","c2","i","o1","o2","keys1","keys2","deepExtend","rest","result","extendObject","o1","o2","keys","i","key","isUnsafeMergeKey","deepFlatten","obj","delimiter","shouldFlatten","stack","result","deepFlattenHelper","prefix","o","key"]}
|
|
1
|
+
{"version":3,"sources":["../src/data.ts","../src/deepClone.ts","../src/deepEqual.ts","../src/deepExtend.ts","../src/deepFlatten.ts"],"sourcesContent":["/** The structural data types supported by cloning and equality. */\nexport function isPlainObject(value: unknown): value is object {\n if (value === null || typeof value !== 'object') return false;\n const prototype = Object.getPrototypeOf(value);\n return prototype === null || prototype === Object.prototype;\n}\n\nexport function enumerableKeys(value: object): (string | symbol)[] {\n return Reflect.ownKeys(value).filter(key =>\n Object.prototype.propertyIsEnumerable.call(value, key)\n );\n}\n","import { enumerableKeys, isPlainObject } from './data.js';\n\n/**\n * Copies plain objects, arrays and Dates, preserving cycles, shared references,\n * sparse arrays and null prototypes. Other values (including class instances,\n * Files, Maps and Sets) retain their identity.\n *\n * Enumerable own string/symbol properties are read and copied as writable data\n * properties; accessors, non-enumerable properties and descriptors are not cloned.\n */\nexport function deepClone<T>(value: T): T {\n const seen = new WeakMap<object, object>();\n\n function clone(source: any): any {\n if (\n !Array.isArray(source) &&\n !(source instanceof Date) &&\n !isPlainObject(source)\n ) {\n return source;\n }\n if (seen.has(source)) return seen.get(source);\n const result = Array.isArray(source)\n ? new Array(source.length)\n : source instanceof Date\n ? new Date(source.getTime())\n : Object.create(Object.getPrototypeOf(source));\n seen.set(source, result);\n for (const key of enumerableKeys(source)) {\n Object.defineProperty(result, key, {\n value: clone(Reflect.get(source, key)),\n enumerable: true,\n configurable: true,\n writable: true\n });\n }\n return result;\n }\n\n return clone(value);\n}\n","import { enumerableKeys, isPlainObject } from './data.js';\n\nfunction isArrayIndex(key: string | symbol): boolean {\n if (typeof key !== 'string') return false;\n const index = Number(key);\n return (\n Number.isInteger(index) &&\n index >= 0 &&\n index < 2 ** 32 - 1 &&\n String(index) === key\n );\n}\n\n/**\n * Structurally compares plain objects and arrays (including cycles). Dates\n * compare by timestamp; primitives and opaque objects use Object.is semantics.\n * Only enumerable own string/symbol properties participate in structural\n * comparisons. Shared-reference topology does not affect equality.\n */\nexport const deepEqual = (\n p1: any,\n p2: any,\n options?: {\n /** Ignore array element order, but preserve duplicate and hole counts. */\n disregardArrayOrder?: boolean;\n }\n): boolean => {\n // Track pairs on the current recursion path, not all objects ever visited.\n // Removing pairs on return also isolates failed unordered-array candidates.\n const active = new WeakMap<object, Set<object>>();\n\n function compareProperties(\n left: object,\n right: object,\n leftKeys: (string | symbol)[],\n rightKeys: (string | symbol)[]\n ): boolean {\n const rightKeySet = new Set(rightKeys);\n return (\n leftKeys.length === rightKeys.length &&\n leftKeys.every(\n key =>\n rightKeySet.has(key) &&\n compare(Reflect.get(left, key), Reflect.get(right, key))\n )\n );\n }\n\n function compareUnordered(\n left: object,\n right: object,\n leftKeys: (string | symbol)[],\n rightKeys: (string | symbol)[]\n ): boolean {\n const leftIndices = leftKeys.filter(isArrayIndex);\n const rightIndices = rightKeys.filter(isArrayIndex);\n if (leftIndices.length !== rightIndices.length) return false;\n if (\n !compareProperties(\n left,\n right,\n leftKeys.filter(key => !isArrayIndex(key)),\n rightKeys.filter(key => !isArrayIndex(key))\n )\n ) {\n return false;\n }\n\n const unmatched = new Set(rightIndices);\n for (const key of leftIndices) {\n const value = Reflect.get(left, key);\n const match = Array.from(unmatched).find(candidate =>\n compare(value, Reflect.get(right, candidate))\n );\n if (match === undefined) return false;\n unmatched.delete(match);\n }\n return true;\n }\n\n function compare(left: any, right: any): boolean {\n if (Object.is(left, right)) return true;\n if (left instanceof Date || right instanceof Date) {\n return (\n left instanceof Date &&\n right instanceof Date &&\n Object.is(left.getTime(), right.getTime())\n );\n }\n if (Array.isArray(left)) {\n if (!Array.isArray(right) || left.length !== right.length) {\n return false;\n }\n } else if (!isPlainObject(left) || !isPlainObject(right)) {\n return false;\n }\n\n let partners = active.get(left);\n if (partners?.has(right)) return true;\n if (!partners) {\n partners = new Set();\n active.set(left, partners);\n }\n partners.add(right);\n try {\n const leftKeys = enumerableKeys(left);\n const rightKeys = enumerableKeys(right);\n return Array.isArray(left) && options?.disregardArrayOrder\n ? compareUnordered(left, right, leftKeys, rightKeys)\n : compareProperties(left, right, leftKeys, rightKeys);\n } finally {\n partners.delete(right);\n }\n }\n\n return compare(p1, p2);\n};\n","type UnsafeMergeKey = '__proto__' | 'constructor' | 'prototype';\n\ntype SafeMergeProps<T> = Omit<T, UnsafeMergeKey>;\n\ntype SafeProp<T, K extends PropertyKey> = K extends keyof SafeMergeProps<T>\n ? SafeMergeProps<T>[K]\n : never;\n\ntype DeepSafeMergeValue<T> = T extends readonly unknown[]\n ? { [K in keyof T]: DeepSafeMergeValue<T[K]> }\n : T extends Record<string, unknown>\n ? DeepSafeMergeProps<T>\n : T;\n\ntype DeepSafeMergeProps<T> = {\n [K in keyof SafeMergeProps<T>]: DeepSafeMergeValue<SafeProp<T, K>>;\n};\n\n/** Properties that exist in both `T1` and `T2`, typed as `T2`'s version. */\nexport type CommonProps<T1, T2> = {\n [k in keyof SafeMergeProps<T1> & keyof SafeMergeProps<T2>]: SafeProp<\n T1,\n k\n > extends never\n ? never\n : SafeProp<T2, k> extends never\n ? never\n : SafeProp<T2, k>;\n};\n\n/** Properties present in `T1` but not in `T2`. */\nexport type PropsInFirstOnly<T1, T2> = Omit<\n DeepSafeMergeProps<T1>,\n keyof SafeMergeProps<T2>\n>;\n\n/** Recursively merges two object types. Matching keys are merged; unique keys are kept. */\nexport type MergeTwo<T1, T2> = PropsInFirstOnly<T1, T2> &\n PropsInFirstOnly<T2, T1> & {\n [k in keyof CommonProps<T1, T2>]: SafeProp<T1, k> extends Record<\n string,\n unknown\n >\n ? SafeProp<T2, k> extends Record<string, unknown>\n ? MergeTwo<SafeProp<T1, k>, SafeProp<T2, k>>\n : DeepSafeMergeValue<SafeProp<T2, k>>\n : DeepSafeMergeValue<SafeProp<T2, k>>;\n };\n\n/** Recursively merges a tuple of object types from left to right. */\nexport type Merge<T extends unknown[]> = T['length'] extends 3\n ? MergeTwo<T[0], MergeTwo<T[1], T[2]>>\n : T['length'] extends 2\n ? MergeTwo<T[0], T[1]>\n : T['length'] extends 1\n ? DeepSafeMergeProps<T[0]>\n : T extends [...infer K, infer PL, infer L]\n ? Merge<[Merge<[...K]>, MergeTwo<PL, L>]>\n : never;\n\n/**\n * Deep-merges multiple objects into one. Later values override earlier ones;\n * nested objects are merged recursively rather than replaced.\n * Prototype-polluting keys (`__proto__`, `constructor`, and `prototype`) are\n * ignored.\n *\n * @example\n * ```ts\n * const a = { x: 1, nested: { a: true } };\n * const b = { y: 2, nested: { b: false } };\n * const result = deepExtend(a, b);\n * // { x: 1, y: 2, nested: { a: true, b: false } }\n * ```\n *\n * @param args - Two or more non-null objects to merge.\n * @returns A new object containing the deep-merged result.\n * @throws If no arguments are provided or any argument is not a non-null object.\n */\nexport const deepExtend = ((...rest) => {\n if (rest.length === 0) throw new Error('no arguments');\n if (typeof rest[0] !== 'object' || rest[0] === null)\n throw new Error('not a non-null object');\n\n const result = {};\n\n const extendObject = (\n o1: any,\n o2: any,\n copiedObjects: WeakMap<object, object>\n ) => {\n const keys = Object.keys(o2);\n\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i];\n if (isUnsafeMergeKey(key)) continue;\n\n const sourceValue = o2[key];\n if (!isMergeableObject(sourceValue)) {\n defineMergeProperty(o1, key, sourceValue);\n continue;\n }\n\n if (copiedObjects.has(sourceValue)) {\n defineMergeProperty(o1, key, copiedObjects.get(sourceValue));\n continue;\n }\n\n const targetValue = Object.hasOwn(o1, key) ? o1[key] : undefined;\n const targetBranch = isMergeableObject(targetValue)\n ? targetValue\n : createMergeTarget(sourceValue);\n\n copiedObjects.set(sourceValue, targetBranch);\n extendObject(targetBranch, sourceValue, copiedObjects);\n defineMergeProperty(o1, key, targetBranch);\n }\n };\n\n for (let i = 0; i < rest.length; i++) {\n const source = rest[i];\n if (typeof source === 'object' && source !== null) {\n const copiedObjects = new WeakMap<object, object>();\n copiedObjects.set(source, result);\n extendObject(result, source, copiedObjects);\n } else {\n throw new Error('not a non-null object');\n }\n }\n\n return result;\n}) as <T extends unknown[]>(...args: T) => Merge<T>;\n\nfunction isUnsafeMergeKey(key: string): boolean {\n return key === '__proto__' || key === 'constructor' || key === 'prototype';\n}\n\nfunction isMergeableObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== 'object' || value === null) return false;\n if (Array.isArray(value)) return true;\n\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n}\n\nfunction createMergeTarget(source: Record<string, unknown>): object {\n if (Array.isArray(source)) return [];\n return Object.getPrototypeOf(source) === null ? Object.create(null) : {};\n}\n\nfunction defineMergeProperty(\n target: object,\n key: string,\n value: unknown\n): void {\n Object.defineProperty(target, key, {\n configurable: true,\n enumerable: true,\n value,\n writable: true\n });\n}\n","/**\n * Flattens an object to a single level, with the nested keys separated by a `delimiter`.\n * @example\n * ```ts\n * deepFlatten({ a: { b: 1, c: 2 } });\n * // => { 'a.b': 1, 'a.c': 2 }\n *\n * deepFlatten({ a: { b: 1, c: 2 } }, '/');\n * // => { 'a/b': 1, 'a/c': 2 }\n *\n * deepFlatten({ a: { b: 1, c: { d: 'some val' } }, d: 3 });\n * // => { 'a.b': 1, 'a.c.d': 'some val', d: 3 }\n *\n * ```\n * @param {string} [delimiter]\n */\nexport function deepFlatten(\n obj: Record<string, any>,\n delimiter = '.'\n): Record<string, any> {\n const shouldFlatten = (obj: any) =>\n typeof obj === 'object' &&\n obj !== null &&\n !Array.isArray(obj) &&\n Object.getPrototypeOf(obj) === Object.prototype;\n\n if (!shouldFlatten(obj)) throw new Error('cannot flatten this object');\n\n const stack: any[] = [];\n\n const result: Record<string, any> = {};\n\n const deepFlattenHelper = (obj: any, prefix = '') => {\n if (stack.find(o => o === obj))\n throw new Error('circular reference detected');\n\n stack.push(obj);\n\n Object.keys(obj).forEach(key => {\n if (!shouldFlatten(obj[key])) {\n result[prefix ? `${prefix}${delimiter}${key}` : key] = obj[key];\n return;\n }\n deepFlattenHelper(\n obj[key],\n prefix ? `${prefix}${delimiter}${key}` : key\n );\n });\n\n stack.pop();\n };\n\n deepFlattenHelper(obj);\n\n return result;\n}\n"],"mappings":"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","names":["isPlainObject","value","prototype","enumerableKeys","key","deepClone","value","seen","clone","source","isPlainObject","result","key","enumerableKeys","isArrayIndex","key","index","deepEqual","p1","p2","options","active","compareProperties","left","right","leftKeys","rightKeys","rightKeySet","compare","compareUnordered","leftIndices","rightIndices","unmatched","value","match","candidate","isPlainObject","partners","enumerableKeys","deepExtend","rest","result","extendObject","o1","o2","copiedObjects","keys","i","key","isUnsafeMergeKey","sourceValue","isMergeableObject","defineMergeProperty","targetValue","targetBranch","createMergeTarget","source","value","prototype","target","deepFlatten","obj","delimiter","shouldFlatten","stack","result","deepFlattenHelper","prefix","o","key"]}
|
package/package.json
CHANGED