diff --git a/packages/npm/es-iterator-helpers/Iterator.concat/implementation.js b/packages/npm/es-iterator-helpers/Iterator.concat/implementation.js index a9a814e4..6ef1b193 100644 --- a/packages/npm/es-iterator-helpers/Iterator.concat/implementation.js +++ b/packages/npm/es-iterator-helpers/Iterator.concat/implementation.js @@ -21,11 +21,9 @@ module.exports = typeof IteratorConcat === 'function' ? IteratorConcat : function concat(...iterables) { - // ECMAScript Standard Built-in Objects + // Built-in functions that are not identified as constructors do + // not implement [[Construct]] unless otherwise specified. // https://tc39.es/ecma262/#sec-ecmascript-standard-built-in-objects - // Built-in function objects that are not identified as constructors do - // not implement the [[Construct]] internal method unless otherwise - // specified in the description of a particular function. if (new.target) { throw new TypeErrorCtor('`Iterator.concat` is not a constructor') } @@ -36,8 +34,15 @@ module.exports = for (let i = 0; i < length; i += 1) { const iterable = iterables[i] // Step 2.a: If item is not an Object, throw a TypeError exception. + ensureObject(iterable, 'iterable') // Step 2.b: Let method be GetMethod(item, %Symbol.iterator%). + const method = getMethod(iterable, SymbolIterator) // Step 2.c: If method is undefined, throw a TypeError exception. + if (method === undefined) { + throw new TypeErrorCtor( + '`Iterator.concat` requires all arguments to be iterable' + ) + } // (Handled by getMethod, which throws if method is missing or not callable.) records[i] = { iterable, @@ -45,28 +50,32 @@ module.exports = } } let index = 0 + let innerIterator = null // Step 3: Let closure be a new Abstract Closure that captures iterables. const closure = { // This closure will perform the steps defined in Step 3.a. next() { - const { length } = records while (index < length) { - const { iterable, openMethod } = records[index] - // Step 3.a.i: Let iter be Call(iterable.[[OpenMethod]], iterable.[[Iterable]]). - const iterator = ReflectApply(openMethod, iterable, []) - // Step 3.a.ii: If iter is not an Object, throw a TypeError exception. - ensureObject(iterator) + if (!innerIterator) { + // If we haven't initialized an inner iterator yet, do so + const { iterable, openMethod } = records[index] + // Step 3.a.i: Let iter be Call(iterable.[[OpenMethod]], iterable.[[Iterable]]). + innerIterator = ReflectApply(openMethod, iterable, []) + // Step 3.a.ii: If iter is not an Object, throw a TypeError exception. + ensureObject(innerIterator, 'iterator') + } // Step 3.a.iii: Let iteratorRecord be GetIteratorDirect(iter). - const { next } = getIteratorDirect(iterator) + const { next } = getIteratorDirect(innerIterator) // Step 3.a.iv: Let innerAlive be true. // (Handled by the loop structure) // Step 3.a.v: Repeat, while innerAlive is true. - const result = ReflectApply(next, iterator, []) + const result = ReflectApply(next, innerIterator, []) if (!result.done) { // Step 3.a.v.3.a: Yield the value of the iterator. return result } // Step 3.a.v.2: If innerValue is done, move to the next iterable. + innerIterator = null index += 1 } // Step 3.b: Return Completion(undefined). diff --git a/packages/npm/es-iterator-helpers/Iterator.concat/polyfill.js b/packages/npm/es-iterator-helpers/Iterator.concat/polyfill.js index c69f248e..ff68a60c 100644 --- a/packages/npm/es-iterator-helpers/Iterator.concat/polyfill.js +++ b/packages/npm/es-iterator-helpers/Iterator.concat/polyfill.js @@ -1,8 +1,7 @@ 'use strict' const impl = require('./implementation') -const Iterator = require('../Iterator/implementation') module.exports = function getPolyfill() { - return typeof Iterator.concat === 'function' ? Iterator.concat : impl + return impl } diff --git a/packages/npm/es-iterator-helpers/Iterator.concat/shim.js b/packages/npm/es-iterator-helpers/Iterator.concat/shim.js index e2123812..9e3fc006 100644 --- a/packages/npm/es-iterator-helpers/Iterator.concat/shim.js +++ b/packages/npm/es-iterator-helpers/Iterator.concat/shim.js @@ -1,14 +1,14 @@ 'use strict' const getPolyfill = require('./polyfill') -const Iterator = require('../Iterator/implementation') +const IteratorCtor = require('../Iterator/implementation') const { defineProperty: ObjectDefineProperty } = Object module.exports = function shimIteratorConcat() { const polyfill = getPolyfill() - if (Iterator.concat !== polyfill) { - ObjectDefineProperty(Iterator, 'concat', { + if (IteratorCtor.concat !== polyfill) { + ObjectDefineProperty(IteratorCtor, 'concat', { __proto__: null, configurable: true, enumerable: false, diff --git a/packages/npm/es-iterator-helpers/Iterator.from/implementation.js b/packages/npm/es-iterator-helpers/Iterator.from/implementation.js index dfa9b8d2..ffb8d24d 100644 --- a/packages/npm/es-iterator-helpers/Iterator.from/implementation.js +++ b/packages/npm/es-iterator-helpers/Iterator.from/implementation.js @@ -1,23 +1,41 @@ 'use strict' +const IteratorCtor = require('../Iterator/implementation') const { - ReflectApply, + IteratorCtor: IteratorCtorRaw, + ObjectCreate, TypeErrorCtor, - createIteratorFromClosure, + WrapForValidIteratorPrototype, getIteratorFlattenable, - setUnderlyingIterator + setIterated } = require('../shared') -module.exports = function from(O) { - if (new.target) { - throw new TypeErrorCtor('`Iterator.from` is not a constructor') - } - const { iterator, next } = getIteratorFlattenable(O) - const wrapper = createIteratorFromClosure({ - next() { - return ReflectApply(next, iterator, []) - } - }) - setUnderlyingIterator(wrapper, iterator) - return wrapper -} +const IteratorFrom = IteratorCtorRaw?.from + +// Based specification text: +// https://tc39.es/ecma262/#sec-iterator.from +module.exports = + typeof IteratorFrom === 'function' + ? IteratorFrom + : function from(O) { + // Built-in functions that are not identified as constructors do + // not implement [[Construct]] unless otherwise specified. + // https://tc39.es/ecma262/#sec-ecmascript-standard-built-in-objects + if (new.target) { + throw new TypeErrorCtor('`Iterator.from` is not a constructor') + } + // Step 1: Let iteratorRecord be GetIteratorFlattenable(O, iterate-string-primitives). + const { iterator, next } = getIteratorFlattenable(O, true) + // Step 2: Let hasInstance be OrdinaryHasInstance(%Iterator%, iteratorRecord.[[Iterator]]). + // Step 3: If hasInstance is true, then + if (iterator instanceof IteratorCtor) { + // Step 3.a: Return iteratorRecord.[[Iterator]]. + return iterator + } + // Step 4: Let wrapper be OrdinaryObjectCreate(%WrapForValidIteratorPrototype%, << [[Iterated]] >>). + const wrapper = ObjectCreate(WrapForValidIteratorPrototype) + // Step 5: Set wrapper.[[Iterated]] to iteratorRecord. + setIterated(wrapper, { iterator, next }) + // Step 6: Return wrapper. + return wrapper + } diff --git a/packages/npm/es-iterator-helpers/Iterator.from/shim.js b/packages/npm/es-iterator-helpers/Iterator.from/shim.js index 12208b34..82f1fbc8 100644 --- a/packages/npm/es-iterator-helpers/Iterator.from/shim.js +++ b/packages/npm/es-iterator-helpers/Iterator.from/shim.js @@ -1,14 +1,14 @@ 'use strict' const getPolyfill = require('./polyfill') -const Iterator = require('../Iterator/implementation') +const IteratorCtor = require('../Iterator/implementation') const { defineProperty: ObjectDefineProperty } = Object module.exports = function shimIteratorFrom() { const polyfill = getPolyfill() if (Iterator.from !== polyfill) { - ObjectDefineProperty(Iterator, 'from', { + ObjectDefineProperty(IteratorCtor, 'from', { __proto__: null, configurable: true, enumerable: false, diff --git a/packages/npm/es-iterator-helpers/Iterator.prototype.drop/implementation.js b/packages/npm/es-iterator-helpers/Iterator.prototype.drop/implementation.js index 451d2b52..8179e1ba 100644 --- a/packages/npm/es-iterator-helpers/Iterator.prototype.drop/implementation.js +++ b/packages/npm/es-iterator-helpers/Iterator.prototype.drop/implementation.js @@ -16,11 +16,9 @@ const { // Based specification text: // https://tc39.es/ecma262/#sec-iterator.prototype.drop module.exports = function drop(limit) { - // ECMAScript Standard Built-in Objects + // Built-in functions that are not identified as constructors do + // not implement [[Construct]] unless otherwise specified. // https://tc39.es/ecma262/#sec-ecmascript-standard-built-in-objects - // Built-in function objects that are not identified as constructors do - // not implement the [[Construct]] internal method unless otherwise - // specified in the description of a particular function. if (new.target) { throw new TypeErrorCtor('`drop` is not a constructor') } diff --git a/packages/npm/es-iterator-helpers/Iterator.prototype.filter/implementation.js b/packages/npm/es-iterator-helpers/Iterator.prototype.filter/implementation.js index b251cf2e..2737ea3f 100644 --- a/packages/npm/es-iterator-helpers/Iterator.prototype.filter/implementation.js +++ b/packages/npm/es-iterator-helpers/Iterator.prototype.filter/implementation.js @@ -13,11 +13,9 @@ const { // Based specification text: // https://tc39.es/ecma262/#sec-iterator.prototype.filter module.exports = function filter(predicate) { - // ECMAScript Standard Built-in Objects + // Built-in functions that are not identified as constructors do + // not implement [[Construct]] unless otherwise specified. // https://tc39.es/ecma262/#sec-ecmascript-standard-built-in-objects - // Built-in function objects that are not identified as constructors do - // not implement the [[Construct]] internal method unless otherwise - // specified in the description of a particular function. if (new.target) { throw new TypeErrorCtor('`filter` is not a constructor') } diff --git a/packages/npm/es-iterator-helpers/Iterator.prototype.flatMap/implementation.js b/packages/npm/es-iterator-helpers/Iterator.prototype.flatMap/implementation.js index 0980f819..5f7490ff 100644 --- a/packages/npm/es-iterator-helpers/Iterator.prototype.flatMap/implementation.js +++ b/packages/npm/es-iterator-helpers/Iterator.prototype.flatMap/implementation.js @@ -14,11 +14,9 @@ const { } = require('../shared') module.exports = function flatMap(mapper) { - // ECMAScript Standard Built-in Objects + // Built-in functions that are not identified as constructors do + // not implement [[Construct]] unless otherwise specified. // https://tc39.es/ecma262/#sec-ecmascript-standard-built-in-objects - // Built-in function objects that are not identified as constructors do - // not implement the [[Construct]] internal method unless otherwise - // specified in the description of a particular function. if (new.target) { throw new TypeErrorCtor('`flatMap` is not a constructor') } diff --git a/packages/npm/es-iterator-helpers/Iterator.prototype.map/implementation.js b/packages/npm/es-iterator-helpers/Iterator.prototype.map/implementation.js index ec1e4e17..a0de1093 100644 --- a/packages/npm/es-iterator-helpers/Iterator.prototype.map/implementation.js +++ b/packages/npm/es-iterator-helpers/Iterator.prototype.map/implementation.js @@ -13,11 +13,9 @@ const { // Based on the specification text: // https://tc39.es/ecma262/#sec-iterator.prototype.map module.exports = function map(mapper) { - // ECMAScript Standard Built-in Objects + // Built-in functions that are not identified as constructors do + // not implement [[Construct]] unless otherwise specified. // https://tc39.es/ecma262/#sec-ecmascript-standard-built-in-objects - // Built-in function objects that are not identified as constructors do - // not implement the [[Construct]] internal method unless otherwise - // specified in the description of a particular function. if (new.target) { throw new TypeErrorCtor('`Iterator.map` is not a constructor') } diff --git a/packages/npm/es-iterator-helpers/Iterator.prototype.toArray/implementation.js b/packages/npm/es-iterator-helpers/Iterator.prototype.toArray/implementation.js index 60873f2e..624401e1 100644 --- a/packages/npm/es-iterator-helpers/Iterator.prototype.toArray/implementation.js +++ b/packages/npm/es-iterator-helpers/Iterator.prototype.toArray/implementation.js @@ -8,17 +8,29 @@ const { } = require('../shared') module.exports = function toArray() { + // Built-in functions that are not identified as constructors do + // not implement [[Construct]] unless otherwise specified. + // https://tc39.es/ecma262/#sec-ecmascript-standard-built-in-objects if (new.target) { throw new TypeErrorCtor('`toArray` is not a constructor') } - ensureObject(this) + // Step 1: Let O be the this value. + const O = this + // Step 2: If O is not an Object, throw a TypeError exception. + ensureObject(O) + // Step 3: Let iterated be GetIteratorDirect(O). const { iterator, next } = getIteratorDirect(this) + // Step 4: Let items be a new empty List. const items = [] + // Step 5: Repeat. while (true) { + // Step 5.a: Let value be IteratorStepValue(iterated). const result = ReflectApply(next, iterator, []) + // Step 5.b: If value is done, return CreateArrayFromList(items). if (result.done) { return items } + // Step 5.c: Append value to items. items[items.length] = result.value } } diff --git a/packages/npm/es-iterator-helpers/Iterator.prototype/shim.js b/packages/npm/es-iterator-helpers/Iterator.prototype/shim.js index 8078d510..2dc2f6b8 100644 --- a/packages/npm/es-iterator-helpers/Iterator.prototype/shim.js +++ b/packages/npm/es-iterator-helpers/Iterator.prototype/shim.js @@ -1,14 +1,14 @@ 'use strict' const getPolyfill = require('./polyfill') -const Iterator = require('../Iterator/implementation') +const IteratorCtor = require('../Iterator/implementation') const { defineProperty: ObjectDefineProperty } = Object module.exports = function shimIteratorProto() { const polyfill = getPolyfill() - if (Iterator.prototype !== polyfill) { - ObjectDefineProperty(Iterator, 'prototype', { + if (IteratorCtor.prototype !== polyfill) { + ObjectDefineProperty(IteratorCtor, 'prototype', { __proto__: null, configurable: true, enumerable: false, diff --git a/packages/npm/es-iterator-helpers/shared.d.ts b/packages/npm/es-iterator-helpers/shared.d.ts index 30b369b2..20d03769 100644 --- a/packages/npm/es-iterator-helpers/shared.d.ts +++ b/packages/npm/es-iterator-helpers/shared.d.ts @@ -1,22 +1,32 @@ -declare interface IteratorResult { - value: T - done: boolean -} declare interface Iterator { next(value?: any): IteratorResult return?(value?: any): IteratorResult [Symbol.iterator](): Iterator } +declare interface IteratorHelper extends Iterator { + [Symbol.toStringTag](): 'Iterator Helper' +} +declare interface IteratorRecord { + iterator: Iterator + next: () => IteratorResult +} +declare interface IteratorResult { + value: T + done: boolean +} declare interface InternalShared { SLOT: WeakMap SLOT_GENERATOR_CONTEXT: string SLOT_GENERATOR_STATE: string + SLOT_ITERATED: string SLOT_UNDERLYING_ITERATOR: string GENERATOR_STATE_COMPLETED: string GENERATOR_STATE_SUSPENDED_STARTED: string IteratorCtor: typeof globalThis.Iterator - IteratorPrototype: any - IteratorHelperPrototype: any + ArrayCtor: ArrayConstructor + IteratorPrototype: Iterator + IteratorHelperPrototype: IteratorHelper + WrapForValidIteratorPrototype: Iterator NumberCtor: NumberConstructor MathTrunc: (x: number) => number NegativeInfinity: number @@ -30,17 +40,11 @@ declare interface InternalShared { SymbolToStringTag: symbol TypeErrorCtor: typeof TypeError abruptCloseIterator(iterator: Iterator, error: any): void - closeIterator(iterator: Iterator, completion: T): T + closeIterator(iterator: Iterator, completion: T): T createIteratorFromClosure(closure: Iterator): Iterator ensureObject(thisArg: any, what?: string): void - getIteratorDirect(obj: any): { - next: () => IteratorResult - iterator: Iterator - } - getIteratorFlattenable(obj: any): { - next: () => IteratorResult - iterator: Iterator - } + getIteratorDirect(obj: any): IteratorRecord + getIteratorFlattenable(obj: any): IteratorRecord getMethod( obj: any, key: string | symbol @@ -53,7 +57,8 @@ declare interface InternalShared { isObjectType(value: any): boolean resolveSlots(O: any, slot: string): any setSlot(O: any, slot: string, value: any): void - setUnderlyingIterator(generator: any, iterator: any): void + setUnderlyingIterator(generator: Iterator, iterator: Iterator): void + setIterated(wrapper: Iterator, record: IteratorRecord): void toIntegerOrInfinity(value: any): number } declare const shared: InternalShared diff --git a/packages/npm/es-iterator-helpers/shared.js b/packages/npm/es-iterator-helpers/shared.js index e2aba35b..cdd57e23 100644 --- a/packages/npm/es-iterator-helpers/shared.js +++ b/packages/npm/es-iterator-helpers/shared.js @@ -1,9 +1,14 @@ 'use strict' //const { toString: fnToStr } = Function.prototype +const ArrayCtor = Array const { trunc: MathTrunc } = Math const { isNaN: NumberIsNaN } = Number -const { create: ObjectCreate, defineProperty: ObjectDefineProperty } = Object +const { + create: ObjectCreate, + defineProperty: ObjectDefineProperty, + hasOwn: ObjectHasOwn +} = Object const { apply: ReflectApply, getPrototypeOf: ReflectGetPrototypeOf } = Reflect const { iterator: SymbolIterator, toStringTag: SymbolToStringTag } = Symbol const NumberCtor = Number @@ -12,8 +17,9 @@ const RangeErrorCtor = RangeError const SLOT = new WeakMap() -const SLOT_GENERATOR_CONTEXT = '[[generator]]' +const SLOT_GENERATOR_CONTEXT = '[[GeneratorContext]]' const SLOT_GENERATOR_STATE = '[[GeneratorState]]' +const SLOT_ITERATED = '[[Iterated]]' const SLOT_UNDERLYING_ITERATOR = '[[UnderlyingIterator]]' const GENERATOR_STATE_COMPLETED = 'completed' @@ -22,6 +28,9 @@ const GENERATOR_STATE_SUSPENDED_STARTED = 'suspended-start' const ArrayIteratorPrototype = ReflectGetPrototypeOf([][SymbolIterator]()) const { Iterator: IteratorCtor } = globalThis const IteratorPrototype = ReflectGetPrototypeOf(ArrayIteratorPrototype) + +// Based on specification text: +// https://tc39.es/ecma262/#sec-%iteratorhelperprototype%-object const IteratorHelperPrototype = ObjectCreate(IteratorPrototype, { next: { __proto__: null, @@ -92,6 +101,64 @@ const IteratorHelperPrototype = ObjectCreate(IteratorPrototype, { } }) +// Based on specification text: +// https://tc39.es/ecma262/#sec-%wrapforvaliditeratorprototype%-object +const WrapForValidIteratorPrototype = ObjectCreate(IteratorPrototype, { + // Based on specification text: + // https://tc39.es/ecma262/#sec-%wrapforvaliditeratorprototype%.next + next: { + __proto__: null, + configurable: true, + enumerable: false, + value: function next() { + // Step 1: Let O be this value. + const O = this + // Step 2: Perform RequireInternalSlot(O, [[Iterated]]) + ensureObject(O) + const slots = SLOT.get(O) + if (!(slots && ObjectHasOwn(slots, SLOT_ITERATED))) { + throw new TypeError(`"${SLOT_ITERATED}" is not present on "O"`) + } + // Step 3: Let iteratorRecord be O.[[Iterated]]. + const { iterator, next } = slots[SLOT_ITERATED] + // Step 4: Return Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]). + return ReflectApply(next, iterator, []) + }, + writable: true + }, + // Based on specification text: + // https://tc39.es/ecma262/#sec-%wrapforvaliditeratorprototype%.return + return: { + __proto__: null, + configurable: true, + enumerable: false, + value: function () { + // Step 1: Let O be this value. + const O = this + // Step 2: Perform RequireInternalSlot(O, [[Iterated]]). + ensureObject(O) + const slots = SLOT.get(O) + if (!(slots && ObjectHasOwn(slots, SLOT_ITERATED))) { + throw new TypeError(`"${SLOT_ITERATED}" is not present on "O"`) + } + // Step 3: Let iterator be O.[[Iterated]].[[Iterator]]. + const { iterator } = slots[SLOT_ITERATED] + // Step 4: Assert: iterator is an Object. + ensureObject(iterator, 'iterator') + // Step 5: Let returnMethod be GetMethod(iterator, "return"). + const returnMethod = getMethod(iterator, 'return') + // Step 6: If returnMethod is undefined, then + if (returnMethod === undefined) { + // Step 6.a: Return CreateIteratorResultObject(undefined, true). + return { value: undefined, done: true } + } + // Step 7: Return Call(returnMethod, iterator). + return ReflectApply(returnMethod, iterator, []) + }, + writable: true + } +}) + // Based on specification text: // https://tc39.es/ecma262/#sec-ifabruptcloseiterator function abruptCloseIterator(iterator, error) { @@ -157,9 +224,9 @@ function getIteratorDirect(obj) { // Based on specification text: // https://tc39.es/ecma262/#sec-getiteratorflattenable -function getIteratorFlattenable(obj) { +function getIteratorFlattenable(obj, allowStrings) { // Step 1: If obj is not an Object - if (!isObjectType(obj)) { + if (!isObjectType(obj) && !(allowStrings && typeof obj === 'string')) { // Step 1.a: If primitiveHandling is reject-primitives, throw a TypeError throw new TypeErrorCtor('Primitives are not iterable') } @@ -236,6 +303,10 @@ function setSlot(O, slot, value) { slots[slot] = value } +function setIterated(wrapper, record) { + setSlot(wrapper, SLOT_ITERATED, record) +} + function setUnderlyingIterator(generator, iterator) { setSlot(generator, SLOT_UNDERLYING_ITERATOR, iterator) } @@ -259,6 +330,7 @@ function toIntegerOrInfinity(value) { } module.exports = { + ArrayCtor, IteratorCtor, IteratorPrototype, NumberCtor, @@ -270,6 +342,7 @@ module.exports = { ReflectGetPrototypeOf, SymbolIterator, TypeErrorCtor, + WrapForValidIteratorPrototype, abruptCloseIterator, closeIterator, createIteratorFromClosure, @@ -279,6 +352,7 @@ module.exports = { getMethod, isIteratorProtoNextCheckBuggy, isObjectType, + setIterated, setUnderlyingIterator, toIntegerOrInfinity } diff --git a/packages/npm/object.groupby/implementation.js b/packages/npm/object.groupby/implementation.js index c0ad6d2d..b60262fc 100644 --- a/packages/npm/object.groupby/implementation.js +++ b/packages/npm/object.groupby/implementation.js @@ -65,8 +65,8 @@ module.exports = } const iterator = ReflectApply(method, items, []) if ( - typeof iterator !== 'function' && - (iterator === null || typeof iterator !== 'object') + iterator === null || + (typeof iterator !== 'object' && typeof iterator !== 'function') ) { throw new TypeErrorCtor('`iterator` value must be an Object') } diff --git a/scripts/constants.js b/scripts/constants.js index 0b54eaca..753ef255 100644 --- a/scripts/constants.js +++ b/scripts/constants.js @@ -451,10 +451,10 @@ const skipTestsByEcosystem = Object.freeze({ // testing ourselves. 'array-flatten', // date tests fail for some Node versions and platforms, but pass in CI - // environments for the time being. + // Win32 environments for the time being. // https://github.com/es-shims/Date/issues/3 // https://github.com/es-shims/Date/tree/v2.0.5 - ...(ENV.CI ? [] : ['date']), + ...(ENV.WIN_32 ? [] : ['date']), // es6-object-assign has no unit tests. // https://github.com/rubennorte/es6-object-assign/tree/v1.1.0 'es6-object-assign',