Skip to content

Commit

Permalink
[Fix] drop, filter, flatMap, map: rpatch a v8 bug when polyfi…
Browse files Browse the repository at this point in the history
  • Loading branch information
ljharb committed Apr 24, 2024
1 parent d2b47a5 commit 3670395
Show file tree
Hide file tree
Showing 15 changed files with 71 additions and 32 deletions.
12 changes: 9 additions & 3 deletions Iterator.prototype.drop/polyfill.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@
var implementation = require('./implementation');

module.exports = function getPolyfill() {
return typeof Iterator === 'function' && typeof Iterator.prototype.drop === 'function'
? Iterator.prototype.drop
: implementation;
if (typeof Iterator === 'function' && typeof Iterator.prototype.drop === 'function') {
try {
// https://issues.chromium.org/issues/336839115
Iterator.prototype.drop.call({ next: null }, 0).next();
} catch (e) {
return Iterator.prototype.drop;
}
}
return implementation;
};
12 changes: 9 additions & 3 deletions Iterator.prototype.filter/polyfill.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@
var implementation = require('./implementation');

module.exports = function getPolyfill() {
return typeof Iterator === 'function' && typeof Iterator.prototype.filter === 'function'
? Iterator.prototype.filter
: implementation;
if (typeof Iterator === 'function' && typeof Iterator.prototype.filter === 'function') {
try {
// https://issues.chromium.org/issues/336839115
Iterator.prototype.filter.call({ next: null }, function () {}).next();
} catch (e) {
return Iterator.prototype.filter;
}
}
return implementation;
};
12 changes: 9 additions & 3 deletions Iterator.prototype.flatMap/polyfill.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@
var implementation = require('./implementation');

module.exports = function getPolyfill() {
return typeof Iterator === 'function' && typeof Iterator.prototype.flatMap === 'function'
? Iterator.prototype.flatMap
: implementation;
if (typeof Iterator === 'function' && typeof Iterator.prototype.flatMap === 'function') {
try {
// https://issues.chromium.org/issues/336839115
Iterator.prototype.flatMap.call({ next: null }, function () {}).next();
} catch (e) {
return Iterator.prototype.flatMap;
}
}
return implementation;
};
12 changes: 9 additions & 3 deletions Iterator.prototype.map/polyfill.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@
var implementation = require('./implementation');

