307 lines
7.6 KiB
JavaScript
307 lines
7.6 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
var _assign = require('object-assign');
|
||
|
|
||
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
||
|
|
||
|
/**
|
||
|
* Copyright (c) 2013-present, Facebook, Inc.
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* This source code is licensed under the BSD-style license found in the
|
||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||
|
*
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
var KIND_KEYS = 'keys';
|
||
|
var KIND_VALUES = 'values';
|
||
|
var KIND_ENTRIES = 'entries';
|
||
|
|
||
|
/**
|
||
|
* Specific Array iterators.
|
||
|
*/
|
||
|
var ArrayIterators = function () {
|
||
|
|
||
|
var hasNative = hasNativeIterator(Array);
|
||
|
var ArrayIterator = void 0;
|
||
|
|
||
|
if (!hasNative) {
|
||
|
ArrayIterator = function () {
|
||
|
// 22.1.5.1 CreateArrayIterator Abstract Operation
|
||
|
function ArrayIterator(array, kind) {
|
||
|
_classCallCheck(this, ArrayIterator);
|
||
|
|
||
|
this._iteratedObject = array;
|
||
|
this._kind = kind;
|
||
|
this._nextIndex = 0;
|
||
|
}
|
||
|
|
||
|
// 22.1.5.2.1 %ArrayIteratorPrototype%.next()
|
||
|
|
||
|
|
||
|
ArrayIterator.prototype.next = function next() {
|
||
|
if (this._iteratedObject == null) {
|
||
|
return { value: undefined, done: true };
|
||
|
}
|
||
|
|
||
|
var array = this._iteratedObject;
|
||
|
var len = this._iteratedObject.length;
|
||
|
var index = this._nextIndex;
|
||
|
var kind = this._kind;
|
||
|
|
||
|
if (index >= len) {
|
||
|
this._iteratedObject = undefined;
|
||
|
return { value: undefined, done: true };
|
||
|
}
|
||
|
|
||
|
this._nextIndex = index + 1;
|
||
|
|
||
|
if (kind === KIND_KEYS) {
|
||
|
return { value: index, done: false };
|
||
|
} else if (kind === KIND_VALUES) {
|
||
|
return { value: array[index], done: false };
|
||
|
} else if (kind === KIND_ENTRIES) {
|
||
|
return { value: [index, array[index]], done: false };
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// 22.1.5.2.2 %ArrayIteratorPrototype%[@@iterator]()
|
||
|
|
||
|
|
||
|
ArrayIterator.prototype[Symbol.iterator] = function () {
|
||
|
return this;
|
||
|
};
|
||
|
|
||
|
return ArrayIterator;
|
||
|
}();
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
keys: hasNative ? function (array) {
|
||
|
return array.keys();
|
||
|
} : function (array) {
|
||
|
return new ArrayIterator(array, KIND_KEYS);
|
||
|
},
|
||
|
|
||
|
values: hasNative ? function (array) {
|
||
|
return array.values();
|
||
|
} : function (array) {
|
||
|
return new ArrayIterator(array, KIND_VALUES);
|
||
|
},
|
||
|
|
||
|
entries: hasNative ? function (array) {
|
||
|
return array.entries();
|
||
|
} : function (array) {
|
||
|
return new ArrayIterator(array, KIND_ENTRIES);
|
||
|
}
|
||
|
};
|
||
|
}();
|
||
|
|
||
|
// -----------------------------------------------------------------
|
||
|
|
||
|
/**
|
||
|
* Specific String iterators.
|
||
|
*/
|
||
|
var StringIterators = function () {
|
||
|
|
||
|
var hasNative = hasNativeIterator(String);
|
||
|
var StringIterator = void 0;
|
||
|
|
||
|
if (!hasNative) {
|
||
|
StringIterator = function () {
|
||
|
// 21.1.5.1 CreateStringIterator Abstract Operation
|
||
|
function StringIterator(string) {
|
||
|
_classCallCheck(this, StringIterator);
|
||
|
|
||
|
this._iteratedString = string;
|
||
|
this._nextIndex = 0;
|
||
|
}
|
||
|
|
||
|
// 21.1.5.2.1 %StringIteratorPrototype%.next()
|
||
|
|
||
|
|
||
|
StringIterator.prototype.next = function next() {
|
||
|
if (this._iteratedString == null) {
|
||
|
return { value: undefined, done: true };
|
||
|
}
|
||
|
|
||
|
var index = this._nextIndex;
|
||
|
var s = this._iteratedString;
|
||
|
var len = s.length;
|
||
|
|
||
|
if (index >= len) {
|
||
|
this._iteratedString = undefined;
|
||
|
return { value: undefined, done: true };
|
||
|
}
|
||
|
|
||
|
var ret = void 0;
|
||
|
var first = s.charCodeAt(index);
|
||
|
|
||
|
if (first < 0xD800 || first > 0xDBFF || index + 1 === len) {
|
||
|
ret = s[index];
|
||
|
} else {
|
||
|
var second = s.charCodeAt(index + 1);
|
||
|
if (second < 0xDC00 || second > 0xDFFF) {
|
||
|
ret = s[index];
|
||
|
} else {
|
||
|
ret = s[index] + s[index + 1];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this._nextIndex = index + ret.length;
|
||
|
|
||
|
return { value: ret, done: false };
|
||
|
};
|
||
|
|
||
|
// 21.1.5.2.2 %StringIteratorPrototype%[@@iterator]()
|
||
|
|
||
|
|
||
|
StringIterator.prototype[Symbol.iterator] = function () {
|
||
|
return this;
|
||
|
};
|
||
|
|
||
|
return StringIterator;
|
||
|
}();
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
keys: function keys() {
|
||
|
throw TypeError('Strings default iterator doesn\'t implement keys.');
|
||
|
},
|
||
|
|
||
|
|
||
|
values: hasNative ? function (string) {
|
||
|
return string[Symbol.iterator]();
|
||
|
} : function (string) {
|
||
|
return new StringIterator(string);
|
||
|
},
|
||
|
|
||
|
entries: function entries() {
|
||
|
throw TypeError('Strings default iterator doesn\'t implement entries.');
|
||
|
}
|
||
|
};
|
||
|
}();
|
||
|
|
||
|
function hasNativeIterator(classObject) {
|
||
|
return typeof classObject.prototype[Symbol.iterator] === 'function' && typeof classObject.prototype.values === 'function' && typeof classObject.prototype.keys === 'function' && typeof classObject.prototype.entries === 'function';
|
||
|
}
|
||
|
|
||
|
// -----------------------------------------------------------------
|
||
|
|
||
|
/**
|
||
|
* Generic object iterator.
|
||
|
*/
|
||
|
|
||
|
var ObjectIterator = function () {
|
||
|
function ObjectIterator(object, kind) {
|
||
|
_classCallCheck(this, ObjectIterator);
|
||
|
|
||
|
this._iteratedObject = object;
|
||
|
this._kind = kind;
|
||
|
this._keys = Object.keys(object);
|
||
|
this._nextIndex = 0;
|
||
|
}
|
||
|
|
||
|
ObjectIterator.prototype.next = function next() {
|
||
|
var len = this._keys.length;
|
||
|
var index = this._nextIndex;
|
||
|
var kind = this._kind;
|
||
|
var key = this._keys[index];
|
||
|
|
||
|
if (index >= len) {
|
||
|
this._iteratedObject = undefined;
|
||
|
return { value: undefined, done: true };
|
||
|
}
|
||
|
|
||
|
this._nextIndex = index + 1;
|
||
|
|
||
|
if (kind === KIND_KEYS) {
|
||
|
return { value: key, done: false };
|
||
|
} else if (kind === KIND_VALUES) {
|
||
|
return { value: this._iteratedObject[key], done: false };
|
||
|
} else if (kind === KIND_ENTRIES) {
|
||
|
return { value: [key, this._iteratedObject[key]], done: false };
|
||
|
}
|
||
|
};
|
||
|
|
||
|
ObjectIterator.prototype[Symbol.iterator] = function () {
|
||
|
return this;
|
||
|
};
|
||
|
|
||
|
return ObjectIterator;
|
||
|
}();
|
||
|
|
||
|
/**
|
||
|
* Generic object iterator, iterates over all own enumerable
|
||
|
* properties. Used only if if no specific iterator is available,
|
||
|
* and object don't implement iterator protocol.
|
||
|
*/
|
||
|
|
||
|
|
||
|
var GenericIterators = {
|
||
|
keys: function keys(object) {
|
||
|
return new ObjectIterator(object, KIND_KEYS);
|
||
|
},
|
||
|
values: function values(object) {
|
||
|
return new ObjectIterator(object, KIND_VALUES);
|
||
|
},
|
||
|
entries: function entries(object) {
|
||
|
return new ObjectIterator(object, KIND_ENTRIES);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// -----------------------------------------------------------------
|
||
|
|
||
|
/**
|
||
|
* Main iterator function. Returns default iterator based
|
||
|
* on the class of an instance.
|
||
|
*/
|
||
|
function enumerate(object, kind) {
|
||
|
|
||
|
// First check specific iterators.
|
||
|
if (typeof object === 'string') {
|
||
|
return StringIterators[kind || KIND_VALUES](object);
|
||
|
} else if (Array.isArray(object)) {
|
||
|
return ArrayIterators[kind || KIND_VALUES](object);
|
||
|
|
||
|
// Then see if an object implements own.
|
||
|
} else if (object[Symbol.iterator]) {
|
||
|
return object[Symbol.iterator]();
|
||
|
|
||
|
// And fallback to generic with entries.
|
||
|
} else {
|
||
|
return GenericIterators[kind || KIND_ENTRIES](object);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_assign(enumerate, {
|
||
|
/**
|
||
|
* Export constants
|
||
|
*/
|
||
|
|
||
|
KIND_KEYS: KIND_KEYS,
|
||
|
KIND_VALUES: KIND_VALUES,
|
||
|
KIND_ENTRIES: KIND_ENTRIES,
|
||
|
|
||
|
/**
|
||
|
* Convenient explicit iterators for special kinds.
|
||
|
*/
|
||
|
|
||
|
keys: function keys(object) {
|
||
|
return enumerate(object, KIND_KEYS);
|
||
|
},
|
||
|
values: function values(object) {
|
||
|
return enumerate(object, KIND_VALUES);
|
||
|
},
|
||
|
entries: function entries(object) {
|
||
|
return enumerate(object, KIND_ENTRIES);
|
||
|
},
|
||
|
|
||
|
|
||
|
generic: GenericIterators.entries
|
||
|
|
||
|
});
|
||
|
|
||
|
module.exports = enumerate;
|