diff options
Diffstat (limited to 'node_modules/fbjs/lib/enumerate.js.flow')
-rw-r--r-- | node_modules/fbjs/lib/enumerate.js.flow | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/node_modules/fbjs/lib/enumerate.js.flow b/node_modules/fbjs/lib/enumerate.js.flow new file mode 100644 index 000000000..f4112803a --- /dev/null +++ b/node_modules/fbjs/lib/enumerate.js.flow @@ -0,0 +1,265 @@ +/** + * 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. + * + * @providesModule enumerate + * + */ + +const KIND_KEYS = 'keys'; +const KIND_VALUES = 'values'; +const KIND_ENTRIES = 'entries'; + +/** + * Specific Array iterators. + */ +const ArrayIterators = function () { + + let hasNative = hasNativeIterator(Array); + let ArrayIterator; + + if (!hasNative) { + ArrayIterator = class ArrayIterator { + // 22.1.5.1 CreateArrayIterator Abstract Operation + constructor(array, kind) { + this._iteratedObject = array; + this._kind = kind; + this._nextIndex = 0; + } + + // 22.1.5.2.1 %ArrayIteratorPrototype%.next() + next() { + if (this._iteratedObject == null) { + return { value: undefined, done: true }; + } + + let array = this._iteratedObject; + let len = this._iteratedObject.length; + let index = this._nextIndex; + let 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]() + [Symbol.iterator]() { + return this; + } + }; + } + + return { + keys: hasNative ? array => array.keys() : array => new ArrayIterator(array, KIND_KEYS), + + values: hasNative ? array => array.values() : array => new ArrayIterator(array, KIND_VALUES), + + entries: hasNative ? array => array.entries() : array => new ArrayIterator(array, KIND_ENTRIES) + }; +}(); + +// ----------------------------------------------------------------- + +/** + * Specific String iterators. + */ +const StringIterators = function () { + + let hasNative = hasNativeIterator(String); + let StringIterator; + + if (!hasNative) { + StringIterator = class StringIterator { + // 21.1.5.1 CreateStringIterator Abstract Operation + constructor(string) { + this._iteratedString = string; + this._nextIndex = 0; + } + + // 21.1.5.2.1 %StringIteratorPrototype%.next() + next() { + if (this._iteratedString == null) { + return { value: undefined, done: true }; + } + + let index = this._nextIndex; + let s = this._iteratedString; + let len = s.length; + + if (index >= len) { + this._iteratedString = undefined; + return { value: undefined, done: true }; + } + + let ret; + let first = s.charCodeAt(index); + + if (first < 0xD800 || first > 0xDBFF || index + 1 === len) { + ret = s[index]; + } else { + let 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]() + [Symbol.iterator]() { + return this; + } + }; + } + + return { + keys() { + throw TypeError(`Strings default iterator doesn't implement keys.`); + }, + + values: hasNative ? string => string[Symbol.iterator]() : string => new StringIterator(string), + + 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. + */ +class ObjectIterator { + constructor(object, kind) { + this._iteratedObject = object; + this._kind = kind; + this._keys = Object.keys(object); + this._nextIndex = 0; + } + + next() { + let len = this._keys.length; + let index = this._nextIndex; + let kind = this._kind; + let 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 }; + } + } + + [Symbol.iterator]() { + return this; + } +} + +/** + * 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. + */ +const GenericIterators = { + keys(object) { + return new ObjectIterator(object, KIND_KEYS); + }, + + values(object) { + return new ObjectIterator(object, KIND_VALUES); + }, + + 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); + } +} + +Object.assign(enumerate, { + /** + * Export constants + */ + + KIND_KEYS, + KIND_VALUES, + KIND_ENTRIES, + + /** + * Convenient explicit iterators for special kinds. + */ + + keys(object) { + return enumerate(object, KIND_KEYS); + }, + + values(object) { + return enumerate(object, KIND_VALUES); + }, + + entries(object) { + return enumerate(object, KIND_ENTRIES); + }, + + generic: GenericIterators.entries + +}); + +module.exports = enumerate;
\ No newline at end of file |