module.exports = function getPolyfill() {
return typeof Iterator === 'function' && typeof Iterator.prototype.map === 'function'
? Iterator.prototype.map
: implementation;
if (typeof Iterator === 'function' && typeof Iterator.prototype.map === 'function') {
try {
// https://issues.chromium.org/issues/336839115
Iterator.prototype.map.call({ next: null }, function () {}).next();
} catch (e) {
return Iterator.prototype.map;
}
}
return implementation;
};
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ The main export of the package itself is simply an array of the available direct
- [`Iterator.prototype.take`](https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.take)
- [`Iterator.prototype.toArray`](https://tc39.es/proposal-iterator-helpers/#sec-iteratorprototype.toarray)

## Environments where this is needed

- node v22, Chrome >= v122: has a [bug](https://issues.chromium.org/issues/336839115)
- node < v22, Chrome < v122, Safari <= v17.1, Firefox <= v125: not implemented

## Getting started

```sh
Expand Down
5 changes: 3 additions & 2 deletions test/Iterator.prototype.every.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ var debug = require('object-inspect');
var v = require('es-value-fixtures');
var hasSymbols = require('has-symbols/shams')();
var hasPropertyDescriptors = require('has-property-descriptors')();
var iterate = require('iterate-iterator');

var index = require('../Iterator.prototype.every');
var impl = require('../Iterator.prototype.every/implementation');
Expand All @@ -30,14 +31,14 @@ module.exports = {

forEach(v.primitives.concat(v.objects), function (nonIterator) {
t['throws'](
function () { every(nonIterator); },
function () { iterate(every(nonIterator, function () {})); },
TypeError,
debug(nonIterator) + ' is not an Object with a callable `next` method'
);

var badNext = { next: nonIterator };
t['throws'](
function () { every(badNext); },
function () { iterate(every(badNext, function () {})); },
TypeError,
debug(badNext) + ' is not an Object with a callable `next` method'
);
Expand Down
5 changes: 3 additions & 2 deletions test/Iterator.prototype.filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ var debug = require('object-inspect');
var v = require('es-value-fixtures');
var hasSymbols = require('has-symbols/shams')();
var hasPropertyDescriptors = require('has-property-descriptors')();
var iterate = require('iterate-iterator');

var index = require('../Iterator.prototype.filter');
var impl = require('../Iterator.prototype.filter/implementation');
Expand All @@ -30,14 +31,14 @@ module.exports = {

forEach(v.primitives.concat(v.objects), function (nonIterator) {
t['throws'](
function () { filter(nonIterator); },
function () { iterate(filter(nonIterator, function () {})); },
TypeError,
debug(nonIterator) + ' is not an Object with a callable `next` method'
);

var badNext = { next: nonIterator };
t['throws'](
function () { filter(badNext); },
function () { iterate(filter(badNext, function () {})); },
TypeError,
debug(badNext) + ' is not an Object with a callable `next` method'
);
Expand Down
5 changes: 3 additions & 2 deletions test/Iterator.prototype.find.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ var forEach = require('for-each');
var debug = require('object-inspect');
var v = require('es-value-fixtures');
var hasSymbols = require('has-symbols/shams')();
var iterate = require('iterate-iterator');

var index = require('../Iterator.prototype.find');
var impl = require('../Iterator.prototype.find/implementation');
Expand All @@ -29,14 +30,14 @@ module.exports = {

forEach(v.primitives.concat(v.objects), function (nonIterator) {
t['throws'](
function () { find(nonIterator); },
function () { iterate(find(nonIterator, function () {})); },
TypeError,
debug(nonIterator) + ' is not an Object with a callable `next` method'
);

var badNext = { next: nonIterator };
t['throws'](
function () { find(badNext); },
function () { iterate(find(badNext, function () {})); },
TypeError,
debug(badNext) + ' is not an Object with a callable `next` method'
);
Expand Down
5 changes: 3 additions & 2 deletions test/Iterator.prototype.flatMap.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ var forEach = require('for-each');
var debug = require('object-inspect');
var v = require('es-value-fixtures');
var hasSymbols = require('has-symbols/shams')();
var iterate = require('iterate-iterator');

var StringToCodePoints = require('es-abstract/2024/StringToCodePoints');

Expand All @@ -31,14 +32,14 @@ module.exports = {

forEach(v.primitives.concat(v.objects), function (nonIterator) {
t['throws'](
function () { flatMap(nonIterator); },
function () { iterate(flatMap(nonIterator, function () {})); },
TypeError,
debug(nonIterator) + ' is not an Object with a callable `next` method'
);

var badNext = { next: nonIterator };
t['throws'](
function () { flatMap(badNext); },
function () { iterate(flatMap(badNext, function () {})); },
TypeError,
debug(badNext) + ' is not an Object with a callable `next` method'
);
Expand Down
5 changes: 3 additions & 2 deletions test/Iterator.prototype.forEach.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ var forEachNormal = require('for-each');
var debug = require('object-inspect');
var v = require('es-value-fixtures');
var hasSymbols = require('has-symbols/shams')();
var iterate = require('iterate-iterator');

var index = require('../Iterator.prototype.forEach');
var impl = require('../Iterator.prototype.forEach/implementation');
Expand All @@ -29,14 +30,14 @@ module.exports = {

forEachNormal(v.primitives.concat(v.objects), function (nonIterator) {
t['throws'](
function () { forEach(nonIterator); },
function () { iterate(forEach(nonIterator, function () {})); },
TypeError,
debug(nonIterator) + ' is not an Object with a callable `next` method'
);

var badNext = { next: nonIterator };
t['throws'](
function () { forEach(badNext); },
function () { iterate(forEach(badNext, function () {})); },
TypeError,
debug(badNext) + ' is not an Object with a callable `next` method'
);
Expand Down
5 changes: 3 additions & 2 deletions test/Iterator.prototype.map.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ var debug = require('object-inspect');
var v = require('es-value-fixtures');
var hasSymbols = require('has-symbols/shams')();
var generators = require('make-generator-function')();
var iterate = require('iterate-iterator');

var index = require('../Iterator.prototype.map');
var impl = require('../Iterator.prototype.map/implementation');
Expand All @@ -30,14 +31,14 @@ module.exports = {

forEach(v.primitives.concat(v.objects), function (nonIterator) {
t['throws'](
function () { map(nonIterator); },
function () { iterate(map(nonIterator, function () {})); },
TypeError,
debug(nonIterator) + ' is not an Object with a callable `next` method'
);

var badNext = { next: nonIterator };
t['throws'](
function () { map(badNext); },
function () { iterate(map(badNext, function () {})); },
TypeError,
debug(badNext) + ' is not an Object with a callable `next` method'
);
Expand Down
5 changes: 3 additions & 2 deletions test/Iterator.prototype.reduce.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ var forEach = require('for-each');
var debug = require('object-inspect');
var v = require('es-value-fixtures');
var hasSymbols = require('has-symbols/shams')();
var iterate = require('iterate-iterator');

var index = require('../Iterator.prototype.reduce');
var impl = require('../Iterator.prototype.reduce/implementation');
Expand All @@ -29,14 +30,14 @@ module.exports = {

forEach(v.primitives.concat(v.objects), function (nonIterator) {
t['throws'](
function () { reduce(nonIterator); },
function () { iterate(reduce(nonIterator, function () {})); },
TypeError,
debug(nonIterator) + ' is not an Object with a callable `next` method'
);

var badNext = { next: nonIterator };
t['throws'](
function () { reduce(badNext); },
function () { iterate(reduce(badNext, function () {})); },
TypeError,
debug(badNext) + ' is not an Object with a callable `next` method'
);
Expand Down
5 changes: 3 additions & 2 deletions test/Iterator.prototype.some.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ var forEach = require('for-each');
var debug = require('object-inspect');
var v = require('es-value-fixtures');
var hasSymbols = require('has-symbols/shams')();
var iterate = require('iterate-iterator');

var index = require('../Iterator.prototype.some');
var impl = require('../Iterator.prototype.some/implementation');
Expand All @@ -29,14 +30,14 @@ module.exports = {

forEach(v.primitives.concat(v.objects), function (nonIterator) {
t['throws'](
function () { some(nonIterator); },
function () { iterate(some(nonIterator, function () {})); },
TypeError,
debug(nonIterator) + ' is not an Object with a callable `next` method'
);

var badNext = { next: nonIterator };
t['throws'](
function () { some(badNext); },
function () { iterate(some(badNext, function () {})); },
TypeError,
debug(badNext) + ' is not an Object with a callable `next` method'
);
Expand Down
5 changes: 3 additions & 2 deletions test/Iterator.prototype.take.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ var forEach = require('for-each');
var debug = require('object-inspect');
var v = require('es-value-fixtures');
var hasSymbols = require('has-symbols/shams')();
var iterate = require('iterate-iterator');

var index = require('../Iterator.prototype.take');
var impl = require('../Iterator.prototype.take/implementation');
Expand All @@ -29,15 +30,15 @@ module.exports = {

forEach(v.primitives.concat(v.objects), function (nonIterator) {
t['throws'](
function () { take(nonIterator, 1).next(); },
function () { iterate(take(nonIterator, 1)); },
TypeError,
debug(nonIterator) + ' is not an Object with a callable `next` method'
);

if (nonIterator != null && typeof nonIterator !== 'string') {
var badNext = { next: nonIterator };
t['throws'](
function () { take(badNext, 1).next(); },
function () { iterate(take(badNext, 1)); },
TypeError,
debug(badNext) + ' is not an Object with a callable `next` method'
);
Expand Down
5 changes: 3 additions & 2 deletions test/Iterator.prototype.toArray.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ var forEach = require('for-each');
var debug = require('object-inspect');
var v = require('es-value-fixtures');
var hasSymbols = require('has-symbols/shams')();
var iterate = require('iterate-iterator');

var index = require('../Iterator.prototype.toArray');
var impl = require('../Iterator.prototype.toArray/implementation');
Expand All @@ -29,14 +30,14 @@ module.exports = {

forEach(v.primitives.concat(v.objects), function (nonIterator) {
t['throws'](
function () { toArray(nonIterator); },
function () { iterate(toArray(nonIterator)); },
TypeError,
debug(nonIterator) + ' is not an Object with a callable `next` method'
);

var badNext = { next: nonIterator };
t['throws'](
function () { toArray(badNext); },
function () { iterate(toArray(badNext)); },
TypeError,
debug(badNext) + ' is not an Object with a callable `next` method'
);
Expand Down

0 comments on commit 3670395

Please sign in to comment.