Skip to content

Commit 0b40261

Browse files
add library
1 parent 0bf6d9c commit 0b40261

1 file changed

Lines changed: 256 additions & 1 deletion

File tree

lib/eql.js

Lines changed: 256 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,257 @@
1+
/*!
2+
* deep-eql
3+
* Copyright(c) 2013 Jake Luer <jake@alogicalparadox.com>
4+
* MIT Licensed
5+
*/
16

2-
exports.version = '0.0.0';
7+
/*!
8+
* Module dependencies
9+
*/
10+
11+
var type = require('type-detect');
12+
13+
/*!
14+
* Buffer.isBuffer browser shim
15+
*/
16+
17+
var Buffer;
18+
try { Buffer = require('buffer').Buffer; }
19+
catch(ex) {
20+
Buffer = {};
21+
Buffer.isBuffer = function() { return false; }
22+
}
23+
24+
/*!
25+
* Primary Export
26+
*/
27+
28+
module.exports = deepEqual;
29+
30+
/**
31+
* Assert super-strict (egal) equality between
32+
* two objects of any type.
33+
*
34+
* @param {Mixed} a
35+
* @param {Mixed} b
36+
* @param {Array} memoised (optional)
37+
* @return {Boolean} equal match
38+
*/
39+
40+
function deepEqual(a, b, m) {
41+
if (sameValue(a, b)) {
42+
return true;
43+
} else if ('date' === type(a)) {
44+
return dateEqual(a, b);
45+
} else if ('regexp' === type(a)) {
46+
return regexpEqual(a, b);
47+
} else if (Buffer.isBuffer(a)) {
48+
return bufferEqual(a, b);
49+
} else if ('arguments' === type(a)) {
50+
return argumentsEqual(a, b, m);
51+
} else if (!typeEqual(a, b)) {
52+
return false;
53+
} else if (('object' !== type(a) && 'object' !== type(b))
54+
&& ('array' !== type(a) && 'array' !== type(b))) {
55+
return sameValue(a, b);
56+
} else {
57+
return objectEqual(a, b, m);
58+
}
59+
}
60+
61+
/*!
62+
* Strict (egal) equality test. Ensures that NaN always
63+
* equals NaN and `-0` does not equal `+0`.
64+
*
65+
* @param {Mixed} a
66+
* @param {Mixed} b
67+
* @return {Boolean} equal match
68+
*/
69+
70+
function sameValue(a, b) {
71+
if (a === b) return a !== 0 || 1 / a === 1 / b;
72+
return a !== a && b !== b;
73+
}
74+
75+
/*!
76+
* Compare the types of two given objects and
77+
* return if they are equal. Note that an Array
78+
* has a type of `array` (not `object`) and arguments
79+
* have a type of `arguments` (not `array`/`object`).
80+
*
81+
* @param {Mixed} a
82+
* @param {Mixed} b
83+
* @return {Boolean} result
84+
*/
85+
86+
function typeEqual(a, b) {
87+
return type(a) === type(b);
88+
}
89+
90+
/*!
91+
* Compare two Date objects by asserting that
92+
* the time values are equal using `saveValue`.
93+
*
94+
* @param {Date} a
95+
* @param {Date} b
96+
* @return {Boolean} result
97+
*/
98+
99+
function dateEqual(a, b) {
100+
if ('date' !== type(b)) return false;
101+
return sameValue(a.getTime(), b.getTime());
102+
}
103+
104+
/*!
105+
* Compare two regular expressions by converting them
106+
* to string and checking for `sameValue`.
107+
*
108+
* @param {RegExp} a
109+
* @param {RegExp} b
110+
* @return {Boolean} result
111+
*/
112+
113+
function regexpEqual(a, b) {
114+
if ('regexp' !== type(b)) return false;
115+
return sameValue(a.toString(), b.toString());
116+
}
117+
118+
/*!
119+
* Assert deep equality of two `arguments` objects.
120+
* Unfortunately, these must be sliced to arrays
121+
* prior to test to ensure no bad behavior.
122+
*
123+
* @param {Arguments} a
124+
* @param {Arguments} b
125+
* @param {Array} memoize (optional)
126+
* @return {Boolean} result
127+
*/
128+
129+
function argumentsEqual(a, b, m) {
130+
if ('arguments' !== type(b)) return false;
131+
a = [].slice.call(a);
132+
b = [].slice.call(b);
133+
return deepEqual(a, b, m);
134+
}
135+
136+
/*!
137+
* Get enumerable properties of a given object.
138+
*
139+
* @param {Object} a
140+
* @return {Array} property names
141+
*/
142+
143+
function enumerable(a) {
144+
var res = [];
145+
for (var key in a) res.push(key);
146+
return res;
147+
}
148+
149+
/*!
150+
* Simple equality for flat iterable objects
151+
* such as Arrays or Node.js buffers.
152+
*
153+
* @param {Iterable} a
154+
* @param {Iterable} b
155+
* @return {Boolean} result
156+
*/
157+
158+
function iterableEqual(a, b) {
159+
if (a.length !== b.length) return false;
160+
161+
var i = 0;
162+
var match = true;
163+
164+
for (; i < a.length; i++) {
165+
if (a[i] !== b[i]) {
166+
match = false;
167+
break;
168+
}
169+
}
170+
171+
return match;
172+
}
173+
174+
/*!
175+
* Extension to `iterableEqual` specifically
176+
* for Node.js Buffers.
177+
*
178+
* @param {Buffer} a
179+
* @param {Mixed} b
180+
* @return {Boolean} result
181+
*/
182+
183+
function bufferEqual(a, b) {
184+
if (!Buffer.isBuffer(b)) return false;
185+
return iterableEqual(a, b);
186+
}
187+
188+
/*!
189+
* Block for `objectEqual` ensuring non-existing
190+
* values don't get in.
191+
*
192+
* @param {Mixed} object
193+
* @return {Boolean} result
194+
*/
195+
196+
function isValue(a) {
197+
return a !== null && a !== undefined;
198+
}
199+
200+
/*!
201+
* Recursively check the equality of two objects.
202+
* Once basic sameness has been established it will
203+
* defer to `deepEqual` for each enumerable key
204+
* in the object.
205+
*
206+
* @param {Mixed} a
207+
* @param {Mixed} b
208+
* @return {Boolean} result
209+
*/
210+
211+
function objectEqual(a, b, m) {
212+
if (!isValue(a) || !isValue(b)) {
213+
return false;
214+
}
215+
216+
if (a.prototype !== b.prototype) {
217+
return false;
218+
}
219+
220+
var i;
221+
if (m) {
222+
for (i = 0; i < m.length; i++) {
223+
if ((memos[i][0] === a && memos[i][1] === b)
224+
|| (memos[i][0] === b && memos[i][1] === a)) {
225+
return true;
226+
}
227+
}
228+
} else {
229+
m = [];
230+
}
231+
232+
try {
233+
var ka = enumerable(a);
234+
var kb = enumerable(b);
235+
} catch (ex) {
236+
return false;
237+
}
238+
239+
ka.sort();
240+
kb.sort();
241+
242+
if (!iterableEqual(ka, kb)) {
243+
return false;
244+
}
245+
246+
m.push([ a, b ]);
247+
248+
var key;
249+
for (i = ka.length - 1; i >= 1; i--) {
250+
key = ka[i];
251+
if (!deepEqual(a[key], b[key], m)) {
252+
return false;
253+
}
254+
}
255+
256+
return true;
257+
}

0 commit comments

Comments
 (0)