[Pkg-javascript-commits] [node-es6-shim] 01/03: Imported Upstream version 0.34.1+ds
Julien Puydt
julien.puydt at laposte.net
Fri Jan 8 16:41:06 UTC 2016
This is an automated email from the git hooks/post-receive script.
jpuydt-guest pushed a commit to branch master
in repository node-es6-shim.
commit 13ea6c6df849e3fceff182655a97e4661888f9f9
Author: Julien Puydt <julien.puydt at laposte.net>
Date: Fri Jan 8 14:59:21 2016 +0100
Imported Upstream version 0.34.1+ds
---
.gitignore | 2 -
.jscs.json | 4 +-
.jshintrc | 3 +-
.npmignore | 3 -
.travis.yml | 4 +
CHANGELOG.md | 17 +
component.json | 2 +-
es6-sham.js | 4 +-
es6-sham.min.js | 4 +-
es6-shim.js | 396 +++++++++++------
es6-shim.map | 2 +-
es6-shim.min.js | 8 +-
package.json | 6 +-
test/collections.js | 1173 ---------------------------------------------------
test/index.html | 3 +-
test/map.js | 605 ++++++++++++++++++++++++++
test/native.html | 3 +-
test/set.js | 639 ++++++++++++++++++++++++++++
test/string.js | 9 +-
testling.html | 3 +-
20 files changed, 1565 insertions(+), 1325 deletions(-)
diff --git a/.gitignore b/.gitignore
index e66145f..646ac51 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,2 @@
.DS_Store
node_modules/
-components
-build
diff --git a/.jscs.json b/.jscs.json
index a31c73a..f00a97b 100644
--- a/.jscs.json
+++ b/.jscs.json
@@ -147,6 +147,8 @@
"requireEnhancedObjectLiterals": false,
- "requireObjectDestructuring": false
+ "requireObjectDestructuring": false,
+
+ "requireEarlyReturn": false
}
diff --git a/.jshintrc b/.jshintrc
index 36d4331..d2e7ca6 100644
--- a/.jshintrc
+++ b/.jshintrc
@@ -2,5 +2,6 @@
"es3": true,
"esnext": true,
"sub": true,
- "newcap": false
+ "newcap": false,
+ "notypeof": true
}
diff --git a/.npmignore b/.npmignore
index d681c02..70cf7b1 100644
--- a/.npmignore
+++ b/.npmignore
@@ -1,7 +1,4 @@
.DS_Store
node_modules/
-test/
-components
-build
.travis.yml
testling.html
diff --git a/.travis.yml b/.travis.yml
index 841474b..3d0baf5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,7 @@
language: node_js
node_js:
+ - "5.3"
+ - "5.2"
- "5.1"
- "5.0"
- "4.2"
@@ -51,6 +53,8 @@ matrix:
- node_js: "0.12"
env: TRAVIS_RUN_SAUCE=false TRAVIS_RUN_LINT_ONLY=false
allow_failures:
+ - node_js: "5.2"
+ - node_js: "5.1"
- node_js: "5.0"
- node_js: "4.1"
- node_js: "4.0"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4850d79..5a57682 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,22 @@
# es6-shim x.x.x (not yet released)
+# es6-shim 0.34.1 (5 Jan 2016)
+* [Fix] `RegExp#[Symbol.search]` was broken with a regex argument (#394)
+* [Fix] ensure that Set#clear works with both primitive and object values
+* [Fix] static Promise methods have the wrong length in Firefox
+* [Robustness] Cache `Object.keys`
+* [Performance] Avoid accessing arguments array without length check
+* [Performance] Optimize ES.TypeIsObject (#388)
+* [Performance] Promises: lots of improvements (#383)
+* [Performance] Only use slow implementation of IsCallable where necessary (old browsers)
+* [Performance] Promises: remove unnecessary `.bind` on `setImmediate`
+* [Refactor] extract “decode fast Map key” logic
+* [Dev Deps] update `s5-shim`, `@ljharb/eslint-config`
+* Don’t npmignore tests
+* [Tests] Fix a bug with “deep equal” wrt NaN
+* [Tests] split up Map and Set test files
+* [Tests] up to `node` `v5.3`
+
# es6-shim 0.34.0 (14 Dec 2015)
* [Breaking] Remove `Symbol.species` from `Promise.all` and `Promise.race` (#34)
* [Fix] Firefox has enumerable Promise static methods
diff --git a/component.json b/component.json
index 22bea44..c971adf 100644
--- a/component.json
+++ b/component.json
@@ -1,6 +1,6 @@
{
"name": "es6-shim",
- "version": "0.34.0",
+ "version": "0.34.1",
"repo": "paulmillr/es6-shim",
"description": "ECMAScript 6 (Harmony) compatibility shims for legacy JavaScript engines",
"keywords": [
diff --git a/es6-sham.js b/es6-sham.js
index d3f16a6..7e49121 100644
--- a/es6-sham.js
+++ b/es6-sham.js
@@ -2,8 +2,8 @@
* https://github.com/paulmillr/es6-shim
* @license es6-shim Copyright 2013-2015 by Paul Miller (http://paulmillr.com)
* and contributors, MIT License
- * es6-sham: v0.34.0
- * see https://github.com/paulmillr/es6-shim/blob/0.34.0/LICENSE
+ * es6-sham: v0.34.1
+ * see https://github.com/paulmillr/es6-shim/blob/0.34.1/LICENSE
* Details and documentation:
* https://github.com/paulmillr/es6-shim/
*/
diff --git a/es6-sham.min.js b/es6-sham.min.js
index 909edd8..1dda0d0 100644
--- a/es6-sham.min.js
+++ b/es6-sham.min.js
@@ -2,8 +2,8 @@
* https://github.com/paulmillr/es6-shim
* @license es6-shim Copyright 2013-2015 by Paul Miller (http://paulmillr.com)
* and contributors, MIT License
- * es6-sham: v0.34.0
- * see https://github.com/paulmillr/es6-shim/blob/0.34.0/LICENSE
+ * es6-sham: v0.34.1
+ * see https://github.com/paulmillr/es6-shim/blob/0.34.1/LICENSE
* Details and documentation:
* https://github.com/paulmillr/es6-shim/
*/
diff --git a/es6-shim.js b/es6-shim.js
index 18b90be..f6058ae 100644
--- a/es6-shim.js
+++ b/es6-shim.js
@@ -2,8 +2,8 @@
* https://github.com/paulmillr/es6-shim
* @license es6-shim Copyright 2013-2015 by Paul Miller (http://paulmillr.com)
* and contributors, MIT License
- * es6-shim: v0.34.0
- * see https://github.com/paulmillr/es6-shim/blob/0.34.0/LICENSE
+ * es6-shim: v0.34.1
+ * see https://github.com/paulmillr/es6-shim/blob/0.34.1/LICENSE
* Details and documentation:
* https://github.com/paulmillr/es6-shim/
*/
@@ -30,6 +30,7 @@
var _apply = Function.call.bind(Function.apply);
var _call = Function.call.bind(Function.call);
var isArray = Array.isArray;
+ var keys = Object.keys;
var not = function notThunker(func) {
return function notThunk() { return !_apply(func, this, arguments); };
@@ -80,17 +81,17 @@
// Define configurable, writable and non-enumerable props
// if they don’t exist.
var defineProperties = function (object, map, forceOverride) {
- _forEach(Object.keys(map), function (name) {
+ _forEach(keys(map), function (name) {
var method = map[name];
defineProperty(object, name, method, !!forceOverride);
});
};
var _toString = Function.call.bind(Object.prototype.toString);
- var isCallable = function isCallable(x) {
- // some old browsers (IE, FF) say that typeof /abc/ === 'function'
+ var isCallable = typeof /abc/ === 'function' ? function IsCallableSlow(x) {
+ // Some old browsers (IE, FF) say that typeof /abc/ === 'function'
return typeof x === 'function' && _toString(x) === '[object Function]';
- };
+ } : function IsCallableFast(x) { return typeof x === 'function'; };
var Value = {
getter: function (object, name, getter) {
@@ -145,7 +146,7 @@
Prototype.prototype = prototype;
var object = new Prototype();
if (typeof properties !== 'undefined') {
- Object.keys(properties).forEach(function (key) {
+ keys(properties).forEach(function (key) {
Value.defineByDescriptor(object, key, properties[key]);
});
}
@@ -285,11 +286,20 @@
return x;
},
+ // This might miss the "(non-standard exotic and does not implement
+ // [[Call]])" case from
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-typeof-operator-runtime-semantics-evaluation
+ // but we can't find any evidence these objects exist in practice.
+ // If we find some in the future, you could test `Object(x) === x`,
+ // which is reliable according to
+ // http://www.ecma-international.org/ecma-262/6.0/#sec-toobject
+ // but is not well optimized by runtimes and creates an object
+ // whenever it returns false, and thus is very slow.
TypeIsObject: function (x) {
- /* jshint eqnull:true */
- // this is expensive when it returns false; use this function
- // when you expect it to return true in the common case.
- return x != null && Object(x) === x;
+ if (x === void 0 || x === null || x === true || x === false) {
+ return false;
+ }
+ return typeof x === 'function' || typeof x === 'object';
},
ToObject: function (o, optMessage) {
@@ -506,7 +516,7 @@
var symbolSearch = defineWellKnownSymbol('search');
var originalSearch = String.prototype.search;
defineProperty(RegExp.prototype, symbolSearch, function search(string) {
- return ES.Call(originalSearch, string, [ES.ToString(this)]);
+ return ES.Call(originalSearch, string, [this]);
});
var searchShim = function search(regexp) {
var O = ES.RequireObjectCoercible(this);
@@ -752,27 +762,33 @@
},
startsWith: function startsWith(searchString) {
- var thisStr = ES.ToString(ES.RequireObjectCoercible(this));
+ var S = ES.ToString(ES.RequireObjectCoercible(this));
if (ES.IsRegExp(searchString)) {
throw new TypeError('Cannot call method "startsWith" with a regex');
}
var searchStr = ES.ToString(searchString);
- var startArg = arguments.length > 1 ? arguments[1] : void 0;
- var start = _max(ES.ToInteger(startArg), 0);
- return _strSlice(thisStr, start, start + searchStr.length) === searchStr;
+ var position;
+ if (arguments.length > 1) {
+ position = arguments[1];
+ }
+ var start = _max(ES.ToInteger(position), 0);
+ return _strSlice(S, start, start + searchStr.length) === searchStr;
},
endsWith: function endsWith(searchString) {
- var thisStr = ES.ToString(ES.RequireObjectCoercible(this));
+ var S = ES.ToString(ES.RequireObjectCoercible(this));
if (ES.IsRegExp(searchString)) {
throw new TypeError('Cannot call method "endsWith" with a regex');
}
var searchStr = ES.ToString(searchString);
- var thisLen = thisStr.length;
- var posArg = arguments.length > 1 ? arguments[1] : void 0;
- var pos = typeof posArg === 'undefined' ? thisLen : ES.ToInteger(posArg);
- var end = _min(_max(pos, 0), thisLen);
- return _strSlice(thisStr, end - searchStr.length, end) === searchStr;
+ var len = S.length;
+ var endPosition;
+ if (arguments.length > 1) {
+ endPosition = arguments[1];
+ }
+ var pos = typeof endPosition === 'undefined' ? len : ES.ToInteger(endPosition);
+ var end = _min(_max(pos, 0), len);
+ return _strSlice(S, end - searchStr.length, end) === searchStr;
},
includes: function includes(searchString) {
@@ -894,15 +910,20 @@
var ArrayShims = {
from: function from(items) {
var C = this;
- var mapFn = arguments.length > 1 ? arguments[1] : void 0;
+ var mapFn;
+ if (arguments.length > 1) {
+ mapFn = arguments[1];
+ }
var mapping, T;
- if (mapFn === void 0) {
+ if (typeof mapFn === 'undefined') {
mapping = false;
} else {
if (!ES.IsCallable(mapFn)) {
throw new TypeError('Array.from: when provided, the second argument must be a function');
}
- T = arguments.length > 2 ? arguments[2] : void 0;
+ if (arguments.length > 2) {
+ T = arguments[2];
+ }
mapping = true;
}
@@ -925,7 +946,7 @@
nextValue = next.value;
try {
if (mapping) {
- nextValue = T === undefined ? mapFn(nextValue, i) : _call(mapFn, T, nextValue, i);
+ nextValue = typeof T === 'undefined' ? mapFn(nextValue, i) : _call(mapFn, T, nextValue, i);
}
result[i] = nextValue;
} catch (e) {
@@ -943,7 +964,7 @@
for (i = 0; i < length; ++i) {
value = arrayLike[i];
if (mapping) {
- value = T !== undefined ? _call(mapFn, T, value, i) : mapFn(value, i);
+ value = typeof T === 'undefined' ? mapFn(value, i) : _call(mapFn, T, value, i);
}
result[i] = value;
}
@@ -1092,16 +1113,19 @@
var ArrayPrototypeShims = {
copyWithin: function copyWithin(target, start) {
- var end = arguments[2]; // copyWithin.length must be 2
var o = ES.ToObject(this);
var len = ES.ToLength(o.length);
var relativeTarget = ES.ToInteger(target);
var relativeStart = ES.ToInteger(start);
var to = relativeTarget < 0 ? _max(len + relativeTarget, 0) : _min(relativeTarget, len);
var from = relativeStart < 0 ? _max(len + relativeStart, 0) : _min(relativeStart, len);
- end = typeof end === 'undefined' ? len : ES.ToInteger(end);
- var fin = end < 0 ? _max(len + end, 0) : _min(end, len);
- var count = _min(fin - from, len - to);
+ var end;
+ if (arguments.length > 2) {
+ end = arguments[2];
+ }
+ var relativeEnd = typeof end === 'undefined' ? len : ES.ToInteger(end);
+ var finalItem = relativeEnd < 0 ? _max(len + relativeEnd, 0) : _min(relativeEnd, len);
+ var count = _min(finalItem - from, len - to);
var direction = 1;
if (from < to && to < (from + count)) {
direction = -1;
@@ -1122,8 +1146,14 @@
},
fill: function fill(value) {
- var start = arguments.length > 1 ? arguments[1] : void 0;
- var end = arguments.length > 2 ? arguments[2] : void 0;
+ var start;
+ if (arguments.length > 1) {
+ start = arguments[1];
+ }
+ var end;
+ if (arguments.length > 2) {
+ end = arguments[2];
+ }
var O = ES.ToObject(this);
var len = ES.ToLength(O.length);
start = ES.ToInteger(typeof start === 'undefined' ? 0 : start);
@@ -1234,12 +1264,12 @@
var arrayFromHandlesUndefinedMapFunction = (function () {
// Microsoft Edge v0.11 throws if the mapFn argument is *provided* but undefined,
// but the spec doesn't care if it's provided or not - undefined doesn't throw.
- return valueOrFalseIfThrows(function () { return Array.from([0], undefined); });
+ return valueOrFalseIfThrows(function () { return Array.from([0], void 0); });
}());
if (!arrayFromHandlesUndefinedMapFunction) {
var origArrayFrom = Array.from;
overrideNative(Array, 'from', function from(items) {
- if (arguments.length > 0 && typeof arguments[1] !== 'undefined') {
+ if (arguments.length > 1 && typeof arguments[1] !== 'undefined') {
return ES.Call(origArrayFrom, this, arguments);
} else {
return _call(origArrayFrom, this, items);
@@ -1439,12 +1469,12 @@
};
};
var assignReducer = function (target, source) {
- var keys = Object.keys(Object(source));
+ var sourceKeys = keys(Object(source));
var symbols;
if (ES.IsCallable(Object.getOwnPropertySymbols)) {
symbols = _filter(Object.getOwnPropertySymbols(Object(source)), isEnumerableOn(source));
}
- return _reduce(_concat(keys, symbols || []), assignTo(source), target);
+ return _reduce(_concat(sourceKeys, symbols || []), assignTo(source), target);
};
var ObjectShims = {
@@ -1559,6 +1589,7 @@
overrideNative(Object, 'keys', function keys(value) {
return originalObjectKeys(ES.ToObject(value));
});
+ keys = Object.keys;
}
if (Object.getOwnPropertyNames) {
@@ -1747,7 +1778,7 @@
leftContext: '$`',
rightContext: '$\''
};
- _forEach(Object.keys(regexGlobals), function (prop) {
+ _forEach(keys(regexGlobals), function (prop) {
if (prop in RegExp && !(regexGlobals[prop] in RegExp)) {
Value.getter(RegExp, regexGlobals[prop], function get() {
return RegExp[prop];
@@ -2033,6 +2064,9 @@
capability.resolve = resolve;
capability.reject = reject;
};
+ // Initialize fields to inform optimizers about the object shape.
+ capability.resolve = void 0;
+ capability.reject = void 0;
capability.promise = new C(resolver);
if (!(ES.IsCallable(capability.resolve) && ES.IsCallable(capability.reject))) {
throw new TypeError('Bad promise constructor');
@@ -2069,14 +2103,15 @@
// global Promise below (in order to workaround bugs)
// https://github.com/Raynos/observ-hash/issues/2#issuecomment-35857671
var P = globals.Promise;
- return P && P.resolve && function (task) {
- return P.resolve().then(task);
+ var pr = P && P.resolve && P.resolve();
+ return pr && function (task) {
+ return pr.then(task);
};
};
/*global process */
/* jscs:disable disallowMultiLineTernary */
var enqueue = ES.IsCallable(globals.setImmediate) ?
- globals.setImmediate.bind(globals) :
+ globals.setImmediate :
typeof process === 'object' && process.nextTick ? process.nextTick :
makePromiseAsap() ||
(ES.IsCallable(makeZeroTimeout) ? makeZeroTimeout() :
@@ -2084,59 +2119,99 @@
/* jscs:enable disallowMultiLineTernary */
// Constants for Promise implementation
- var PROMISE_IDENTITY = 1;
- var PROMISE_THROWER = 2;
- var PROMISE_PENDING = 3;
- var PROMISE_FULFILLED = 4;
- var PROMISE_REJECTED = 5;
-
- var promiseReactionJob = function (reaction, argument) {
- var promiseCapability = reaction.capabilities;
- var handler = reaction.handler;
- var handlerResult, handlerException = false, f;
- if (handler === PROMISE_IDENTITY) {
- handlerResult = argument;
- } else if (handler === PROMISE_THROWER) {
- handlerResult = argument;
- handlerException = true;
- } else {
- try {
- handlerResult = handler(argument);
- } catch (e) {
- handlerResult = e;
- handlerException = true;
- }
- }
- f = handlerException ? promiseCapability.reject : promiseCapability.resolve;
- f(handlerResult);
+ var PROMISE_IDENTITY = function (x) { return x; };
+ var PROMISE_THROWER = function (e) { throw e; };
+ var PROMISE_PENDING = 0;
+ var PROMISE_FULFILLED = 1;
+ var PROMISE_REJECTED = 2;
+ // We store fulfill/reject handlers and capabilities in a single array.
+ var PROMISE_FULFILL_OFFSET = 0;
+ var PROMISE_REJECT_OFFSET = 1;
+ var PROMISE_CAPABILITY_OFFSET = 2;
+ // This is used in an optimization for chaining promises via then.
+ var PROMISE_FAKE_CAPABILITY = {};
+
+ var enqueuePromiseReactionJob = function (handler, capability, argument) {
+ enqueue(function () {
+ promiseReactionJob(handler, capability, argument);
+ });
};
- var triggerPromiseReactions = function (reactions, argument) {
- _forEach(reactions, function (reaction) {
- enqueue(function () {
- promiseReactionJob(reaction, argument);
- });
- });
+ var promiseReactionJob = function (handler, promiseCapability, argument) {
+ var handlerResult, f;
+ if (promiseCapability === PROMISE_FAKE_CAPABILITY) {
+ // Fast case, when we don't actually need to chain through to a
+ // (real) promiseCapability.
+ return handler(argument);
+ }
+ try {
+ handlerResult = handler(argument);
+ f = promiseCapability.resolve;
+ } catch (e) {
+ handlerResult = e;
+ f = promiseCapability.reject;
+ }
+ f(handlerResult);
};
var fulfillPromise = function (promise, value) {
var _promise = promise._promise;
- var reactions = _promise.fulfillReactions;
+ var length = _promise.reactionLength;
+ if (length > 0) {
+ enqueuePromiseReactionJob(
+ _promise.fulfillReactionHandler0,
+ _promise.reactionCapability0,
+ value
+ );
+ _promise.fulfillReactionHandler0 = void 0;
+ _promise.rejectReactions0 = void 0;
+ _promise.reactionCapability0 = void 0;
+ if (length > 1) {
+ for (var i = 1, idx = 0; i < length; i++, idx += 3) {
+ enqueuePromiseReactionJob(
+ _promise[idx + PROMISE_FULFILL_OFFSET],
+ _promise[idx + PROMISE_CAPABILITY_OFFSET],
+ value
+ );
+ promise[idx + PROMISE_FULFILL_OFFSET] = void 0;
+ promise[idx + PROMISE_REJECT_OFFSET] = void 0;
+ promise[idx + PROMISE_CAPABILITY_OFFSET] = void 0;
+ }
+ }
+ }
_promise.result = value;
- _promise.fulfillReactions = void 0;
- _promise.rejectReactions = void 0;
_promise.state = PROMISE_FULFILLED;
- triggerPromiseReactions(reactions, value);
+ _promise.reactionLength = 0;
};
var rejectPromise = function (promise, reason) {
var _promise = promise._promise;
- var reactions = _promise.rejectReactions;
+ var length = _promise.reactionLength;
+ if (length > 0) {
+ enqueuePromiseReactionJob(
+ _promise.rejectReactionHandler0,
+ _promise.reactionCapability0,
+ reason
+ );
+ _promise.fulfillReactionHandler0 = void 0;
+ _promise.rejectReactions0 = void 0;
+ _promise.reactionCapability0 = void 0;
+ if (length > 1) {
+ for (var i = 1, idx = 0; i < length; i++, idx += 3) {
+ enqueuePromiseReactionJob(
+ _promise[idx + PROMISE_REJECT_OFFSET],
+ _promise[idx + PROMISE_CAPABILITY_OFFSET],
+ reason
+ );
+ promise[idx + PROMISE_FULFILL_OFFSET] = void 0;
+ promise[idx + PROMISE_REJECT_OFFSET] = void 0;
+ promise[idx + PROMISE_CAPABILITY_OFFSET] = void 0;
+ }
+ }
+ }
_promise.result = reason;
- _promise.fulfillReactions = void 0;
- _promise.rejectReactions = void 0;
_promise.state = PROMISE_REJECTED;
- triggerPromiseReactions(reactions, reason);
+ _promise.reactionLength = 0;
};
var createResolvingFunctions = function (promise) {
@@ -2171,18 +2246,29 @@
return { resolve: resolve, reject: reject };
};
+ var optimizedThen = function (then, thenable, resolve, reject) {
+ // Optimization: since we discard the result, we can pass our
+ // own then implementation a special hint to let it know it
+ // doesn't have to create it. (The PROMISE_FAKE_CAPABILITY
+ // object is local to this implementation and unforgeable outside.)
+ if (then === Promise$prototype$then) {
+ _call(then, thenable, resolve, reject, PROMISE_FAKE_CAPABILITY);
+ } else {
+ _call(then, thenable, resolve, reject);
+ }
+ };
var promiseResolveThenableJob = function (promise, thenable, then) {
var resolvingFunctions = createResolvingFunctions(promise);
var resolve = resolvingFunctions.resolve;
var reject = resolvingFunctions.reject;
try {
- _call(then, thenable, resolve, reject);
+ optimizedThen(then, thenable, resolve, reject);
} catch (e) {
reject(e);
}
};
- var Promise$prototype;
+ var Promise$prototype, Promise$prototype$then;
var Promise = (function () {
var PromiseShim = function Promise(resolver) {
if (!(this instanceof PromiseShim)) {
@@ -2199,8 +2285,15 @@
_promise: {
result: void 0,
state: PROMISE_PENDING,
- fulfillReactions: [],
- rejectReactions: []
+ // The first member of the "reactions" array is inlined here,
+ // since most promises only have one reaction.
+ // We've also exploded the 'reaction' object to inline the
+ // "handler" and "capability" fields, since both fulfill and
+ // reject reactions share the same capability.
+ reactionLength: 0,
+ fulfillReactionHandler0: void 0,
+ rejectReactionHandler0: void 0,
+ reactionCapability0: void 0
}
});
var resolvingFunctions = createResolvingFunctions(promise);
@@ -2251,7 +2344,7 @@
index, values, resultCapability, remaining
);
remaining.count += 1;
- nextPromise.then(resolveElement, resultCapability.reject);
+ optimizedThen(nextPromise.then, nextPromise, resolveElement, resultCapability.reject);
index += 1;
}
if ((--remaining.count) === 0) {
@@ -2280,7 +2373,7 @@
throw e;
}
nextPromise = C.resolve(nextValue);
- nextPromise.then(resultCapability.resolve, resultCapability.reject);
+ optimizedThen(nextPromise.then, nextPromise, resultCapability.resolve, resultCapability.reject);
}
return resultCapability.promise;
};
@@ -2368,44 +2461,60 @@
defineProperties(Promise$prototype, {
'catch': function (onRejected) {
- return this.then(void 0, onRejected);
+ return this.then(null, onRejected);
},
then: function then(onFulfilled, onRejected) {
var promise = this;
if (!ES.IsPromise(promise)) { throw new TypeError('not a promise'); }
var C = ES.SpeciesConstructor(promise, Promise);
- var resultCapability = new PromiseCapability(C);
+ var resultCapability;
+ var returnValueIsIgnored = arguments.length > 2 && arguments[2] === PROMISE_FAKE_CAPABILITY;
+ if (returnValueIsIgnored && C === Promise) {
+ resultCapability = PROMISE_FAKE_CAPABILITY;
+ } else {
+ resultCapability = new PromiseCapability(C);
+ }
// PerformPromiseThen(promise, onFulfilled, onRejected, resultCapability)
- var fulfillReaction = {
- capabilities: resultCapability,
- handler: ES.IsCallable(onFulfilled) ? onFulfilled : PROMISE_IDENTITY
- };
- var rejectReaction = {
- capabilities: resultCapability,
- handler: ES.IsCallable(onRejected) ? onRejected : PROMISE_THROWER
- };
+ // Note that we've split the 'reaction' object into its two
+ // components, "capabilities" and "handler"
+ // "capabilities" is always equal to `resultCapability`
+ var fulfillReactionHandler = ES.IsCallable(onFulfilled) ? onFulfilled : PROMISE_IDENTITY;
+ var rejectReactionHandler = ES.IsCallable(onRejected) ? onRejected : PROMISE_THROWER;
var _promise = promise._promise;
var value;
if (_promise.state === PROMISE_PENDING) {
- _push(_promise.fulfillReactions, fulfillReaction);
- _push(_promise.rejectReactions, rejectReaction);
+ if (_promise.reactionLength === 0) {
+ _promise.fulfillReactionHandler0 = fulfillReactionHandler;
+ _promise.rejectReactionHandler0 = rejectReactionHandler;
+ _promise.reactionCapability0 = resultCapability;
+ } else {
+ var idx = 3 * (_promise.reactionLength - 1);
+ _promise[idx + PROMISE_FULFILL_OFFSET] = fulfillReactionHandler;
+ _promise[idx + PROMISE_REJECT_OFFSET] = rejectReactionHandler;
+ _promise[idx + PROMISE_CAPABILITY_OFFSET] = resultCapability;
+ }
+ _promise.reactionLength += 1;
} else if (_promise.state === PROMISE_FULFILLED) {
value = _promise.result;
- enqueue(function () {
- promiseReactionJob(fulfillReaction, value);
- });
+ enqueuePromiseReactionJob(
+ fulfillReactionHandler, resultCapability, value
+ );
} else if (_promise.state === PROMISE_REJECTED) {
value = _promise.result;
- enqueue(function () {
- promiseReactionJob(rejectReaction, value);
- });
+ enqueuePromiseReactionJob(
+ rejectReactionHandler, resultCapability, value
+ );
} else {
throw new TypeError('unexpected Promise state');
}
return resultCapability.promise;
}
});
+ // This helps the optimizer by ensuring that methods which take
+ // capabilities aren't polymorphic.
+ PROMISE_FAKE_CAPABILITY = new PromiseCapability(Promise);
+ Promise$prototype$then = Promise$prototype.then;
return Promise;
}());
@@ -2471,6 +2580,30 @@
/*globals Promise: false */
overrideNative(globals, 'Promise', PromiseShim);
}
+ if (Promise.all.length !== 1) {
+ var origAll = Promise.all;
+ overrideNative(Promise, 'all', function all(iterable) {
+ return ES.Call(origAll, this, arguments);
+ });
+ }
+ if (Promise.race.length !== 1) {
+ var origRace = Promise.race;
+ overrideNative(Promise, 'race', function race(iterable) {
+ return ES.Call(origRace, this, arguments);
+ });
+ }
+ if (Promise.resolve.length !== 1) {
+ var origResolve = Promise.resolve;
+ overrideNative(Promise, 'resolve', function resolve(x) {
+ return ES.Call(origResolve, this, arguments);
+ });
+ }
+ if (Promise.reject.length !== 1) {
+ var origReject = Promise.reject;
+ overrideNative(Promise, 'reject', function reject(r) {
+ return ES.Call(origReject, this, arguments);
+ });
+ }
ensureEnumerable(Promise, 'all');
ensureEnumerable(Promise, 'race');
ensureEnumerable(Promise, 'resolve');
@@ -2482,7 +2615,7 @@
// Their fast path also requires that the environment preserve
// property insertion order, which is not guaranteed by the spec.
var testOrder = function (a) {
- var b = Object.keys(_reduce(a, function (o, k) {
+ var b = keys(_reduce(a, function (o, k) {
o[k] = true;
return o;
}, {}));
@@ -2870,36 +3003,42 @@
};
Set$prototype = SetShim.prototype;
+ var decodeKey = function (key) {
+ var k = key;
+ if (k === '^null') {
+ return null;
+ } else if (k === '^undefined') {
+ return void 0;
+ } else {
+ var first = k.charAt(0);
+ if (first === '$') {
+ return _strSlice(k, 1);
+ } else if (first === 'n') {
+ return +_strSlice(k, 1);
+ } else if (first === 'b') {
+ return k === 'btrue';
+ }
+ }
+ return +k;
+ };
// Switch from the object backing storage to a full Map.
var ensureMap = function ensureMap(set) {
if (!set['[[SetData]]']) {
var m = set['[[SetData]]'] = new collectionShims.Map();
- _forEach(Object.keys(set._storage), function (key) {
- var k = key;
- if (k === '^null') {
- k = null;
- } else if (k === '^undefined') {
- k = void 0;
- } else {
- var first = k.charAt(0);
- if (first === '$') {
- k = _strSlice(k, 1);
- } else if (first === 'n') {
- k = +_strSlice(k, 1);
- } else if (first === 'b') {
- k = k === 'btrue';
- } else {
- k = +k;
- }
- }
+ _forEach(keys(set._storage), function (key) {
+ var k = decodeKey(key);
m.set(k, k);
});
- set._storage = null; // free old backing storage
+ set['[[SetData]]'] = m;
}
+ set._storage = null; // free old backing storage
};
Value.getter(SetShim.prototype, 'size', function () {
requireSetSlot(this, 'size');
+ if (this._storage) {
+ return keys(this._storage).length;
+ }
ensureMap(this);
return this['[[SetData]]'].size;
});
@@ -2942,7 +3081,8 @@
requireSetSlot(this, 'clear');
if (this._storage) {
this._storage = emptyObject();
- } else {
+ }
+ if (this['[[SetData]]']) {
this['[[SetData]]'].clear();
}
},
@@ -3194,7 +3334,7 @@
if (!ES.IsConstructor(constructor)) {
throw new TypeError('First argument must be a constructor.');
}
- var newTarget = arguments.length < 3 ? constructor : arguments[2];
+ var newTarget = arguments.length > 2 ? arguments[2] : constructor;
if (!ES.IsConstructor(newTarget)) {
throw new TypeError('new.target must be a constructor.');
}
@@ -3277,7 +3417,7 @@
var parent = Object.getPrototypeOf(target);
if (parent === null) {
- return undefined;
+ return void 0;
}
return internalGet(parent, key, receiver);
@@ -3291,7 +3431,7 @@
return ES.Call(desc.get, receiver);
}
- return undefined;
+ return void 0;
};
var internalSet = function set(target, key, value, receiver) {
diff --git a/es6-shim.map b/es6-shim.map
index 811d7f8..00277e7 100644
--- a/es6-shim.map
+++ b/es6-shim.map
@@ -1 +1 @@
-{"version":3,"sources":["es6-shim.js"],"names":["root","factory","define","amd","exports","module","returnExports","this","_apply","Function","call","bind","apply","_call","isArray","Array","not","notThunker","func","notThunk","arguments","throwsError","e","valueOrFalseIfThrows","isCallableWithoutNew","arePropertyDescriptorsSupported","Object","defineProperty","get","supportsDescriptors","functionsHaveNames","foo","name","_forEach","prototype","forEach","_reduce","reduce","_filter","filt [...]
\ No newline at end of file
+{"version":3,"sources":["es6-shim.js"],"names":["root","factory","define","amd","exports","module","returnExports","this","_apply","Function","call","bind","apply","_call","isArray","Array","keys","Object","not","notThunker","func","notThunk","arguments","throwsError","e","valueOrFalseIfThrows","isCallableWithoutNew","arePropertyDescriptorsSupported","defineProperty","get","supportsDescriptors","functionsHaveNames","foo","name","_forEach","prototype","forEach","_reduce","reduce","_filter [...]
\ No newline at end of file
diff --git a/es6-shim.min.js b/es6-shim.min.js
index 8bd12d3..00241b8 100644
--- a/es6-shim.min.js
+++ b/es6-shim.min.js
@@ -2,11 +2,11 @@
* https://github.com/paulmillr/es6-shim
* @license es6-shim Copyright 2013-2015 by Paul Miller (http://paulmillr.com)
* and contributors, MIT License
- * es6-shim: v0.34.0
- * see https://github.com/paulmillr/es6-shim/blob/0.34.0/LICENSE
+ * es6-shim: v0.34.1
+ * see https://github.com/paulmillr/es6-shim/blob/0.34.1/LICENSE
* Details and documentation:
* https://github.com/paulmillr/es6-shim/
*/
-(function(e,t){if(typeof define==="function"&&define.amd){define(t)}else if(typeof exports==="object"){module.exports=t()}else{e.returnExports=t()}})(this,function(){"use strict";var e=Function.call.bind(Function.apply);var t=Function.call.bind(Function.call);var r=Array.isArray;var n=function notThunker(t){return function notThunk(){return!e(t,this,arguments)}};var o=function(e){try{e();return false}catch(t){return true}};var i=function valueOrFalseIfThrows(e){try{return e()}catch(t){re [...]
-throw new TypeError("Bad Promise implementation!")}t.resolve=e;t.reject=r};t.promise=new e(r);if(!(Y.IsCallable(t.resolve)&&Y.IsCallable(t.reject))){throw new TypeError("Bad promise constructor")}};var n;if(typeof window!=="undefined"&&Y.IsCallable(window.postMessage)){n=function(){var e=[];var t="zero-timeout-message";var r=function(r){P(e,r);window.postMessage(t,"*")};var n=function(r){if(r.source===window&&r.data===t){r.stopPropagation();if(e.length===0){return}var n=x(e);n()}};window [...]
+(function(e,t){if(typeof define==="function"&&define.amd){define(t)}else if(typeof exports==="object"){module.exports=t()}else{e.returnExports=t()}})(this,function(){"use strict";var e=Function.call.bind(Function.apply);var t=Function.call.bind(Function.call);var r=Array.isArray;var n=Object.keys;var o=function notThunker(t){return function notThunk(){return!e(t,this,arguments)}};var i=function(e){try{e();return false}catch(t){return true}};var a=function valueOrFalseIfThrows(e){try{retu [...]
+if(typeof e!=="function"&&typeof e!=="object"){return}ee.IsPromise=function(e){if(!ee.TypeIsObject(e)){return false}if(typeof e._promise==="undefined"){return false}return true};var r=function(e){if(!ee.IsConstructor(e)){throw new TypeError("Bad promise constructor")}var t=this;var r=function(e,r){if(t.resolve!==void 0||t.reject!==void 0){throw new TypeError("Bad Promise implementation!")}t.resolve=e;t.reject=r};t.resolve=void 0;t.reject=void 0;t.promise=new e(r);if(!(ee.IsCallable(t.res [...]
//# sourceMappingURL=es6-shim.map
diff --git a/package.json b/package.json
index aee8525..feca237 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "es6-shim",
- "version": "0.34.0",
+ "version": "0.34.1",
"author": "Paul Miller (http://paulmillr.com)",
"description": "ECMAScript 6 (Harmony) compatibility shims for legacy JavaScript engines",
"keywords": [
@@ -68,9 +68,9 @@
"dependencies": {},
"devDependencies": {
"chai": "^3.4.1",
- "es5-shim": "^4.4.0",
+ "es5-shim": "^4.4.1",
"eslint": "^1.10.3",
- "@ljharb/eslint-config": "^1.6.0",
+ "@ljharb/eslint-config": "^1.6.1",
"grunt": "^0.4.5",
"grunt-contrib-connect": "^0.11.2",
"grunt-contrib-watch": "^0.6.1",
diff --git a/test/collections.js b/test/collections.js
deleted file mode 100644
index 7a48f34..0000000
--- a/test/collections.js
+++ /dev/null
@@ -1,1173 +0,0 @@
-/* global describe, it, xit, expect, require, beforeEach, afterEach */
-
-// Big thanks to V8 folks for test ideas.
-// v8/test/mjsunit/harmony/collections.js
-
-var Assertion = expect().constructor;
-Assertion.addMethod('theSameSet', function (otherArray) {
- var array = this._obj;
-
- expect(Array.isArray(array)).to.equal(true);
- expect(Array.isArray(otherArray)).to.equal(true);
-
- var diff = array.filter(function (value) {
- return otherArray.every(function (otherValue) {
- var areBothNaN = typeof value === 'number' && typeof otherValue === 'number' && value !== value && otherValue !== otherValue;
- return !areBothNaN && value !== otherValue;
- });
- });
-
- this.assert(
- diff.length === 0,
- 'expected #{this} to be equal to #{exp} (as sets, i.e. no order)',
- array,
- otherArray
- );
-});
-
-Assertion.addMethod('entries', function (expected) {
- var collection = this._obj;
-
- expect(Array.isArray(expected)).to.equal(true);
- var expectedEntries = expected.slice();
-
- var iterator = collection.entries();
- var result;
- do {
- result = iterator.next();
- expect(result.value).to.be.eql(expectedEntries.shift());
- } while (!result.done);
-});
-
-describe('Collections', function () {
- var functionsHaveNames = (function foo() {}).name === 'foo';
- var ifFunctionsHaveNamesIt = functionsHaveNames ? it : xit;
- var ifShimIt = (typeof process !== 'undefined' && process.env.NO_ES6_SHIM) ? it.skip : it;
-
- var range = function (from, to) {
- var result = [];
- for (var value = from; value < to; value++) {
- result.push(value);
- }
- return result;
- };
-
- var prototypePropIsEnumerable = (function () {}).propertyIsEnumerable('prototype');
- var expectNotEnumerable = function (object) {
- if (prototypePropIsEnumerable && typeof object === 'function') {
- expect(Object.keys(object)).to.eql(['prototype']);
- } else {
- expect(Object.keys(object)).to.eql([]);
- }
- };
-
- var Sym = typeof Symbol === 'undefined' ? {} : Symbol;
- var isSymbol = function (sym) {
- return typeof Sym === 'function' && typeof sym === 'symbol';
- };
- var ifSymbolIteratorIt = isSymbol(Sym.iterator) ? it : xit;
-
- var testMapping = function (map, key, value) {
- expect(map.has(key)).to.equal(false);
- expect(map.get(key)).to.equal(undefined);
- expect(map.set(key, value)).to.equal(map);
- expect(map.get(key)).to.equal(value);
- expect(map.has(key)).to.equal(true);
- };
-
- describe('Map', function () {
- if (typeof Map === 'undefined') {
- return it('exists', function () {
- expect(typeof Map).to.equal('function');
- });
- }
-
- var map;
- beforeEach(function () {
- map = new Map();
- });
-
- afterEach(function () {
- map = null;
- });
-
- ifShimIt('is on the exported object', function () {
- var exported = require('../');
- expect(exported.Map).to.equal(Map);
- });
-
- it('should exist in global namespace', function () {
- expect(typeof Map).to.equal('function');
- });
-
- it('should have the right arity', function () {
- expect(Map).to.have.property('length', 0);
- });
-
- it('should has valid getter and setter calls', function () {
- ['get', 'set', 'has', 'delete'].forEach(function (method) {
- expect(function () {
- map[method]({});
- }).to.not['throw']();
- });
- });
-
- it('should accept an iterable as argument', function () {
- testMapping(map, 'a', 'b');
- testMapping(map, 'c', 'd');
- var map2;
- expect(function () { map2 = new Map(map); }).not.to['throw'](Error);
- expect(map2).to.be.an.instanceOf(Map);
- expect(map2.has('a')).to.equal(true);
- expect(map2.has('c')).to.equal(true);
- expect(map2).to.have.entries([['a', 'b'], ['c', 'd']]);
- });
-
- it('should throw with iterables that return primitives', function () {
- expect(function () { return new Map('123'); }).to['throw'](TypeError);
- expect(function () { return new Map([1, 2, 3]); }).to['throw'](TypeError);
- expect(function () { return new Map(['1', '2', '3']); }).to['throw'](TypeError);
- expect(function () { return new Map([true]); }).to['throw'](TypeError);
- });
-
- it('should not be callable without "new"', function () {
- expect(Map).to['throw'](TypeError);
- });
-
- it('should be subclassable', function () {
- if (!Object.setPrototypeOf) { return; } // skip test if on IE < 11
- var MyMap = function MyMap() {
- var testMap = new Map([['a', 'b']]);
- Object.setPrototypeOf(testMap, MyMap.prototype);
- return testMap;
- };
- Object.setPrototypeOf(MyMap, Map);
- MyMap.prototype = Object.create(Map.prototype, {
- constructor: { value: MyMap }
- });
-
- var myMap = new MyMap();
- testMapping(myMap, 'c', 'd');
- expect(myMap).to.have.entries([['a', 'b'], ['c', 'd']]);
- });
-
- it('uses SameValueZero even on a Map of size > 4', function () {
- // Chrome 38-42, node 0.11/0.12, iojs 1/2 have a bug when the Map has a size > 4
- var firstFour = [[1, 0], [2, 0], [3, 0], [4, 0]];
- var fourMap = new Map(firstFour);
- expect(fourMap.size).to.equal(4);
- expect(fourMap.has(-0)).to.equal(false);
- expect(fourMap.has(0)).to.equal(false);
-
- fourMap.set(-0, fourMap);
-
- expect(fourMap.has(0)).to.equal(true);
- expect(fourMap.has(-0)).to.equal(true);
- });
-
- it('treats positive and negative zero the same', function () {
- var value1 = {};
- var value2 = {};
- testMapping(map, +0, value1);
- expect(map.has(-0)).to.equal(true);
- expect(map.get(-0)).to.equal(value1);
- expect(map.set(-0, value2)).to.equal(map);
- expect(map.get(-0)).to.equal(value2);
- expect(map.get(+0)).to.equal(value2);
- });
-
- it('should map values correctly', function () {
- // Run this test twice, one with the "fast" implementation (which only
- // allows string and numeric keys) and once with the "slow" impl.
- [true, false].forEach(function (slowkeys) {
- map = new Map();
-
- range(1, 20).forEach(function (number) {
- if (slowkeys) { testMapping(map, number, {}); }
- testMapping(map, number / 100, {});
- testMapping(map, 'key-' + number, {});
- testMapping(map, String(number), {});
- if (slowkeys) { testMapping(map, Object(String(number)), {}); }
- });
-
- var testkeys = [Infinity, -Infinity, NaN];
- if (slowkeys) {
- testkeys.push(true, false, null, undefined);
- }
- testkeys.forEach(function (key) {
- testMapping(map, key, {});
- testMapping(map, String(key), {});
- });
- testMapping(map, '', {});
-
- // verify that properties of Object don't peek through.
- [
- 'hasOwnProperty',
- 'constructor',
- 'toString',
- 'isPrototypeOf',
- '__proto__',
- '__parent__',
- '__count__'
- ].forEach(function (key) {
- testMapping(map, key, {});
- });
- });
- });
-
- it('should map empty values correctly', function () {
- testMapping(map, {}, true);
- testMapping(map, null, true);
- testMapping(map, undefined, true);
- testMapping(map, '', true);
- testMapping(map, NaN, true);
- testMapping(map, 0, true);
- });
-
- it('should has correct querying behavior', function () {
- var key = {};
- testMapping(map, key, 'to-be-present');
- expect(map.has(key)).to.equal(true);
- expect(map.has({})).to.equal(false);
- expect(map.set(key, void 0)).to.equal(map);
- expect(map.get(key)).to.equal(undefined);
- expect(map.has(key)).to.equal(true);
- expect(map.has({})).to.equal(false);
- });
-
- it('should allow NaN values as keys', function () {
- expect(map.has(NaN)).to.equal(false);
- expect(map.has(NaN + 1)).to.equal(false);
- expect(map.has(23)).to.equal(false);
- expect(map.set(NaN, 'value')).to.equal(map);
- expect(map.has(NaN)).to.equal(true);
- expect(map.has(NaN + 1)).to.equal(true);
- expect(map.has(23)).to.equal(false);
- });
-
- it('should not have [[Enumerable]] props', function () {
- expectNotEnumerable(Map);
- expectNotEnumerable(Map.prototype);
- expectNotEnumerable(new Map());
- });
-
- it('should not have an own constructor', function () {
- var m = new Map();
- expect(m).not.to.haveOwnPropertyDescriptor('constructor');
- expect(m.constructor).to.equal(Map);
- });
-
- it('should allow common ecmascript idioms', function () {
- expect(map).to.be.an.instanceOf(Map);
- expect(typeof Map.prototype.get).to.equal('function');
- expect(typeof Map.prototype.set).to.equal('function');
- expect(typeof Map.prototype.has).to.equal('function');
- expect(typeof Map.prototype['delete']).to.equal('function');
- });
-
- it('should have a unique constructor', function () {
- expect(Map.prototype).to.not.equal(Object.prototype);
- });
-
- describe('#clear()', function () {
- ifFunctionsHaveNamesIt('has the right name', function () {
- expect(Map.prototype.clear).to.have.property('name', 'clear');
- });
-
- it('is not enumerable', function () {
- expect(Map.prototype).ownPropertyDescriptor('clear').to.have.property('enumerable', false);
- });
-
- it('has the right arity', function () {
- expect(Map.prototype.clear).to.have.property('length', 0);
- });
-
- it('should have #clear method', function () {
- expect(map.set(1, 2)).to.equal(map);
- expect(map.set(5, 2)).to.equal(map);
- expect(map.size).to.equal(2);
- expect(map.has(5)).to.equal(true);
- map.clear();
- expect(map.size).to.equal(0);
- expect(map.has(5)).to.equal(false);
- });
- });
-
- describe('#keys()', function () {
- if (!Map.prototype.hasOwnProperty('keys')) {
- return it('exists', function () {
- expect(Map.prototype).to.have.property('keys');
- });
- }
-
- ifFunctionsHaveNamesIt('has the right name', function () {
- expect(Map.prototype.keys).to.have.property('name', 'keys');
- });
-
- it('is not enumerable', function () {
- expect(Map.prototype).ownPropertyDescriptor('keys').to.have.property('enumerable', false);
- });
-
- it('has the right arity', function () {
- expect(Map.prototype.keys).to.have.property('length', 0);
- });
- });
-
- describe('#values()', function () {
- if (!Map.prototype.hasOwnProperty('values')) {
- return it('exists', function () {
- expect(Map.prototype).to.have.property('values');
- });
- }
-
- ifFunctionsHaveNamesIt('has the right name', function () {
- expect(Map.prototype.values).to.have.property('name', 'values');
- });
-
- it('is not enumerable', function () {
- expect(Map.prototype).ownPropertyDescriptor('values').to.have.property('enumerable', false);
- });
-
- it('has the right arity', function () {
- expect(Map.prototype.values).to.have.property('length', 0);
- });
- });
-
- describe('#entries()', function () {
- if (!Map.prototype.hasOwnProperty('entries')) {
- return it('exists', function () {
- expect(Map.prototype).to.have.property('entries');
- });
- }
-
- ifFunctionsHaveNamesIt('has the right name', function () {
- expect(Map.prototype.entries).to.have.property('name', 'entries');
- });
-
- it('is not enumerable', function () {
- expect(Map.prototype).ownPropertyDescriptor('entries').to.have.property('enumerable', false);
- });
-
- it('has the right arity', function () {
- expect(Map.prototype.entries).to.have.property('length', 0);
- });
-
- it('throws when called on a non-Map', function () {
- var expectedMessage = /^(Method )?Map.prototype.entries called on incompatible receiver |^entries method called on incompatible |^Cannot create a Map entry iterator for a non-Map object.|^Map\.prototype\.entries: 'this' is not a Map object$/;
- var nonMaps = [true, false, 'abc', NaN, new Set([1, 2]), { a: true }, [1], Object('abc'), Object(NaN)];
- nonMaps.forEach(function (nonMap) {
- expect(function () { return Map.prototype.entries.call(nonMap); }).to['throw'](TypeError, expectedMessage);
- });
- });
- });
-
- describe('#size', function () {
- it('throws TypeError when accessed directly', function () {
- // see https://github.com/paulmillr/es6-shim/issues/176
- expect(function () { return Map.prototype.size; }).to['throw'](TypeError);
- expect(function () { return Map.prototype.size; }).to['throw'](TypeError);
- });
-
- it('is an accessor function on the prototype', function () {
- expect(Map.prototype).ownPropertyDescriptor('size').to.have.property('get');
- expect(typeof Object.getOwnPropertyDescriptor(Map.prototype, 'size').get).to.equal('function');
- expect(new Map()).not.to.haveOwnPropertyDescriptor('size');
- });
- });
-
- it('should return false when deleting a nonexistent key', function () {
- expect(map.has('a')).to.equal(false);
- expect(map['delete']('a')).to.equal(false);
- });
-
- it('should have keys, values and size props', function () {
- expect(map.set('a', 1)).to.equal(map);
- expect(map.set('b', 2)).to.equal(map);
- expect(map.set('c', 3)).to.equal(map);
- expect(typeof map.keys).to.equal('function');
- expect(typeof map.values).to.equal('function');
- expect(map.size).to.equal(3);
- expect(map['delete']('a')).to.equal(true);
- expect(map.size).to.equal(2);
- });
-
- it('should have an iterator that works with Array.from', function () {
- expect(Array).to.have.property('from');
-
- expect(map.set('a', 1)).to.equal(map);
- expect(map.set('b', NaN)).to.equal(map);
- expect(map.set('c', false)).to.equal(map);
- expect(Array.from(map)).to.eql([['a', 1], ['b', NaN], ['c', false]]);
- expect(Array.from(map.keys())).to.eql(['a', 'b', 'c']);
- expect(Array.from(map.values())).to.eql([1, NaN, false]);
- expect(map).to.have.entries(Array.from(map.entries()));
- });
-
- ifSymbolIteratorIt('has the right default iteration function', function () {
- // fixed in Webkit https://bugs.webkit.org/show_bug.cgi?id=143838
- expect(Map.prototype).to.have.property(Sym.iterator, Map.prototype.entries);
- });
-
- describe('#forEach', function () {
- var mapToIterate;
-
- beforeEach(function () {
- mapToIterate = new Map();
- expect(mapToIterate.set('a', 1)).to.equal(mapToIterate);
- expect(mapToIterate.set('b', 2)).to.equal(mapToIterate);
- expect(mapToIterate.set('c', 3)).to.equal(mapToIterate);
- });
-
- afterEach(function () {
- mapToIterate = null;
- });
-
- ifFunctionsHaveNamesIt('has the right name', function () {
- expect(Map.prototype.forEach).to.have.property('name', 'forEach');
- });
-
- it('is not enumerable', function () {
- expect(Map.prototype).ownPropertyDescriptor('forEach').to.have.property('enumerable', false);
- });
-
- it('has the right arity', function () {
- expect(Map.prototype.forEach).to.have.property('length', 1);
- });
-
- it('should be iterable via forEach', function () {
- var expectedMap = {
- a: 1,
- b: 2,
- c: 3
- };
- var foundMap = {};
- mapToIterate.forEach(function (value, key, entireMap) {
- expect(entireMap).to.equal(mapToIterate);
- foundMap[key] = value;
- });
- expect(foundMap).to.eql(expectedMap);
- });
-
- it('should iterate over empty keys', function () {
- var mapWithEmptyKeys = new Map();
- var expectedKeys = [{}, null, undefined, '', NaN, 0];
- expectedKeys.forEach(function (key) {
- expect(mapWithEmptyKeys.set(key, true)).to.equal(mapWithEmptyKeys);
- });
- var foundKeys = [];
- mapWithEmptyKeys.forEach(function (value, key, entireMap) {
- expect(entireMap.get(key)).to.equal(value);
- foundKeys.push(key);
- });
- expect(foundKeys).to.be.theSameSet(expectedKeys);
- });
-
- it('should support the thisArg', function () {
- var context = function () {};
- mapToIterate.forEach(function () {
- expect(this).to.equal(context);
- }, context);
- });
-
- it('should have a length of 1', function () {
- expect(Map.prototype.forEach.length).to.equal(1);
- });
-
- it('should not revisit modified keys', function () {
- var hasModifiedA = false;
- mapToIterate.forEach(function (value, key) {
- if (!hasModifiedA && key === 'a') {
- expect(mapToIterate.set('a', 4)).to.equal(mapToIterate);
- hasModifiedA = true;
- } else {
- expect(key).not.to.equal('a');
- }
- });
- });
-
- it('returns the map from #set() for chaining', function () {
- expect(mapToIterate.set({}, {})).to.equal(mapToIterate);
- expect(mapToIterate.set(42, {})).to.equal(mapToIterate);
- expect(mapToIterate.set(0, {})).to.equal(mapToIterate);
- expect(mapToIterate.set(NaN, {})).to.equal(mapToIterate);
- expect(mapToIterate.set(-0, {})).to.equal(mapToIterate);
- });
-
- it('visits keys added in the iterator', function () {
- var hasAdded = false;
- var hasFoundD = false;
- mapToIterate.forEach(function (value, key) {
- if (!hasAdded) {
- mapToIterate.set('d', 5);
- hasAdded = true;
- } else if (key === 'd') {
- hasFoundD = true;
- }
- });
- expect(hasFoundD).to.equal(true);
- });
-
- it('visits keys added in the iterator when there is a deletion', function () {
- var hasSeenFour = false;
- var mapToMutate = new Map();
- mapToMutate.set('0', 42);
- mapToMutate.forEach(function (value, key) {
- if (key === '0') {
- expect(mapToMutate['delete']('0')).to.equal(true);
- mapToMutate.set('4', 'a value');
- } else if (key === '4') {
- hasSeenFour = true;
- }
- });
- expect(hasSeenFour).to.equal(true);
- });
-
- it('does not visit keys deleted before a visit', function () {
- var hasVisitedC = false;
- var hasDeletedC = false;
- mapToIterate.forEach(function (value, key) {
- if (key === 'c') {
- hasVisitedC = true;
- }
- if (!hasVisitedC && !hasDeletedC) {
- hasDeletedC = mapToIterate['delete']('c');
- expect(hasDeletedC).to.equal(true);
- }
- });
- expect(hasVisitedC).to.equal(false);
- });
-
- it('should work after deletion of the current key', function () {
- var expectedMap = {
- a: 1,
- b: 2,
- c: 3
- };
- var foundMap = {};
- mapToIterate.forEach(function (value, key) {
- foundMap[key] = value;
- expect(mapToIterate['delete'](key)).to.equal(true);
- });
- expect(foundMap).to.eql(expectedMap);
- });
-
- it('should convert key -0 to +0', function () {
- var zeroMap = new Map();
- var result = [];
- zeroMap.set(-0, 'a');
- zeroMap.forEach(function (value, key) {
- result.push(String(1 / key) + ' ' + value);
- });
- zeroMap.set(1, 'b');
- zeroMap.set(0, 'c'); // shouldn't cause reordering
- zeroMap.forEach(function (value, key) {
- result.push(String(1 / key) + ' ' + value);
- });
- expect(result.join(', ')).to.equal(
- 'Infinity a, Infinity c, 1 b'
- );
- });
- });
-
- it('should preserve insertion order', function () {
- var convertToPairs = function (item) { return [item, true]; };
- var arr1 = ['d', 'a', 'b'];
- var arr2 = [3, 2, 'z', 'a', 1];
- var arr3 = [3, 2, 'z', {}, 'a', 1];
-
- [arr1, arr2, arr3].forEach(function (array) {
- var entries = array.map(convertToPairs);
- expect(new Map(entries)).to.have.entries(entries);
- });
- });
- });
-
- it('map iteration', function () {
- var map = new Map();
- map.set('a', 1);
- map.set('b', 2);
- map.set('c', 3);
- map.set('d', 4);
-
- var keys = [];
- var iterator = map.keys();
- keys.push(iterator.next().value);
- expect(map['delete']('a')).to.equal(true);
- expect(map['delete']('b')).to.equal(true);
- expect(map['delete']('c')).to.equal(true);
- map.set('e');
- keys.push(iterator.next().value);
- keys.push(iterator.next().value);
-
- expect(iterator.next().done).to.equal(true);
- map.set('f');
- expect(iterator.next().done).to.equal(true);
- expect(keys).to.eql(['a', 'd', 'e']);
- });
-
- it('set iteration', function () {
- var set = new Set();
- expect(set.add('a')).to.equal(set);
- expect(set.add('b')).to.equal(set);
- expect(set.add('c')).to.equal(set);
- expect(set.add('d')).to.equal(set);
-
- var keys = [];
- var iterator = set.keys();
- keys.push(iterator.next().value);
- expect(set['delete']('a')).to.equal(true);
- expect(set['delete']('b')).to.equal(true);
- expect(set['delete']('c')).to.equal(true);
- expect(set.add('e')).to.equal(set);
- keys.push(iterator.next().value);
- keys.push(iterator.next().value);
-
- expect(iterator.next().done).to.equal(true);
- expect(set.add('f')).to.equal(set);
- expect(iterator.next().done).to.equal(true);
- expect(keys).to.eql(['a', 'd', 'e']);
- });
-
- var testSet = function (set, key) {
- expect(set.has(key)).to.equal(false);
- expect(set['delete'](key)).to.equal(false);
- expect(set.add(key)).to.equal(set);
- expect(set.has(key)).to.equal(true);
- expect(set['delete'](key)).to.equal(true);
- expect(set.has(key)).to.equal(false);
- expect(set.add(key)).to.equal(set); // add it back
- };
-
- describe('Set', function () {
- if (typeof Set === 'undefined') {
- return it('exists', function () {
- expect(typeof Set).to.equal('function');
- });
- }
-
- var set;
- beforeEach(function () {
- set = new Set();
- });
-
- afterEach(function () {
- set = null;
- });
-
- ifShimIt('is on the exported object', function () {
- var exported = require('../');
- expect(exported.Set).to.equal(Set);
- });
-
- it('should exist in global namespace', function () {
- expect(typeof Set).to.equal('function');
- });
-
- it('has the right arity', function () {
- expect(Set).to.have.property('length', 0);
- });
-
- it('returns the set from #add() for chaining', function () {
- expect(set.add({})).to.equal(set);
- });
-
- it('should return false when deleting an item not in the set', function () {
- expect(set.has('a')).to.equal(false);
- expect(set['delete']('a')).to.equal(false);
- });
-
- it('should accept an iterable as argument', function () {
- testSet(set, 'a');
- testSet(set, 'b');
- var set2 = new Set(set);
- expect(set2.has('a')).to.equal(true);
- expect(set2.has('b')).to.equal(true);
- expect(set2).to.have.entries([['a', 'a'], ['b', 'b']]);
- });
-
- it('accepts an array as an argument', function () {
- var arr = ['a', 'b', 'c'];
- var setFromArray = new Set(arr);
- expect(setFromArray).to.have.entries([['a', 'a'], ['b', 'b'], ['c', 'c']]);
- });
-
- it('should not be callable without "new"', function () {
- expect(Set).to['throw'](TypeError);
- });
-
- it('should be subclassable', function () {
- if (!Object.setPrototypeOf) { return; } // skip test if on IE < 11
- var MySet = function MySet() {
- var actualSet = new Set(['a', 'b']);
- Object.setPrototypeOf(actualSet, MySet.prototype);
- return actualSet;
- };
- Object.setPrototypeOf(MySet, Set);
- MySet.prototype = Object.create(Set.prototype, {
- constructor: { value: MySet }
- });
-
- var mySet = new MySet();
- testSet(mySet, 'c');
- testSet(mySet, 'd');
- expect(mySet).to.have.entries([['a', 'a'], ['b', 'b'], ['c', 'c'], ['d', 'd']]);
- });
-
- it('should has valid getter and setter calls', function () {
- ['add', 'has', 'delete'].forEach(function (method) {
- expect(function () {
- set[method]({});
- }).to.not['throw']();
- });
- });
-
- it('uses SameValueZero even on a Set of size > 4', function () {
- var firstFour = [1, 2, 3, 4];
- var fourSet = new Set(firstFour);
- expect(fourSet.size).to.equal(4);
- expect(fourSet.has(-0)).to.equal(false);
- expect(fourSet.has(0)).to.equal(false);
-
- fourSet.add(-0);
-
- expect(fourSet.size).to.equal(5);
- expect(fourSet.has(0)).to.equal(true);
- expect(fourSet.has(-0)).to.equal(true);
- });
-
- it('should work as expected', function () {
- // Run this test twice, one with the "fast" implementation (which only
- // allows string and numeric keys) and once with the "slow" impl.
- [true, false].forEach(function (slowkeys) {
- set = new Set();
-
- range(1, 20).forEach(function (number) {
- if (slowkeys) { testSet(set, {}); }
- testSet(set, number);
- testSet(set, number / 100);
- testSet(set, 'key-' + number);
- testSet(set, String(number));
- if (slowkeys) { testSet(set, Object(String(number))); }
- });
-
- var testkeys = [+0, Infinity, -Infinity, NaN];
- if (slowkeys) {
- testkeys.push(true, false, null, undefined);
- }
- testkeys.forEach(function (number) {
- testSet(set, number);
- testSet(set, String(number));
- });
- testSet(set, '');
-
- // -0 and +0 should be the same key (Set uses SameValueZero)
- expect(set.has(-0)).to.equal(true);
- expect(set['delete'](+0)).to.equal(true);
- testSet(set, -0);
- expect(set.has(+0)).to.equal(true);
-
- // verify that properties of Object don't peek through.
- [
- 'hasOwnProperty',
- 'constructor',
- 'toString',
- 'isPrototypeOf',
- '__proto__',
- '__parent__',
- '__count__'
- ].forEach(function (prop) { testSet(set, prop); });
- });
- });
-
- describe('#size', function () {
- it('returns the expected size', function () {
- expect(set.add(1)).to.equal(set);
- expect(set.add(5)).to.equal(set);
- expect(set.size).to.equal(2);
- });
- });
-
- describe('#clear()', function () {
- ifFunctionsHaveNamesIt('has the right name', function () {
- expect(Set.prototype.clear).to.have.property('name', 'clear');
- });
-
- it('is not enumerable', function () {
- expect(Set.prototype).ownPropertyDescriptor('clear').to.have.property('enumerable', false);
- });
-
- it('has the right arity', function () {
- expect(Set.prototype.clear).to.have.property('length', 0);
- });
-
- it('should have #clear method', function () {
- expect(set.add(1)).to.equal(set);
- expect(set.add(5)).to.equal(set);
- expect(set.size).to.equal(2);
- expect(set.has(5)).to.equal(true);
- set.clear();
- expect(set.size).to.equal(0);
- expect(set.has(5)).to.equal(false);
- });
- });
-
- describe('#keys()', function () {
- if (!Set.prototype.hasOwnProperty('keys')) {
- return it('exists', function () {
- expect(Set.prototype).to.have.property('keys');
- });
- }
-
- it('is the same object as #values()', function () {
- expect(Set.prototype.keys).to.equal(Set.prototype.values);
- });
-
- ifFunctionsHaveNamesIt('has the right name', function () {
- expect(Set.prototype.keys).to.have.property('name', 'values');
- });
-
- it('is not enumerable', function () {
- expect(Set.prototype).ownPropertyDescriptor('keys').to.have.property('enumerable', false);
- });
-
- it('has the right arity', function () {
- expect(Set.prototype.keys).to.have.property('length', 0);
- });
- });
-
- describe('#values()', function () {
- if (!Set.prototype.hasOwnProperty('values')) {
- return it('exists', function () {
- expect(Set.prototype).to.have.property('values');
- });
- }
-
- ifFunctionsHaveNamesIt('has the right name', function () {
- expect(Set.prototype.values).to.have.property('name', 'values');
- });
-
- it('is not enumerable', function () {
- expect(Set.prototype).ownPropertyDescriptor('values').to.have.property('enumerable', false);
- });
-
- it('has the right arity', function () {
- expect(Set.prototype.values).to.have.property('length', 0);
- });
-
- it('throws when called on a non-Set', function () {
- var expectedMessage = /^(Method )?Set.prototype.values called on incompatible receiver |^values method called on incompatible |^Cannot create a Set value iterator for a non-Set object.$|^Set.prototype.values: 'this' is not a Set object$/;
- var nonSets = [true, false, 'abc', NaN, new Map([[1, 2]]), { a: true }, [1], Object('abc'), Object(NaN)];
- nonSets.forEach(function (nonSet) {
- expect(function () { return Set.prototype.values.call(nonSet); }).to['throw'](TypeError, expectedMessage);
- });
- });
- });
-
- describe('#entries()', function () {
- if (!Set.prototype.hasOwnProperty('entries')) {
- return it('exists', function () {
- expect(Set.prototype).to.have.property('entries');
- });
- }
-
- ifFunctionsHaveNamesIt('has the right name', function () {
- expect(Set.prototype.entries).to.have.property('name', 'entries');
- });
-
- it('is not enumerable', function () {
- expect(Set.prototype).ownPropertyDescriptor('entries').to.have.property('enumerable', false);
- });
-
- it('has the right arity', function () {
- expect(Set.prototype.entries).to.have.property('length', 0);
- });
- });
-
- describe('#has()', function () {
- if (!Set.prototype.hasOwnProperty('has')) {
- return it('exists', function () {
- expect(Set.prototype).to.have.property('has');
- });
- }
-
- ifFunctionsHaveNamesIt('has the right name', function () {
- expect(Set.prototype.has).to.have.property('name', 'has');
- });
-
- it('is not enumerable', function () {
- expect(Set.prototype).ownPropertyDescriptor('has').to.have.property('enumerable', false);
- });
-
- it('has the right arity', function () {
- expect(Set.prototype.has).to.have.property('length', 1);
- });
- });
-
- it('should allow NaN values as keys', function () {
- expect(set.has(NaN)).to.equal(false);
- expect(set.has(NaN + 1)).to.equal(false);
- expect(set.has(23)).to.equal(false);
- expect(set.add(NaN)).to.equal(set);
- expect(set.has(NaN)).to.equal(true);
- expect(set.has(NaN + 1)).to.equal(true);
- expect(set.has(23)).to.equal(false);
- });
-
- it('should not have [[Enumerable]] props', function () {
- expectNotEnumerable(Set);
- expectNotEnumerable(Set.prototype);
- expectNotEnumerable(new Set());
- });
-
- it('should not have an own constructor', function () {
- var s = new Set();
- expect(s).not.to.haveOwnPropertyDescriptor('constructor');
- expect(s.constructor).to.equal(Set);
- });
-
- it('should allow common ecmascript idioms', function () {
- expect(set instanceof Set).to.equal(true);
- expect(typeof Set.prototype.add).to.equal('function');
- expect(typeof Set.prototype.has).to.equal('function');
- expect(typeof Set.prototype['delete']).to.equal('function');
- });
-
- it('should have a unique constructor', function () {
- expect(Set.prototype).to.not.equal(Object.prototype);
- });
-
- describe('has an iterator that works with Array.from', function () {
- if (!Array.hasOwnProperty('from')) {
- return it('requires Array.from to exist', function () {
- expect(Array).to.have.property('from');
- });
- }
-
- var setToIterate;
- beforeEach(function () {
- setToIterate = new Set([1, NaN, false, true, null, undefined, 'a']);
- });
-
- afterEach(function () {
- setToIterate = null;
- });
-
- it('works with the full set', function () {
- expect(Array.from(setToIterate)).to.eql([1, NaN, false, true, null, undefined, 'a']);
- });
-
- it('works with Set#keys()', function () {
- expect(Array.from(setToIterate.keys())).to.eql(Array.from(setToIterate));
- });
-
- it('works with Set#values()', function () {
- expect(Array.from(setToIterate.values())).to.eql(Array.from(setToIterate));
- });
-
- it('works with Set#entries()', function () {
- expect(Array.from(setToIterate.entries())).to.eql([
- [1, 1],
- [NaN, NaN],
- [false, false],
- [true, true],
- [null, null],
- [undefined, undefined],
- ['a', 'a']
- ]);
- });
- });
-
- ifSymbolIteratorIt('has the right default iteration function', function () {
- // fixed in Webkit https://bugs.webkit.org/show_bug.cgi?id=143838
- expect(Set.prototype).to.have.property(Sym.iterator, Set.prototype.values);
- });
-
- it('should preserve insertion order', function () {
- var arr1 = ['d', 'a', 'b'];
- var arr2 = [3, 2, 'z', 'a', 1];
- var arr3 = [3, 2, 'z', {}, 'a', 1];
-
- var makeEntries = function (n) { return [n, n]; };
- [arr1, arr2, arr3].forEach(function (array) {
- var entries = array.map(makeEntries);
- expect(new Set(array)).to.have.entries(entries);
- });
- });
-
- describe('#forEach', function () {
- var setToIterate;
- beforeEach(function () {
- setToIterate = new Set();
- expect(setToIterate.add('a')).to.equal(setToIterate);
- expect(setToIterate.add('b')).to.equal(setToIterate);
- expect(setToIterate.add('c')).to.equal(setToIterate);
- });
-
- afterEach(function () {
- setToIterate = null;
- });
-
- ifFunctionsHaveNamesIt('has the right name', function () {
- expect(Set.prototype.forEach).to.have.property('name', 'forEach');
- });
-
- it('is not enumerable', function () {
- expect(Set.prototype).ownPropertyDescriptor('forEach').to.have.property('enumerable', false);
- });
-
- it('has the right arity', function () {
- expect(Set.prototype.forEach).to.have.property('length', 1);
- });
-
- it('should be iterable via forEach', function () {
- var expectedSet = ['a', 'b', 'c'];
- var foundSet = [];
- setToIterate.forEach(function (value, alsoValue, entireSet) {
- expect(entireSet).to.equal(setToIterate);
- expect(value).to.equal(alsoValue);
- foundSet.push(value);
- });
- expect(foundSet).to.eql(expectedSet);
- });
-
- it('should iterate over empty keys', function () {
- var setWithEmptyKeys = new Set();
- var expectedKeys = [{}, null, undefined, '', NaN, 0];
- expectedKeys.forEach(function (key) {
- expect(setWithEmptyKeys.add(key)).to.equal(setWithEmptyKeys);
- });
- var foundKeys = [];
- setWithEmptyKeys.forEach(function (value, key, entireSet) {
- expect([key]).to.be.theSameSet([value]); // handles NaN correctly
- expect(entireSet.has(key)).to.equal(true);
- foundKeys.push(key);
- });
- expect(foundKeys).to.be.theSameSet(expectedKeys);
- });
-
- it('should support the thisArg', function () {
- var context = function () {};
- setToIterate.forEach(function () {
- expect(this).to.equal(context);
- }, context);
- });
-
- it('should have a length of 1', function () {
- expect(Set.prototype.forEach.length).to.equal(1);
- });
-
- it('should not revisit modified keys', function () {
- var hasModifiedA = false;
- setToIterate.forEach(function (value, key) {
- if (!hasModifiedA && key === 'a') {
- expect(setToIterate.add('a')).to.equal(setToIterate);
- hasModifiedA = true;
- } else {
- expect(key).not.to.equal('a');
- }
- });
- });
-
- it('visits keys added in the iterator', function () {
- var hasAdded = false;
- var hasFoundD = false;
- setToIterate.forEach(function (value, key) {
- if (!hasAdded) {
- expect(setToIterate.add('d')).to.equal(setToIterate);
- hasAdded = true;
- } else if (key === 'd') {
- hasFoundD = true;
- }
- });
- expect(hasFoundD).to.equal(true);
- });
-
- it('visits keys added in the iterator when there is a deletion (slow path)', function () {
- var hasSeenFour = false;
- var setToMutate = new Set();
- expect(setToMutate.add({})).to.equal(setToMutate); // force use of the slow O(N) implementation
- expect(setToMutate.add('0')).to.equal(setToMutate);
- setToMutate.forEach(function (value, key) {
- if (key === '0') {
- expect(setToMutate['delete']('0')).to.equal(true);
- expect(setToMutate.add('4')).to.equal(setToMutate);
- } else if (key === '4') {
- hasSeenFour = true;
- }
- });
- expect(hasSeenFour).to.equal(true);
- });
-
- it('visits keys added in the iterator when there is a deletion (fast path)', function () {
- var hasSeenFour = false;
- var setToMutate = new Set();
- expect(setToMutate.add('0')).to.equal(setToMutate);
- setToMutate.forEach(function (value, key) {
- if (key === '0') {
- expect(setToMutate['delete']('0')).to.equal(true);
- expect(setToMutate.add('4')).to.equal(setToMutate);
- } else if (key === '4') {
- hasSeenFour = true;
- }
- });
- expect(hasSeenFour).to.equal(true);
- });
-
- it('does not visit keys deleted before a visit', function () {
- var hasVisitedC = false;
- var hasDeletedC = false;
- setToIterate.forEach(function (value, key) {
- if (key === 'c') {
- hasVisitedC = true;
- }
- if (!hasVisitedC && !hasDeletedC) {
- hasDeletedC = setToIterate['delete']('c');
- expect(hasDeletedC).to.equal(true);
- }
- });
- expect(hasVisitedC).to.equal(false);
- });
-
- it('should work after deletion of the current key', function () {
- var expectedSet = {
- a: 'a',
- b: 'b',
- c: 'c'
- };
- var foundSet = {};
- setToIterate.forEach(function (value, key) {
- foundSet[key] = value;
- expect(setToIterate['delete'](key)).to.equal(true);
- });
- expect(foundSet).to.eql(expectedSet);
- });
-
- it('should convert key -0 to +0', function () {
- var zeroSet = new Set();
- var result = [];
- expect(zeroSet.add(-0)).to.equal(zeroSet);
- zeroSet.forEach(function (key) {
- result.push(String(1 / key));
- });
- expect(zeroSet.add(1)).to.equal(zeroSet);
- expect(zeroSet.add(0)).to.equal(zeroSet); // shouldn't cause reordering
- zeroSet.forEach(function (key) {
- result.push(String(1 / key));
- });
- expect(result.join(', ')).to.equal(
- 'Infinity, Infinity, 1'
- );
- });
- });
-
- it('Set.prototype.size should throw TypeError', function () {
- // see https://github.com/paulmillr/es6-shim/issues/176
- expect(function () { return Set.prototype.size; }).to['throw'](TypeError);
- expect(function () { return Set.prototype.size; }).to['throw'](TypeError);
- });
-
- it.skip('should throw proper errors when user invokes methods with wrong types of receiver', function () {
-
- });
- });
-});
diff --git a/test/index.html b/test/index.html
index 64e09b7..f2e14a7 100644
--- a/test/index.html
+++ b/test/index.html
@@ -11,7 +11,8 @@
<script src="../es6-shim.js"></script>
<script src="browser-setup.js"></script>
<script src="array.js"></script>
- <script src="collections.js"></script>
+ <script src="map.js"></script>
+ <script src="set.js"></script>
<script src="json.js"></script>
<script src="math.js"></script>
<script src="number.js"></script>
diff --git a/test/map.js b/test/map.js
new file mode 100644
index 0000000..a16b086
--- /dev/null
+++ b/test/map.js
@@ -0,0 +1,605 @@
+/* global describe, it, xit, expect, require, beforeEach, afterEach */
+
+// Big thanks to V8 folks for test ideas.
+// v8/test/mjsunit/harmony/collections.js
+
+var Assertion = expect().constructor;
+Assertion.addMethod('theSameSet', function (otherArray) {
+ var array = this._obj;
+
+ expect(Array.isArray(array)).to.equal(true);
+ expect(Array.isArray(otherArray)).to.equal(true);
+
+ var diff = array.filter(function (value) {
+ return otherArray.every(function (otherValue) {
+ var areBothNaN = typeof value === 'number' && typeof otherValue === 'number' && value !== value && otherValue !== otherValue;
+ return !areBothNaN && value !== otherValue;
+ });
+ });
+
+ this.assert(
+ diff.length === 0,
+ 'expected #{this} to be equal to #{exp} (as sets, i.e. no order)',
+ array,
+ otherArray
+ );
+});
+
+Assertion.addMethod('entries', function (expected) {
+ var collection = this._obj;
+
+ expect(Array.isArray(expected)).to.equal(true);
+ var expectedEntries = expected.slice();
+
+ var iterator = collection.entries();
+ var result;
+ do {
+ result = iterator.next();
+ expect(result.value).to.be.eql(expectedEntries.shift());
+ } while (!result.done);
+});
+
+describe('Map', function () {
+ var functionsHaveNames = (function foo() {}).name === 'foo';
+ var ifFunctionsHaveNamesIt = functionsHaveNames ? it : xit;
+ var ifShimIt = (typeof process !== 'undefined' && process.env.NO_ES6_SHIM) ? it.skip : it;
+
+ var range = function range(from, to) {
+ var result = [];
+ for (var value = from; value < to; value++) {
+ result.push(value);
+ }
+ return result;
+ };
+
+ var prototypePropIsEnumerable = (function () {}).propertyIsEnumerable('prototype');
+ var expectNotEnumerable = function (object) {
+ if (prototypePropIsEnumerable && typeof object === 'function') {
+ expect(Object.keys(object)).to.eql(['prototype']);
+ } else {
+ expect(Object.keys(object)).to.eql([]);
+ }
+ };
+
+ var Sym = typeof Symbol === 'undefined' ? {} : Symbol;
+ var isSymbol = function (sym) {
+ return typeof Sym === 'function' && typeof sym === 'symbol';
+ };
+ var ifSymbolIteratorIt = isSymbol(Sym.iterator) ? it : xit;
+
+ var testMapping = function (map, key, value) {
+ expect(map.has(key)).to.equal(false);
+ expect(map.get(key)).to.equal(undefined);
+ expect(map.set(key, value)).to.equal(map);
+ expect(map.get(key)).to.equal(value);
+ expect(map.has(key)).to.equal(true);
+ };
+
+ if (typeof Map === 'undefined') {
+ return it('exists', function () {
+ expect(typeof Map).to.equal('function');
+ });
+ }
+
+ var map;
+ beforeEach(function () {
+ map = new Map();
+ });
+
+ afterEach(function () {
+ map = null;
+ });
+
+ ifShimIt('is on the exported object', function () {
+ var exported = require('../');
+ expect(exported.Map).to.equal(Map);
+ });
+
+ it('should exist in global namespace', function () {
+ expect(typeof Map).to.equal('function');
+ });
+
+ it('should have the right arity', function () {
+ expect(Map).to.have.property('length', 0);
+ });
+
+ it('should has valid getter and setter calls', function () {
+ ['get', 'set', 'has', 'delete'].forEach(function (method) {
+ expect(function () {
+ map[method]({});
+ }).to.not['throw']();
+ });
+ });
+
+ it('should accept an iterable as argument', function () {
+ testMapping(map, 'a', 'b');
+ testMapping(map, 'c', 'd');
+ var map2;
+ expect(function () { map2 = new Map(map); }).not.to['throw'](Error);
+ expect(map2).to.be.an.instanceOf(Map);
+ expect(map2.has('a')).to.equal(true);
+ expect(map2.has('c')).to.equal(true);
+ expect(map2).to.have.entries([['a', 'b'], ['c', 'd']]);
+ });
+
+ it('should throw with iterables that return primitives', function () {
+ expect(function () { return new Map('123'); }).to['throw'](TypeError);
+ expect(function () { return new Map([1, 2, 3]); }).to['throw'](TypeError);
+ expect(function () { return new Map(['1', '2', '3']); }).to['throw'](TypeError);
+ expect(function () { return new Map([true]); }).to['throw'](TypeError);
+ });
+
+ it('should not be callable without "new"', function () {
+ expect(Map).to['throw'](TypeError);
+ });
+
+ it('should be subclassable', function () {
+ if (!Object.setPrototypeOf) { return; } // skip test if on IE < 11
+ var MyMap = function MyMap() {
+ var testMap = new Map([['a', 'b']]);
+ Object.setPrototypeOf(testMap, MyMap.prototype);
+ return testMap;
+ };
+ Object.setPrototypeOf(MyMap, Map);
+ MyMap.prototype = Object.create(Map.prototype, {
+ constructor: { value: MyMap }
+ });
+
+ var myMap = new MyMap();
+ testMapping(myMap, 'c', 'd');
+ expect(myMap).to.have.entries([['a', 'b'], ['c', 'd']]);
+ });
+
+ it('uses SameValueZero even on a Map of size > 4', function () {
+ // Chrome 38-42, node 0.11/0.12, iojs 1/2 have a bug when the Map has a size > 4
+ var firstFour = [[1, 0], [2, 0], [3, 0], [4, 0]];
+ var fourMap = new Map(firstFour);
+ expect(fourMap.size).to.equal(4);
+ expect(fourMap.has(-0)).to.equal(false);
+ expect(fourMap.has(0)).to.equal(false);
+
+ fourMap.set(-0, fourMap);
+
+ expect(fourMap.has(0)).to.equal(true);
+ expect(fourMap.has(-0)).to.equal(true);
+ });
+
+ it('treats positive and negative zero the same', function () {
+ var value1 = {};
+ var value2 = {};
+ testMapping(map, +0, value1);
+ expect(map.has(-0)).to.equal(true);
+ expect(map.get(-0)).to.equal(value1);
+ expect(map.set(-0, value2)).to.equal(map);
+ expect(map.get(-0)).to.equal(value2);
+ expect(map.get(+0)).to.equal(value2);
+ });
+
+ it('should map values correctly', function () {
+ // Run this test twice, one with the "fast" implementation (which only
+ // allows string and numeric keys) and once with the "slow" impl.
+ [true, false].forEach(function (slowkeys) {
+ map = new Map();
+
+ range(1, 20).forEach(function (number) {
+ if (slowkeys) { testMapping(map, number, {}); }
+ testMapping(map, number / 100, {});
+ testMapping(map, 'key-' + number, {});
+ testMapping(map, String(number), {});
+ if (slowkeys) { testMapping(map, Object(String(number)), {}); }
+ });
+
+ var testkeys = [Infinity, -Infinity, NaN];
+ if (slowkeys) {
+ testkeys.push(true, false, null, undefined);
+ }
+ testkeys.forEach(function (key) {
+ testMapping(map, key, {});
+ testMapping(map, String(key), {});
+ });
+ testMapping(map, '', {});
+
+ // verify that properties of Object don't peek through.
+ [
+ 'hasOwnProperty',
+ 'constructor',
+ 'toString',
+ 'isPrototypeOf',
+ '__proto__',
+ '__parent__',
+ '__count__'
+ ].forEach(function (key) {
+ testMapping(map, key, {});
+ });
+ });
+ });
+
+ it('should map empty values correctly', function () {
+ testMapping(map, {}, true);
+ testMapping(map, null, true);
+ testMapping(map, undefined, true);
+ testMapping(map, '', true);
+ testMapping(map, NaN, true);
+ testMapping(map, 0, true);
+ });
+
+ it('should has correct querying behavior', function () {
+ var key = {};
+ testMapping(map, key, 'to-be-present');
+ expect(map.has(key)).to.equal(true);
+ expect(map.has({})).to.equal(false);
+ expect(map.set(key, void 0)).to.equal(map);
+ expect(map.get(key)).to.equal(undefined);
+ expect(map.has(key)).to.equal(true);
+ expect(map.has({})).to.equal(false);
+ });
+
+ it('should allow NaN values as keys', function () {
+ expect(map.has(NaN)).to.equal(false);
+ expect(map.has(NaN + 1)).to.equal(false);
+ expect(map.has(23)).to.equal(false);
+ expect(map.set(NaN, 'value')).to.equal(map);
+ expect(map.has(NaN)).to.equal(true);
+ expect(map.has(NaN + 1)).to.equal(true);
+ expect(map.has(23)).to.equal(false);
+ });
+
+ it('should not have [[Enumerable]] props', function () {
+ expectNotEnumerable(Map);
+ expectNotEnumerable(Map.prototype);
+ expectNotEnumerable(new Map());
+ });
+
+ it('should not have an own constructor', function () {
+ var m = new Map();
+ expect(m).not.to.haveOwnPropertyDescriptor('constructor');
+ expect(m.constructor).to.equal(Map);
+ });
+
+ it('should allow common ecmascript idioms', function () {
+ expect(map).to.be.an.instanceOf(Map);
+ expect(typeof Map.prototype.get).to.equal('function');
+ expect(typeof Map.prototype.set).to.equal('function');
+ expect(typeof Map.prototype.has).to.equal('function');
+ expect(typeof Map.prototype['delete']).to.equal('function');
+ });
+
+ it('should have a unique constructor', function () {
+ expect(Map.prototype).to.not.equal(Object.prototype);
+ });
+
+ describe('#clear()', function () {
+ ifFunctionsHaveNamesIt('has the right name', function () {
+ expect(Map.prototype.clear).to.have.property('name', 'clear');
+ });
+
+ it('is not enumerable', function () {
+ expect(Map.prototype).ownPropertyDescriptor('clear').to.have.property('enumerable', false);
+ });
+
+ it('has the right arity', function () {
+ expect(Map.prototype.clear).to.have.property('length', 0);
+ });
+
+ it('should have #clear method', function () {
+ expect(map.set(1, 2)).to.equal(map);
+ expect(map.set(5, 2)).to.equal(map);
+ expect(map.size).to.equal(2);
+ expect(map.has(5)).to.equal(true);
+ map.clear();
+ expect(map.size).to.equal(0);
+ expect(map.has(5)).to.equal(false);
+ });
+ });
+
+ describe('#keys()', function () {
+ if (!Map.prototype.hasOwnProperty('keys')) {
+ return it('exists', function () {
+ expect(Map.prototype).to.have.property('keys');
+ });
+ }
+
+ ifFunctionsHaveNamesIt('has the right name', function () {
+ expect(Map.prototype.keys).to.have.property('name', 'keys');
+ });
+
+ it('is not enumerable', function () {
+ expect(Map.prototype).ownPropertyDescriptor('keys').to.have.property('enumerable', false);
+ });
+
+ it('has the right arity', function () {
+ expect(Map.prototype.keys).to.have.property('length', 0);
+ });
+ });
+
+ describe('#values()', function () {
+ if (!Map.prototype.hasOwnProperty('values')) {
+ return it('exists', function () {
+ expect(Map.prototype).to.have.property('values');
+ });
+ }
+
+ ifFunctionsHaveNamesIt('has the right name', function () {
+ expect(Map.prototype.values).to.have.property('name', 'values');
+ });
+
+ it('is not enumerable', function () {
+ expect(Map.prototype).ownPropertyDescriptor('values').to.have.property('enumerable', false);
+ });
+
+ it('has the right arity', function () {
+ expect(Map.prototype.values).to.have.property('length', 0);
+ });
+ });
+
+ describe('#entries()', function () {
+ if (!Map.prototype.hasOwnProperty('entries')) {
+ return it('exists', function () {
+ expect(Map.prototype).to.have.property('entries');
+ });
+ }
+
+ ifFunctionsHaveNamesIt('has the right name', function () {
+ expect(Map.prototype.entries).to.have.property('name', 'entries');
+ });
+
+ it('is not enumerable', function () {
+ expect(Map.prototype).ownPropertyDescriptor('entries').to.have.property('enumerable', false);
+ });
+
+ it('has the right arity', function () {
+ expect(Map.prototype.entries).to.have.property('length', 0);
+ });
+
+ it('throws when called on a non-Map', function () {
+ var expectedMessage = /^(Method )?Map.prototype.entries called on incompatible receiver |^entries method called on incompatible |^Cannot create a Map entry iterator for a non-Map object.|^Map\.prototype\.entries: 'this' is not a Map object$/;
+ var nonMaps = [true, false, 'abc', NaN, new Set([1, 2]), { a: true }, [1], Object('abc'), Object(NaN)];
+ nonMaps.forEach(function (nonMap) {
+ expect(function () { return Map.prototype.entries.call(nonMap); }).to['throw'](TypeError, expectedMessage);
+ });
+ });
+ });
+
+ describe('#size', function () {
+ it('throws TypeError when accessed directly', function () {
+ // see https://github.com/paulmillr/es6-shim/issues/176
+ expect(function () { return Map.prototype.size; }).to['throw'](TypeError);
+ expect(function () { return Map.prototype.size; }).to['throw'](TypeError);
+ });
+
+ it('is an accessor function on the prototype', function () {
+ expect(Map.prototype).ownPropertyDescriptor('size').to.have.property('get');
+ expect(typeof Object.getOwnPropertyDescriptor(Map.prototype, 'size').get).to.equal('function');
+ expect(new Map()).not.to.haveOwnPropertyDescriptor('size');
+ });
+ });
+
+ it('should return false when deleting a nonexistent key', function () {
+ expect(map.has('a')).to.equal(false);
+ expect(map['delete']('a')).to.equal(false);
+ });
+
+ it('should have keys, values and size props', function () {
+ expect(map.set('a', 1)).to.equal(map);
+ expect(map.set('b', 2)).to.equal(map);
+ expect(map.set('c', 3)).to.equal(map);
+ expect(typeof map.keys).to.equal('function');
+ expect(typeof map.values).to.equal('function');
+ expect(map.size).to.equal(3);
+ expect(map['delete']('a')).to.equal(true);
+ expect(map.size).to.equal(2);
+ });
+
+ it('should have an iterator that works with Array.from', function () {
+ expect(Array).to.have.property('from');
+
+ expect(map.set('a', 1)).to.equal(map);
+ expect(map.set('b', NaN)).to.equal(map);
+ expect(map.set('c', false)).to.equal(map);
+ expect(Array.from(map)).to.eql([['a', 1], ['b', NaN], ['c', false]]);
+ expect(Array.from(map.keys())).to.eql(['a', 'b', 'c']);
+ expect(Array.from(map.values())).to.eql([1, NaN, false]);
+ expect(map).to.have.entries(Array.from(map.entries()));
+ });
+
+ ifSymbolIteratorIt('has the right default iteration function', function () {
+ // fixed in Webkit https://bugs.webkit.org/show_bug.cgi?id=143838
+ expect(Map.prototype).to.have.property(Sym.iterator, Map.prototype.entries);
+ });
+
+ describe('#forEach', function () {
+ var mapToIterate;
+
+ beforeEach(function () {
+ mapToIterate = new Map();
+ expect(mapToIterate.set('a', 1)).to.equal(mapToIterate);
+ expect(mapToIterate.set('b', 2)).to.equal(mapToIterate);
+ expect(mapToIterate.set('c', 3)).to.equal(mapToIterate);
+ });
+
+ afterEach(function () {
+ mapToIterate = null;
+ });
+
+ ifFunctionsHaveNamesIt('has the right name', function () {
+ expect(Map.prototype.forEach).to.have.property('name', 'forEach');
+ });
+
+ it('is not enumerable', function () {
+ expect(Map.prototype).ownPropertyDescriptor('forEach').to.have.property('enumerable', false);
+ });
+
+ it('has the right arity', function () {
+ expect(Map.prototype.forEach).to.have.property('length', 1);
+ });
+
+ it('should be iterable via forEach', function () {
+ var expectedMap = {
+ a: 1,
+ b: 2,
+ c: 3
+ };
+ var foundMap = {};
+ mapToIterate.forEach(function (value, key, entireMap) {
+ expect(entireMap).to.equal(mapToIterate);
+ foundMap[key] = value;
+ });
+ expect(foundMap).to.eql(expectedMap);
+ });
+
+ it('should iterate over empty keys', function () {
+ var mapWithEmptyKeys = new Map();
+ var expectedKeys = [{}, null, undefined, '', NaN, 0];
+ expectedKeys.forEach(function (key) {
+ expect(mapWithEmptyKeys.set(key, true)).to.equal(mapWithEmptyKeys);
+ });
+ var foundKeys = [];
+ mapWithEmptyKeys.forEach(function (value, key, entireMap) {
+ expect(entireMap.get(key)).to.equal(value);
+ foundKeys.push(key);
+ });
+ expect(foundKeys).to.be.theSameSet(expectedKeys);
+ });
+
+ it('should support the thisArg', function () {
+ var context = function () {};
+ mapToIterate.forEach(function () {
+ expect(this).to.equal(context);
+ }, context);
+ });
+
+ it('should have a length of 1', function () {
+ expect(Map.prototype.forEach.length).to.equal(1);
+ });
+
+ it('should not revisit modified keys', function () {
+ var hasModifiedA = false;
+ mapToIterate.forEach(function (value, key) {
+ if (!hasModifiedA && key === 'a') {
+ expect(mapToIterate.set('a', 4)).to.equal(mapToIterate);
+ hasModifiedA = true;
+ } else {
+ expect(key).not.to.equal('a');
+ }
+ });
+ });
+
+ it('returns the map from #set() for chaining', function () {
+ expect(mapToIterate.set({}, {})).to.equal(mapToIterate);
+ expect(mapToIterate.set(42, {})).to.equal(mapToIterate);
+ expect(mapToIterate.set(0, {})).to.equal(mapToIterate);
+ expect(mapToIterate.set(NaN, {})).to.equal(mapToIterate);
+ expect(mapToIterate.set(-0, {})).to.equal(mapToIterate);
+ });
+
+ it('visits keys added in the iterator', function () {
+ var hasAdded = false;
+ var hasFoundD = false;
+ mapToIterate.forEach(function (value, key) {
+ if (!hasAdded) {
+ mapToIterate.set('d', 5);
+ hasAdded = true;
+ } else if (key === 'd') {
+ hasFoundD = true;
+ }
+ });
+ expect(hasFoundD).to.equal(true);
+ });
+
+ it('visits keys added in the iterator when there is a deletion', function () {
+ var hasSeenFour = false;
+ var mapToMutate = new Map();
+ mapToMutate.set('0', 42);
+ mapToMutate.forEach(function (value, key) {
+ if (key === '0') {
+ expect(mapToMutate['delete']('0')).to.equal(true);
+ mapToMutate.set('4', 'a value');
+ } else if (key === '4') {
+ hasSeenFour = true;
+ }
+ });
+ expect(hasSeenFour).to.equal(true);
+ });
+
+ it('does not visit keys deleted before a visit', function () {
+ var hasVisitedC = false;
+ var hasDeletedC = false;
+ mapToIterate.forEach(function (value, key) {
+ if (key === 'c') {
+ hasVisitedC = true;
+ }
+ if (!hasVisitedC && !hasDeletedC) {
+ hasDeletedC = mapToIterate['delete']('c');
+ expect(hasDeletedC).to.equal(true);
+ }
+ });
+ expect(hasVisitedC).to.equal(false);
+ });
+
+ it('should work after deletion of the current key', function () {
+ var expectedMap = {
+ a: 1,
+ b: 2,
+ c: 3
+ };
+ var foundMap = {};
+ mapToIterate.forEach(function (value, key) {
+ foundMap[key] = value;
+ expect(mapToIterate['delete'](key)).to.equal(true);
+ });
+ expect(foundMap).to.eql(expectedMap);
+ });
+
+ it('should convert key -0 to +0', function () {
+ var zeroMap = new Map();
+ var result = [];
+ zeroMap.set(-0, 'a');
+ zeroMap.forEach(function (value, key) {
+ result.push(String(1 / key) + ' ' + value);
+ });
+ zeroMap.set(1, 'b');
+ zeroMap.set(0, 'c'); // shouldn't cause reordering
+ zeroMap.forEach(function (value, key) {
+ result.push(String(1 / key) + ' ' + value);
+ });
+ expect(result.join(', ')).to.equal(
+ 'Infinity a, Infinity c, 1 b'
+ );
+ });
+ });
+
+ it('should preserve insertion order', function () {
+ var convertToPairs = function (item) { return [item, true]; };
+ var arr1 = ['d', 'a', 'b'];
+ var arr2 = [3, 2, 'z', 'a', 1];
+ var arr3 = [3, 2, 'z', {}, 'a', 1];
+
+ [arr1, arr2, arr3].forEach(function (array) {
+ var entries = array.map(convertToPairs);
+ expect(new Map(entries)).to.have.entries(entries);
+ });
+ });
+
+ it('map iteration', function () {
+ var map = new Map();
+ map.set('a', 1);
+ map.set('b', 2);
+ map.set('c', 3);
+ map.set('d', 4);
+
+ var keys = [];
+ var iterator = map.keys();
+ keys.push(iterator.next().value);
+ expect(map['delete']('a')).to.equal(true);
+ expect(map['delete']('b')).to.equal(true);
+ expect(map['delete']('c')).to.equal(true);
+ map.set('e');
+ keys.push(iterator.next().value);
+ keys.push(iterator.next().value);
+
+ expect(iterator.next().done).to.equal(true);
+ map.set('f');
+ expect(iterator.next().done).to.equal(true);
+ expect(keys).to.eql(['a', 'd', 'e']);
+ });
+});
diff --git a/test/native.html b/test/native.html
index 251efc8..51f8dc0 100644
--- a/test/native.html
+++ b/test/native.html
@@ -9,7 +9,8 @@
<script src="../node_modules/chai/chai.js"></script>
<script src="browser-setup.js"></script>
<script src="array.js"></script>
- <script src="collections.js"></script>
+ <script src="map.js"></script>
+ <script src="set.js"></script>
<script src="json.js"></script>
<script src="math.js"></script>
<script src="number.js"></script>
diff --git a/test/set.js b/test/set.js
new file mode 100644
index 0000000..1e5e40d
--- /dev/null
+++ b/test/set.js
@@ -0,0 +1,639 @@
+/* global describe, it, xit, expect, require, beforeEach, afterEach */
+
+// Big thanks to V8 folks for test ideas.
+// v8/test/mjsunit/harmony/collections.js
+
+var Assertion = expect().constructor;
+Assertion.addMethod('theSameSet', function (otherArray) {
+ var array = this._obj;
+
+ expect(Array.isArray(array)).to.equal(true);
+ expect(Array.isArray(otherArray)).to.equal(true);
+
+ var diff = array.filter(function (value) {
+ return otherArray.every(function (otherValue) {
+ var areBothNaN = typeof value === 'number' && typeof otherValue === 'number' && value !== value && otherValue !== otherValue;
+ return !areBothNaN && value !== otherValue;
+ });
+ });
+
+ this.assert(
+ diff.length === 0,
+ 'expected #{this} to be equal to #{exp} (as sets, i.e. no order)',
+ array,
+ otherArray
+ );
+});
+
+var $iterator$ = typeof Symbol === 'function' ? Symbol.iterator : void 0;
+if (!$iterator$ && typeof Set === 'function') {
+ $iterator$ = typeof Set['@@iterator'] === 'function' ? '@@iterator' : '_es6-shim iterator_';
+}
+
+Assertion.addMethod('iterations', function (expected) {
+ var iterator = this._obj[$iterator$]();
+
+ expect(Array.isArray(expected)).to.equal(true);
+ var expectedValues = expected.slice();
+
+ var result;
+ do {
+ result = iterator.next();
+ expect(result.value).to.eql(expectedValues.shift());
+ } while (!result.done);
+});
+
+describe('Set', function () {
+ var functionsHaveNames = (function foo() {}).name === 'foo';
+ var ifFunctionsHaveNamesIt = functionsHaveNames ? it : xit;
+ var ifShimIt = (typeof process !== 'undefined' && process.env.NO_ES6_SHIM) ? it.skip : it;
+
+ var range = function (from, to) {
+ var result = [];
+ for (var value = from; value < to; value++) {
+ result.push(value);
+ }
+ return result;
+ };
+
+ var prototypePropIsEnumerable = (function () {}).propertyIsEnumerable('prototype');
+ var expectNotEnumerable = function (object) {
+ if (prototypePropIsEnumerable && typeof object === 'function') {
+ expect(Object.keys(object)).to.eql(['prototype']);
+ } else {
+ expect(Object.keys(object)).to.eql([]);
+ }
+ };
+
+ var Sym = typeof Symbol === 'undefined' ? {} : Symbol;
+ var isSymbol = function (sym) {
+ return typeof Sym === 'function' && typeof sym === 'symbol';
+ };
+ var ifSymbolIteratorIt = isSymbol(Sym.iterator) ? it : xit;
+
+ var testSet = function (set, key) {
+ expect(set.has(key)).to.equal(false);
+ expect(set['delete'](key)).to.equal(false);
+ expect(set.add(key)).to.equal(set);
+ expect(set.has(key)).to.equal(true);
+ expect(set['delete'](key)).to.equal(true);
+ expect(set.has(key)).to.equal(false);
+ expect(set.add(key)).to.equal(set); // add it back
+ };
+
+ if (typeof Set === 'undefined') {
+ return it('exists', function () {
+ expect(typeof Set).to.equal('function');
+ });
+ }
+
+ var set;
+ beforeEach(function () {
+ set = new Set();
+ });
+
+ afterEach(function () {
+ set = null;
+ });
+
+ it('set iteration', function () {
+ expect(set.add('a')).to.equal(set);
+ expect(set.add('b')).to.equal(set);
+ expect(set.add('c')).to.equal(set);
+ expect(set.add('d')).to.equal(set);
+
+ var keys = [];
+ var iterator = set.keys();
+ keys.push(iterator.next().value);
+ expect(set['delete']('a')).to.equal(true);
+ expect(set['delete']('b')).to.equal(true);
+ expect(set['delete']('c')).to.equal(true);
+ expect(set.add('e')).to.equal(set);
+ keys.push(iterator.next().value);
+ keys.push(iterator.next().value);
+
+ expect(iterator.next().done).to.equal(true);
+ expect(set.add('f')).to.equal(set);
+ expect(iterator.next().done).to.equal(true);
+ expect(keys).to.eql(['a', 'd', 'e']);
+ });
+
+ ifShimIt('is on the exported object', function () {
+ var exported = require('../');
+ expect(exported.Set).to.equal(Set);
+ });
+
+ it('should exist in global namespace', function () {
+ expect(typeof Set).to.equal('function');
+ });
+
+ it('has the right arity', function () {
+ expect(Set).to.have.property('length', 0);
+ });
+
+ it('returns the set from #add() for chaining', function () {
+ expect(set.add({})).to.equal(set);
+ });
+
+ it('should return false when deleting an item not in the set', function () {
+ expect(set.has('a')).to.equal(false);
+ expect(set['delete']('a')).to.equal(false);
+ });
+
+ it('should accept an iterable as argument', function () {
+ testSet(set, 'a');
+ testSet(set, 'b');
+ var set2 = new Set(set);
+ expect(set2.has('a')).to.equal(true);
+ expect(set2.has('b')).to.equal(true);
+ expect(set2).to.have.iterations(['a', 'b']);
+ });
+
+ it('accepts an array as an argument', function () {
+ var arr = ['a', 'b', 'c'];
+ var setFromArray = new Set(arr);
+ expect(setFromArray).to.have.iterations(['a', 'b', 'c']);
+ });
+
+ it('should not be callable without "new"', function () {
+ expect(Set).to['throw'](TypeError);
+ });
+
+ it('should be subclassable', function () {
+ if (!Object.setPrototypeOf) { return; } // skip test if on IE < 11
+ var MySet = function MySet() {
+ var actualSet = new Set(['a', 'b']);
+ Object.setPrototypeOf(actualSet, MySet.prototype);
+ return actualSet;
+ };
+ Object.setPrototypeOf(MySet, Set);
+ MySet.prototype = Object.create(Set.prototype, {
+ constructor: { value: MySet }
+ });
+
+ var mySet = new MySet();
+ testSet(mySet, 'c');
+ testSet(mySet, 'd');
+ expect(mySet).to.have.iterations(['a', 'b', 'c', 'd']);
+ });
+
+ it('should has valid getter and setter calls', function () {
+ ['add', 'has', 'delete'].forEach(function (method) {
+ expect(function () {
+ set[method]({});
+ }).to.not['throw']();
+ });
+ });
+
+ it('uses SameValueZero even on a Set of size > 4', function () {
+ var firstFour = [1, 2, 3, 4];
+ var fourSet = new Set(firstFour);
+ expect(fourSet.size).to.equal(4);
+ expect(fourSet.has(-0)).to.equal(false);
+ expect(fourSet.has(0)).to.equal(false);
+
+ fourSet.add(-0);
+
+ expect(fourSet.size).to.equal(5);
+ expect(fourSet.has(0)).to.equal(true);
+ expect(fourSet.has(-0)).to.equal(true);
+ });
+
+ it('should work as expected', function () {
+ // Run this test twice, one with the "fast" implementation (which only
+ // allows string and numeric keys) and once with the "slow" impl.
+ [true, false].forEach(function (slowkeys) {
+ set = new Set();
+
+ range(1, 20).forEach(function (number) {
+ if (slowkeys) { testSet(set, {}); }
+ testSet(set, number);
+ testSet(set, number / 100);
+ testSet(set, 'key-' + number);
+ testSet(set, String(number));
+ if (slowkeys) { testSet(set, Object(String(number))); }
+ });
+
+ var testkeys = [+0, Infinity, -Infinity, NaN];
+ if (slowkeys) {
+ testkeys.push(true, false, null, undefined);
+ }
+ testkeys.forEach(function (number) {
+ testSet(set, number);
+ testSet(set, String(number));
+ });
+ testSet(set, '');
+
+ // -0 and +0 should be the same key (Set uses SameValueZero)
+ expect(set.has(-0)).to.equal(true);
+ expect(set['delete'](+0)).to.equal(true);
+ testSet(set, -0);
+ expect(set.has(+0)).to.equal(true);
+
+ // verify that properties of Object don't peek through.
+ [
+ 'hasOwnProperty',
+ 'constructor',
+ 'toString',
+ 'isPrototypeOf',
+ '__proto__',
+ '__parent__',
+ '__count__'
+ ].forEach(function (prop) { testSet(set, prop); });
+ });
+ });
+
+ describe('#size', function () {
+ it('returns the expected size', function () {
+ expect(set.add(1)).to.equal(set);
+ expect(set.add(5)).to.equal(set);
+ expect(set.size).to.equal(2);
+ });
+ });
+
+ describe('#clear()', function () {
+ ifFunctionsHaveNamesIt('has the right name', function () {
+ expect(Set.prototype.clear).to.have.property('name', 'clear');
+ });
+
+ it('is not enumerable', function () {
+ expect(Set.prototype).ownPropertyDescriptor('clear').to.have.property('enumerable', false);
+ });
+
+ it('has the right arity', function () {
+ expect(Set.prototype.clear).to.have.property('length', 0);
+ });
+
+ it('clears a Set with only primitives', function () {
+ expect(set.add(1)).to.equal(set);
+ expect(set.size).to.equal(1);
+ expect(set.add(5)).to.equal(set);
+ expect(set.size).to.equal(2);
+ expect(set.has(5)).to.equal(true);
+ set.clear();
+ expect(set.size).to.equal(0);
+ expect(set.has(5)).to.equal(false);
+ });
+
+ it('clears a Set with primitives and objects', function () {
+ expect(set.add(1)).to.equal(set);
+ expect(set.size).to.equal(1);
+ var obj = {};
+ expect(set.add(obj)).to.equal(set);
+ expect(set.size).to.equal(2);
+ expect(set.has(obj)).to.equal(true);
+ set.clear();
+ expect(set.size).to.equal(0);
+ expect(set.has(obj)).to.equal(false);
+ });
+ });
+
+ describe('#keys()', function () {
+ if (!Set.prototype.hasOwnProperty('keys')) {
+ return it('exists', function () {
+ expect(Set.prototype).to.have.property('keys');
+ });
+ }
+
+ it('is the same object as #values()', function () {
+ expect(Set.prototype.keys).to.equal(Set.prototype.values);
+ });
+
+ ifFunctionsHaveNamesIt('has the right name', function () {
+ expect(Set.prototype.keys).to.have.property('name', 'values');
+ });
+
+ it('is not enumerable', function () {
+ expect(Set.prototype).ownPropertyDescriptor('keys').to.have.property('enumerable', false);
+ });
+
+ it('has the right arity', function () {
+ expect(Set.prototype.keys).to.have.property('length', 0);
+ });
+ });
+
+ describe('#values()', function () {
+ if (!Set.prototype.hasOwnProperty('values')) {
+ return it('exists', function () {
+ expect(Set.prototype).to.have.property('values');
+ });
+ }
+
+ ifFunctionsHaveNamesIt('has the right name', function () {
+ expect(Set.prototype.values).to.have.property('name', 'values');
+ });
+
+ it('is not enumerable', function () {
+ expect(Set.prototype).ownPropertyDescriptor('values').to.have.property('enumerable', false);
+ });
+
+ it('has the right arity', function () {
+ expect(Set.prototype.values).to.have.property('length', 0);
+ });
+
+ it('throws when called on a non-Set', function () {
+ var expectedMessage = /^(Method )?Set.prototype.values called on incompatible receiver |^values method called on incompatible |^Cannot create a Set value iterator for a non-Set object.$|^Set.prototype.values: 'this' is not a Set object$/;
+ var nonSets = [true, false, 'abc', NaN, new Map([[1, 2]]), { a: true }, [1], Object('abc'), Object(NaN)];
+ nonSets.forEach(function (nonSet) {
+ expect(function () { return Set.prototype.values.call(nonSet); }).to['throw'](TypeError, expectedMessage);
+ });
+ });
+ });
+
+ describe('#entries()', function () {
+ if (!Set.prototype.hasOwnProperty('entries')) {
+ return it('exists', function () {
+ expect(Set.prototype).to.have.property('entries');
+ });
+ }
+
+ ifFunctionsHaveNamesIt('has the right name', function () {
+ expect(Set.prototype.entries).to.have.property('name', 'entries');
+ });
+
+ it('is not enumerable', function () {
+ expect(Set.prototype).ownPropertyDescriptor('entries').to.have.property('enumerable', false);
+ });
+
+ it('has the right arity', function () {
+ expect(Set.prototype.entries).to.have.property('length', 0);
+ });
+ });
+
+ describe('#has()', function () {
+ if (!Set.prototype.hasOwnProperty('has')) {
+ return it('exists', function () {
+ expect(Set.prototype).to.have.property('has');
+ });
+ }
+
+ ifFunctionsHaveNamesIt('has the right name', function () {
+ expect(Set.prototype.has).to.have.property('name', 'has');
+ });
+
+ it('is not enumerable', function () {
+ expect(Set.prototype).ownPropertyDescriptor('has').to.have.property('enumerable', false);
+ });
+
+ it('has the right arity', function () {
+ expect(Set.prototype.has).to.have.property('length', 1);
+ });
+ });
+
+ it('should allow NaN values as keys', function () {
+ expect(set.has(NaN)).to.equal(false);
+ expect(set.has(NaN + 1)).to.equal(false);
+ expect(set.has(23)).to.equal(false);
+ expect(set.add(NaN)).to.equal(set);
+ expect(set.has(NaN)).to.equal(true);
+ expect(set.has(NaN + 1)).to.equal(true);
+ expect(set.has(23)).to.equal(false);
+ });
+
+ it('should not have [[Enumerable]] props', function () {
+ expectNotEnumerable(Set);
+ expectNotEnumerable(Set.prototype);
+ expectNotEnumerable(new Set());
+ });
+
+ it('should not have an own constructor', function () {
+ var s = new Set();
+ expect(s).not.to.haveOwnPropertyDescriptor('constructor');
+ expect(s.constructor).to.equal(Set);
+ });
+
+ it('should allow common ecmascript idioms', function () {
+ expect(set instanceof Set).to.equal(true);
+ expect(typeof Set.prototype.add).to.equal('function');
+ expect(typeof Set.prototype.has).to.equal('function');
+ expect(typeof Set.prototype['delete']).to.equal('function');
+ });
+
+ it('should have a unique constructor', function () {
+ expect(Set.prototype).to.not.equal(Object.prototype);
+ });
+
+ describe('has an iterator that works with Array.from', function () {
+ if (!Array.hasOwnProperty('from')) {
+ return it('requires Array.from to exist', function () {
+ expect(Array).to.have.property('from');
+ });
+ }
+
+ var values = [1, NaN, false, true, null, undefined, 'a'];
+
+ it('works with the full set', function () {
+ expect(new Set(values)).to.have.iterations(values);
+ });
+
+ it('works with Set#keys()', function () {
+ expect(new Set(values).keys()).to.have.iterations(values);
+ });
+
+ it('works with Set#values()', function () {
+ expect(new Set(values).values()).to.have.iterations(values);
+ });
+
+ it('works with Set#entries()', function () {
+ expect(new Set(values).entries()).to.have.iterations([
+ [1, 1],
+ [NaN, NaN],
+ [false, false],
+ [true, true],
+ [null, null],
+ [undefined, undefined],
+ ['a', 'a']
+ ]);
+ });
+ });
+
+ ifSymbolIteratorIt('has the right default iteration function', function () {
+ // fixed in Webkit https://bugs.webkit.org/show_bug.cgi?id=143838
+ expect(Set.prototype).to.have.property(Sym.iterator, Set.prototype.values);
+ });
+
+ it('should preserve insertion order', function () {
+ var arr1 = ['d', 'a', 'b'];
+ var arr2 = [3, 2, 'z', 'a', 1];
+ var arr3 = [3, 2, 'z', {}, 'a', 1];
+
+ [arr1, arr2, arr3].forEach(function (array) {
+ expect(new Set(array)).to.have.iterations(array);
+ });
+ });
+
+ describe('#forEach', function () {
+ var setToIterate;
+ beforeEach(function () {
+ setToIterate = new Set();
+ expect(setToIterate.add('a')).to.equal(setToIterate);
+ expect(setToIterate.add('b')).to.equal(setToIterate);
+ expect(setToIterate.add('c')).to.equal(setToIterate);
+ });
+
+ afterEach(function () {
+ setToIterate = null;
+ });
+
+ ifFunctionsHaveNamesIt('has the right name', function () {
+ expect(Set.prototype.forEach).to.have.property('name', 'forEach');
+ });
+
+ it('is not enumerable', function () {
+ expect(Set.prototype).ownPropertyDescriptor('forEach').to.have.property('enumerable', false);
+ });
+
+ it('has the right arity', function () {
+ expect(Set.prototype.forEach).to.have.property('length', 1);
+ });
+
+ it('should be iterable via forEach', function () {
+ var expectedSet = ['a', 'b', 'c'];
+ var foundSet = [];
+ setToIterate.forEach(function (value, alsoValue, entireSet) {
+ expect(entireSet).to.equal(setToIterate);
+ expect(value).to.equal(alsoValue);
+ foundSet.push(value);
+ });
+ expect(foundSet).to.eql(expectedSet);
+ });
+
+ it('should iterate over empty keys', function () {
+ var setWithEmptyKeys = new Set();
+ var expectedKeys = [{}, null, undefined, '', NaN, 0];
+ expectedKeys.forEach(function (key) {
+ expect(setWithEmptyKeys.add(key)).to.equal(setWithEmptyKeys);
+ });
+ var foundKeys = [];
+ setWithEmptyKeys.forEach(function (value, key, entireSet) {
+ expect([key]).to.be.theSameSet([value]); // handles NaN correctly
+ expect(entireSet.has(key)).to.equal(true);
+ foundKeys.push(key);
+ });
+ expect(foundKeys).to.be.theSameSet(expectedKeys);
+ });
+
+ it('should support the thisArg', function () {
+ var context = function () {};
+ setToIterate.forEach(function () {
+ expect(this).to.equal(context);
+ }, context);
+ });
+
+ it('should have a length of 1', function () {
+ expect(Set.prototype.forEach.length).to.equal(1);
+ });
+
+ it('should not revisit modified keys', function () {
+ var hasModifiedA = false;
+ setToIterate.forEach(function (value, key) {
+ if (!hasModifiedA && key === 'a') {
+ expect(setToIterate.add('a')).to.equal(setToIterate);
+ hasModifiedA = true;
+ } else {
+ expect(key).not.to.equal('a');
+ }
+ });
+ });
+
+ it('visits keys added in the iterator', function () {
+ var hasAdded = false;
+ var hasFoundD = false;
+ setToIterate.forEach(function (value, key) {
+ if (!hasAdded) {
+ expect(setToIterate.add('d')).to.equal(setToIterate);
+ hasAdded = true;
+ } else if (key === 'd') {
+ hasFoundD = true;
+ }
+ });
+ expect(hasFoundD).to.equal(true);
+ });
+
+ it('visits keys added in the iterator when there is a deletion (slow path)', function () {
+ var hasSeenFour = false;
+ var setToMutate = new Set();
+ expect(setToMutate.add({})).to.equal(setToMutate); // force use of the slow O(N) implementation
+ expect(setToMutate.add('0')).to.equal(setToMutate);
+ setToMutate.forEach(function (value, key) {
+ if (key === '0') {
+ expect(setToMutate['delete']('0')).to.equal(true);
+ expect(setToMutate.add('4')).to.equal(setToMutate);
+ } else if (key === '4') {
+ hasSeenFour = true;
+ }
+ });
+ expect(hasSeenFour).to.equal(true);
+ });
+
+ it('visits keys added in the iterator when there is a deletion (fast path)', function () {
+ var hasSeenFour = false;
+ var setToMutate = new Set();
+ expect(setToMutate.add('0')).to.equal(setToMutate);
+ setToMutate.forEach(function (value, key) {
+ if (key === '0') {
+ expect(setToMutate['delete']('0')).to.equal(true);
+ expect(setToMutate.add('4')).to.equal(setToMutate);
+ } else if (key === '4') {
+ hasSeenFour = true;
+ }
+ });
+ expect(hasSeenFour).to.equal(true);
+ });
+
+ it('does not visit keys deleted before a visit', function () {
+ var hasVisitedC = false;
+ var hasDeletedC = false;
+ setToIterate.forEach(function (value, key) {
+ if (key === 'c') {
+ hasVisitedC = true;
+ }
+ if (!hasVisitedC && !hasDeletedC) {
+ hasDeletedC = setToIterate['delete']('c');
+ expect(hasDeletedC).to.equal(true);
+ }
+ });
+ expect(hasVisitedC).to.equal(false);
+ });
+
+ it('should work after deletion of the current key', function () {
+ var expectedSet = {
+ a: 'a',
+ b: 'b',
+ c: 'c'
+ };
+ var foundSet = {};
+ setToIterate.forEach(function (value, key) {
+ foundSet[key] = value;
+ expect(setToIterate['delete'](key)).to.equal(true);
+ });
+ expect(foundSet).to.eql(expectedSet);
+ });
+
+ it('should convert key -0 to +0', function () {
+ var zeroSet = new Set();
+ var result = [];
+ expect(zeroSet.add(-0)).to.equal(zeroSet);
+ zeroSet.forEach(function (key) {
+ result.push(String(1 / key));
+ });
+ expect(zeroSet.add(1)).to.equal(zeroSet);
+ expect(zeroSet.add(0)).to.equal(zeroSet); // shouldn't cause reordering
+ zeroSet.forEach(function (key) {
+ result.push(String(1 / key));
+ });
+ expect(result.join(', ')).to.equal(
+ 'Infinity, Infinity, 1'
+ );
+ });
+ });
+
+ it('Set.prototype.size should throw TypeError', function () {
+ // see https://github.com/paulmillr/es6-shim/issues/176
+ expect(function () { return Set.prototype.size; }).to['throw'](TypeError);
+ expect(function () { return Set.prototype.size; }).to['throw'](TypeError);
+ });
+
+ it.skip('should throw proper errors when user invokes methods with wrong types of receiver', function () {
+ });
+});
diff --git a/test/string.js b/test/string.js
index 3b497a7..5a714cd 100644
--- a/test/string.js
+++ b/test/string.js
@@ -684,13 +684,20 @@ var runStringTests = function (it) {
});
describe('#search()', function () {
- it('works', function () {
+ it('works with strings', function () {
expect('abc'.search('a')).to.equal(0);
expect('abc'.search('b')).to.equal(1);
expect('abc'.search('c')).to.equal(2);
expect('abc'.search('d')).to.equal(-1);
});
+ it('works with regexes', function () {
+ expect('abc'.search(/a/)).to.equal(0);
+ expect('abc'.search(/b/)).to.equal(1);
+ expect('abc'.search(/c/)).to.equal(2);
+ expect('abc'.search(/d/)).to.equal(-1);
+ });
+
ifSymbolsDescribe('Symbol.search', function () {
it('is a symbol', function () {
expect(typeof Symbol.search).to.equal('symbol');
diff --git a/testling.html b/testling.html
index ec54071..e9746a4 100644
--- a/testling.html
+++ b/testling.html
@@ -11,7 +11,8 @@
<script src="es6-shim.js"></script>
<script>chai.config.includeStack=true; window.expect=chai.expect; window.assert=chai.assert; mocha.setup({ui:'bdd',reporter:'tap'});</script>
<script src="test/array.js"></script>
- <script src="test/collections.js"></script>
+ <script src="test/map.js"></script>
+ <script src="test/set.js"></script>
<script src="test/math.js"></script>
<script src="test/number.js"></script>
<script src="test/object.js"></script>
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-es6-shim.git
More information about the Pkg-javascript-commits
mailing list