X-Git-Url: http://git.cyclocoop.org/?a=blobdiff_plain;f=resources%2Flib%2Fes5-shim%2Fes5-shim.js;h=91a7a39762b43779d50dc9349f26845f4549bb09;hb=a303296f2730d6279a249bde77f3e0b9b42e494f;hp=4595994058606e7a28e16011cd464b1594738831;hpb=96366c1cf1966ca07e8f0b4361bbca28bfaf43a0;p=lhc%2Fweb%2Fwiklou.git diff --git a/resources/lib/es5-shim/es5-shim.js b/resources/lib/es5-shim/es5-shim.js index 4595994058..91a7a39762 100644 --- a/resources/lib/es5-shim/es5-shim.js +++ b/resources/lib/es5-shim/es5-shim.js @@ -1,17 +1,20 @@ /*! * https://github.com/es-shims/es5-shim - * @license es5-shim Copyright 2009-2014 by contributors, MIT License + * @license es5-shim Copyright 2009-2015 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 concated code. +// Add semicolon to prevent IIFE from being passed as argument to concatenated code. ; // UMD (Universal Module Definition) -// see https://github.com/umdjs/umd/blob/master/returnExports.js +// see https://github.com/umdjs/umd/blob/master/templates/returnExports.js (function (root, factory) { + 'use strict'; + + /* global define, exports, module */ if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define(factory); @@ -36,146 +39,146 @@ */ // Shortcut to an often accessed properties, in order to avoid multiple -// dereference that costs universally. -var ArrayPrototype = Array.prototype; -var ObjectPrototype = Object.prototype; -var FunctionPrototype = Function.prototype; -var StringPrototype = String.prototype; -var NumberPrototype = Number.prototype; -var _Array_slice_ = ArrayPrototype.slice; +// 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; -// Having a toString local variable name breaks in Opera so use _toString. -var _toString = ObjectPrototype.toString; +// Having a toString local variable name breaks in Opera so use to_string. +var to_string = ObjectPrototype.toString; -var isFunction = function (val) { - return ObjectPrototype.toString.call(val) === '[object Function]'; -}; -var isRegex = function (val) { - return ObjectPrototype.toString.call(val) === '[object RegExp]'; -}; -var isArray = function isArray(obj) { - return _toString.call(obj) === "[object Array]"; -}; -var isString = function isString(obj) { - return _toString.call(obj) === "[object String]"; -}; -var isArguments = function isArguments(value) { - var str = _toString.call(value); - var isArgs = str === '[object Arguments]'; - if (!isArgs) { - isArgs = !isArray(str) - && value !== null - && typeof value === 'object' - && typeof value.length === 'number' - && value.length >= 0 - && isFunction(value.callee); - } - return isArgs; -}; +/* global Symbol */ +/* 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 */ -var supportsDescriptors = Object.defineProperty && (function () { +/* inlined from http://npmjs.com/define-properties */ +var supportsDescriptors = $Object.defineProperty && (function () { try { - Object.defineProperty({}, 'x', {}); - return true; + var obj = {}; + $Object.defineProperty(obj, 'x', { enumerable: false, value: obj }); + for (var _ in obj) { return false; } + return obj.x === obj; } catch (e) { /* this is ES3 */ return false; } }()); - -// 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; - }; -} -var defineProperties = function (object, map, forceAssign) { - for (var name in map) { - if (ObjectPrototype.hasOwnProperty.call(map, name)) { - defineProperty(object, name, map[name], forceAssign); - } - } -}; +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; + }; + } + return function defineProperties(object, map, forceAssign) { + for (var name in map) { + if (has.call(map, name)) { + defineProperty(object, name, map[name], forceAssign); + } + } + }; +}(ObjectPrototype.hasOwnProperty)); // // Util // ====== // -// ES5 9.4 -// http://es5.github.com/#x9.4 -// http://jsperf.com/to-integer - -function toInteger(n) { - n = +n; - if (n !== n) { // isNaN - n = 0; - } else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) { - n = (n > 0 || -1) * Math.floor(Math.abs(n)); - } - return n; -} - -function isPrimitive(input) { +/* replaceable with https://npmjs.com/package/es-abstract /helpers/isPrimitive */ +var isPrimitive = function isPrimitive(input) { var type = typeof input; - return ( - input === null || - type === "undefined" || - type === "boolean" || - type === "number" || - type === "string" - ); -} + return input === null || (type !== 'object' && type !== 'function'); +}; -function toPrimitive(input) { - var val, valueOf, toStr; - if (isPrimitive(input)) { - return input; - } - valueOf = input.valueOf; - if (isFunction(valueOf)) { - val = valueOf.call(input); - if (isPrimitive(val)) { - return val; +var isActualNaN = $Number.isNaN || function (x) { return x !== x; }; + +var ES = { + // ES5 9.4 + // http://es5.github.com/#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) * Math.floor(Math.abs(n)); } - } - toStr = input.toString; - if (isFunction(toStr)) { - val = toStr.call(input); - if (isPrimitive(val)) { - return val; + 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; } - } - throw new TypeError(); -} + 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 + // http://es5.github.com/#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); + }, -// ES5 9.9 -// http://es5.github.com/#x9.9 -var toObject = function (o) { - if (o == null) { // this matches both null and undefined - throw new TypeError("can't convert " + o + " to object"); + /* replaceable with https://npmjs.com/package/es-abstract ES5.ToUint32 */ + ToUint32: function ToUint32(x) { + return x >>> 0; } - return Object(o); -}; - -var ToUint32 = function ToUint32(x) { - return x >>> 0; }; // @@ -186,20 +189,20 @@ var ToUint32 = function ToUint32(x) { // ES-5 15.3.4.5 // http://es5.github.com/#x15.3.4.5 -function Empty() {} +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 (!isFunction(target)) { - throw new TypeError("Function.prototype.bind called on incompatible " + target); + 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 + 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. @@ -209,6 +212,7 @@ defineProperties(FunctionPrototype, { // 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) { @@ -228,11 +232,12 @@ defineProperties(FunctionPrototype, { // 5. Return the result of calling the [[Construct]] internal // method of target providing args as the arguments. - var result = target.apply( + var result = apply.call( + target, this, - args.concat(_Array_slice_.call(arguments)) + array_concat.call(args, array_slice.call(arguments)) ); - if (Object(result) === result) { + if ($Object(result) === result) { return result; } return this; @@ -257,9 +262,10 @@ defineProperties(FunctionPrototype, { // providing args as the arguments. // equiv: target.call(this, ...boundArgs, ...args) - return target.apply( + return apply.call( + target, that, - args.concat(_Array_slice_.call(arguments)) + array_concat.call(args, array_slice.call(arguments)) ); } @@ -272,13 +278,13 @@ defineProperties(FunctionPrototype, { // larger. // 16. Else set the length own property of F to 0. - var boundLength = Math.max(0, target.length - args.length); + 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++) { - boundArgs.push("$" + i); + array_push.call(boundArgs, '$' + i); } // XXX Build a dynamic function with desired amount of arguments is the only @@ -287,7 +293,7 @@ defineProperties(FunctionPrototype, { // 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. - var bound = Function("binder", "return function (" + boundArgs.join(",") + "){return binder.apply(this,arguments)}")(binder); + bound = $Function('binder', 'return function (' + array_join.call(boundArgs, ',') + '){ return binder.apply(this, arguments); }')(binder); if (target.prototype) { Empty.prototype = target.prototype; @@ -322,66 +328,26 @@ defineProperties(FunctionPrototype, { }); // _Please note: Shortcuts are defined after `Function.prototype.bind` as we -// us it in defining shortcuts. +// use it in defining shortcuts. var owns = call.bind(ObjectPrototype.hasOwnProperty); - -// If JS engine supports accessors creating shortcuts. -var defineGetter; -var defineSetter; -var lookupGetter; -var lookupSetter; -var supportsAccessors; -if ((supportsAccessors = owns(ObjectPrototype, "__defineGetter__"))) { - defineGetter = call.bind(ObjectPrototype.__defineGetter__); - defineSetter = call.bind(ObjectPrototype.__defineSetter__); - lookupGetter = call.bind(ObjectPrototype.__lookupGetter__); - lookupSetter = call.bind(ObjectPrototype.__lookupSetter__); -} +var toStr = call.bind(ObjectPrototype.toString); +var arraySlice = call.bind(array_slice); +var arraySliceApply = apply.bind(array_slice); +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 // ===== // -// ES5 15.4.4.12 -// http://es5.github.com/#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 []; - } else { - return array_splice.apply(this, arguments); - } - } -}, spliceNoopReturnsEmptyArray); - -var spliceWorksWithEmptyObject = (function () { - var obj = {}; - ArrayPrototype.splice.call(obj, 0, 0, 1); - return obj.length === 1; -}()); -defineProperties(ArrayPrototype, { - splice: function splice(start, deleteCount) { - if (arguments.length === 0) { return []; } - var args = arguments; - this.length = Math.max(toInteger(this.length), 0); - if (arguments.length > 0 && typeof deleteCount !== 'number') { - args = _Array_slice_.call(arguments); - if (args.length < 2) { - args.push(this.length - start); - } else { - args[1] = toInteger(deleteCount); - } - } - return array_splice.apply(this, args); - } -}, !spliceWorksWithEmptyObject); +var isArray = $Array.isArray || function isArray(obj) { + return toStr(obj) === '[object Array]'; +}; // ES5 15.4.4.12 // http://es5.github.com/#x15.4.4.13 @@ -399,7 +365,7 @@ defineProperties(ArrayPrototype, { // ES5 15.4.3.2 // http://es5.github.com/#x15.4.3.2 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray -defineProperties(Array, { isArray: isArray }); +defineProperties($Array, { isArray: isArray }); // The IsCallable() check in the Array functions // has been replaced with a strict check on the @@ -419,45 +385,59 @@ defineProperties(Array, { isArray: isArray }); // 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 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) { - method.call('foo', function (_, __, context) { - if (typeof context !== 'object') { properlyBoxesNonStrict = false; } - }); + try { + method.call('foo', function (_, __, context) { + if (typeof context !== 'object') { + properlyBoxesNonStrict = false; + } + }); - method.call([1], function () { - 'use strict'; - properlyBoxesStrict = typeof this === 'string'; - }, 'x'); + method.call([1], function () { + 'use strict'; + + properlyBoxesStrict = typeof this === 'string'; + }, 'x'); + } catch (e) { + threwException = true; + } } - return !!method && properlyBoxesNonStrict && properlyBoxesStrict; + return !!method && !threwException && properlyBoxesNonStrict && properlyBoxesStrict; }; defineProperties(ArrayPrototype, { - forEach: function forEach(fun /*, thisp*/) { - var object = toObject(this), - self = splitString && isString(this) ? this.split('') : object, - thisp = arguments[1], - i = -1, - length = self.length >>> 0; + 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 (!isFunction(fun)) { - throw new TypeError(); // TODO message + 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 - // context - fun.call(thisp, self[i], i, object); + if (typeof T === 'undefined') { + callbackfn(self[i], i, object); + } else { + callbackfn.call(T, self[i], i, object); + } } } } @@ -467,21 +447,28 @@ defineProperties(ArrayPrototype, { // http://es5.github.com/#x15.4.4.19 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map defineProperties(ArrayPrototype, { - map: function map(fun /*, thisp*/) { - var object = toObject(this), - self = splitString && isString(this) ? this.split('') : object, - length = self.length >>> 0, - result = Array(length), - thisp = arguments[1]; + 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 (!isFunction(fun)) { - throw new TypeError(fun + " is not a 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) { - result[i] = fun.call(thisp, self[i], i, object); + if (typeof T === 'undefined') { + result[i] = callbackfn(self[i], i, object); + } else { + result[i] = callbackfn.call(T, self[i], i, object); + } } } return result; @@ -492,24 +479,27 @@ defineProperties(ArrayPrototype, { // http://es5.github.com/#x15.4.4.20 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter defineProperties(ArrayPrototype, { - filter: function filter(fun /*, thisp */) { - var object = toObject(this), - self = splitString && isString(this) ? this.split('') : object, - length = self.length >>> 0, - result = [], - value, - thisp = arguments[1]; + 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 (!isFunction(fun)) { - throw new TypeError(fun + " is not a 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 (fun.call(thisp, value, i, object)) { - result.push(value); + if (typeof T === 'undefined' ? callbackfn(value, i, object) : callbackfn.call(T, value, i, object)) { + pushCall(result, value); } } } @@ -521,19 +511,22 @@ defineProperties(ArrayPrototype, { // http://es5.github.com/#x15.4.4.16 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every defineProperties(ArrayPrototype, { - every: function every(fun /*, thisp */) { - var object = toObject(this), - self = splitString && isString(this) ? this.split('') : object, - length = self.length >>> 0, - thisp = arguments[1]; + 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 (!isFunction(fun)) { - throw new TypeError(fun + " is not a 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 && !fun.call(thisp, self[i], i, object)) { + if (i in self && !(typeof T === 'undefined' ? callbackfn(self[i], i, object) : callbackfn.call(T, self[i], i, object))) { return false; } } @@ -545,19 +538,22 @@ defineProperties(ArrayPrototype, { // http://es5.github.com/#x15.4.4.17 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some defineProperties(ArrayPrototype, { - some: function some(fun /*, thisp */) { - var object = toObject(this), - self = splitString && isString(this) ? this.split('') : object, - length = self.length >>> 0, - thisp = arguments[1]; + 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 (!isFunction(fun)) { - throw new TypeError(fun + " is not a 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 && fun.call(thisp, self[i], i, object)) { + if (i in self && (typeof T === 'undefined' ? callbackfn(self[i], i, object) : callbackfn.call(T, self[i], i, object))) { return true; } } @@ -570,22 +566,24 @@ defineProperties(ArrayPrototype, { // 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'; + reduceCoercesToObject = typeof ArrayPrototype.reduce.call('es5', function (_, __, ___, list) { + return list; + }) === 'object'; } defineProperties(ArrayPrototype, { - reduce: function reduce(fun /*, initial*/) { - var object = toObject(this), - self = splitString && isString(this) ? this.split('') : object, - length = self.length >>> 0; + 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 (!isFunction(fun)) { - throw new TypeError(fun + " is not a 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 && arguments.length === 1) { - throw new TypeError("reduce of empty array with no initial value"); + if (length === 0 && arguments.length === 1) { + throw new TypeError('reduce of empty array with no initial value'); } var i = 0; @@ -601,14 +599,14 @@ defineProperties(ArrayPrototype, { // if array contains no values, no initial value to return if (++i >= length) { - throw new TypeError("reduce of empty array with no initial value"); + throw new TypeError('reduce of empty array with no initial value'); } } while (true); } for (; i < length; i++) { if (i in self) { - result = fun.call(void 0, result, self[i], i, object); + result = callbackfn(result, self[i], i, object); } } @@ -621,25 +619,28 @@ defineProperties(ArrayPrototype, { // 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'; + reduceRightCoercesToObject = typeof ArrayPrototype.reduceRight.call('es5', function (_, __, ___, list) { + return list; + }) === 'object'; } defineProperties(ArrayPrototype, { - reduceRight: function reduceRight(fun /*, initial*/) { - var object = toObject(this), - self = splitString && isString(this) ? this.split('') : object, - length = self.length >>> 0; + 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 (!isFunction(fun)) { - throw new TypeError(fun + " is not a 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 && arguments.length === 1) { - throw new TypeError("reduceRight of empty array with no initial value"); + if (length === 0 && arguments.length === 1) { + throw new TypeError('reduceRight of empty array with no initial value'); } - var result, i = length - 1; + var result; + var i = length - 1; if (arguments.length >= 2) { result = arguments[1]; } else { @@ -651,7 +652,7 @@ defineProperties(ArrayPrototype, { // if array contains no values, no initial value to return if (--i < 0) { - throw new TypeError("reduceRight of empty array with no initial value"); + throw new TypeError('reduceRight of empty array with no initial value'); } } while (true); } @@ -662,7 +663,7 @@ defineProperties(ArrayPrototype, { do { if (i in self) { - result = fun.call(void 0, result, self[i], i, object); + result = callbackfn(result, self[i], i, object); } } while (i--); @@ -673,25 +674,25 @@ defineProperties(ArrayPrototype, { // ES5 15.4.4.14 // http://es5.github.com/#x15.4.4.14 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf -var hasFirefox2IndexOfBug = Array.prototype.indexOf && [0, 1].indexOf(1, 2) !== -1; +var hasFirefox2IndexOfBug = ArrayPrototype.indexOf && [0, 1].indexOf(1, 2) !== -1; defineProperties(ArrayPrototype, { - indexOf: function indexOf(sought /*, fromIndex */ ) { - var self = splitString && isString(this) ? this.split('') : toObject(this), - length = self.length >>> 0; + indexOf: function indexOf(searchElement/*, fromIndex */) { + var self = splitString && isString(this) ? strSplit(this, '') : ES.ToObject(this); + var length = ES.ToUint32(self.length); - if (!length) { + if (length === 0) { return -1; } var i = 0; if (arguments.length > 1) { - i = toInteger(arguments[1]); + i = ES.ToInteger(arguments[1]); } // handle negative indices - i = i >= 0 ? i : Math.max(0, length + i); + i = i >= 0 ? i : max(0, length + i); for (; i < length; i++) { - if (i in self && self[i] === sought) { + if (i in self && self[i] === searchElement) { return i; } } @@ -702,23 +703,23 @@ defineProperties(ArrayPrototype, { // ES5 15.4.4.15 // http://es5.github.com/#x15.4.4.15 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf -var hasFirefox2LastIndexOfBug = Array.prototype.lastIndexOf && [0, 1].lastIndexOf(0, -3) !== -1; +var hasFirefox2LastIndexOfBug = ArrayPrototype.lastIndexOf && [0, 1].lastIndexOf(0, -3) !== -1; defineProperties(ArrayPrototype, { - lastIndexOf: function lastIndexOf(sought /*, fromIndex */) { - var self = splitString && isString(this) ? this.split('') : toObject(this), - length = self.length >>> 0; + lastIndexOf: function lastIndexOf(searchElement/*, fromIndex */) { + var self = splitString && isString(this) ? strSplit(this, '') : ES.ToObject(this); + var length = ES.ToUint32(self.length); - if (!length) { + if (length === 0) { return -1; } var i = length - 1; if (arguments.length > 1) { - i = Math.min(i, toInteger(arguments[1])); + i = min(i, ES.ToInteger(arguments[1])); } // handle negative indices i = i >= 0 ? i : length - Math.abs(i); for (; i >= 0; i--) { - if (i in self && sought === self[i]) { + if (i in self && searchElement === self[i]) { return i; } } @@ -726,6 +727,236 @@ defineProperties(ArrayPrototype, { } }, hasFirefox2LastIndexOfBug); +// ES5 15.4.4.12 +// http://es5.github.com/#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 []; + } else { + return array_splice.apply(this, arguments); + } + } +}, !spliceNoopReturnsEmptyArray); + +var spliceWorksWithEmptyObject = (function () { + var obj = {}; + ArrayPrototype.splice.call(obj, 0, 0, 1); + return obj.length === 1; +}()); +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); +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 = 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 +// http://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); + [1, 2].sort({}); + return true; + } catch (e) { /**/ } + return false; +}()); +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 // ====== @@ -735,51 +966,106 @@ defineProperties(ArrayPrototype, { // http://es5.github.com/#x15.2.3.14 // http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation -var hasDontEnumBug = !({'toString': null}).propertyIsEnumerable('toString'), - hasProtoEnumBug = (function () {}).propertyIsEnumerable('prototype'), - dontEnums = [ - "toString", - "toLocaleString", - "valueOf", - "hasOwnProperty", - "isPrototypeOf", - "propertyIsEnumerable", - "constructor" - ], - dontEnumsLength = dontEnums.length; - -defineProperties(Object, { +var hasDontEnumBug = !({ 'toString': null }).propertyIsEnumerable('toString'); +var hasProtoEnumBug = function () {}.propertyIsEnumerable('prototype'); +var hasStringEnumBug = !owns('x', '0'); +var equalsConstructorPrototype = function (o) { + var ctor = o.constructor; + return ctor && ctor.prototype === o; +}; +var blacklistedKeys = { + $window: true, + $console: true, + $parent: true, + $self: true, + $frame: true, + $frames: true, + $frameElement: true, + $webkitIndexedDB: true, + $webkitStorageInfo: true, + $external: true +}; +var hasAutomationEqualityBug = (function () { + /* globals window */ + if (typeof window === 'undefined') { return false; } + for (var k in window) { + try { + if (!blacklistedKeys['$' + 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 = isFunction(object), - isArgs = isArguments(object), - isObject = object !== null && typeof object === 'object', - isStr = isObject && isString(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"); + throw new TypeError('Object.keys called on a non-object'); } var theKeys = []; var skipProto = hasProtoEnumBug && isFn; - if (isStr || isArgs) { + if ((isStr && hasStringEnumBug) || isArgs) { for (var i = 0; i < object.length; ++i) { - theKeys.push(String(i)); + pushCall(theKeys, $String(i)); } - } else { + } + + if (!isArgs) { for (var name in object) { if (!(skipProto && name === 'prototype') && owns(object, name)) { - theKeys.push(String(name)); + pushCall(theKeys, $String(name)); } } } if (hasDontEnumBug) { - var ctor = object.constructor, - skipConstructor = ctor && ctor.prototype === object; + var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object); for (var j = 0; j < dontEnumsLength; j++) { var dontEnum = dontEnums[j]; if (!(skipConstructor && dontEnum === 'constructor') && owns(object, dontEnum)) { - theKeys.push(dontEnum); + pushCall(theKeys, dontEnum); } } } @@ -787,26 +1073,214 @@ defineProperties(Object, { } }); -var keysWorksWithArguments = Object.keys && (function () { +var keysWorksWithArguments = $Object.keys && (function () { // Safari 5.0 bug - return Object.keys(arguments).length === 2; + return $Object.keys(arguments).length === 2; }(1, 2)); -var originalKeys = Object.keys; -defineProperties(Object, { +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(ArrayPrototype.slice.call(object)); + return originalKeys(arraySlice(object)); } else { return originalKeys(object); } } -}, !keysWorksWithArguments); +}, !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(aPositiveTestDate.toString()); +} 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(aPositiveTestDate.toString()); +} + +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 = originalGetMonth(this); + if (year < 0 && month > 11) { + return 0; + } + return month; + }, + getDate: function getDate() { + if (!this || !(this instanceof Date)) { + throw new TypeError('this is not a Date object.'); + } + var year = originalGetFullYear(this); + var month = originalGetMonth(this); + var date = originalGetDate(this); + if (year < 0 && month > 11) { + if (month === 12) { + return date; + } + var days = daysInMonth(0, year + 1); + return (days - date) + 1; + } + return date; + }, + getUTCFullYear: function getUTCFullYear() { + if (!this || !(this instanceof Date)) { + throw new TypeError('this is not a Date object.'); + } + var year = originalGetUTCFullYear(this); + if (year < 0 && originalGetUTCMonth(this) > 11) { + return year + 1; + } + return year; + }, + getUTCMonth: function getUTCMonth() { + if (!this || !(this instanceof Date)) { + throw new TypeError('this is not a Date object.'); + } + var year = originalGetUTCFullYear(this); + var month = originalGetUTCMonth(this); + if (year < 0 && month > 11) { + return 0; + } + return month; + }, + getUTCDate: function getUTCDate() { + if (!this || !(this instanceof Date)) { + throw new TypeError('this is not a Date object.'); + } + var year = originalGetUTCFullYear(this); + var month = originalGetUTCMonth(this); + var date = originalGetUTCDate(this); + if (year < 0 && month > 11) { + if (month === 12) { + return date; + } + var days = daysInMonth(0, year + 1); + return (days - date) + 1; + } + return date; + } +}, hasNegativeMonthYearBug); + +defineProperties(Date.prototype, { + toUTCString: function toUTCString() { + if (!this || !(this instanceof Date)) { + throw new TypeError('this is not a Date object.'); + } + var day = originalGetUTCDay(this); + var date = originalGetUTCDate(this); + var month = originalGetUTCMonth(this); + var year = originalGetUTCFullYear(this); + var hour = originalGetUTCHours(this); + var minute = originalGetUTCMinutes(this); + var second = originalGetUTCSeconds(this); + return dayName[day] + ', ' + + (date < 10 ? '0' + date : date) + ' ' + + monthName[month] + ' ' + + year + ' ' + + (hour < 10 ? '0' + hour : hour) + ':' + + (minute < 10 ? '0' + minute : minute) + ':' + + (second < 10 ? '0' + second : second) + ' GMT'; + } +}, hasNegativeMonthYearBug || hasToUTCStringFormatBug); + +// Opera 12 has `,` +defineProperties(Date.prototype, { + toDateString: function toDateString() { + if (!this || !(this instanceof Date)) { + throw new TypeError('this is not a Date object.'); + } + var day = this.getDay(); + var date = this.getDate(); + var month = this.getMonth(); + var year = this.getFullYear(); + return dayName[day] + ' ' + + monthName[month] + ' ' + + (date < 10 ? '0' + date : date) + ' ' + + year; + } +}, hasNegativeMonthYearBug || hasToDateStringFormatBug); + +// can't use defineProperties here because of toString enumeration issue in IE <= 8 +if (hasNegativeMonthYearBug || hasToStringFormatBug) { + Date.prototype.toString = function toString() { + if (!this || !(this instanceof Date)) { + throw new TypeError('this is not a Date object.'); + } + var day = this.getDay(); + var date = this.getDate(); + var month = this.getMonth(); + var year = this.getFullYear(); + var hour = this.getHours(); + var minute = this.getMinutes(); + var second = this.getSeconds(); + var timezoneOffset = this.getTimezoneOffset(); + var hoursOffset = Math.floor(Math.abs(timezoneOffset) / 60); + var minutesOffset = Math.floor(Math.abs(timezoneOffset) % 60); + return dayName[day] + ' ' + + monthName[month] + ' ' + + (date < 10 ? '0' + date : date) + ' ' + + year + ' ' + + (hour < 10 ? '0' + hour : hour) + ':' + + (minute < 10 ? '0' + minute : minute) + ':' + + (second < 10 ? '0' + second : second) + ' GMT' + + (timezoneOffset > 0 ? '-' : '+') + + (hoursOffset < 10 ? '0' + hoursOffset : hoursOffset) + + (minutesOffset < 10 ? '0' + minutesOffset : minutesOffset); + }; + if (supportsDescriptors) { + $Object.defineProperty(Date.prototype, 'toString', { + configurable: true, + enumerable: false, + writable: true + }); + } +} + // ES5 15.9.5.43 // http://es5.github.com/#x15.9.5.43 // This function returns a String value represent the instance in time @@ -815,67 +1289,62 @@ defineProperties(Object, { // The time zone is always UTC, denoted by the suffix Z. If the time value of // this object is not a finite Number a RangeError exception is thrown. var negativeDate = -62198755200000; -var negativeYearString = "-000001"; +var negativeYearString = '-000001'; var hasNegativeDateBug = Date.prototype.toISOString && new Date(negativeDate).toISOString().indexOf(negativeYearString) === -1; +var hasSafari51DateBug = Date.prototype.toISOString && new Date(-1).toISOString() !== '1969-12-31T23:59:59.999Z'; + +var getTime = call.bind(Date.prototype.getTime); defineProperties(Date.prototype, { toISOString: function toISOString() { - var result, length, value, year, month; - if (!isFinite(this)) { - throw new RangeError("Date.prototype.toISOString called on non-finite value."); + if (!isFinite(this) || !isFinite(getTime(this))) { + // Adope Photoshop requires the second check. + throw new RangeError('Date.prototype.toISOString called on non-finite value.'); } - year = this.getUTCFullYear(); + var year = originalGetUTCFullYear(this); - month = this.getUTCMonth(); + var month = originalGetUTCMonth(this); // see https://github.com/es-shims/es5-shim/issues/111 year += Math.floor(month / 12); month = (month % 12 + 12) % 12; // the date time string format is specified in 15.9.1.15. - result = [month + 1, this.getUTCDate(), this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds()]; + var result = [month + 1, originalGetUTCDate(this), originalGetUTCHours(this), originalGetUTCMinutes(this), originalGetUTCSeconds(this)]; year = ( - (year < 0 ? "-" : (year > 9999 ? "+" : "")) + - ("00000" + Math.abs(year)).slice(0 <= year && year <= 9999 ? -4 : -6) + (year < 0 ? '-' : (year > 9999 ? '+' : '')) + + strSlice('00000' + Math.abs(year), (0 <= year && year <= 9999) ? -4 : -6) ); - length = result.length; - while (length--) { - value = result[length]; - // pad months, days, hours, minutes, and seconds to have two - // digits. - if (value < 10) { - result[length] = "0" + value; - } + for (var i = 0; i < result.length; ++i) { + // pad months, days, hours, minutes, and seconds to have two digits. + result[i] = strSlice('00' + result[i], -2); } // pad milliseconds to have three digits. return ( - year + "-" + result.slice(0, 2).join("-") + - "T" + result.slice(2).join(":") + "." + - ("000" + this.getUTCMilliseconds()).slice(-3) + "Z" + year + '-' + arraySlice(result, 0, 2).join('-') + + 'T' + arraySlice(result, 2).join(':') + '.' + + strSlice('000' + originalGetUTCMilliseconds(this), -3) + 'Z' ); } -}, hasNegativeDateBug); - +}, hasNegativeDateBug || hasSafari51DateBug); // ES5 15.9.5.44 // http://es5.github.com/#x15.9.5.44 // This function provides a String representation of a Date object for use by // JSON.stringify (15.12.3). -var dateToJSONIsSupported = false; -try { - dateToJSONIsSupported = ( - Date.prototype.toJSON && - new Date(NaN).toJSON() === null && - new Date(negativeDate).toJSON().indexOf(negativeYearString) !== -1 && - Date.prototype.toJSON.call({ // generic - toISOString: function () { - return true; - } - }) - ); -} catch (e) { -} +var dateToJSONIsSupported = (function () { + try { + return Date.prototype.toJSON && + new Date(NaN).toJSON() === null && + new Date(negativeDate).toJSON().indexOf(negativeYearString) !== -1 && + Date.prototype.toJSON.call({ // generic + toISOString: function () { return true; } + }); + } catch (e) { + return false; + } +}()); if (!dateToJSONIsSupported) { Date.prototype.toJSON = function toJSON(key) { // When the toJSON method is called with argument key, the following @@ -883,24 +1352,23 @@ if (!dateToJSONIsSupported) { // 1. Let O be the result of calling ToObject, giving it the this // value as its argument. - // 2. Let tv be toPrimitive(O, hint Number). - var o = Object(this), - tv = toPrimitive(o), - toISO; + // 2. Let tv be ES.ToPrimitive(O, hint Number). + var O = $Object(this); + var tv = ES.ToPrimitive(O); // 3. If tv is a Number and is not finite, return null. - if (typeof tv === "number" && !isFinite(tv)) { + if (typeof tv === 'number' && !isFinite(tv)) { return null; } // 4. Let toISO be the result of calling the [[Get]] internal method of // O with argument "toISOString". - toISO = o.toISOString; + var toISO = O.toISOString; // 5. If IsCallable(toISO) is false, throw a TypeError exception. - if (typeof toISO !== "function") { - throw new TypeError("toISOString property is not callable"); + if (!isCallable(toISO)) { + throw new TypeError('toISOString property is not callable'); } // 6. Return the result of calling the [[Call]] internal method of // toISO with O as the this value and an empty argument list. - return toISO.call(o); + return toISO.call(O); // NOTE 1 The argument is ignored. @@ -918,65 +1386,82 @@ if (!dateToJSONIsSupported) { // based on work shared by Daniel Friesen (dantman) // http://gist.github.com/303249 var supportsExtendedYears = Date.parse('+033658-09-27T01:46:40.000Z') === 1e15; -var acceptsInvalidDates = !isNaN(Date.parse('2012-04-04T24:00:00.500Z')) || !isNaN(Date.parse('2012-11-31T23:59:59.000Z')); -var doesNotParseY2KNewYear = isNaN(Date.parse("2000-01-01T00:00:00.000Z")); -if (!Date.parse || doesNotParseY2KNewYear || acceptsInvalidDates || !supportsExtendedYears) { +var acceptsInvalidDates = !isNaN(Date.parse('2012-04-04T24:00:00.500Z')) || !isNaN(Date.parse('2012-11-31T23:59:59.000Z')) || !isNaN(Date.parse('2012-12-31T23:59:60.000Z')); +var doesNotParseY2KNewYear = isNaN(Date.parse('2000-01-01T00:00:00.000Z')); +if (doesNotParseY2KNewYear || acceptsInvalidDates || !supportsExtendedYears) { // XXX global assignment won't work in embeddings that use // an alternate object for the context. + /* global Date: true */ + /* eslint-disable no-undef */ + var maxSafeUnsigned32Bit = Math.pow(2, 31) - 1; + var hasSafariSignedIntBug = isActualNaN(new Date(1970, 0, 1, 0, 0, 0, maxSafeUnsigned32Bit + 1).getTime()); + /* eslint-disable no-implicit-globals */ Date = (function (NativeDate) { - + /* eslint-enable no-implicit-globals */ + /* eslint-enable no-undef */ // Date.length === 7 - function Date(Y, M, D, h, m, s, ms) { + var DateShim = function Date(Y, M, D, h, m, s, ms) { var length = arguments.length; + var date; if (this instanceof NativeDate) { - var date = length === 1 && String(Y) === Y ? // isString(Y) + var seconds = s; + var millis = ms; + if (hasSafariSignedIntBug && length >= 7 && ms > maxSafeUnsigned32Bit) { + // work around a Safari 8/9 bug where it treats the seconds as signed + var msToShift = Math.floor(ms / maxSafeUnsigned32Bit) * maxSafeUnsigned32Bit; + var sToShift = Math.floor(msToShift / 1e3); + seconds += sToShift; + millis -= sToShift * 1e3; + } + date = length === 1 && $String(Y) === Y ? // isString(Y) // We explicitly pass it through parse: - new NativeDate(Date.parse(Y)) : + new NativeDate(DateShim.parse(Y)) : // We have to manually make calls depending on argument // length here - length >= 7 ? new NativeDate(Y, M, D, h, m, s, ms) : - length >= 6 ? new NativeDate(Y, M, D, h, m, s) : + length >= 7 ? new NativeDate(Y, M, D, h, m, seconds, millis) : + length >= 6 ? new NativeDate(Y, M, D, h, m, seconds) : length >= 5 ? new NativeDate(Y, M, D, h, m) : length >= 4 ? new NativeDate(Y, M, D, h) : length >= 3 ? new NativeDate(Y, M, D) : length >= 2 ? new NativeDate(Y, M) : - length >= 1 ? new NativeDate(Y) : + length >= 1 ? new NativeDate(Y instanceof NativeDate ? +Y : Y) : new NativeDate(); - // Prevent mixups with unfixed Date object - date.constructor = Date; - return date; + } else { + date = NativeDate.apply(this, arguments); } - return NativeDate.apply(this, arguments); - } + if (!isPrimitive(date)) { + // Prevent mixups with unfixed Date object + defineProperties(date, { constructor: DateShim }, true); + } + return date; + }; // 15.9.1.15 Date Time String Format. - var isoDateExpression = new RegExp("^" + - "(\\d{4}|[\+\-]\\d{6})" + // four-digit year capture or sign + + var isoDateExpression = new RegExp('^' + + '(\\d{4}|[+-]\\d{6})' + // four-digit year capture or sign + // 6-digit extended year - "(?:-(\\d{2})" + // optional month capture - "(?:-(\\d{2})" + // optional day capture - "(?:" + // capture hours:minutes:seconds.milliseconds - "T(\\d{2})" + // hours capture - ":(\\d{2})" + // minutes capture - "(?:" + // optional :seconds.milliseconds - ":(\\d{2})" + // seconds capture - "(?:(\\.\\d{1,}))?" + // milliseconds capture - ")?" + - "(" + // capture UTC offset component - "Z|" + // UTC capture - "(?:" + // offset specifier +/-hours:minutes - "([-+])" + // sign capture - "(\\d{2})" + // hours offset capture - ":(\\d{2})" + // minutes offset capture - ")" + - ")?)?)?)?" + - "$"); - - var months = [ - 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 - ]; - - function dayFromMonth(year, month) { + '(?:-(\\d{2})' + // optional month capture + '(?:-(\\d{2})' + // optional day capture + '(?:' + // capture hours:minutes:seconds.milliseconds + 'T(\\d{2})' + // hours capture + ':(\\d{2})' + // minutes capture + '(?:' + // optional :seconds.milliseconds + ':(\\d{2})' + // seconds capture + '(?:(\\.\\d{1,}))?' + // milliseconds capture + ')?' + + '(' + // capture UTC offset component + 'Z|' + // UTC capture + '(?:' + // offset specifier +/-hours:minutes + '([-+])' + // sign capture + '(\\d{2})' + // hours offset capture + ':(\\d{2})' + // minutes offset capture + ')' + + ')?)?)?)?' + + '$'); + + var months = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]; + + var dayFromMonth = function dayFromMonth(year, month) { var t = month > 1 ? 1 : 0; return ( months[month] + @@ -985,58 +1470,68 @@ if (!Date.parse || doesNotParseY2KNewYear || acceptsInvalidDates || !supportsExt Math.floor((year - 1601 + t) / 400) + 365 * (year - 1970) ); - } + }; - function toUTC(t) { - return Number(new NativeDate(1970, 0, 1, 0, 0, 0, t)); - } + var toUTC = function toUTC(t) { + var s = 0; + var ms = t; + if (hasSafariSignedIntBug && ms > maxSafeUnsigned32Bit) { + // work around a Safari 8/9 bug where it treats the seconds as signed + var msToShift = Math.floor(ms / maxSafeUnsigned32Bit) * maxSafeUnsigned32Bit; + var sToShift = Math.floor(msToShift / 1e3); + s += sToShift; + ms -= sToShift * 1e3; + } + return $Number(new NativeDate(1970, 0, 1, 0, 0, s, ms)); + }; // Copy any custom methods a 3rd party library may have added for (var key in NativeDate) { - Date[key] = NativeDate[key]; + if (owns(NativeDate, key)) { + DateShim[key] = NativeDate[key]; + } } // Copy "native" methods explicitly; they may be non-enumerable - Date.now = NativeDate.now; - Date.UTC = NativeDate.UTC; - Date.prototype = NativeDate.prototype; - Date.prototype.constructor = Date; + defineProperties(DateShim, { + now: NativeDate.now, + UTC: NativeDate.UTC + }, true); + DateShim.prototype = NativeDate.prototype; + defineProperties(DateShim.prototype, { + constructor: DateShim + }, true); // Upgrade Date.parse to handle simplified ISO 8601 strings - Date.parse = function parse(string) { + var parseShim = function parse(string) { var match = isoDateExpression.exec(string); if (match) { // parse months, days, hours, minutes, seconds, and milliseconds // provide default values if necessary // parse the UTC offset component - var year = Number(match[1]), - month = Number(match[2] || 1) - 1, - day = Number(match[3] || 1) - 1, - hour = Number(match[4] || 0), - minute = Number(match[5] || 0), - second = Number(match[6] || 0), - millisecond = Math.floor(Number(match[7] || 0) * 1000), + var year = $Number(match[1]), + month = $Number(match[2] || 1) - 1, + day = $Number(match[3] || 1) - 1, + hour = $Number(match[4] || 0), + minute = $Number(match[5] || 0), + second = $Number(match[6] || 0), + millisecond = Math.floor($Number(match[7] || 0) * 1000), // When time zone is missed, local offset should be used // (ES 5.1 bug) // see https://bugs.ecmascript.org/show_bug.cgi?id=112 isLocalTime = Boolean(match[4] && !match[8]), - signOffset = match[9] === "-" ? 1 : -1, - hourOffset = Number(match[10] || 0), - minuteOffset = Number(match[11] || 0), + signOffset = match[9] === '-' ? 1 : -1, + hourOffset = $Number(match[10] || 0), + minuteOffset = $Number(match[11] || 0), result; + var hasMinutesOrSecondsOrMilliseconds = minute > 0 || second > 0 || millisecond > 0; if ( - hour < ( - minute > 0 || second > 0 || millisecond > 0 ? - 24 : 25 - ) && + hour < (hasMinutesOrSecondsOrMilliseconds ? 24 : 25) && minute < 60 && second < 60 && millisecond < 1000 && month > -1 && month < 12 && hourOffset < 24 && minuteOffset < 60 && // detect invalid offsets day > -1 && - day < ( - dayFromMonth(year, month + 1) - - dayFromMonth(year, month) - ) + day < (dayFromMonth(year, month + 1) - dayFromMonth(year, month)) ) { result = ( (dayFromMonth(year, month) + day) * 24 + @@ -1058,9 +1553,11 @@ if (!Date.parse || doesNotParseY2KNewYear || acceptsInvalidDates || !supportsExt } return NativeDate.parse.apply(this, arguments); }; + defineProperties(DateShim, { parse: parseShim }); - return Date; - })(Date); + return DateShim; + }(Date)); + /* global Date: false */ } // ES5 15.9.4.4 @@ -1071,7 +1568,6 @@ if (!Date.now) { }; } - // // Number // ====== @@ -1080,10 +1576,10 @@ if (!Date.now) { // ES5.1 15.7.4.5 // http://es5.github.com/#x15.7.4.5 var hasToFixedBugs = NumberPrototype.toFixed && ( - (0.00008).toFixed(3) !== '0.000' - || (0.9).toFixed(0) !== '1' - || (1.255).toFixed(2) !== '1.25' - || (1000000000000000128).toFixed(0) !== "1000000000000000128" + (0.00008).toFixed(3) !== '0.000' || + (0.9).toFixed(0) !== '1' || + (1.255).toFixed(2) !== '1.25' || + (1000000000000000128).toFixed(0) !== '1000000000000000128' ); var toFixedHelpers = { @@ -1092,14 +1588,16 @@ var toFixedHelpers = { data: [0, 0, 0, 0, 0, 0], multiply: function multiply(n, c) { var i = -1; + var c2 = c; while (++i < toFixedHelpers.size) { - c += n * toFixedHelpers.data[i]; - toFixedHelpers.data[i] = c % toFixedHelpers.base; - c = Math.floor(c / toFixedHelpers.base); + c2 += n * toFixedHelpers.data[i]; + toFixedHelpers.data[i] = c2 % toFixedHelpers.base; + c2 = Math.floor(c2 / toFixedHelpers.base); } }, divide: function divide(n) { - var i = toFixedHelpers.size, c = 0; + var i = toFixedHelpers.size; + var c = 0; while (--i >= 0) { c += toFixedHelpers.data[i]; toFixedHelpers.data[i] = Math.floor(c / n); @@ -1111,11 +1609,11 @@ var toFixedHelpers = { var s = ''; while (--i >= 0) { if (s !== '' || i === 0 || toFixedHelpers.data[i] !== 0) { - var t = String(toFixedHelpers.data[i]); + var t = $String(toFixedHelpers.data[i]); if (s === '') { s = t; } else { - s += '0000000'.slice(0, 7 - t.length) + t; + s += strSlice('0000000', 0, 7 - t.length) + t; } } } @@ -1126,105 +1624,117 @@ var toFixedHelpers = { }, log: function log(x) { var n = 0; - while (x >= 4096) { + var x2 = x; + while (x2 >= 4096) { n += 12; - x /= 4096; + x2 /= 4096; } - while (x >= 2) { + while (x2 >= 2) { n += 1; - x /= 2; + x2 /= 2; } return n; } }; -defineProperties(NumberPrototype, { - toFixed: function toFixed(fractionDigits) { - var f, x, s, m, e, z, j, k; - - // Test for NaN and round fractionDigits down - f = Number(fractionDigits); - f = f !== f ? 0 : Math.floor(f); - - if (f < 0 || f > 20) { - throw new RangeError("Number.toFixed called with invalid number of decimals"); - } - - x = Number(this); - - // Test for NaN - if (x !== x) { - return "NaN"; - } +var toFixedShim = function toFixed(fractionDigits) { + var f, x, s, m, e, z, j, k; - // If it is too big or small, return the string value of the number - if (x <= -1e21 || x >= 1e21) { - return String(x); - } + // Test for NaN and round fractionDigits down + f = $Number(fractionDigits); + f = isActualNaN(f) ? 0 : Math.floor(f); - s = ""; + if (f < 0 || f > 20) { + throw new RangeError('Number.toFixed called with invalid number of decimals'); + } - if (x < 0) { - s = "-"; - x = -x; - } + x = $Number(this); - m = "0"; + if (isActualNaN(x)) { + return 'NaN'; + } - if (x > 1e-21) { - // 1e-21 < x < 1e21 - // -70 < log2(x) < 70 - e = toFixedHelpers.log(x * toFixedHelpers.pow(2, 69, 1)) - 69; - z = (e < 0 ? x * toFixedHelpers.pow(2, -e, 1) : x / toFixedHelpers.pow(2, e, 1)); - z *= 0x10000000000000; // Math.pow(2, 52); - e = 52 - e; + // If it is too big or small, return the string value of the number + if (x <= -1e21 || x >= 1e21) { + return $String(x); + } - // -18 < e < 122 - // x = z / 2 ^ e - if (e > 0) { - toFixedHelpers.multiply(0, z); - j = f; + s = ''; - while (j >= 7) { - toFixedHelpers.multiply(1e7, 0); - j -= 7; - } + if (x < 0) { + s = '-'; + x = -x; + } - toFixedHelpers.multiply(toFixedHelpers.pow(10, j, 1), 0); - j = e - 1; + m = '0'; + + if (x > 1e-21) { + // 1e-21 < x < 1e21 + // -70 < log2(x) < 70 + e = toFixedHelpers.log(x * toFixedHelpers.pow(2, 69, 1)) - 69; + z = (e < 0 ? x * toFixedHelpers.pow(2, -e, 1) : x / toFixedHelpers.pow(2, e, 1)); + z *= 0x10000000000000; // Math.pow(2, 52); + e = 52 - e; + + // -18 < e < 122 + // x = z / 2 ^ e + if (e > 0) { + toFixedHelpers.multiply(0, z); + j = f; + + while (j >= 7) { + toFixedHelpers.multiply(1e7, 0); + j -= 7; + } - while (j >= 23) { - toFixedHelpers.divide(1 << 23); - j -= 23; - } + toFixedHelpers.multiply(toFixedHelpers.pow(10, j, 1), 0); + j = e - 1; - toFixedHelpers.divide(1 << j); - toFixedHelpers.multiply(1, 1); - toFixedHelpers.divide(2); - m = toFixedHelpers.numToString(); - } else { - toFixedHelpers.multiply(0, z); - toFixedHelpers.multiply(1 << (-e), 0); - m = toFixedHelpers.numToString() + '0.00000000000000000000'.slice(2, 2 + f); + while (j >= 23) { + toFixedHelpers.divide(1 << 23); + j -= 23; } + + toFixedHelpers.divide(1 << j); + toFixedHelpers.multiply(1, 1); + toFixedHelpers.divide(2); + m = toFixedHelpers.numToString(); + } else { + toFixedHelpers.multiply(0, z); + toFixedHelpers.multiply(1 << (-e), 0); + m = toFixedHelpers.numToString() + strSlice('0.00000000000000000000', 2, 2 + f); } + } - if (f > 0) { - k = m.length; + if (f > 0) { + k = m.length; - if (k <= f) { - m = s + '0.0000000000000000000'.slice(0, f - k + 2) + m; - } else { - m = s + m.slice(0, k - f) + '.' + m.slice(k - f); - } + if (k <= f) { + m = s + strSlice('0.0000000000000000000', 0, f - k + 2) + m; } else { - m = s + m; + m = s + strSlice(m, 0, k - f) + '.' + strSlice(m, k - f); } - - return m; + } else { + m = s + m; } -}, hasToFixedBugs); + return m; +}; +defineProperties(NumberPrototype, { toFixed: toFixedShim }, hasToFixedBugs); + +var hasToPrecisionUndefinedBug = (function () { + try { + return 1.0.toPrecision(undefined) === '1'; + } catch (e) { + return true; + } +}()); +var originalToPrecision = NumberPrototype.toPrecision; +defineProperties(NumberPrototype, { + toPrecision: function toPrecision(precision) { + return typeof precision === 'undefined' ? originalToPrecision.call(this) : originalToPrecision.call(this, precision); + } +}, hasToPrecisionUndefinedBug); // // String @@ -1246,90 +1756,91 @@ defineProperties(NumberPrototype, { // ''.split(/.?/) should be [], not [""] // '.'.split(/()()/) should be ["."], not ["", "", "."] -var string_split = StringPrototype.split; if ( 'ab'.split(/(?:ab)*/).length !== 2 || '.'.split(/(.?)(.?)/).length !== 4 || - 'tesst'.split(/(s)*/)[1] === "t" || + 'tesst'.split(/(s)*/)[1] === 't' || 'test'.split(/(?:)/, -1).length !== 4 || ''.split(/.?/).length || '.'.split(/()()/).length > 1 ) { (function () { - var compliantExecNpcg = /()??/.exec("")[1] === void 0; // NPCG: nonparticipating capturing group + var compliantExecNpcg = typeof (/()??/).exec('')[1] === 'undefined'; // NPCG: nonparticipating capturing group + var maxSafe32BitInt = Math.pow(2, 32) - 1; StringPrototype.split = function (separator, limit) { - var string = this; - if (separator === void 0 && limit === 0) { + var string = String(this); + if (typeof separator === 'undefined' && limit === 0) { return []; } // If `separator` is not a regex, use native split - if (_toString.call(separator) !== "[object RegExp]") { - return string_split.call(this, separator, limit); + if (!isRegex(separator)) { + return strSplit(this, separator, limit); } - var output = [], - flags = (separator.ignoreCase ? "i" : "") + - (separator.multiline ? "m" : "") + - (separator.extended ? "x" : "") + // Proposed for ES6 - (separator.sticky ? "y" : ""), // Firefox 3+ + var output = []; + var flags = (separator.ignoreCase ? 'i' : '') + + (separator.multiline ? 'm' : '') + + (separator.unicode ? 'u' : '') + // in ES6 + (separator.sticky ? 'y' : ''), // Firefox 3+ and ES6 lastLastIndex = 0, // Make `global` and avoid `lastIndex` issues by working with a copy separator2, match, lastIndex, lastLength; - separator = new RegExp(separator.source, flags + "g"); - string += ""; // Type-convert + var separatorCopy = new RegExp(separator.source, flags + 'g'); if (!compliantExecNpcg) { // Doesn't need flags gy, but they don't hurt - separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags); + separator2 = new RegExp('^' + separatorCopy.source + '$(?!\\s)', flags); } /* Values for `limit`, per the spec: - * If undefined: 4294967295 // Math.pow(2, 32) - 1 + * If undefined: 4294967295 // maxSafe32BitInt * If 0, Infinity, or NaN: 0 * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296; * If negative number: 4294967296 - Math.floor(Math.abs(limit)) * If other: Type-convert, then use the above rules */ - limit = limit === void 0 ? - -1 >>> 0 : // Math.pow(2, 32) - 1 - ToUint32(limit); - while (match = separator.exec(string)) { - // `separator.lastIndex` is not reliable cross-browser + var splitLimit = typeof limit === 'undefined' ? maxSafe32BitInt : ES.ToUint32(limit); + match = separatorCopy.exec(string); + while (match) { + // `separatorCopy.lastIndex` is not reliable cross-browser lastIndex = match.index + match[0].length; if (lastIndex > lastLastIndex) { - output.push(string.slice(lastLastIndex, match.index)); + pushCall(output, strSlice(string, lastLastIndex, match.index)); // Fix browsers whose `exec` methods don't consistently return `undefined` for // nonparticipating capturing groups if (!compliantExecNpcg && match.length > 1) { + /* eslint-disable no-loop-func */ match[0].replace(separator2, function () { for (var i = 1; i < arguments.length - 2; i++) { - if (arguments[i] === void 0) { + if (typeof arguments[i] === 'undefined') { match[i] = void 0; } } }); + /* eslint-enable no-loop-func */ } if (match.length > 1 && match.index < string.length) { - ArrayPrototype.push.apply(output, match.slice(1)); + array_push.apply(output, arraySlice(match, 1)); } lastLength = match[0].length; lastLastIndex = lastIndex; - if (output.length >= limit) { + if (output.length >= splitLimit) { break; } } - if (separator.lastIndex === match.index) { - separator.lastIndex++; // Avoid an infinite loop + if (separatorCopy.lastIndex === match.index) { + separatorCopy.lastIndex++; // Avoid an infinite loop } + match = separatorCopy.exec(string); } if (lastLastIndex === string.length) { - if (lastLength || !separator.test("")) { - output.push(""); + if (lastLength || !separatorCopy.test('')) { + pushCall(output, ''); } } else { - output.push(string.slice(lastLastIndex)); + pushCall(output, strSlice(string, lastLastIndex)); } - return output.length > limit ? output.slice(0, limit) : output; + return output.length > splitLimit ? arraySlice(output, 0, splitLimit) : output; }; }()); @@ -1339,10 +1850,10 @@ if ( // then the output array is truncated so that it contains no more than limit // elements. // "0".split(undefined, 0) -> [] -} else if ("0".split(void 0, 0).length) { +} else if ('0'.split(void 0, 0).length) { StringPrototype.split = function split(separator, limit) { - if (separator === void 0 && limit === 0) { return []; } - return string_split.call(this, separator, limit); + if (typeof separator === 'undefined' && limit === 0) { return []; } + return strSplit(this, separator, limit); }; } @@ -1350,14 +1861,14 @@ var str_replace = StringPrototype.replace; var replaceReportsGroupsCorrectly = (function () { var groups = []; 'x'.replace(/x(.)?/g, function (match, group) { - groups.push(group); + pushCall(groups, group); }); return groups.length === 1 && typeof groups[0] === 'undefined'; }()); if (!replaceReportsGroupsCorrectly) { StringPrototype.replace = function replace(searchValue, replaceValue) { - var isFn = isFunction(replaceValue); + var isFn = isCallable(replaceValue); var hasCapturingGroups = isRegex(searchValue) && (/\)[*?]/).test(searchValue.source); if (!isFn || !hasCapturingGroups) { return str_replace.call(this, searchValue, replaceValue); @@ -1366,9 +1877,9 @@ if (!replaceReportsGroupsCorrectly) { var length = arguments.length; var originalLastIndex = searchValue.lastIndex; searchValue.lastIndex = 0; - var args = searchValue.exec(match); + var args = searchValue.exec(match) || []; searchValue.lastIndex = originalLastIndex; - args.push(arguments[length - 2], arguments[length - 1]); + pushCall(args, arguments[length - 2], arguments[length - 1]); return replaceValue.apply(this, args); }; return str_replace.call(this, searchValue, wrappedReplaceValue); @@ -1382,50 +1893,159 @@ if (!replaceReportsGroupsCorrectly) { // normalized across all browsers // [bugfix, IE lt 9] IE < 9 substr() with negative value not working in IE var string_substr = StringPrototype.substr; -var hasNegativeSubstrBug = "".substr && "0b".substr(-1) !== "b"; +var hasNegativeSubstrBug = ''.substr && '0b'.substr(-1) !== 'b'; defineProperties(StringPrototype, { substr: function substr(start, length) { - return string_substr.call( - this, - start < 0 ? ((start = this.length + start) < 0 ? 0 : start) : start, - length - ); + var normalizedStart = start; + if (start < 0) { + normalizedStart = max(this.length + start, 0); + } + return string_substr.call(this, normalizedStart, length); } }, hasNegativeSubstrBug); // ES5 15.5.4.20 // whitespace from: http://es5.github.io/#x15.5.4.20 -var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" + - "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" + - "\u2029\uFEFF"; +var ws = '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003' + + '\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028' + + '\u2029\uFEFF'; var zeroWidth = '\u200b'; -var wsRegexChars = "[" + ws + "]"; -var trimBeginRegexp = new RegExp("^" + wsRegexChars + wsRegexChars + "*"); -var trimEndRegexp = new RegExp(wsRegexChars + wsRegexChars + "*$"); +var wsRegexChars = '[' + ws + ']'; +var trimBeginRegexp = new RegExp('^' + wsRegexChars + wsRegexChars + '*'); +var trimEndRegexp = new RegExp(wsRegexChars + wsRegexChars + '*$'); var hasTrimWhitespaceBug = StringPrototype.trim && (ws.trim() || !zeroWidth.trim()); defineProperties(StringPrototype, { // http://blog.stevenlevithan.com/archives/faster-trim-javascript // http://perfectionkills.com/whitespace-deviations/ trim: function trim() { - if (this === void 0 || this === null) { - throw new TypeError("can't convert " + this + " to object"); + if (typeof this === 'undefined' || this === null) { + throw new TypeError("can't convert " + this + ' to object'); } - return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, ""); + return $String(this).replace(trimBeginRegexp, '').replace(trimEndRegexp, ''); } }, hasTrimWhitespaceBug); +var trim = call.bind(String.prototype.trim); + +var hasLastIndexBug = StringPrototype.lastIndexOf && 'abcあい'.lastIndexOf('あい', 2) !== -1; +defineProperties(StringPrototype, { + lastIndexOf: function lastIndexOf(searchString) { + if (typeof this === 'undefined' || this === null) { + throw new TypeError("can't convert " + this + ' to object'); + } + var S = $String(this); + var searchStr = $String(searchString); + var numPos = arguments.length > 1 ? $Number(arguments[1]) : NaN; + var pos = isActualNaN(numPos) ? Infinity : ES.ToInteger(numPos); + var start = min(max(pos, 0), S.length); + var searchLen = searchStr.length; + var k = start + searchLen; + while (k > 0) { + k = max(0, k - searchLen); + var index = strIndexOf(strSlice(S, k, start + searchLen), searchStr); + if (index !== -1) { + return k + index; + } + } + return -1; + } +}, hasLastIndexBug); + +var originalLastIndexOf = StringPrototype.lastIndexOf; +defineProperties(StringPrototype, { + lastIndexOf: function lastIndexOf(searchString) { + return originalLastIndexOf.apply(this, arguments); + } +}, StringPrototype.lastIndexOf.length !== 1); // ES-5 15.1.2.2 +/* eslint-disable radix */ if (parseInt(ws + '08') !== 8 || parseInt(ws + '0x16') !== 22) { +/* eslint-enable radix */ + /* global parseInt: true */ parseInt = (function (origParseInt) { - var hexRegex = /^0[xX]/; - return function parseIntES5(str, radix) { - str = String(str).trim(); - if (!Number(radix)) { - radix = hexRegex.test(str) ? 16 : 10; - } - return origParseInt(str, radix); + var hexRegex = /^[\-+]?0[xX]/; + return function parseInt(str, radix) { + var string = trim(str); + var defaultedRadix = $Number(radix) || (hexRegex.test(string) ? 16 : 10); + return origParseInt(string, defaultedRadix); }; }(parseInt)); } +// https://es5.github.io/#x15.1.2.3 +if (1 / parseFloat('-0') !== -Infinity) { + /* global parseFloat: true */ + parseFloat = (function (origParseFloat) { + return function parseFloat(string) { + var inputString = trim(string); + var result = origParseFloat(inputString); + return result === 0 && strSlice(inputString, 0, 1) === '-' ? -0 : result; + }; + }(parseFloat)); +} + +if (String(new RangeError('test')) !== 'RangeError: test') { + var errorToStringShim = function toString() { + if (typeof this === 'undefined' || this === null) { + throw new TypeError("can't convert " + this + ' to object'); + } + var name = this.name; + if (typeof name === 'undefined') { + name = 'Error'; + } else if (typeof name !== 'string') { + name = $String(name); + } + var msg = this.message; + if (typeof msg === 'undefined') { + msg = ''; + } else if (typeof msg !== 'string') { + msg = $String(msg); + } + if (!name) { + return msg; + } + if (!msg) { + return name; + } + return name + ': ' + msg; + }; + // can't use defineProperties here because of toString enumeration issue in IE <= 8 + Error.prototype.toString = errorToStringShim; +} + +if (supportsDescriptors) { + var ensureNonEnumerable = function (obj, prop) { + if (isEnum(obj, prop)) { + var desc = Object.getOwnPropertyDescriptor(obj, prop); + if (desc.configurable) { + desc.enumerable = false; + Object.defineProperty(obj, prop, desc); + } + } + }; + ensureNonEnumerable(Error.prototype, 'message'); + if (Error.prototype.message !== '') { + Error.prototype.message = ''; + } + ensureNonEnumerable(Error.prototype, 'name'); +} + +if (String(/a/mig) !== '/a/gim') { + var regexToString = function toString() { + var str = '/' + this.source + '/'; + if (this.global) { + str += 'g'; + } + if (this.ignoreCase) { + str += 'i'; + } + if (this.multiline) { + str += 'm'; + } + return str; + }; + // can't use defineProperties here because of toString enumeration issue in IE <= 8 + RegExp.prototype.toString = regexToString; +} + }));