@helpers4/object 2.0.0-alpha.2 → 2.0.0-alpha.3
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 +2 -0
- package/lib/index.d.ts +5 -0
- package/lib/index.js +153 -0
- package/package.json +3 -1
package/README.md
CHANGED
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
export declare function get<T = any>(obj: any, path: string, defaultValue?: T): T | undefined;
|
|
2
2
|
export declare function set(obj: Record<string, any>, path: string, value: any): Record<string, any>;
|
|
3
|
+
export declare function quickCompare(objA: object, objB: object): boolean;
|
|
4
|
+
export interface DeepCompareResult {
|
|
5
|
+
[key: string]: "onlyA" | "onlyB" | false | DeepCompareResult;
|
|
6
|
+
}
|
|
7
|
+
export declare function deepCompare(objA: object | undefined | null, objB: object | undefined | null): true | false | DeepCompareResult;
|
|
3
8
|
export declare function deepMerge<T extends Record<string, any>>(target: T, ...sources: Record<string, any>[]): T;
|
|
4
9
|
export declare function removeUndefinedNull<T extends Record<string, string | boolean | number>>(obj: T): T; /** * Remove null and undefined values from an object. * * @param obj a null object * @returns null */ export function removeUndefinedNull<T extends Record<string, string | boolean | number>>(obj: null): null; /** * Remove null and undefined values from an object. * * @param obj an undefined object * @returns undefined */ export function removeUndefinedNull<T extends Record<string, string | boolean | number>>(obj: undefined): undefined; /** * Remove null and undefined values from an object. * * @param obj an object * @returns A shallow copy of the object without null or undefined values */ export function removeUndefinedNull<T extends Record<string, string | boolean | number>>(obj: T | null | undefined): T | null | undefined;
|
|
5
10
|
export declare function deepClone<T>(obj: T): T;
|
package/lib/index.js
CHANGED
|
@@ -24,6 +24,157 @@ function set(obj, path, value) {
|
|
|
24
24
|
current[keys[keys.length - 1]] = value;
|
|
25
25
|
return obj;
|
|
26
26
|
}
|
|
27
|
+
// helpers/object/quickCompare.ts
|
|
28
|
+
function quickCompare(objA, objB) {
|
|
29
|
+
if (objA === objB) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
if (typeof objA === "function" || typeof objB === "function") {
|
|
33
|
+
return objA === objB;
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
return JSON.stringify(objA) === JSON.stringify(objB);
|
|
37
|
+
} catch {
|
|
38
|
+
return objA === objB;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// helpers/array/quickCompare.ts
|
|
42
|
+
function quickCompare2(arrA, arrB) {
|
|
43
|
+
try {
|
|
44
|
+
return JSON.stringify(arrA) === JSON.stringify(arrB);
|
|
45
|
+
} catch {
|
|
46
|
+
return arrA === arrB;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// helpers/date/compare.ts
|
|
51
|
+
function compare(dateA, dateB, options = {}) {
|
|
52
|
+
const { precision = "milliseconds" } = options;
|
|
53
|
+
if (!(dateA instanceof Date) || !(dateB instanceof Date)) {
|
|
54
|
+
return dateA === dateB;
|
|
55
|
+
}
|
|
56
|
+
if (isNaN(dateA.getTime()) || isNaN(dateB.getTime())) {
|
|
57
|
+
return isNaN(dateA.getTime()) && isNaN(dateB.getTime());
|
|
58
|
+
}
|
|
59
|
+
switch (precision) {
|
|
60
|
+
case "days":
|
|
61
|
+
return dateA.toDateString() === dateB.toDateString();
|
|
62
|
+
case "hours":
|
|
63
|
+
const hoursA = Math.floor(dateA.getTime() / (1000 * 60 * 60));
|
|
64
|
+
const hoursB = Math.floor(dateB.getTime() / (1000 * 60 * 60));
|
|
65
|
+
return hoursA === hoursB;
|
|
66
|
+
case "minutes":
|
|
67
|
+
const minutesA = Math.floor(dateA.getTime() / (1000 * 60));
|
|
68
|
+
const minutesB = Math.floor(dateB.getTime() / (1000 * 60));
|
|
69
|
+
return minutesA === minutesB;
|
|
70
|
+
case "seconds":
|
|
71
|
+
const secondsA = Math.floor(dateA.getTime() / 1000);
|
|
72
|
+
const secondsB = Math.floor(dateB.getTime() / 1000);
|
|
73
|
+
return secondsA === secondsB;
|
|
74
|
+
case "milliseconds":
|
|
75
|
+
default:
|
|
76
|
+
return dateA.getTime() === dateB.getTime();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// helpers/type/isSpecialObject.ts
|
|
81
|
+
function isSpecialObject(value) {
|
|
82
|
+
if (value === null || value === undefined) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
if (typeof value === "function") {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
if (typeof value !== "object") {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
if (Array.isArray(value)) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
if (value instanceof Date || value instanceof Promise || value instanceof RegExp || value instanceof Error || value instanceof Map || value instanceof Set || value instanceof WeakMap || value instanceof WeakSet || value instanceof ArrayBuffer || value instanceof DataView) {
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
if (value.constructor?.name === "Observable") {
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
if (typeof HTMLElement !== "undefined" && value instanceof HTMLElement) {
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
const constructorName = value.constructor?.name;
|
|
104
|
+
if (constructorName && [
|
|
105
|
+
"Buffer",
|
|
106
|
+
"URL",
|
|
107
|
+
"URLSearchParams",
|
|
108
|
+
"File",
|
|
109
|
+
"Blob",
|
|
110
|
+
"FormData",
|
|
111
|
+
"Headers",
|
|
112
|
+
"Request",
|
|
113
|
+
"Response",
|
|
114
|
+
"EventTarget",
|
|
115
|
+
"Symbol"
|
|
116
|
+
].includes(constructorName)) {
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// helpers/object/deepCompare.ts
|
|
123
|
+
function deepCompare(objA, objB) {
|
|
124
|
+
if (objA === objB) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
if (objA == null || objB == null) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
if (objA instanceof Date && objB instanceof Date) {
|
|
131
|
+
return compare(objA, objB);
|
|
132
|
+
}
|
|
133
|
+
if (Array.isArray(objA) && Array.isArray(objB)) {
|
|
134
|
+
return quickCompare2(objA, objB);
|
|
135
|
+
}
|
|
136
|
+
if (Array.isArray(objA) || Array.isArray(objB)) {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
if (isSpecialObject(objA) || isSpecialObject(objB)) {
|
|
140
|
+
return objA === objB;
|
|
141
|
+
}
|
|
142
|
+
const keys = Array.from(new Set([...Object.keys(objA), ...Object.keys(objB)]));
|
|
143
|
+
const differences = {};
|
|
144
|
+
for (const key of keys) {
|
|
145
|
+
const hasA = key in objA;
|
|
146
|
+
const hasB = key in objB;
|
|
147
|
+
if (!hasA && hasB) {
|
|
148
|
+
differences[key] = "onlyB";
|
|
149
|
+
} else if (hasA && !hasB) {
|
|
150
|
+
differences[key] = "onlyA";
|
|
151
|
+
} else if (hasA && hasB) {
|
|
152
|
+
const valueA = objA[key];
|
|
153
|
+
const valueB = objB[key];
|
|
154
|
+
if (Array.isArray(valueA) && Array.isArray(valueB)) {
|
|
155
|
+
if (!quickCompare2(valueA, valueB)) {
|
|
156
|
+
differences[key] = false;
|
|
157
|
+
}
|
|
158
|
+
} else if (valueA instanceof Date && valueB instanceof Date) {
|
|
159
|
+
if (!compare(valueA, valueB)) {
|
|
160
|
+
differences[key] = false;
|
|
161
|
+
}
|
|
162
|
+
} else if (isSpecialObject(valueA) || isSpecialObject(valueB)) {
|
|
163
|
+
if (valueA !== valueB) {
|
|
164
|
+
differences[key] = false;
|
|
165
|
+
}
|
|
166
|
+
} else if (valueA !== null && valueB !== null && valueA !== undefined && valueB !== undefined && typeof valueA === "object" && typeof valueB === "object" && !isSpecialObject(valueA) && !isSpecialObject(valueB)) {
|
|
167
|
+
const nestedResult = deepCompare(valueA, valueB);
|
|
168
|
+
if (nestedResult !== true) {
|
|
169
|
+
differences[key] = nestedResult === false ? false : nestedResult;
|
|
170
|
+
}
|
|
171
|
+
} else if (valueA !== valueB) {
|
|
172
|
+
differences[key] = false;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return Object.keys(differences).length > 0 ? differences : true;
|
|
177
|
+
}
|
|
27
178
|
// helpers/object/deepMerge.ts
|
|
28
179
|
function deepMerge(target, ...sources) {
|
|
29
180
|
if (!sources.length)
|
|
@@ -72,7 +223,9 @@ function deepClone(obj) {
|
|
|
72
223
|
export {
|
|
73
224
|
set,
|
|
74
225
|
removeUndefinedNull,
|
|
226
|
+
quickCompare,
|
|
75
227
|
get,
|
|
76
228
|
deepMerge,
|
|
229
|
+
deepCompare,
|
|
77
230
|
deepClone
|
|
78
231
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@helpers4/object",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.3",
|
|
4
4
|
"description": "A set of helpers in TS/JS, compatible with tree-shaking, for object.",
|
|
5
5
|
"author": "baxyz <baxy@etik.com>",
|
|
6
6
|
"license": "AGPL-3.0",
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
"object",
|
|
23
23
|
"get",
|
|
24
24
|
"set",
|
|
25
|
+
"quickCompare",
|
|
26
|
+
"deepCompare",
|
|
25
27
|
"deepMerge",
|
|
26
28
|
"removeUndefinedNull",
|
|
27
29
|
"deepClone"
|