git-off

git off handles large files in git repos
git clone https://noulin.net/git/git-off.git
Log | Files | Refs | README

eql.js (4869B)


      1 /*!
      2  * deep-eql
      3  * Copyright(c) 2013 Jake Luer <jake@alogicalparadox.com>
      4  * MIT Licensed
      5  */
      6 
      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 ((m[i][0] === a && m[i][1] === b)
    224       ||  (m[i][0] === b && m[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 >= 0; i--) {
    250     key = ka[i];
    251     if (!deepEqual(a[key], b[key], m)) {
    252       return false;
    253     }
    254   }
    255 
    256   return true;
    257 }