833 lines
30 KiB
JavaScript
833 lines
30 KiB
JavaScript
|
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.deepEqual = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
||
|
'use strict';
|
||
|
/* globals Symbol: false, Uint8Array: false, WeakMap: false */
|
||
|
/*!
|
||
|
* deep-eql
|
||
|
* Copyright(c) 2013 Jake Luer <jake@alogicalparadox.com>
|
||
|
* MIT Licensed
|
||
|
*/
|
||
|
|
||
|
var type = require('type-detect');
|
||
|
function FakeMap() {
|
||
|
this._key = 'chai/deep-eql__' + Math.random() + Date.now();
|
||
|
}
|
||
|
|
||
|
FakeMap.prototype = {
|
||
|
get: function getMap(key) {
|
||
|
return key[this._key];
|
||
|
},
|
||
|
set: function setMap(key, value) {
|
||
|
if (Object.isExtensible(key)) {
|
||
|
Object.defineProperty(key, this._key, {
|
||
|
value: value,
|
||
|
configurable: true,
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
};
|
||
|
|
||
|
var MemoizeMap = typeof WeakMap === 'function' ? WeakMap : FakeMap;
|
||
|
/*!
|
||
|
* Check to see if the MemoizeMap has recorded a result of the two operands
|
||
|
*
|
||
|
* @param {Mixed} leftHandOperand
|
||
|
* @param {Mixed} rightHandOperand
|
||
|
* @param {MemoizeMap} memoizeMap
|
||
|
* @returns {Boolean|null} result
|
||
|
*/
|
||
|
function memoizeCompare(leftHandOperand, rightHandOperand, memoizeMap) {
|
||
|
// Technically, WeakMap keys can *only* be objects, not primitives.
|
||
|
if (!memoizeMap || isPrimitive(leftHandOperand) || isPrimitive(rightHandOperand)) {
|
||
|
return null;
|
||
|
}
|
||
|
var leftHandMap = memoizeMap.get(leftHandOperand);
|
||
|
if (leftHandMap) {
|
||
|
var result = leftHandMap.get(rightHandOperand);
|
||
|
if (typeof result === 'boolean') {
|
||
|
return result;
|
||
|
}
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Set the result of the equality into the MemoizeMap
|
||
|
*
|
||
|
* @param {Mixed} leftHandOperand
|
||
|
* @param {Mixed} rightHandOperand
|
||
|
* @param {MemoizeMap} memoizeMap
|
||
|
* @param {Boolean} result
|
||
|
*/
|
||
|
function memoizeSet(leftHandOperand, rightHandOperand, memoizeMap, result) {
|
||
|
// Technically, WeakMap keys can *only* be objects, not primitives.
|
||
|
if (!memoizeMap || isPrimitive(leftHandOperand) || isPrimitive(rightHandOperand)) {
|
||
|
return;
|
||
|
}
|
||
|
var leftHandMap = memoizeMap.get(leftHandOperand);
|
||
|
if (leftHandMap) {
|
||
|
leftHandMap.set(rightHandOperand, result);
|
||
|
} else {
|
||
|
leftHandMap = new MemoizeMap();
|
||
|
leftHandMap.set(rightHandOperand, result);
|
||
|
memoizeMap.set(leftHandOperand, leftHandMap);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Primary Export
|
||
|
*/
|
||
|
|
||
|
module.exports = deepEqual;
|
||
|
module.exports.MemoizeMap = MemoizeMap;
|
||
|
|
||
|
/**
|
||
|
* Assert deeply nested sameValue equality between two objects of any type.
|
||
|
*
|
||
|
* @param {Mixed} leftHandOperand
|
||
|
* @param {Mixed} rightHandOperand
|
||
|
* @param {Object} [options] (optional) Additional options
|
||
|
* @param {Array} [options.comparator] (optional) Override default algorithm, determining custom equality.
|
||
|
* @param {Array} [options.memoize] (optional) Provide a custom memoization object which will cache the results of
|
||
|
complex objects for a speed boost. By passing `false` you can disable memoization, but this will cause circular
|
||
|
references to blow the stack.
|
||
|
* @return {Boolean} equal match
|
||
|
*/
|
||
|
function deepEqual(leftHandOperand, rightHandOperand, options) {
|
||
|
// If we have a comparator, we can't assume anything; so bail to its check first.
|
||
|
if (options && options.comparator) {
|
||
|
return extensiveDeepEqual(leftHandOperand, rightHandOperand, options);
|
||
|
}
|
||
|
|
||
|
var simpleResult = simpleEqual(leftHandOperand, rightHandOperand);
|
||
|
if (simpleResult !== null) {
|
||
|
return simpleResult;
|
||
|
}
|
||
|
|
||
|
// Deeper comparisons are pushed through to a larger function
|
||
|
return extensiveDeepEqual(leftHandOperand, rightHandOperand, options);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Many comparisons can be canceled out early via simple equality or primitive checks.
|
||
|
* @param {Mixed} leftHandOperand
|
||
|
* @param {Mixed} rightHandOperand
|
||
|
* @return {Boolean|null} equal match
|
||
|
*/
|
||
|
function simpleEqual(leftHandOperand, rightHandOperand) {
|
||
|
// Equal references (except for Numbers) can be returned early
|
||
|
if (leftHandOperand === rightHandOperand) {
|
||
|
// Handle +-0 cases
|
||
|
return leftHandOperand !== 0 || 1 / leftHandOperand === 1 / rightHandOperand;
|
||
|
}
|
||
|
|
||
|
// handle NaN cases
|
||
|
if (
|
||
|
leftHandOperand !== leftHandOperand && // eslint-disable-line no-self-compare
|
||
|
rightHandOperand !== rightHandOperand // eslint-disable-line no-self-compare
|
||
|
) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// Anything that is not an 'object', i.e. symbols, functions, booleans, numbers,
|
||
|
// strings, and undefined, can be compared by reference.
|
||
|
if (isPrimitive(leftHandOperand) || isPrimitive(rightHandOperand)) {
|
||
|
// Easy out b/c it would have passed the first equality check
|
||
|
return false;
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* The main logic of the `deepEqual` function.
|
||
|
*
|
||
|
* @param {Mixed} leftHandOperand
|
||
|
* @param {Mixed} rightHandOperand
|
||
|
* @param {Object} [options] (optional) Additional options
|
||
|
* @param {Array} [options.comparator] (optional) Override default algorithm, determining custom equality.
|
||
|
* @param {Array} [options.memoize] (optional) Provide a custom memoization object which will cache the results of
|
||
|
complex objects for a speed boost. By passing `false` you can disable memoization, but this will cause circular
|
||
|
references to blow the stack.
|
||
|
* @return {Boolean} equal match
|
||
|
*/
|
||
|
function extensiveDeepEqual(leftHandOperand, rightHandOperand, options) {
|
||
|
options = options || {};
|
||
|
options.memoize = options.memoize === false ? false : options.memoize || new MemoizeMap();
|
||
|
var comparator = options && options.comparator;
|
||
|
|
||
|
// Check if a memoized result exists.
|
||
|
var memoizeResultLeft = memoizeCompare(leftHandOperand, rightHandOperand, options.memoize);
|
||
|
if (memoizeResultLeft !== null) {
|
||
|
return memoizeResultLeft;
|
||
|
}
|
||
|
var memoizeResultRight = memoizeCompare(rightHandOperand, leftHandOperand, options.memoize);
|
||
|
if (memoizeResultRight !== null) {
|
||
|
return memoizeResultRight;
|
||
|
}
|
||
|
|
||
|
// If a comparator is present, use it.
|
||
|
if (comparator) {
|
||
|
var comparatorResult = comparator(leftHandOperand, rightHandOperand);
|
||
|
// Comparators may return null, in which case we want to go back to default behavior.
|
||
|
if (comparatorResult === false || comparatorResult === true) {
|
||
|
memoizeSet(leftHandOperand, rightHandOperand, options.memoize, comparatorResult);
|
||
|
return comparatorResult;
|
||
|
}
|
||
|
// To allow comparators to override *any* behavior, we ran them first. Since it didn't decide
|
||
|
// what to do, we need to make sure to return the basic tests first before we move on.
|
||
|
var simpleResult = simpleEqual(leftHandOperand, rightHandOperand);
|
||
|
if (simpleResult !== null) {
|
||
|
// Don't memoize this, it takes longer to set/retrieve than to just compare.
|
||
|
return simpleResult;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var leftHandType = type(leftHandOperand);
|
||
|
if (leftHandType !== type(rightHandOperand)) {
|
||
|
memoizeSet(leftHandOperand, rightHandOperand, options.memoize, false);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Temporarily set the operands in the memoize object to prevent blowing the stack
|
||
|
memoizeSet(leftHandOperand, rightHandOperand, options.memoize, true);
|
||
|
|
||
|
var result = extensiveDeepEqualByType(leftHandOperand, rightHandOperand, leftHandType, options);
|
||
|
memoizeSet(leftHandOperand, rightHandOperand, options.memoize, result);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
function extensiveDeepEqualByType(leftHandOperand, rightHandOperand, leftHandType, options) {
|
||
|
switch (leftHandType) {
|
||
|
case 'String':
|
||
|
case 'Number':
|
||
|
case 'Boolean':
|
||
|
case 'Date':
|
||
|
// If these types are their instance types (e.g. `new Number`) then re-deepEqual against their values
|
||
|
return deepEqual(leftHandOperand.valueOf(), rightHandOperand.valueOf());
|
||
|
case 'Promise':
|
||
|
case 'Symbol':
|
||
|
case 'function':
|
||
|
case 'WeakMap':
|
||
|
case 'WeakSet':
|
||
|
case 'Error':
|
||
|
return leftHandOperand === rightHandOperand;
|
||
|
case 'Arguments':
|
||
|
case 'Int8Array':
|
||
|
case 'Uint8Array':
|
||
|
case 'Uint8ClampedArray':
|
||
|
case 'Int16Array':
|
||
|
case 'Uint16Array':
|
||
|
case 'Int32Array':
|
||
|
case 'Uint32Array':
|
||
|
case 'Float32Array':
|
||
|
case 'Float64Array':
|
||
|
case 'Array':
|
||
|
return iterableEqual(leftHandOperand, rightHandOperand, options);
|
||
|
case 'RegExp':
|
||
|
return regexpEqual(leftHandOperand, rightHandOperand);
|
||
|
case 'Generator':
|
||
|
return generatorEqual(leftHandOperand, rightHandOperand, options);
|
||
|
case 'DataView':
|
||
|
return iterableEqual(new Uint8Array(leftHandOperand.buffer), new Uint8Array(rightHandOperand.buffer), options);
|
||
|
case 'ArrayBuffer':
|
||
|
return iterableEqual(new Uint8Array(leftHandOperand), new Uint8Array(rightHandOperand), options);
|
||
|
case 'Set':
|
||
|
return entriesEqual(leftHandOperand, rightHandOperand, options);
|
||
|
case 'Map':
|
||
|
return entriesEqual(leftHandOperand, rightHandOperand, options);
|
||
|
default:
|
||
|
return objectEqual(leftHandOperand, rightHandOperand, options);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Compare two Regular Expressions for equality.
|
||
|
*
|
||
|
* @param {RegExp} leftHandOperand
|
||
|
* @param {RegExp} rightHandOperand
|
||
|
* @return {Boolean} result
|
||
|
*/
|
||
|
|
||
|
function regexpEqual(leftHandOperand, rightHandOperand) {
|
||
|
return leftHandOperand.toString() === rightHandOperand.toString();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Compare two Sets/Maps for equality. Faster than other equality functions.
|
||
|
*
|
||
|
* @param {Set} leftHandOperand
|
||
|
* @param {Set} rightHandOperand
|
||
|
* @param {Object} [options] (Optional)
|
||
|
* @return {Boolean} result
|
||
|
*/
|
||
|
|
||
|
function entriesEqual(leftHandOperand, rightHandOperand, options) {
|
||
|
// IE11 doesn't support Set#entries or Set#@@iterator, so we need manually populate using Set#forEach
|
||
|
if (leftHandOperand.size !== rightHandOperand.size) {
|
||
|
return false;
|
||
|
}
|
||
|
if (leftHandOperand.size === 0) {
|
||
|
return true;
|
||
|
}
|
||
|
var leftHandItems = [];
|
||
|
var rightHandItems = [];
|
||
|
leftHandOperand.forEach(function gatherEntries(key, value) {
|
||
|
leftHandItems.push([ key, value ]);
|
||
|
});
|
||
|
rightHandOperand.forEach(function gatherEntries(key, value) {
|
||
|
rightHandItems.push([ key, value ]);
|
||
|
});
|
||
|
return iterableEqual(leftHandItems.sort(), rightHandItems.sort(), options);
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Simple equality for flat iterable objects such as Arrays, TypedArrays or Node.js buffers.
|
||
|
*
|
||
|
* @param {Iterable} leftHandOperand
|
||
|
* @param {Iterable} rightHandOperand
|
||
|
* @param {Object} [options] (Optional)
|
||
|
* @return {Boolean} result
|
||
|
*/
|
||
|
|
||
|
function iterableEqual(leftHandOperand, rightHandOperand, options) {
|
||
|
var length = leftHandOperand.length;
|
||
|
if (length !== rightHandOperand.length) {
|
||
|
return false;
|
||
|
}
|
||
|
if (length === 0) {
|
||
|
return true;
|
||
|
}
|
||
|
var index = -1;
|
||
|
while (++index < length) {
|
||
|
if (deepEqual(leftHandOperand[index], rightHandOperand[index], options) === false) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Simple equality for generator objects such as those returned by generator functions.
|
||
|
*
|
||
|
* @param {Iterable} leftHandOperand
|
||
|
* @param {Iterable} rightHandOperand
|
||
|
* @param {Object} [options] (Optional)
|
||
|
* @return {Boolean} result
|
||
|
*/
|
||
|
|
||
|
function generatorEqual(leftHandOperand, rightHandOperand, options) {
|
||
|
return iterableEqual(getGeneratorEntries(leftHandOperand), getGeneratorEntries(rightHandOperand), options);
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Determine if the given object has an @@iterator function.
|
||
|
*
|
||
|
* @param {Object} target
|
||
|
* @return {Boolean} `true` if the object has an @@iterator function.
|
||
|
*/
|
||
|
function hasIteratorFunction(target) {
|
||
|
return typeof Symbol !== 'undefined' &&
|
||
|
typeof target === 'object' &&
|
||
|
typeof Symbol.iterator !== 'undefined' &&
|
||
|
typeof target[Symbol.iterator] === 'function';
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Gets all iterator entries from the given Object. If the Object has no @@iterator function, returns an empty array.
|
||
|
* This will consume the iterator - which could have side effects depending on the @@iterator implementation.
|
||
|
*
|
||
|
* @param {Object} target
|
||
|
* @returns {Array} an array of entries from the @@iterator function
|
||
|
*/
|
||
|
function getIteratorEntries(target) {
|
||
|
if (hasIteratorFunction(target)) {
|
||
|
try {
|
||
|
return getGeneratorEntries(target[Symbol.iterator]());
|
||
|
} catch (iteratorError) {
|
||
|
return [];
|
||
|
}
|
||
|
}
|
||
|
return [];
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Gets all entries from a Generator. This will consume the generator - which could have side effects.
|
||
|
*
|
||
|
* @param {Generator} target
|
||
|
* @returns {Array} an array of entries from the Generator.
|
||
|
*/
|
||
|
function getGeneratorEntries(generator) {
|
||
|
var generatorResult = generator.next();
|
||
|
var accumulator = [ generatorResult.value ];
|
||
|
while (generatorResult.done === false) {
|
||
|
generatorResult = generator.next();
|
||
|
accumulator.push(generatorResult.value);
|
||
|
}
|
||
|
return accumulator;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Gets all own and inherited enumerable keys from a target.
|
||
|
*
|
||
|
* @param {Object} target
|
||
|
* @returns {Array} an array of own and inherited enumerable keys from the target.
|
||
|
*/
|
||
|
function getEnumerableKeys(target) {
|
||
|
var keys = [];
|
||
|
for (var key in target) {
|
||
|
keys.push(key);
|
||
|
}
|
||
|
return keys;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Determines if two objects have matching values, given a set of keys. Defers to deepEqual for the equality check of
|
||
|
* each key. If any value of the given key is not equal, the function will return false (early).
|
||
|
*
|
||
|
* @param {Mixed} leftHandOperand
|
||
|
* @param {Mixed} rightHandOperand
|
||
|
* @param {Array} keys An array of keys to compare the values of leftHandOperand and rightHandOperand against
|
||
|
* @param {Object} [options] (Optional)
|
||
|
* @return {Boolean} result
|
||
|
*/
|
||
|
function keysEqual(leftHandOperand, rightHandOperand, keys, options) {
|
||
|
var length = keys.length;
|
||
|
if (length === 0) {
|
||
|
return true;
|
||
|
}
|
||
|
for (var i = 0; i < length; i += 1) {
|
||
|
if (deepEqual(leftHandOperand[keys[i]], rightHandOperand[keys[i]], options) === false) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Recursively check the equality of two Objects. Once basic sameness has been established it will defer to `deepEqual`
|
||
|
* for each enumerable key in the object.
|
||
|
*
|
||
|
* @param {Mixed} leftHandOperand
|
||
|
* @param {Mixed} rightHandOperand
|
||
|
* @param {Object} [options] (Optional)
|
||
|
* @return {Boolean} result
|
||
|
*/
|
||
|
|
||
|
function objectEqual(leftHandOperand, rightHandOperand, options) {
|
||
|
var leftHandKeys = getEnumerableKeys(leftHandOperand);
|
||
|
var rightHandKeys = getEnumerableKeys(rightHandOperand);
|
||
|
if (leftHandKeys.length && leftHandKeys.length === rightHandKeys.length) {
|
||
|
leftHandKeys.sort();
|
||
|
rightHandKeys.sort();
|
||
|
if (iterableEqual(leftHandKeys, rightHandKeys) === false) {
|
||
|
return false;
|
||
|
}
|
||
|
return keysEqual(leftHandOperand, rightHandOperand, leftHandKeys, options);
|
||
|
}
|
||
|
|
||
|
var leftHandEntries = getIteratorEntries(leftHandOperand);
|
||
|
var rightHandEntries = getIteratorEntries(rightHandOperand);
|
||
|
if (leftHandEntries.length && leftHandEntries.length === rightHandEntries.length) {
|
||
|
leftHandEntries.sort();
|
||
|
rightHandEntries.sort();
|
||
|
return iterableEqual(leftHandEntries, rightHandEntries, options);
|
||
|
}
|
||
|
|
||
|
if (leftHandKeys.length === 0 &&
|
||
|
leftHandEntries.length === 0 &&
|
||
|
rightHandKeys.length === 0 &&
|
||
|
rightHandEntries.length === 0) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* Returns true if the argument is a primitive.
|
||
|
*
|
||
|
* This intentionally returns true for all objects that can be compared by reference,
|
||
|
* including functions and symbols.
|
||
|
*
|
||
|
* @param {Mixed} value
|
||
|
* @return {Boolean} result
|
||
|
*/
|
||
|
function isPrimitive(value) {
|
||
|
return value === null || typeof value !== 'object';
|
||
|
}
|
||
|
|
||
|
},{"type-detect":2}],2:[function(require,module,exports){
|
||
|
(function (global){
|
||
|
'use strict';
|
||
|
|
||
|
/* !
|
||
|
* type-detect
|
||
|
* Copyright(c) 2013 jake luer <jake@alogicalparadox.com>
|
||
|
* MIT Licensed
|
||
|
*/
|
||
|
var promiseExists = typeof Promise === 'function';
|
||
|
var globalObject = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : self; // eslint-disable-line
|
||
|
var isDom = 'location' in globalObject && 'document' in globalObject;
|
||
|
var symbolExists = typeof Symbol !== 'undefined';
|
||
|
var mapExists = typeof Map !== 'undefined';
|
||
|
var setExists = typeof Set !== 'undefined';
|
||
|
var weakMapExists = typeof WeakMap !== 'undefined';
|
||
|
var weakSetExists = typeof WeakSet !== 'undefined';
|
||
|
var dataViewExists = typeof DataView !== 'undefined';
|
||
|
var symbolIteratorExists = symbolExists && typeof Symbol.iterator !== 'undefined';
|
||
|
var symbolToStringTagExists = symbolExists && typeof Symbol.toStringTag !== 'undefined';
|
||
|
var setEntriesExists = setExists && typeof Set.prototype.entries === 'function';
|
||
|
var mapEntriesExists = mapExists && typeof Map.prototype.entries === 'function';
|
||
|
var setIteratorPrototype = setEntriesExists && Object.getPrototypeOf(new Set().entries());
|
||
|
var mapIteratorPrototype = mapEntriesExists && Object.getPrototypeOf(new Map().entries());
|
||
|
var arrayIteratorExists = symbolIteratorExists && typeof Array.prototype[Symbol.iterator] === 'function';
|
||
|
var arrayIteratorPrototype = arrayIteratorExists && Object.getPrototypeOf([][Symbol.iterator]());
|
||
|
var stringIteratorExists = symbolIteratorExists && typeof String.prototype[Symbol.iterator] === 'function';
|
||
|
var stringIteratorPrototype = stringIteratorExists && Object.getPrototypeOf(''[Symbol.iterator]());
|
||
|
var toStringLeftSliceLength = 8;
|
||
|
var toStringRightSliceLength = -1;
|
||
|
/**
|
||
|
* ### typeOf (obj)
|
||
|
*
|
||
|
* Uses `Object.prototype.toString` to determine the type of an object,
|
||
|
* normalising behaviour across engine versions & well optimised.
|
||
|
*
|
||
|
* @param {Mixed} object
|
||
|
* @return {String} object type
|
||
|
* @api public
|
||
|
*/
|
||
|
module.exports = function typeDetect(obj) {
|
||
|
/* ! Speed optimisation
|
||
|
* Pre:
|
||
|
* string literal x 3,039,035 ops/sec ±1.62% (78 runs sampled)
|
||
|
* boolean literal x 1,424,138 ops/sec ±4.54% (75 runs sampled)
|
||
|
* number literal x 1,653,153 ops/sec ±1.91% (82 runs sampled)
|
||
|
* undefined x 9,978,660 ops/sec ±1.92% (75 runs sampled)
|
||
|
* function x 2,556,769 ops/sec ±1.73% (77 runs sampled)
|
||
|
* Post:
|
||
|
* string literal x 38,564,796 ops/sec ±1.15% (79 runs sampled)
|
||
|
* boolean literal x 31,148,940 ops/sec ±1.10% (79 runs sampled)
|
||
|
* number literal x 32,679,330 ops/sec ±1.90% (78 runs sampled)
|
||
|
* undefined x 32,363,368 ops/sec ±1.07% (82 runs sampled)
|
||
|
* function x 31,296,870 ops/sec ±0.96% (83 runs sampled)
|
||
|
*/
|
||
|
var typeofObj = typeof obj;
|
||
|
if (typeofObj !== 'object') {
|
||
|
return typeofObj;
|
||
|
}
|
||
|
|
||
|
/* ! Speed optimisation
|
||
|
* Pre:
|
||
|
* null x 28,645,765 ops/sec ±1.17% (82 runs sampled)
|
||
|
* Post:
|
||
|
* null x 36,428,962 ops/sec ±1.37% (84 runs sampled)
|
||
|
*/
|
||
|
if (obj === null) {
|
||
|
return 'null';
|
||
|
}
|
||
|
|
||
|
/* ! Spec Conformance
|
||
|
* Test: `Object.prototype.toString.call(window)``
|
||
|
* - Node === "[object global]"
|
||
|
* - Chrome === "[object global]"
|
||
|
* - Firefox === "[object Window]"
|
||
|
* - PhantomJS === "[object Window]"
|
||
|
* - Safari === "[object Window]"
|
||
|
* - IE 11 === "[object Window]"
|
||
|
* - IE Edge === "[object Window]"
|
||
|
* Test: `Object.prototype.toString.call(this)``
|
||
|
* - Chrome Worker === "[object global]"
|
||
|
* - Firefox Worker === "[object DedicatedWorkerGlobalScope]"
|
||
|
* - Safari Worker === "[object DedicatedWorkerGlobalScope]"
|
||
|
* - IE 11 Worker === "[object WorkerGlobalScope]"
|
||
|
* - IE Edge Worker === "[object WorkerGlobalScope]"
|
||
|
*/
|
||
|
if (obj === globalObject) {
|
||
|
return 'global';
|
||
|
}
|
||
|
|
||
|
/* ! Speed optimisation
|
||
|
* Pre:
|
||
|
* array literal x 2,888,352 ops/sec ±0.67% (82 runs sampled)
|
||
|
* Post:
|
||
|
* array literal x 22,479,650 ops/sec ±0.96% (81 runs sampled)
|
||
|
*/
|
||
|
if (
|
||
|
Array.isArray(obj) &&
|
||
|
(symbolToStringTagExists === false || !(Symbol.toStringTag in obj))
|
||
|
) {
|
||
|
return 'Array';
|
||
|
}
|
||
|
|
||
|
if (isDom) {
|
||
|
/* ! Spec Conformance
|
||
|
* (https://html.spec.whatwg.org/multipage/browsers.html#location)
|
||
|
* WhatWG HTML$7.7.3 - The `Location` interface
|
||
|
* Test: `Object.prototype.toString.call(window.location)``
|
||
|
* - IE <=11 === "[object Object]"
|
||
|
* - IE Edge <=13 === "[object Object]"
|
||
|
*/
|
||
|
if (obj === globalObject.location) {
|
||
|
return 'Location';
|
||
|
}
|
||
|
|
||
|
/* ! Spec Conformance
|
||
|
* (https://html.spec.whatwg.org/#document)
|
||
|
* WhatWG HTML$3.1.1 - The `Document` object
|
||
|
* Note: Most browsers currently adher to the W3C DOM Level 2 spec
|
||
|
* (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-26809268)
|
||
|
* which suggests that browsers should use HTMLTableCellElement for
|
||
|
* both TD and TH elements. WhatWG separates these.
|
||
|
* WhatWG HTML states:
|
||
|
* > For historical reasons, Window objects must also have a
|
||
|
* > writable, configurable, non-enumerable property named
|
||
|
* > HTMLDocument whose value is the Document interface object.
|
||
|
* Test: `Object.prototype.toString.call(document)``
|
||
|
* - Chrome === "[object HTMLDocument]"
|
||
|
* - Firefox === "[object HTMLDocument]"
|
||
|
* - Safari === "[object HTMLDocument]"
|
||
|
* - IE <=10 === "[object Document]"
|
||
|
* - IE 11 === "[object HTMLDocument]"
|
||
|
* - IE Edge <=13 === "[object HTMLDocument]"
|
||
|
*/
|
||
|
if (obj === globalObject.document) {
|
||
|
return 'Document';
|
||
|
}
|
||
|
|
||
|
/* ! Spec Conformance
|
||
|
* (https://html.spec.whatwg.org/multipage/webappapis.html#mimetypearray)
|
||
|
* WhatWG HTML$8.6.1.5 - Plugins - Interface MimeTypeArray
|
||
|
* Test: `Object.prototype.toString.call(navigator.mimeTypes)``
|
||
|
* - IE <=10 === "[object MSMimeTypesCollection]"
|
||
|
*/
|
||
|
if (obj === (globalObject.navigator || {}).mimeTypes) {
|
||
|
return 'MimeTypeArray';
|
||
|
}
|
||
|
|
||
|
/* ! Spec Conformance
|
||
|
* (https://html.spec.whatwg.org/multipage/webappapis.html#pluginarray)
|
||
|
* WhatWG HTML$8.6.1.5 - Plugins - Interface PluginArray
|
||
|
* Test: `Object.prototype.toString.call(navigator.plugins)``
|
||
|
* - IE <=10 === "[object MSPluginsCollection]"
|
||
|
*/
|
||
|
if (obj === (globalObject.navigator || {}).plugins) {
|
||
|
return 'PluginArray';
|
||
|
}
|
||
|
|
||
|
/* ! Spec Conformance
|
||
|
* (https://html.spec.whatwg.org/multipage/webappapis.html#pluginarray)
|
||
|
* WhatWG HTML$4.4.4 - The `blockquote` element - Interface `HTMLQuoteElement`
|
||
|
* Test: `Object.prototype.toString.call(document.createElement('blockquote'))``
|
||
|
* - IE <=10 === "[object HTMLBlockElement]"
|
||
|
*/
|
||
|
if (obj instanceof HTMLElement && obj.tagName === 'BLOCKQUOTE') {
|
||
|
return 'HTMLQuoteElement';
|
||
|
}
|
||
|
|
||
|
/* ! Spec Conformance
|
||
|
* (https://html.spec.whatwg.org/#htmltabledatacellelement)
|
||
|
* WhatWG HTML$4.9.9 - The `td` element - Interface `HTMLTableDataCellElement`
|
||
|
* Note: Most browsers currently adher to the W3C DOM Level 2 spec
|
||
|
* (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-82915075)
|
||
|
* which suggests that browsers should use HTMLTableCellElement for
|
||
|
* both TD and TH elements. WhatWG separates these.
|
||
|
* Test: Object.prototype.toString.call(document.createElement('td'))
|
||
|
* - Chrome === "[object HTMLTableCellElement]"
|
||
|
* - Firefox === "[object HTMLTableCellElement]"
|
||
|
* - Safari === "[object HTMLTableCellElement]"
|
||
|
*/
|
||
|
if (obj instanceof HTMLElement && obj.tagName === 'TD') {
|
||
|
return 'HTMLTableDataCellElement';
|
||
|
}
|
||
|
|
||
|
/* ! Spec Conformance
|
||
|
* (https://html.spec.whatwg.org/#htmltableheadercellelement)
|
||
|
* WhatWG HTML$4.9.9 - The `td` element - Interface `HTMLTableHeaderCellElement`
|
||
|
* Note: Most browsers currently adher to the W3C DOM Level 2 spec
|
||
|
* (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-82915075)
|
||
|
* which suggests that browsers should use HTMLTableCellElement for
|
||
|
* both TD and TH elements. WhatWG separates these.
|
||
|
* Test: Object.prototype.toString.call(document.createElement('th'))
|
||
|
* - Chrome === "[object HTMLTableCellElement]"
|
||
|
* - Firefox === "[object HTMLTableCellElement]"
|
||
|
* - Safari === "[object HTMLTableCellElement]"
|
||
|
*/
|
||
|
if (obj instanceof HTMLElement && obj.tagName === 'TH') {
|
||
|
return 'HTMLTableHeaderCellElement';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* ! Speed optimisation
|
||
|
* Pre:
|
||
|
* Float64Array x 625,644 ops/sec ±1.58% (80 runs sampled)
|
||
|
* Float32Array x 1,279,852 ops/sec ±2.91% (77 runs sampled)
|
||
|
* Uint32Array x 1,178,185 ops/sec ±1.95% (83 runs sampled)
|
||
|
* Uint16Array x 1,008,380 ops/sec ±2.25% (80 runs sampled)
|
||
|
* Uint8Array x 1,128,040 ops/sec ±2.11% (81 runs sampled)
|
||
|
* Int32Array x 1,170,119 ops/sec ±2.88% (80 runs sampled)
|
||
|
* Int16Array x 1,176,348 ops/sec ±5.79% (86 runs sampled)
|
||
|
* Int8Array x 1,058,707 ops/sec ±4.94% (77 runs sampled)
|
||
|
* Uint8ClampedArray x 1,110,633 ops/sec ±4.20% (80 runs sampled)
|
||
|
* Post:
|
||
|
* Float64Array x 7,105,671 ops/sec ±13.47% (64 runs sampled)
|
||
|
* Float32Array x 5,887,912 ops/sec ±1.46% (82 runs sampled)
|
||
|
* Uint32Array x 6,491,661 ops/sec ±1.76% (79 runs sampled)
|
||
|
* Uint16Array x 6,559,795 ops/sec ±1.67% (82 runs sampled)
|
||
|
* Uint8Array x 6,463,966 ops/sec ±1.43% (85 runs sampled)
|
||
|
* Int32Array x 5,641,841 ops/sec ±3.49% (81 runs sampled)
|
||
|
* Int16Array x 6,583,511 ops/sec ±1.98% (80 runs sampled)
|
||
|
* Int8Array x 6,606,078 ops/sec ±1.74% (81 runs sampled)
|
||
|
* Uint8ClampedArray x 6,602,224 ops/sec ±1.77% (83 runs sampled)
|
||
|
*/
|
||
|
var stringTag = (symbolToStringTagExists && obj[Symbol.toStringTag]);
|
||
|
if (typeof stringTag === 'string') {
|
||
|
return stringTag;
|
||
|
}
|
||
|
|
||
|
var objPrototype = Object.getPrototypeOf(obj);
|
||
|
/* ! Speed optimisation
|
||
|
* Pre:
|
||
|
* regex literal x 1,772,385 ops/sec ±1.85% (77 runs sampled)
|
||
|
* regex constructor x 2,143,634 ops/sec ±2.46% (78 runs sampled)
|
||
|
* Post:
|
||
|
* regex literal x 3,928,009 ops/sec ±0.65% (78 runs sampled)
|
||
|
* regex constructor x 3,931,108 ops/sec ±0.58% (84 runs sampled)
|
||
|
*/
|
||
|
if (objPrototype === RegExp.prototype) {
|
||
|
return 'RegExp';
|
||
|
}
|
||
|
|
||
|
/* ! Speed optimisation
|
||
|
* Pre:
|
||
|
* date x 2,130,074 ops/sec ±4.42% (68 runs sampled)
|
||
|
* Post:
|
||
|
* date x 3,953,779 ops/sec ±1.35% (77 runs sampled)
|
||
|
*/
|
||
|
if (objPrototype === Date.prototype) {
|
||
|
return 'Date';
|
||
|
}
|
||
|
|
||
|
/* ! Spec Conformance
|
||
|
* (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-promise.prototype-@@tostringtag)
|
||
|
* ES6$25.4.5.4 - Promise.prototype[@@toStringTag] should be "Promise":
|
||
|
* Test: `Object.prototype.toString.call(Promise.resolve())``
|
||
|
* - Chrome <=47 === "[object Object]"
|
||
|
* - Edge <=20 === "[object Object]"
|
||
|
* - Firefox 29-Latest === "[object Promise]"
|
||
|
* - Safari 7.1-Latest === "[object Promise]"
|
||
|
*/
|
||
|
if (promiseExists && objPrototype === Promise.prototype) {
|
||
|
return 'Promise';
|
||
|
}
|
||
|
|
||
|
/* ! Speed optimisation
|
||
|
* Pre:
|
||
|
* set x 2,222,186 ops/sec ±1.31% (82 runs sampled)
|
||
|
* Post:
|
||
|
* set x 4,545,879 ops/sec ±1.13% (83 runs sampled)
|
||
|
*/
|
||
|
if (setExists && objPrototype === Set.prototype) {
|
||
|
return 'Set';
|
||
|
}
|
||
|
|
||
|
/* ! Speed optimisation
|
||
|
* Pre:
|
||
|
* map x 2,396,842 ops/sec ±1.59% (81 runs sampled)
|
||
|
* Post:
|
||
|
* map x 4,183,945 ops/sec ±6.59% (82 runs sampled)
|
||
|
*/
|
||
|
if (mapExists && objPrototype === Map.prototype) {
|
||
|
return 'Map';
|
||
|
}
|
||
|
|
||
|
/* ! Speed optimisation
|
||
|
* Pre:
|
||
|
* weakset x 1,323,220 ops/sec ±2.17% (76 runs sampled)
|
||
|
* Post:
|
||
|
* weakset x 4,237,510 ops/sec ±2.01% (77 runs sampled)
|
||
|
*/
|
||
|
if (weakSetExists && objPrototype === WeakSet.prototype) {
|
||
|
return 'WeakSet';
|
||
|
}
|
||
|
|
||
|
/* ! Speed optimisation
|
||
|
* Pre:
|
||
|
* weakmap x 1,500,260 ops/sec ±2.02% (78 runs sampled)
|
||
|
* Post:
|
||
|
* weakmap x 3,881,384 ops/sec ±1.45% (82 runs sampled)
|
||
|
*/
|
||
|
if (weakMapExists && objPrototype === WeakMap.prototype) {
|
||
|
return 'WeakMap';
|
||
|
}
|
||
|
|
||
|
/* ! Spec Conformance
|
||
|
* (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-dataview.prototype-@@tostringtag)
|
||
|
* ES6$24.2.4.21 - DataView.prototype[@@toStringTag] should be "DataView":
|
||
|
* Test: `Object.prototype.toString.call(new DataView(new ArrayBuffer(1)))``
|
||
|
* - Edge <=13 === "[object Object]"
|
||
|
*/
|
||
|
if (dataViewExists && objPrototype === DataView.prototype) {
|
||
|
return 'DataView';
|
||
|
}
|
||
|
|
||
|
/* ! Spec Conformance
|
||
|
* (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%mapiteratorprototype%-@@tostringtag)
|
||
|
* ES6$23.1.5.2.2 - %MapIteratorPrototype%[@@toStringTag] should be "Map Iterator":
|
||
|
* Test: `Object.prototype.toString.call(new Map().entries())``
|
||
|
* - Edge <=13 === "[object Object]"
|
||
|
*/
|
||
|
if (mapExists && objPrototype === mapIteratorPrototype) {
|
||
|
return 'Map Iterator';
|
||
|
}
|
||
|
|
||
|
/* ! Spec Conformance
|
||
|
* (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%setiteratorprototype%-@@tostringtag)
|
||
|
* ES6$23.2.5.2.2 - %SetIteratorPrototype%[@@toStringTag] should be "Set Iterator":
|
||
|
* Test: `Object.prototype.toString.call(new Set().entries())``
|
||
|
* - Edge <=13 === "[object Object]"
|
||
|
*/
|
||
|
if (setExists && objPrototype === setIteratorPrototype) {
|
||
|
return 'Set Iterator';
|
||
|
}
|
||
|
|
||
|
/* ! Spec Conformance
|
||
|
* (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%arrayiteratorprototype%-@@tostringtag)
|
||
|
* ES6$22.1.5.2.2 - %ArrayIteratorPrototype%[@@toStringTag] should be "Array Iterator":
|
||
|
* Test: `Object.prototype.toString.call([][Symbol.iterator]())``
|
||
|
* - Edge <=13 === "[object Object]"
|
||
|
*/
|
||
|
if (arrayIteratorExists && objPrototype === arrayIteratorPrototype) {
|
||
|
return 'Array Iterator';
|
||
|
}
|
||
|
|
||
|
/* ! Spec Conformance
|
||
|
* (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%stringiteratorprototype%-@@tostringtag)
|
||
|
* ES6$21.1.5.2.2 - %StringIteratorPrototype%[@@toStringTag] should be "String Iterator":
|
||
|
* Test: `Object.prototype.toString.call(''[Symbol.iterator]())``
|
||
|
* - Edge <=13 === "[object Object]"
|
||
|
*/
|
||
|
if (stringIteratorExists && objPrototype === stringIteratorPrototype) {
|
||
|
return 'String Iterator';
|
||
|
}
|
||
|
|
||
|
/* ! Speed optimisation
|
||
|
* Pre:
|
||
|
* object from null x 2,424,320 ops/sec ±1.67% (76 runs sampled)
|
||
|
* Post:
|
||
|
* object from null x 5,838,000 ops/sec ±0.99% (84 runs sampled)
|
||
|
*/
|
||
|
if (objPrototype === null) {
|
||
|
return 'Object';
|
||
|
}
|
||
|
|
||
|
return Object
|
||
|
.prototype
|
||
|
.toString
|
||
|
.call(obj)
|
||
|
.slice(toStringLeftSliceLength, toStringRightSliceLength);
|
||
|
};
|
||
|
|
||
|
module.exports.typeDetect = module.exports;
|
||
|
|
||
|
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
||
|
},{}]},{},[1])(1)
|
||
|
});
|