UNPKG

es5-shim

Version:

ECMAScript 5 compatibility shims for legacy JavaScript engines

1,246 lines (1,135 loc) 95.4 kB
/*! * https://github.com/es-shims/es5-shim * @license es5-shim Copyright 2009-2020 by contributors, MIT License * see https://github.com/es-shims/es5-shim/blob/master/LICENSE */ // vim: ts=4 sts=4 sw=4 expandtab // Add semicolon to prevent IIFE from being passed as argument to concatenated code. ; // eslint-disable-line no-extra-semi // UMD (Universal Module Definition) // see https://github.com/umdjs/umd/blob/master/templates/returnExports.js (function (root, factory) { 'use strict'; /* global define */ if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define(factory); } else if (typeof exports === 'object') { // Node. Does not work with strict CommonJS, but // only CommonJS-like enviroments that support module.exports, // like Node. module.exports = factory(); } else { // Browser globals (root is window) root.returnExports = factory(); // eslint-disable-line no-param-reassign } }(this, function () { /** * Brings an environment as close to ECMAScript 5 compliance * as is possible with the facilities of erstwhile engines. * * Annotated ES5: https://es5.github.io/ (specific links below) * ES5 Spec: https://www.ecma-international.org/wp-content/uploads/ECMA-262_5.1_edition_june_2011.pdf * Required reading: https://javascriptweblog.wordpress.com/2011/12/05/extending-javascript-natives/ */ // Shortcut to an often accessed properties, in order to avoid multiple // dereference that costs universally. This also holds a reference to known-good // functions. var $Array = Array; var ArrayPrototype = $Array.prototype; var $Object = Object; var ObjectPrototype = $Object.prototype; var $Function = Function; var FunctionPrototype = $Function.prototype; var $String = String; var StringPrototype = $String.prototype; var $Number = Number; var NumberPrototype = $Number.prototype; var array_slice = ArrayPrototype.slice; var array_splice = ArrayPrototype.splice; var array_push = ArrayPrototype.push; var array_unshift = ArrayPrototype.unshift; var array_concat = ArrayPrototype.concat; var array_join = ArrayPrototype.join; var call = FunctionPrototype.call; var apply = FunctionPrototype.apply; var max = Math.max; var min = Math.min; var floor = Math.floor; var abs = Math.abs; var pow = Math.pow; var round = Math.round; var log = Math.log; var LOG10E = Math.LOG10E; var log10 = Math.log10 || function log10(value) { return log(value) * LOG10E; }; // Having a toString local variable name breaks in Opera so use to_string. var to_string = ObjectPrototype.toString; /* eslint-disable one-var-declaration-per-line, no-redeclare, max-statements-per-line */ var hasToStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol'; var isCallable; /* inlined from https://npmjs.com/is-callable */ var fnToStr = Function.prototype.toString, constructorRegex = /^\s*class /, isES6ClassFn = function isES6ClassFn(value) { try { var fnStr = fnToStr.call(value); var singleStripped = fnStr.replace(/\/\/.*\n/g, ''); var multiStripped = singleStripped.replace(/\/\*[.\s\S]*\*\//g, ''); var spaceStripped = multiStripped.replace(/\n/mg, ' ').replace(/ {2}/g, ' '); return constructorRegex.test(spaceStripped); } catch (e) { return false; /* not a function */ } }, tryFunctionObject = function tryFunctionObject(value) { try { if (isES6ClassFn(value)) { return false; } fnToStr.call(value); return true; } catch (e) { return false; } }, fnClass = '[object Function]', genClass = '[object GeneratorFunction]', isCallable = function isCallable(value) { if (!value) { return false; } if (typeof value !== 'function' && typeof value !== 'object') { return false; } if (hasToStringTag) { return tryFunctionObject(value); } if (isES6ClassFn(value)) { return false; } var strClass = to_string.call(value); return strClass === fnClass || strClass === genClass; }; var isRegex; /* inlined from https://npmjs.com/is-regex */ var regexExec = RegExp.prototype.exec, tryRegexExec = function tryRegexExec(value) { try { regexExec.call(value); return true; } catch (e) { return false; } }, regexClass = '[object RegExp]'; isRegex = function isRegex(value) { if (typeof value !== 'object') { return false; } return hasToStringTag ? tryRegexExec(value) : to_string.call(value) === regexClass; }; var isString; /* inlined from https://npmjs.com/is-string */ var strValue = String.prototype.valueOf, tryStringObject = function tryStringObject(value) { try { strValue.call(value); return true; } catch (e) { return false; } }, stringClass = '[object String]'; isString = function isString(value) { if (typeof value === 'string') { return true; } if (typeof value !== 'object') { return false; } return hasToStringTag ? tryStringObject(value) : to_string.call(value) === stringClass; }; /* eslint-enable one-var-declaration-per-line, no-redeclare, max-statements-per-line */ /* inlined from https://npmjs.com/define-properties */ var supportsDescriptors = $Object.defineProperty && (function () { try { var obj = {}; $Object.defineProperty(obj, 'x', { enumerable: false, value: obj }); // eslint-disable-next-line no-unreachable-loop, max-statements-per-line for (var _ in obj) { return false; } // jscs:ignore disallowUnusedVariables return obj.x === obj; } catch (e) { /* this is ES3 */ return false; } }()); var defineProperties = (function (has) { // Define configurable, writable, and non-enumerable props // if they don't exist. var defineProperty; if (supportsDescriptors) { defineProperty = function (object, name, method, forceAssign) { if (!forceAssign && (name in object)) { return; } $Object.defineProperty(object, name, { configurable: true, enumerable: false, writable: true, value: method }); }; } else { defineProperty = function (object, name, method, forceAssign) { if (!forceAssign && (name in object)) { return; } object[name] = method; // eslint-disable-line no-param-reassign }; } return function defineProperties(object, map, forceAssign) { for (var name in map) { if (has.call(map, name)) { defineProperty(object, name, map[name], forceAssign); } } }; }(ObjectPrototype.hasOwnProperty)); // this is needed in Chrome 15 (probably earlier) - 36 // https://bugs.chromium.org/p/v8/issues/detail?id=3334 if ($Object.defineProperty && supportsDescriptors) { var F = function () {}; var toStringSentinel = {}; var sentinel = { toString: toStringSentinel }; $Object.defineProperty(F, 'prototype', { value: sentinel, writable: false }); if ((new F()).toString !== toStringSentinel) { var $dP = $Object.defineProperty; var $gOPD = $Object.getOwnPropertyDescriptor; defineProperties($Object, { defineProperty: function defineProperty(o, k, d) { var key = $String(k); if (typeof o === 'function' && key === 'prototype') { var desc = $gOPD(o, key); if (desc.writable && !d.writable && 'value' in d) { try { o[key] = d.value; // eslint-disable-line no-param-reassign } catch (e) { /**/ } } return $dP(o, key, { configurable: 'configurable' in d ? d.configurable : desc.configurable, enumerable: 'enumerable' in d ? d.enumerable : desc.enumerable, writable: d.writable }); } return $dP(o, key, d); } }, true); } } // // Util // ====== // /* replaceable with https://npmjs.com/package/es-abstract /helpers/isPrimitive */ var isPrimitive = function isPrimitive(input) { var type = typeof input; return input === null || (type !== 'object' && type !== 'function'); }; var isActualNaN = $Number.isNaN || function isActualNaN(x) { return x !== x; }; var ES = { // ES5 9.4 // https://es5.github.io/#x9.4 // http://jsperf.com/to-integer /* replaceable with https://npmjs.com/package/es-abstract ES5.ToInteger */ ToInteger: function ToInteger(num) { var n = +num; if (isActualNaN(n)) { n = 0; } else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) { n = (n > 0 || -1) * floor(abs(n)); } return n; }, /* replaceable with https://npmjs.com/package/es-abstract ES5.ToPrimitive */ ToPrimitive: function ToPrimitive(input) { var val, valueOf, toStr; if (isPrimitive(input)) { return input; } valueOf = input.valueOf; if (isCallable(valueOf)) { val = valueOf.call(input); if (isPrimitive(val)) { return val; } } toStr = input.toString; if (isCallable(toStr)) { val = toStr.call(input); if (isPrimitive(val)) { return val; } } throw new TypeError(); }, // ES5 9.9 // https://es5.github.io/#x9.9 /* replaceable with https://npmjs.com/package/es-abstract ES5.ToObject */ ToObject: function (o) { if (o == null) { // this matches both null and undefined throw new TypeError("can't convert " + o + ' to object'); } return $Object(o); }, /* replaceable with https://npmjs.com/package/es-abstract ES5.ToUint32 */ ToUint32: function ToUint32(x) { return x >>> 0; } }; // // Function // ======== // // ES-5 15.3.4.5 // https://es5.github.io/#x15.3.4.5 var Empty = function Empty() {}; defineProperties(FunctionPrototype, { bind: function bind(that) { // .length is 1 // 1. Let Target be the this value. var target = this; // 2. If IsCallable(Target) is false, throw a TypeError exception. if (!isCallable(target)) { throw new TypeError('Function.prototype.bind called on incompatible ' + target); } // 3. Let A be a new (possibly empty) internal list of all of the // argument values provided after thisArg (arg1, arg2 etc), in order. // XXX slicedArgs will stand in for "A" if used var args = array_slice.call(arguments, 1); // for normal call // 4. Let F be a new native ECMAScript object. // 11. Set the [[Prototype]] internal property of F to the standard // built-in Function prototype object as specified in 15.3.3.1. // 12. Set the [[Call]] internal property of F as described in // 15.3.4.5.1. // 13. Set the [[Construct]] internal property of F as described in // 15.3.4.5.2. // 14. Set the [[HasInstance]] internal property of F as described in // 15.3.4.5.3. var bound; var binder = function () { if (this instanceof bound) { // 15.3.4.5.2 [[Construct]] // When the [[Construct]] internal method of a function object, // F that was created using the bind function is called with a // list of arguments ExtraArgs, the following steps are taken: // 1. Let target be the value of F's [[TargetFunction]] // internal property. // 2. If target has no [[Construct]] internal method, a // TypeError exception is thrown. // 3. Let boundArgs be the value of F's [[BoundArgs]] internal // property. // 4. Let args be a new list containing the same values as the // list boundArgs in the same order followed by the same // values as the list ExtraArgs in the same order. // 5. Return the result of calling the [[Construct]] internal // method of target providing args as the arguments. var result = apply.call( target, this, array_concat.call(args, array_slice.call(arguments)) ); if ($Object(result) === result) { return result; } return this; } // 15.3.4.5.1 [[Call]] // When the [[Call]] internal method of a function object, F, // which was created using the bind function is called with a // this value and a list of arguments ExtraArgs, the following // steps are taken: // 1. Let boundArgs be the value of F's [[BoundArgs]] internal // property. // 2. Let boundThis be the value of F's [[BoundThis]] internal // property. // 3. Let target be the value of F's [[TargetFunction]] internal // property. // 4. Let args be a new list containing the same values as the // list boundArgs in the same order followed by the same // values as the list ExtraArgs in the same order. // 5. Return the result of calling the [[Call]] internal method // of target providing boundThis as the this value and // providing args as the arguments. // equiv: target.call(this, ...boundArgs, ...args) return apply.call( target, that, array_concat.call(args, array_slice.call(arguments)) ); }; // 15. If the [[Class]] internal property of Target is "Function", then // a. Let L be the length property of Target minus the length of A. // b. Set the length own property of F to either 0 or L, whichever is // larger. // 16. Else set the length own property of F to 0. var boundLength = max(0, target.length - args.length); // 17. Set the attributes of the length own property of F to the values // specified in 15.3.5.1. var boundArgs = []; for (var i = 0; i < boundLength; i++) { array_push.call(boundArgs, '$' + i); } // XXX Build a dynamic function with desired amount of arguments is the only // way to set the length property of a function. // In environments where Content Security Policies enabled (Chrome extensions, // for ex.) all use of eval or Function costructor throws an exception. // However in all of these environments Function.prototype.bind exists // and so this code will never be executed. bound = $Function('binder', 'return function (' + array_join.call(boundArgs, ',') + '){ return binder.apply(this, arguments); }')(binder); if (target.prototype) { Empty.prototype = target.prototype; bound.prototype = new Empty(); // Clean up dangling references. Empty.prototype = null; } // TODO // 18. Set the [[Extensible]] internal property of F to true. // TODO // 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3). // 20. Call the [[DefineOwnProperty]] internal method of F with // arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]: // thrower, [[Enumerable]]: false, [[Configurable]]: false}, and // false. // 21. Call the [[DefineOwnProperty]] internal method of F with // arguments "arguments", PropertyDescriptor {[[Get]]: thrower, // [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, // and false. // TODO // NOTE Function objects created using Function.prototype.bind do not // have a prototype property or the [[Code]], [[FormalParameters]], and // [[Scope]] internal properties. // XXX can't delete prototype in pure-js. // 22. Return F. return bound; } }); // _Please note: Shortcuts are defined after `Function.prototype.bind` as we // use it in defining shortcuts. var owns = call.bind(ObjectPrototype.hasOwnProperty); var toStr = call.bind(ObjectPrototype.toString); var arraySlice = call.bind(array_slice); var arraySliceApply = apply.bind(array_slice); /* globals document */ if (typeof document === 'object' && document && document.documentElement) { try { arraySlice(document.documentElement.childNodes); } catch (e) { var origArraySlice = arraySlice; var origArraySliceApply = arraySliceApply; arraySlice = function arraySliceIE(arr) { var r = []; var i = arr.length; while (i-- > 0) { r[i] = arr[i]; } return origArraySliceApply(r, origArraySlice(arguments, 1)); }; arraySliceApply = function arraySliceApplyIE(arr, args) { return origArraySliceApply(arraySlice(arr), args); }; } } var strSlice = call.bind(StringPrototype.slice); var strSplit = call.bind(StringPrototype.split); var strIndexOf = call.bind(StringPrototype.indexOf); var pushCall = call.bind(array_push); var isEnum = call.bind(ObjectPrototype.propertyIsEnumerable); var arraySort = call.bind(ArrayPrototype.sort); // // Array // ===== // var isArray = $Array.isArray || function isArray(obj) { return toStr(obj) === '[object Array]'; }; // ES5 15.4.4.12 // https://es5.github.io/#x15.4.4.13 // Return len+argCount. // [bugfix, ielt8] // IE < 8 bug: [].unshift(0) === undefined but should be "1" var hasUnshiftReturnValueBug = [].unshift(0) !== 1; defineProperties(ArrayPrototype, { unshift: function () { array_unshift.apply(this, arguments); return this.length; } }, hasUnshiftReturnValueBug); // ES5 15.4.3.2 // https://es5.github.io/#x15.4.3.2 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray defineProperties($Array, { isArray: isArray }); // The IsCallable() check in the Array functions // has been replaced with a strict check on the // internal class of the object to trap cases where // the provided function was actually a regular // expression literal, which in V8 and // JavaScriptCore is a typeof "function". Only in // V8 are regular expression literals permitted as // reduce parameters, so it is desirable in the // general case for the shim to match the more // strict and common behavior of rejecting regular // expressions. // ES5 15.4.4.18 // https://es5.github.io/#x15.4.4.18 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/forEach // Check failure of by-index access of string characters (IE < 9) // and failure of `0 in boxedString` (Rhino) var boxedString = $Object('a'); var splitString = boxedString[0] !== 'a' || !(0 in boxedString); var properlyBoxesContext = function properlyBoxed(method) { // Check node 0.6.21 bug where third parameter is not boxed var properlyBoxesNonStrict = true; var properlyBoxesStrict = true; var threwException = false; if (method) { try { method.call('foo', function (_, __, context) { if (typeof context !== 'object') { properlyBoxesNonStrict = false; } }); method.call([1], function () { 'use strict'; properlyBoxesStrict = typeof this === 'string'; }, 'x'); } catch (e) { threwException = true; } } return !!method && !threwException && properlyBoxesNonStrict && properlyBoxesStrict; }; defineProperties(ArrayPrototype, { forEach: function forEach(callbackfn/*, thisArg*/) { var object = ES.ToObject(this); var self = splitString && isString(this) ? strSplit(this, '') : object; var i = -1; var length = ES.ToUint32(self.length); var T; if (arguments.length > 1) { T = arguments[1]; } // If no callback function or if callback is not a callable function if (!isCallable(callbackfn)) { throw new TypeError('Array.prototype.forEach callback must be a function'); } while (++i < length) { if (i in self) { // Invoke the callback function with call, passing arguments: // context, property value, property key, thisArg object if (typeof T === 'undefined') { callbackfn(self[i], i, object); } else { callbackfn.call(T, self[i], i, object); } } } } }, !properlyBoxesContext(ArrayPrototype.forEach)); // ES5 15.4.4.19 // https://es5.github.io/#x15.4.4.19 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map defineProperties(ArrayPrototype, { map: function map(callbackfn/*, thisArg*/) { var object = ES.ToObject(this); var self = splitString && isString(this) ? strSplit(this, '') : object; var length = ES.ToUint32(self.length); var result = $Array(length); var T; if (arguments.length > 1) { T = arguments[1]; } // If no callback function or if callback is not a callable function if (!isCallable(callbackfn)) { throw new TypeError('Array.prototype.map callback must be a function'); } for (var i = 0; i < length; i++) { if (i in self) { if (typeof T === 'undefined') { result[i] = callbackfn(self[i], i, object); } else { result[i] = callbackfn.call(T, self[i], i, object); } } } return result; } }, !properlyBoxesContext(ArrayPrototype.map)); // ES5 15.4.4.20 // https://es5.github.io/#x15.4.4.20 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter defineProperties(ArrayPrototype, { filter: function filter(callbackfn/*, thisArg*/) { var object = ES.ToObject(this); var self = splitString && isString(this) ? strSplit(this, '') : object; var length = ES.ToUint32(self.length); var result = []; var value; var T; if (arguments.length > 1) { T = arguments[1]; } // If no callback function or if callback is not a callable function if (!isCallable(callbackfn)) { throw new TypeError('Array.prototype.filter callback must be a function'); } for (var i = 0; i < length; i++) { if (i in self) { value = self[i]; if (typeof T === 'undefined' ? callbackfn(value, i, object) : callbackfn.call(T, value, i, object)) { pushCall(result, value); } } } return result; } }, !properlyBoxesContext(ArrayPrototype.filter)); // ES5 15.4.4.16 // https://es5.github.io/#x15.4.4.16 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every defineProperties(ArrayPrototype, { every: function every(callbackfn/*, thisArg*/) { var object = ES.ToObject(this); var self = splitString && isString(this) ? strSplit(this, '') : object; var length = ES.ToUint32(self.length); var T; if (arguments.length > 1) { T = arguments[1]; } // If no callback function or if callback is not a callable function if (!isCallable(callbackfn)) { throw new TypeError('Array.prototype.every callback must be a function'); } for (var i = 0; i < length; i++) { if (i in self && !(typeof T === 'undefined' ? callbackfn(self[i], i, object) : callbackfn.call(T, self[i], i, object))) { return false; } } return true; } }, !properlyBoxesContext(ArrayPrototype.every)); // ES5 15.4.4.17 // https://es5.github.io/#x15.4.4.17 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some defineProperties(ArrayPrototype, { some: function some(callbackfn/*, thisArg */) { var object = ES.ToObject(this); var self = splitString && isString(this) ? strSplit(this, '') : object; var length = ES.ToUint32(self.length); var T; if (arguments.length > 1) { T = arguments[1]; } // If no callback function or if callback is not a callable function if (!isCallable(callbackfn)) { throw new TypeError('Array.prototype.some callback must be a function'); } for (var i = 0; i < length; i++) { if (i in self && (typeof T === 'undefined' ? callbackfn(self[i], i, object) : callbackfn.call(T, self[i], i, object))) { return true; } } return false; } }, !properlyBoxesContext(ArrayPrototype.some)); // ES5 15.4.4.21 // https://es5.github.io/#x15.4.4.21 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce var reduceCoercesToObject = false; if (ArrayPrototype.reduce) { reduceCoercesToObject = typeof ArrayPrototype.reduce.call('es5', function (_, __, ___, list) { return list; }) === 'object'; } defineProperties(ArrayPrototype, { reduce: function reduce(callbackfn/*, initialValue*/) { var object = ES.ToObject(this); var self = splitString && isString(this) ? strSplit(this, '') : object; var length = ES.ToUint32(self.length); // If no callback function or if callback is not a callable function if (!isCallable(callbackfn)) { throw new TypeError('Array.prototype.reduce callback must be a function'); } // no value to return if no initial value and an empty array if (length === 0 && arguments.length === 1) { throw new TypeError('reduce of empty array with no initial value'); } var i = 0; var result; if (arguments.length >= 2) { result = arguments[1]; } else { do { if (i in self) { result = self[i++]; break; } // if array contains no values, no initial value to return if (++i >= length) { throw new TypeError('reduce of empty array with no initial value'); } } while (true); } for (; i < length; i++) { if (i in self) { result = callbackfn(result, self[i], i, object); } } return result; } }, !reduceCoercesToObject); // ES5 15.4.4.22 // https://es5.github.io/#x15.4.4.22 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight var reduceRightCoercesToObject = false; if (ArrayPrototype.reduceRight) { reduceRightCoercesToObject = typeof ArrayPrototype.reduceRight.call('es5', function (_, __, ___, list) { return list; }) === 'object'; } defineProperties(ArrayPrototype, { reduceRight: function reduceRight(callbackfn/*, initial*/) { var object = ES.ToObject(this); var self = splitString && isString(this) ? strSplit(this, '') : object; var length = ES.ToUint32(self.length); // If no callback function or if callback is not a callable function if (!isCallable(callbackfn)) { throw new TypeError('Array.prototype.reduceRight callback must be a function'); } // no value to return if no initial value, empty array if (length === 0 && arguments.length === 1) { throw new TypeError('reduceRight of empty array with no initial value'); } var result; var i = length - 1; if (arguments.length >= 2) { result = arguments[1]; } else { do { if (i in self) { result = self[i--]; break; } // if array contains no values, no initial value to return if (--i < 0) { throw new TypeError('reduceRight of empty array with no initial value'); } } while (true); } if (i < 0) { return result; } do { if (i in self) { result = callbackfn(result, self[i], i, object); } } while (i--); return result; } }, !reduceRightCoercesToObject); // ES5 15.4.4.14 // https://es5.github.io/#x15.4.4.14 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf var hasFirefox2IndexOfBug = ArrayPrototype.indexOf && [0, 1].indexOf(1, 2) !== -1; defineProperties(ArrayPrototype, { indexOf: function indexOf(searchElement/*, fromIndex */) { var self = splitString && isString(this) ? strSplit(this, '') : ES.ToObject(this); var length = ES.ToUint32(self.length); if (length === 0) { return -1; } var i = 0; if (arguments.length > 1) { i = ES.ToInteger(arguments[1]); } // handle negative indices i = i >= 0 ? i : max(0, length + i); for (; i < length; i++) { if (i in self && self[i] === searchElement) { return i; } } return -1; } }, hasFirefox2IndexOfBug); // ES5 15.4.4.15 // https://es5.github.io/#x15.4.4.15 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf var hasFirefox2LastIndexOfBug = ArrayPrototype.lastIndexOf && [0, 1].lastIndexOf(0, -3) !== -1; defineProperties(ArrayPrototype, { lastIndexOf: function lastIndexOf(searchElement/*, fromIndex */) { var self = splitString && isString(this) ? strSplit(this, '') : ES.ToObject(this); var length = ES.ToUint32(self.length); if (length === 0) { return -1; } var i = length - 1; if (arguments.length > 1) { i = min(i, ES.ToInteger(arguments[1])); } // handle negative indices i = i >= 0 ? i : length - abs(i); for (; i >= 0; i--) { if (i in self && searchElement === self[i]) { return i; } } return -1; } }, hasFirefox2LastIndexOfBug); // ES5 15.4.4.12 // https://es5.github.io/#x15.4.4.12 var spliceNoopReturnsEmptyArray = (function () { var a = [1, 2]; var result = a.splice(); return a.length === 2 && isArray(result) && result.length === 0; }()); defineProperties(ArrayPrototype, { // Safari 5.0 bug where .splice() returns undefined splice: function splice(start, deleteCount) { if (arguments.length === 0) { return []; } return array_splice.apply(this, arguments); } }, !spliceNoopReturnsEmptyArray); var spliceWorksWithEmptyObject = (function () { var obj = {}; ArrayPrototype.splice.call(obj, 0, 0, 1); return obj.length === 1; }()); var hasES6Defaults = [0, 1, 2].splice(0).length === 3; defineProperties(ArrayPrototype, { splice: function splice(start, deleteCount) { if (arguments.length === 0) { return []; } var args = arguments; this.length = max(ES.ToInteger(this.length), 0); if (arguments.length > 0 && typeof deleteCount !== 'number') { args = arraySlice(arguments); if (args.length < 2) { pushCall(args, this.length - start); } else { args[1] = ES.ToInteger(deleteCount); } } return array_splice.apply(this, args); } }, !spliceWorksWithEmptyObject || !hasES6Defaults); var spliceWorksWithLargeSparseArrays = (function () { // Per https://github.com/es-shims/es5-shim/issues/295 // Safari 7/8 breaks with sparse arrays of size 1e5 or greater var arr = new $Array(1e5); // note: the index MUST be 8 or larger or the test will false pass arr[8] = 'x'; arr.splice(1, 1); // note: this test must be defined *after* the indexOf shim // per https://github.com/es-shims/es5-shim/issues/313 return arr.indexOf('x') === 7; }()); var spliceWorksWithSmallSparseArrays = (function () { // Per https://github.com/es-shims/es5-shim/issues/295 // Opera 12.15 breaks on this, no idea why. var n = 256; var arr = []; arr[n] = 'a'; arr.splice(n + 1, 0, 'b'); return arr[n] === 'a'; }()); defineProperties(ArrayPrototype, { splice: function splice(start, deleteCount) { var O = ES.ToObject(this); var A = []; var len = ES.ToUint32(O.length); var relativeStart = ES.ToInteger(start); var actualStart = relativeStart < 0 ? max((len + relativeStart), 0) : min(relativeStart, len); var actualDeleteCount = arguments.length === 0 ? 0 : arguments.length === 1 ? len - actualStart : min(max(ES.ToInteger(deleteCount), 0), len - actualStart); var k = 0; var from; while (k < actualDeleteCount) { from = $String(actualStart + k); if (owns(O, from)) { A[k] = O[from]; } k += 1; } var items = arraySlice(arguments, 2); var itemCount = items.length; var to; if (itemCount < actualDeleteCount) { k = actualStart; var maxK = len - actualDeleteCount; while (k < maxK) { from = $String(k + actualDeleteCount); to = $String(k + itemCount); if (owns(O, from)) { O[to] = O[from]; } else { delete O[to]; } k += 1; } k = len; var minK = len - actualDeleteCount + itemCount; while (k > minK) { delete O[k - 1]; k -= 1; } } else if (itemCount > actualDeleteCount) { k = len - actualDeleteCount; while (k > actualStart) { from = $String(k + actualDeleteCount - 1); to = $String(k + itemCount - 1); if (owns(O, from)) { O[to] = O[from]; } else { delete O[to]; } k -= 1; } } k = actualStart; for (var i = 0; i < items.length; ++i) { O[k] = items[i]; k += 1; } O.length = len - actualDeleteCount + itemCount; return A; } }, !spliceWorksWithLargeSparseArrays || !spliceWorksWithSmallSparseArrays); var originalJoin = ArrayPrototype.join; var hasStringJoinBug; try { hasStringJoinBug = Array.prototype.join.call('123', ',') !== '1,2,3'; } catch (e) { hasStringJoinBug = true; } if (hasStringJoinBug) { defineProperties(ArrayPrototype, { join: function join(separator) { var sep = typeof separator === 'undefined' ? ',' : separator; return originalJoin.call(isString(this) ? strSplit(this, '') : this, sep); } }, hasStringJoinBug); } var hasJoinUndefinedBug = [1, 2].join(undefined) !== '1,2'; if (hasJoinUndefinedBug) { defineProperties(ArrayPrototype, { join: function join(separator) { var sep = typeof separator === 'undefined' ? ',' : separator; return originalJoin.call(this, sep); } }, hasJoinUndefinedBug); } var pushShim = function push(item) { var O = ES.ToObject(this); var n = ES.ToUint32(O.length); var i = 0; while (i < arguments.length) { O[n + i] = arguments[i]; i += 1; } O.length = n + i; return n + i; }; var pushIsNotGeneric = (function () { var obj = {}; var result = Array.prototype.push.call(obj, undefined); return result !== 1 || obj.length !== 1 || typeof obj[0] !== 'undefined' || !owns(obj, 0); }()); defineProperties(ArrayPrototype, { push: function push(item) { if (isArray(this)) { return array_push.apply(this, arguments); } return pushShim.apply(this, arguments); } }, pushIsNotGeneric); // This fixes a very weird bug in Opera 10.6 when pushing `undefined var pushUndefinedIsWeird = (function () { var arr = []; var result = arr.push(undefined); return result !== 1 || arr.length !== 1 || typeof arr[0] !== 'undefined' || !owns(arr, 0); }()); defineProperties(ArrayPrototype, { push: pushShim }, pushUndefinedIsWeird); // ES5 15.2.3.14 // https://es5.github.io/#x15.4.4.10 // Fix boxed string bug defineProperties(ArrayPrototype, { slice: function (start, end) { var arr = isString(this) ? strSplit(this, '') : this; return arraySliceApply(arr, arguments); } }, splitString); var sortIgnoresNonFunctions = (function () { try { [1, 2].sort(null); } catch (e) { try { [1, 2].sort({}); } catch (e2) { return false; } } return true; }()); var sortThrowsOnRegex = (function () { // this is a problem in Firefox 4, in which `typeof /a/ === 'function'` try { [1, 2].sort(/a/); return false; } catch (e) {} return true; }()); var sortIgnoresUndefined = (function () { // applies in IE 8, for one. try { [1, 2].sort(undefined); return true; } catch (e) {} return false; }()); defineProperties(ArrayPrototype, { sort: function sort(compareFn) { if (typeof compareFn === 'undefined') { return arraySort(this); } if (!isCallable(compareFn)) { throw new TypeError('Array.prototype.sort callback must be a function'); } return arraySort(this, compareFn); } }, sortIgnoresNonFunctions || !sortIgnoresUndefined || !sortThrowsOnRegex); // // Object // ====== // // ES5 15.2.3.14 // https://es5.github.io/#x15.2.3.14 // https://web.archive.org/web/20140727042234/http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation // eslint-disable-next-line quote-props var hasDontEnumBug = !isEnum({ 'toString': null }, 'toString'); // jscs:ignore disallowQuotedKeysInObjects var hasProtoEnumBug = isEnum(function () {}, 'prototype'); var hasStringEnumBug = !owns('x', '0'); var equalsConstructorPrototype = function (o) { var ctor = o.constructor; return ctor && ctor.prototype === o; }; var excludedKeys = { $applicationCache: true, $console: true, $external: true, $frame: true, $frameElement: true, $frames: true, $innerHeight: true, $innerWidth: true, $onmozfullscreenchange: true, $onmozfullscreenerror: true, $outerHeight: true, $outerWidth: true, $pageXOffset: true, $pageYOffset: true, $parent: true, $scrollLeft: true, $scrollTop: true, $scrollX: true, $scrollY: true, $self: true, $webkitIndexedDB: true, $webkitStorageInfo: true, $window: true, $width: true, $height: true, $top: true, $localStorage: true }; var hasAutomationEqualityBug = (function () { /* globals window */ if (typeof window === 'undefined') { return false; } for (var k in window) { try { if (!excludedKeys['$' + k] && owns(window, k) && window[k] !== null && typeof window[k] === 'object') { equalsConstructorPrototype(window[k]); } } catch (e) { return true; } } return false; }()); var equalsConstructorPrototypeIfNotBuggy = function (object) { if (typeof window === 'undefined' || !hasAutomationEqualityBug) { return equalsConstructorPrototype(object); } try { return equalsConstructorPrototype(object); } catch (e) { return false; } }; var dontEnums = [ 'toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor' ]; var dontEnumsLength = dontEnums.length; // taken directly from https://github.com/ljharb/is-arguments/blob/master/index.js // can be replaced with require('is-arguments') if we ever use a build process instead var isStandardArguments = function isArguments(value) { return toStr(value) === '[object Arguments]'; }; var isLegacyArguments = function isArguments(value) { return value !== null && typeof value === 'object' && typeof value.length === 'number' && value.length >= 0 && !isArray(value) && isCallable(value.callee); }; var isArguments = isStandardArguments(arguments) ? isStandardArguments : isLegacyArguments; defineProperties($Object, { keys: function keys(object) { var isFn = isCallable(object); var isArgs = isArguments(object); var isObject = object !== null && typeof object === 'object'; var isStr = isObject && isString(object); if (!isObject && !isFn && !isArgs) { throw new TypeError('Object.keys called on a non-object'); } var theKeys = []; var skipProto = hasProtoEnumBug && isFn; if ((isStr && hasStringEnumBug) || isArgs) { for (var i = 0; i < object.length; ++i) { pushCall(theKeys, $String(i)); } } if (!isArgs) { for (var name in object) { if (!(skipProto && name === 'prototype') && owns(object, name)) { pushCall(theKeys, $String(name)); } } } if (hasDontEnumBug) { var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object); for (var j = 0; j < dontEnumsLength; j++) { var dontEnum = dontEnums[j]; if (!(skipConstructor && dontEnum === 'constructor') && owns(object, dontEnum)) { pushCall(theKeys, dontEnum); } } } return theKeys; } }); var keysWorksWithArguments = $Object.keys && (function () { // Safari 5.0 bug return $Object.keys(arguments).length === 2; }(1, 2)); var keysHasArgumentsLengthBug = $Object.keys && (function () { var argKeys = $Object.keys(arguments); return arguments.length !== 1 || argKeys.length !== 1 || argKeys[0] !== 1; }(1)); var originalKeys = $Object.keys; defineProperties($Object, { keys: function keys(object) { if (isArguments(object)) { return originalKeys(arraySlice(object)); } return originalKeys(object); } }, !keysWorksWithArguments || keysHasArgumentsLengthBug); // // Date // ==== // var hasNegativeMonthYearBug = new Date(-3509827329600292).getUTCMonth() !== 0; var aNegativeTestDate = new Date(-1509842289600292); var aPositiveTestDate = new Date(1449662400000); var hasToUTCStringFormatBug = aNegativeTestDate.toUTCString() !== 'Mon, 01 Jan -45875 11:59:59 GMT'; var hasToDateStringFormatBug; var hasToStringFormatBug; var timeZoneOffset = aNegativeTestDate.getTimezoneOffset(); if (timeZoneOffset < -720) { hasToDateStringFormatBug = aNegativeTestDate.toDateString() !== 'Tue Jan 02 -45875'; hasToStringFormatBug = !(/^Thu Dec 10 2015 \d\d:\d\d:\d\d GMT[-+]\d\d\d\d(?: |$)/).test(String(aPositiveTestDate)); } else { hasToDateStringFormatBug = aNegativeTestDate.toDateString() !== 'Mon Jan 01 -45875'; hasToStringFormatBug = !(/^Wed Dec 09 2015 \d\d:\d\d:\d\d GMT[-+]\d\d\d\d(?: |$)/).test(String(aPositiveTestDate)); } var originalGetFullYear = call.bind(Date.prototype.getFullYear); var originalGetMonth = call.bind(Date.prototype.getMonth); var originalGetDate = call.bind(Date.prototype.getDate); var originalGetUTCFullYear = call.bind(Date.prototype.getUTCFullYear); var originalGetUTCMonth = call.bind(Date.prototype.getUTCMonth); var originalGetUTCDate = call.bind(Date.prototype.getUTCDate); var originalGetUTCDay = call.bind(Date.prototype.getUTCDay); var originalGetUTCHours = call.bind(Date.prototype.getUTCHours); var originalGetUTCMinutes = call.bind(Date.prototype.getUTCMinutes); var originalGetUTCSeconds = call.bind(Date.prototype.getUTCSeconds); var originalGetUTCMilliseconds = call.bind(Date.prototype.getUTCMilliseconds); var dayName = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; var monthName = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; var daysInMonth = function daysInMonth(month, year) { return originalGetDate(new Date(year, month, 0)); }; defineProperties(Date.prototype, { getFullYear: function getFullYear() { if (!this || !(this instanceof Date)) { throw new TypeError('this is not a Date object.'); } var year = originalGetFullYear(this); if (year < 0 && originalGetMonth(this) > 11) { return year + 1; } return year; }, getMonth: function getMonth() { if (!this || !(this instanceof Date)) { throw new TypeError('this is not a Date object.'); } var year = originalGetFullYear(this); var month = originalGetMont