source: node_modules/es-toolkit/dist/predicate/isEqualWith.mjs

Last change on this file was a762898, checked in by istevanoska <ilinastevanoska@…>, 5 months ago

Added visualizations

  • Property mode set to 100644
File size: 6.6 KB
Line 
1import { isPlainObject } from './isPlainObject.mjs';
2import { getSymbols } from '../compat/_internal/getSymbols.mjs';
3import { getTag } from '../compat/_internal/getTag.mjs';
4import { functionTag, regexpTag, symbolTag, dateTag, booleanTag, numberTag, stringTag, objectTag, errorTag, dataViewTag, arrayBufferTag, float64ArrayTag, float32ArrayTag, bigInt64ArrayTag, int32ArrayTag, int16ArrayTag, int8ArrayTag, bigUint64ArrayTag, uint32ArrayTag, uint16ArrayTag, uint8ClampedArrayTag, uint8ArrayTag, arrayTag, setTag, mapTag, argumentsTag } from '../compat/_internal/tags.mjs';
5import { isEqualsSameValueZero } from '../_internal/isEqualsSameValueZero.mjs';
6
7function isEqualWith(a, b, areValuesEqual) {
8 return isEqualWithImpl(a, b, undefined, undefined, undefined, undefined, areValuesEqual);
9}
10function isEqualWithImpl(a, b, property, aParent, bParent, stack, areValuesEqual) {
11 const result = areValuesEqual(a, b, property, aParent, bParent, stack);
12 if (result !== undefined) {
13 return result;
14 }
15 if (typeof a === typeof b) {
16 switch (typeof a) {
17 case 'bigint':
18 case 'string':
19 case 'boolean':
20 case 'symbol':
21 case 'undefined': {
22 return a === b;
23 }
24 case 'number': {
25 return a === b || Object.is(a, b);
26 }
27 case 'function': {
28 return a === b;
29 }
30 case 'object': {
31 return areObjectsEqual(a, b, stack, areValuesEqual);
32 }
33 }
34 }
35 return areObjectsEqual(a, b, stack, areValuesEqual);
36}
37function areObjectsEqual(a, b, stack, areValuesEqual) {
38 if (Object.is(a, b)) {
39 return true;
40 }
41 let aTag = getTag(a);
42 let bTag = getTag(b);
43 if (aTag === argumentsTag) {
44 aTag = objectTag;
45 }
46 if (bTag === argumentsTag) {
47 bTag = objectTag;
48 }
49 if (aTag !== bTag) {
50 return false;
51 }
52 switch (aTag) {
53 case stringTag:
54 return a.toString() === b.toString();
55 case numberTag: {
56 const x = a.valueOf();
57 const y = b.valueOf();
58 return isEqualsSameValueZero(x, y);
59 }
60 case booleanTag:
61 case dateTag:
62 case symbolTag:
63 return Object.is(a.valueOf(), b.valueOf());
64 case regexpTag: {
65 return a.source === b.source && a.flags === b.flags;
66 }
67 case functionTag: {
68 return a === b;
69 }
70 }
71 stack = stack ?? new Map();
72 const aStack = stack.get(a);
73 const bStack = stack.get(b);
74 if (aStack != null && bStack != null) {
75 return aStack === b;
76 }
77 stack.set(a, b);
78 stack.set(b, a);
79 try {
80 switch (aTag) {
81 case mapTag: {
82 if (a.size !== b.size) {
83 return false;
84 }
85 for (const [key, value] of a.entries()) {
86 if (!b.has(key) || !isEqualWithImpl(value, b.get(key), key, a, b, stack, areValuesEqual)) {
87 return false;
88 }
89 }
90 return true;
91 }
92 case setTag: {
93 if (a.size !== b.size) {
94 return false;
95 }
96 const aValues = Array.from(a.values());
97 const bValues = Array.from(b.values());
98 for (let i = 0; i < aValues.length; i++) {
99 const aValue = aValues[i];
100 const index = bValues.findIndex(bValue => {
101 return isEqualWithImpl(aValue, bValue, undefined, a, b, stack, areValuesEqual);
102 });
103 if (index === -1) {
104 return false;
105 }
106 bValues.splice(index, 1);
107 }
108 return true;
109 }
110 case arrayTag:
111 case uint8ArrayTag:
112 case uint8ClampedArrayTag:
113 case uint16ArrayTag:
114 case uint32ArrayTag:
115 case bigUint64ArrayTag:
116 case int8ArrayTag:
117 case int16ArrayTag:
118 case int32ArrayTag:
119 case bigInt64ArrayTag:
120 case float32ArrayTag:
121 case float64ArrayTag: {
122 if (typeof Buffer !== 'undefined' && Buffer.isBuffer(a) !== Buffer.isBuffer(b)) {
123 return false;
124 }
125 if (a.length !== b.length) {
126 return false;
127 }
128 for (let i = 0; i < a.length; i++) {
129 if (!isEqualWithImpl(a[i], b[i], i, a, b, stack, areValuesEqual)) {
130 return false;
131 }
132 }
133 return true;
134 }
135 case arrayBufferTag: {
136 if (a.byteLength !== b.byteLength) {
137 return false;
138 }
139 return areObjectsEqual(new Uint8Array(a), new Uint8Array(b), stack, areValuesEqual);
140 }
141 case dataViewTag: {
142 if (a.byteLength !== b.byteLength || a.byteOffset !== b.byteOffset) {
143 return false;
144 }
145 return areObjectsEqual(new Uint8Array(a), new Uint8Array(b), stack, areValuesEqual);
146 }
147 case errorTag: {
148 return a.name === b.name && a.message === b.message;
149 }
150 case objectTag: {
151 const areEqualInstances = areObjectsEqual(a.constructor, b.constructor, stack, areValuesEqual) ||
152 (isPlainObject(a) && isPlainObject(b));
153 if (!areEqualInstances) {
154 return false;
155 }
156 const aKeys = [...Object.keys(a), ...getSymbols(a)];
157 const bKeys = [...Object.keys(b), ...getSymbols(b)];
158 if (aKeys.length !== bKeys.length) {
159 return false;
160 }
161 for (let i = 0; i < aKeys.length; i++) {
162 const propKey = aKeys[i];
163 const aProp = a[propKey];
164 if (!Object.hasOwn(b, propKey)) {
165 return false;
166 }
167 const bProp = b[propKey];
168 if (!isEqualWithImpl(aProp, bProp, propKey, a, b, stack, areValuesEqual)) {
169 return false;
170 }
171 }
172 return true;
173 }
174 default: {
175 return false;
176 }
177 }
178 }
179 finally {
180 stack.delete(a);
181 stack.delete(b);
182 }
183}
184
185export { isEqualWith };
Note: See TracBrowser for help on using the repository browser.