|
2 | 2 | /*#__PURE__*/ |
3 | 3 | function getIteratorPrototype(): Iterator<unknown> | null { |
4 | 4 | try { |
5 | | - // Try to get Iterator prototype from a generator |
6 | | - const GeneratorFunction = Object.getPrototypeOf(function* () {}).constructor |
7 | | - const generator = new GeneratorFunction('return (function*(){})();')() |
8 | | - return Object.getPrototypeOf(Object.getPrototypeOf(generator)) |
| 5 | + // Derive IteratorPrototype from the Array iterator prototype chain. |
| 6 | + // This avoids dynamic evaluation and works under strict CSP. |
| 7 | + if (typeof Symbol !== 'function' || typeof Symbol.iterator !== 'symbol') { |
| 8 | + return null |
| 9 | + } |
| 10 | + const arrayIter = [][Symbol.iterator]() |
| 11 | + const arrayIterProto = Object.getPrototypeOf(arrayIter) |
| 12 | + if (!arrayIterProto) return null |
| 13 | + return Object.getPrototypeOf(arrayIterProto) as Iterator<unknown> | null |
9 | 14 | } catch { |
10 | 15 | return null |
11 | 16 | } |
@@ -279,12 +284,15 @@ function find<T>(this: Iterator<T>, predicate: (value: T, index: number) => bool |
279 | 284 |
|
280 | 285 | /*#__PURE__*/ |
281 | 286 | function iteratorFrom<T>(obj: Iterator<T> | Iterable<T>): Iterator<T> { |
282 | | - if (typeof obj === 'object' && obj !== null) { |
283 | | - if ('next' in obj && typeof obj.next === 'function') { |
| 287 | + if (obj != null) { |
| 288 | + // Check for iterator (an object with a .next method) |
| 289 | + if (typeof obj === 'object' && 'next' in obj && typeof (obj as Iterator<T>).next === 'function') { |
284 | 290 | return obj as Iterator<T> |
285 | 291 | } |
286 | | - if (Symbol.iterator in obj) { |
287 | | - return obj[Symbol.iterator]() |
| 292 | + // Box primitives (e.g. strings) so we can check Symbol.iterator on them |
| 293 | + const iterable = Object(obj) as {[Symbol.iterator]?: () => Iterator<T>} |
| 294 | + if (Symbol.iterator in iterable && typeof iterable[Symbol.iterator] === 'function') { |
| 295 | + return iterable[Symbol.iterator]!() |
288 | 296 | } |
289 | 297 | } |
290 | 298 | throw new TypeError('Object is not an iterator or iterable') |
@@ -322,6 +330,26 @@ export function isPolyfilled(): boolean { |
322 | 330 | IteratorPrototype !== null && |
323 | 331 | 'map' in IteratorPrototype && |
324 | 332 | IteratorPrototype.map === map && |
| 333 | + 'filter' in IteratorPrototype && |
| 334 | + IteratorPrototype.filter === filter && |
| 335 | + 'take' in IteratorPrototype && |
| 336 | + IteratorPrototype.take === take && |
| 337 | + 'drop' in IteratorPrototype && |
| 338 | + IteratorPrototype.drop === drop && |
| 339 | + 'flatMap' in IteratorPrototype && |
| 340 | + IteratorPrototype.flatMap === flatMap && |
| 341 | + 'reduce' in IteratorPrototype && |
| 342 | + IteratorPrototype.reduce === reduce && |
| 343 | + 'toArray' in IteratorPrototype && |
| 344 | + IteratorPrototype.toArray === toArray && |
| 345 | + 'forEach' in IteratorPrototype && |
| 346 | + IteratorPrototype.forEach === forEach && |
| 347 | + 'some' in IteratorPrototype && |
| 348 | + IteratorPrototype.some === some && |
| 349 | + 'every' in IteratorPrototype && |
| 350 | + IteratorPrototype.every === every && |
| 351 | + 'find' in IteratorPrototype && |
| 352 | + IteratorPrototype.find === find && |
325 | 353 | IteratorConstructor !== undefined && |
326 | 354 | 'from' in IteratorConstructor && |
327 | 355 | IteratorConstructor.from === iteratorFrom |
|
0 commit comments