From 3e8afc2a154749ff08d389307d41a92f58603c49 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Sat, 21 Nov 2015 06:24:39 -0800 Subject: [PATCH 01/12] [Tests] on `node` `v5.1` --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index a96d78ca..95aa5798 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: node_js node_js: + - "5.1" - "5.0" - "4.2" - "4.1" @@ -39,6 +40,7 @@ sudo: false matrix: fast_finish: true allow_failures: + - node_js: "5.0" - node_js: "4.1" - node_js: "4.0" - node_js: "iojs-v3.2" From 41d8c50b5aa9b89b5b22a248e3796af5a80857f2 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Sat, 21 Nov 2015 06:25:30 -0800 Subject: [PATCH 02/12] [Dev Deps] update `eslint`, `jscs`, `uglify-js`, `semver` --- .jscs.json | 14 +++++++++++++- es5-shim.js | 3 +-- package.json | 8 ++++---- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/.jscs.json b/.jscs.json index e83d9191..629794b7 100644 --- a/.jscs.json +++ b/.jscs.json @@ -135,6 +135,18 @@ "requireSpacesInGenerator": { "afterStar": true - } + }, + + "disallowSpacesInGenerator": { + "beforeStar": true + }, + + "disallowVar": false, + + "requireArrayDestructuring": false, + + "requireEnhancedObjectLiterals": false, + + "requireObjectDestructuring": false } diff --git a/es5-shim.js b/es5-shim.js index d6563dd0..1f2c4aca 100644 --- a/es5-shim.js +++ b/es5-shim.js @@ -1496,7 +1496,7 @@ if ( var maxSafe32BitInt = Math.pow(2, 32) - 1; StringPrototype.split = function (separator, limit) { - var string = this; + var string = String(this); if (typeof separator === 'undefined' && limit === 0) { return []; } @@ -1515,7 +1515,6 @@ if ( // Make `global` and avoid `lastIndex` issues by working with a copy separator2, match, lastIndex, lastLength; var separatorCopy = new RegExp(separator.source, flags + 'g'); - string += ''; // Type-convert if (!compliantExecNpcg) { // Doesn't need flags gy, but they don't hurt separator2 = new RegExp('^' + separatorCopy.source + '$(?!\\s)', flags); diff --git a/package.json b/package.json index 4c607ceb..7e3bca0a 100644 --- a/package.json +++ b/package.json @@ -33,13 +33,13 @@ "jscs": "jscs tests/helpers/*.js tests/spec/*.js es5-shim.js es5-sham.js" }, "devDependencies": { - "eslint": "^1.9.0", + "eslint": "^1.10.1", "@ljharb/eslint-config": "^1.6.0", "jasmine-node": "^1.14.5", - "jscs": "^2.5.1", - "uglify-js": "^2.6.0", + "jscs": "^2.6.0", + "uglify-js": "^2.6.1", "replace": "^0.3.0", - "semver": "^5.0.3" + "semver": "^5.1.0" }, "engines": { "node": ">=0.4.0" From 59627c0f1815e7b7dfffa142b6f54f712fe0b032 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Sun, 29 Nov 2015 12:21:56 -0800 Subject: [PATCH 03/12] [Fix] Ensure that `Error#message` and `Error#name` are non-enumerable. Broken in IE 9, Firefox 4 - 27, Opera 11/12. Fixes #358. --- es5-shim.js | 36 ++++++++++++++++++++++++------------ tests/spec/s-error.js | 38 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 14 deletions(-) diff --git a/es5-shim.js b/es5-shim.js index 1f2c4aca..e30fcd13 100644 --- a/es5-shim.js +++ b/es5-shim.js @@ -68,19 +68,18 @@ var isRegex; /* inlined from https://npmjs.com/is-regex */ var regexExec = RegEx 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; }; /* inlined from http://npmjs.com/define-properties */ +var supportsDescriptors = $Object.defineProperty && (function () { + try { + 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; + } +}()); var defineProperties = (function (has) { - var supportsDescriptors = $Object.defineProperty && (function () { - try { - 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 + // Define configurable, writable, and non-enumerable props // if they don't exist. var defineProperty; if (supportsDescriptors) { @@ -327,6 +326,7 @@ var strSlice = call.bind(StringPrototype.slice); var strSplit = call.bind(StringPrototype.split); var strIndexOf = call.bind(StringPrototype.indexOf); var push = call.bind(array_push); +var isEnum = call.bind(ObjectPrototype.propertyIsEnumerable); // // Array @@ -1728,4 +1728,16 @@ if (String(new RangeError('test')) !== 'RangeError: test') { Error.prototype.toString = errorToStringShim; } +if (supportsDescriptors) { + var ensureNonEnumerable = function (obj, prop) { + if (isEnum(obj, prop)) { + var desc = Object.getOwnPropertyDescriptor(obj, prop); + desc.enumerable = false; + Object.defineProperty(obj, prop, desc); + } + }; + ensureNonEnumerable(Error.prototype, 'message'); + ensureNonEnumerable(Error.prototype, 'name'); +} + })); diff --git a/tests/spec/s-error.js b/tests/spec/s-error.js index 1326408b..bd9917d0 100644 --- a/tests/spec/s-error.js +++ b/tests/spec/s-error.js @@ -1,8 +1,20 @@ -/* global describe, it, expect */ +/* global describe, it, xit, expect */ describe('Error', function () { 'use strict'; + var supportsDescriptors = Object.defineProperty && (function () { + try { + 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; + } + }()); + var ifSupportsDescriptorsIt = supportsDescriptors ? it : xit; + describe('#toString()', function () { it('stringifies a newed error properly', function () { var msg = 'test'; @@ -19,10 +31,32 @@ describe('Error', function () { throw new RangeError(msg); } catch (e) { error = e; - }; + } expect(error.name).toBe('RangeError'); expect(error.message).toBe(msg); expect(String(error)).toBe(error.name + ': ' + msg); }); }); + + describe('enumerability of prototype properties', function () { + ifSupportsDescriptorsIt('#message', function () { + var desc = Object.getOwnPropertyDescriptor(Error.prototype, 'message'); + expect(desc).toEqual({ + enumerable: false, + writable: true, + configurable: true, + value: '' + }); + }); + + ifSupportsDescriptorsIt('#name', function () { + var desc = Object.getOwnPropertyDescriptor(Error.prototype, 'name'); + expect(desc).toEqual({ + enumerable: false, + writable: true, + configurable: true, + value: 'Error' + }); + }); + }); }); From 7f38f764befe94f20824d2ffcdfcd6f871921224 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joe=CC=88l=20Galeran?= Date: Fri, 13 Nov 2015 11:42:53 +0100 Subject: [PATCH 04/12] [Docs] Fix broken UMD links. Closes #344. --- es5-sham.js | 2 +- es5-shim.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/es5-sham.js b/es5-sham.js index 9a15cbd8..8b46eeac 100644 --- a/es5-sham.js +++ b/es5-sham.js @@ -10,7 +10,7 @@ ; // 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'; diff --git a/es5-shim.js b/es5-shim.js index e30fcd13..abc2a57c 100644 --- a/es5-shim.js +++ b/es5-shim.js @@ -10,7 +10,7 @@ ; // 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'; From 8984f6e230cab6b7606ea3c5a7ddacd8a6834354 Mon Sep 17 00:00:00 2001 From: Xotic750 Date: Thu, 19 Nov 2015 13:36:34 +0100 Subject: [PATCH 05/12] [Tests] `Array#join`: Extend `join` tests --- tests/spec/s-array.js | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/tests/spec/s-array.js b/tests/spec/s-array.js index 0b7c88ed..254c2e1c 100644 --- a/tests/spec/s-array.js +++ b/tests/spec/s-array.js @@ -1499,6 +1499,34 @@ describe('Array', function () { it('defaults to a comma separator when undefined is provided', function () { expect([1, 2].join(undefined)).toBe('1,2'); }); + + it('works, extended', function () { + expect([].join()).toBe(''); + expect([undefined].join()).toBe(''); + expect([undefined, undefined].join()).toBe(','); + expect([null, null].join()).toBe(','); + expect([undefined, undefined].join('|')).toBe('|'); + expect([null, null].join('|')).toBe('|'); + expect([1, 2, 3].join('|')).toBe('1|2|3'); + expect([1, 2, 3].join(null)).toBe('1null2null3'); + expect([1, 2, 3].join({})).toBe('1[object Object]2[object Object]3'); + expect([1, 2, 3].join('')).toBe('123'); + }); + + it('is generic', function () { + var obj = { 0: 1, 1: 2, 2: 3, 3: 4, length: 3 }; + expect(Array.prototype.join.call(obj, ',')).toBe('1,2,3'); + }); + + it('works with a string literal', function () { + var str = '123'; + expect(Array.prototype.join.call(str, ',')).toBe('1,2,3'); + }); + + it('works with `arguments`', function () { + var args = (function () { return arguments; }(1, 2, 3)); + expect(Array.prototype.join.call(args, ',')).toBe('1,2,3'); + }); }); describe('#push()', function () { @@ -1554,7 +1582,7 @@ describe('Array', function () { expect(result).toEqual([2, 3]); }); - it('works with arguments', function () { + it('works with `arguments`', function () { var obj = (function () { return arguments; }(1, 2, 3, 4)); From 82f046e8766a5944aca2472ed3b109018ca72c9a Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Sun, 29 Nov 2015 13:10:46 -0800 Subject: [PATCH 06/12] [Fix] `Array#join`: fix IE 6-8 join called on string literals Fixes #352. --- es5-shim.js | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/es5-shim.js b/es5-shim.js index abc2a57c..7f717806 100644 --- a/es5-shim.js +++ b/es5-shim.js @@ -826,13 +826,26 @@ defineProperties(ArrayPrototype, { } }, !spliceWorksWithLargeSparseArrays || !spliceWorksWithSmallSparseArrays); -var hasJoinUndefinedBug = [1, 2].join(undefined) !== '1,2'; var originalJoin = ArrayPrototype.join; -defineProperties(ArrayPrototype, { - join: function join(separator) { - return originalJoin.call(this, typeof separator === 'undefined' ? ',' : separator); - } -}, hasJoinUndefinedBug); +var hasStringJoinBug = Array.prototype.join.call('123', ',') !== '1,2,3'; +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); From 1062826c779c6c489e50adf7bfdb7f885b760a57 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Sun, 29 Nov 2015 21:49:37 -0800 Subject: [PATCH 07/12] [Robustness] Use a bound form of `Array#slice.call` --- es5-shim.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/es5-shim.js b/es5-shim.js index 7f717806..d6200e6c 100644 --- a/es5-shim.js +++ b/es5-shim.js @@ -322,6 +322,7 @@ defineProperties(FunctionPrototype, { // us it in defining shortcuts. var owns = call.bind(ObjectPrototype.hasOwnProperty); var toStr = call.bind(ObjectPrototype.toString); +var arraySlice = call.bind(array_slice); var strSlice = call.bind(StringPrototype.slice); var strSplit = call.bind(StringPrototype.split); var strIndexOf = call.bind(StringPrototype.indexOf); @@ -733,7 +734,7 @@ defineProperties(ArrayPrototype, { var args = arguments; this.length = max(ES.ToInteger(this.length), 0); if (arguments.length > 0 && typeof deleteCount !== 'number') { - args = array_slice.call(arguments); + args = arraySlice(arguments); if (args.length < 2) { push(args, this.length - start); } else { @@ -782,7 +783,7 @@ defineProperties(ArrayPrototype, { k += 1; } - var items = array_slice.call(arguments, 2); + var items = arraySlice(arguments, 2); var itemCount = items.length; var to; if (itemCount < actualDeleteCount) { @@ -1008,7 +1009,7 @@ var originalKeys = $Object.keys; defineProperties($Object, { keys: function keys(object) { if (isArguments(object)) { - return originalKeys(array_slice.call(object)); + return originalKeys(arraySlice(object)); } else { return originalKeys(object); } @@ -1064,8 +1065,8 @@ defineProperties(Date.prototype, { } // pad milliseconds to have three digits. return ( - year + '-' + array_slice.call(result, 0, 2).join('-') + - 'T' + array_slice.call(result, 2).join(':') + '.' + + year + '-' + arraySlice(result, 0, 2).join('-') + + 'T' + arraySlice(result, 2).join(':') + '.' + strSlice('000' + this.getUTCMilliseconds(), -3) + 'Z' ); } @@ -1560,7 +1561,7 @@ if ( /* eslint-enable no-loop-func */ } if (match.length > 1 && match.index < string.length) { - array_push.apply(output, array_slice.call(match, 1)); + array_push.apply(output, arraySlice(match, 1)); } lastLength = match[0].length; lastLastIndex = lastIndex; From 998a2dcedf244fc3aa7c41aaa3ed93c93dd2ff1c Mon Sep 17 00:00:00 2001 From: Xotic750 Date: Thu, 19 Nov 2015 01:01:30 +0100 Subject: [PATCH 08/12] [Fix] `Array#slice`: boxed string access on IE <= 8 Fixes #349. --- es5-shim.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/es5-shim.js b/es5-shim.js index d6200e6c..68c9cb43 100644 --- a/es5-shim.js +++ b/es5-shim.js @@ -56,6 +56,7 @@ var array_push = ArrayPrototype.push; var array_unshift = ArrayPrototype.unshift; var array_concat = ArrayPrototype.concat; var call = FunctionPrototype.call; +var apply = FunctionPrototype.apply; var max = Math.max; var min = Math.min; @@ -323,6 +324,7 @@ defineProperties(FunctionPrototype, { var owns = call.bind(ObjectPrototype.hasOwnProperty); 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); @@ -882,6 +884,16 @@ var pushUndefinedIsWeird = (function () { }()); 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); + // // Object // ====== From e145cad81034e843d5e49e715e27accc5b1f6349 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Sun, 29 Nov 2015 22:00:36 -0800 Subject: [PATCH 09/12] [Linter] Remove unused variables. --- es5-shim.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/es5-shim.js b/es5-shim.js index 68c9cb43..36855560 100644 --- a/es5-shim.js +++ b/es5-shim.js @@ -1149,7 +1149,6 @@ if (doesNotParseY2KNewYear || acceptsInvalidDates || !supportsExtendedYears) { /* global Date: true */ /* eslint-disable no-undef */ var maxSafeUnsigned32Bit = Math.pow(2, 31) - 1; - var secondsWithinMaxSafeUnsigned32Bit = Math.floor(maxSafeUnsigned32Bit / 1e3); var hasSafariSignedIntBug = isActualNaN(new Date(1970, 0, 1, 0, 0, 0, maxSafeUnsigned32Bit + 1).getTime()); Date = (function (NativeDate) { /* eslint-enable no-undef */ @@ -1725,7 +1724,6 @@ if (parseInt(ws + '08') !== 8 || parseInt(ws + '0x16') !== 22) { } if (String(new RangeError('test')) !== 'RangeError: test') { - var originalErrorToString = Error.prototype.toString; var errorToStringShim = function toString() { if (typeof this === 'undefined' || this === null) { throw new TypeError("can't convert " + this + ' to object'); From bed1cdaa0f038d7472ce5a9bcf965d30cedc252d Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Sun, 29 Nov 2015 22:10:18 -0800 Subject: [PATCH 10/12] [Tests] Properly check for descriptor support in IE <= 8. --- tests/spec/s-object.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/spec/s-object.js b/tests/spec/s-object.js index c17f1bde..0ec804ee 100644 --- a/tests/spec/s-object.js +++ b/tests/spec/s-object.js @@ -1,5 +1,15 @@ /* global describe, it, xit, expect, beforeEach, jasmine, window */ +var supportsDescriptors = Object.defineProperty && (function () { + try { + 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; + } +}()); var ifWindowIt = typeof window === 'undefined' ? xit : it; var extensionsPreventible = typeof Object.preventExtensions === 'function' && (function () { var obj = {}; @@ -131,7 +141,7 @@ describe('Object', function () { var has = Object.prototype.hasOwnProperty; var windowItemKeys, exception; var blacklistedKeys = ['window', 'console', 'parent', 'self', 'frame', 'frames', 'frameElement']; - if (Object.defineProperty) { + if (supportsDescriptors) { Object.defineProperty(window, 'thrower', { configurable: true, get: function () { throw new RangeError('thrower!'); } }); } for (var k in window) { @@ -146,7 +156,9 @@ describe('Object', function () { expect(exception).toBeUndefined(); } } - delete window.thrower; + if (supportsDescriptors) { + delete window.thrower; + } }); }); From 649a59bd8afbb0dcdde6a47c972fd571ef6c242c Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Thu, 3 Dec 2015 23:51:31 -0800 Subject: [PATCH 11/12] [Tests] In Safari 4, `Error#message` is initially "Unknown Error". --- es5-shim.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/es5-shim.js b/es5-shim.js index 36855560..0858e171 100644 --- a/es5-shim.js +++ b/es5-shim.js @@ -1761,6 +1761,9 @@ if (supportsDescriptors) { } }; ensureNonEnumerable(Error.prototype, 'message'); + if (Error.prototype.message !== '') { + Error.prototype.message = ''; + } ensureNonEnumerable(Error.prototype, 'name'); } From 568c3e39a3f876945aaef4dc765f7214aa928ee8 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Thu, 3 Dec 2015 23:57:22 -0800 Subject: [PATCH 12/12] [Fix] In IE 6, `window.external` makes `Object.keys` throw. --- es5-shim.js | 3 ++- tests/spec/s-object.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/es5-shim.js b/es5-shim.js index 0858e171..143ae056 100644 --- a/es5-shim.js +++ b/es5-shim.js @@ -919,7 +919,8 @@ var blacklistedKeys = { $frames: true, $frameElement: true, $webkitIndexedDB: true, - $webkitStorageInfo: true + $webkitStorageInfo: true, + $external: true }; var hasAutomationEqualityBug = (function () { /* globals window */ diff --git a/tests/spec/s-object.js b/tests/spec/s-object.js index 0ec804ee..7bd4ea0d 100644 --- a/tests/spec/s-object.js +++ b/tests/spec/s-object.js @@ -140,7 +140,7 @@ describe('Object', function () { ifWindowIt('can serialize all objects on the `window`', function () { var has = Object.prototype.hasOwnProperty; var windowItemKeys, exception; - var blacklistedKeys = ['window', 'console', 'parent', 'self', 'frame', 'frames', 'frameElement']; + var blacklistedKeys = ['window', 'console', 'parent', 'self', 'frame', 'frames', 'frameElement', 'external']; if (supportsDescriptors) { Object.defineProperty(window, 'thrower', { configurable: true, get: function () { throw new RangeError('thrower!'); } }); }