react-native/Libraries/vendor/core/toIterator.js

171 lines
4.5 KiB
JavaScript

/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
/**
* Given an object `toIterator` will return the itrator for that object. If the
* object has a `Symbol.iterator` method we just call that. Otherwise we
* implement the ES6 `Array` and `String` Iterator.
*/
/**
* Constants
*/
const KIND_KEY = 'key';
const KIND_VALUE = 'value';
const KIND_KEY_VAL = 'key+value';
/*global Symbol: true*/
const ITERATOR_SYMBOL =
typeof Symbol === 'function' ? Symbol.iterator : '@@iterator';
const toIterator = (function() {
if (
!(Array.prototype[ITERATOR_SYMBOL] && String.prototype[ITERATOR_SYMBOL])
) {
// IIFE to avoid creating classes for no reason because of hoisting.
return (function() {
class ArrayIterator {
// 22.1.5.1 CreateArrayIterator Abstract Operation
constructor(array, kind) {
if (!Array.isArray(array)) {
throw new TypeError('Object is not an Array');
}
this._iteratedObject = array;
this._kind = kind;
this._nextIndex = 0;
}
// 22.1.5.2.1 %ArrayIteratorPrototype%.next()
next() {
if (!this instanceof ArrayIterator) {
throw new TypeError('Object is not an ArrayIterator');
}
if (this._iteratedObject == null) {
return createIterResultObject(undefined, true);
}
const array = this._iteratedObject;
const len = this._iteratedObject.length;
const index = this._nextIndex;
const kind = this._kind;
if (index >= len) {
this._iteratedObject = undefined;
return createIterResultObject(undefined, true);
}
this._nextIndex = index + 1;
if (kind === KIND_KEY) {
return createIterResultObject(index, false);
} else if (kind === KIND_VALUE) {
return createIterResultObject(array[index], false);
} else if (kind === KIND_KEY_VAL) {
return createIterResultObject([index, array[index]], false);
}
}
// 22.1.5.2.2 %ArrayIteratorPrototype%[@@iterator]()
'@@iterator'() {
return this;
}
}
class StringIterator {
// 21.1.5.1 CreateStringIterator Abstract Operation
constructor(string) {
if (typeof string !== 'string') {
throw new TypeError('Object is not a string');
}
this._iteratedString = string;
this._nextIndex = 0;
}
// 21.1.5.2.1 %StringIteratorPrototype%.next()
next() {
if (!this instanceof StringIterator) {
throw new TypeError('Object is not a StringIterator');
}
if (this._iteratedString == null) {
return createIterResultObject(undefined, true);
}
const index = this._nextIndex;
const s = this._iteratedString;
const len = s.length;
if (index >= len) {
this._iteratedString = undefined;
return createIterResultObject(undefined, true);
}
let ret;
const first = s.charCodeAt(index);
if (first < 0xd800 || first > 0xdbff || index + 1 === len) {
ret = s[index];
} else {
const 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 createIterResultObject(ret, false);
}
// 21.1.5.2.2 %StringIteratorPrototype%[@@ITERATOR_SYMBOL]()
'@@iterator'() {
return this;
}
}
// 7.4.7 createIterResultObject(value, done)
function createIterResultObject(value, done) {
return {value: value, done: done};
}
return function(object, kind) {
if (typeof object === 'string') {
return new StringIterator(object);
} else if (Array.isArray(object)) {
return new ArrayIterator(object, kind || KIND_VALUE);
} else {
return object[ITERATOR_SYMBOL]();
}
};
})();
} else {
return function(object) {
return object[ITERATOR_SYMBOL]();
};
}
})();
/**
* Export constants
*/
Object.assign(toIterator, {
KIND_KEY,
KIND_VALUE,
KIND_KEY_VAL,
ITERATOR_SYMBOL,
});
module.exports = toIterator;