You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
103 lines
1.9 KiB
103 lines
1.9 KiB
'use strict';
|
|
const AggregateError = require('aggregate-error');
|
|
const PCancelable = require('p-cancelable');
|
|
|
|
const pSome = (iterable, options) => new PCancelable((resolve, reject, onCancel) => {
|
|
options = {
|
|
filter: () => true,
|
|
...options
|
|
};
|
|
|
|
if (!Number.isFinite(options.count)) {
|
|
throw new TypeError(`Expected a finite number, got ${typeof options.count}`);
|
|
}
|
|
|
|
const values = [];
|
|
const errors = [];
|
|
let elementCount = 0;
|
|
let maxErrors = -options.count + 1;
|
|
let maxFiltered = -options.count + 1;
|
|
let isDone = false;
|
|
|
|
const completed = new Set();
|
|
const cancelPendingIfDone = () => {
|
|
if (!isDone) {
|
|
return;
|
|
}
|
|
|
|
for (const promise of iterable) {
|
|
if (!completed.has(promise) && typeof promise.cancel === 'function') {
|
|
promise.cancel();
|
|
}
|
|
}
|
|
};
|
|
|
|
onCancel(() => {
|
|
isDone = true;
|
|
cancelPendingIfDone();
|
|
});
|
|
|
|
const fulfilled = value => {
|
|
if (isDone) {
|
|
return;
|
|
}
|
|
|
|
if (!options.filter(value)) {
|
|
if (--maxFiltered === 0) {
|
|
isDone = true;
|
|
reject(new RangeError('Not enough values pass the `filter` option'));
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
values.push(value);
|
|
|
|
if (--options.count === 0) {
|
|
isDone = true;
|
|
resolve(values);
|
|
}
|
|
};
|
|
|
|
const rejected = error => {
|
|
if (isDone) {
|
|
return;
|
|
}
|
|
|
|
errors.push(error);
|
|
|
|
if (--maxErrors === 0) {
|
|
isDone = true;
|
|
reject(new AggregateError(errors));
|
|
}
|
|
};
|
|
|
|
for (const element of iterable) {
|
|
maxErrors++;
|
|
maxFiltered++;
|
|
elementCount++;
|
|
|
|
(async () => {
|
|
try {
|
|
const value = await Promise.resolve(element);
|
|
fulfilled(value);
|
|
} catch (error) {
|
|
rejected(error);
|
|
}
|
|
|
|
completed.add(element);
|
|
cancelPendingIfDone();
|
|
})();
|
|
}
|
|
|
|
if (options.count > elementCount) {
|
|
throw new RangeError(`Expected input to contain at least ${options.count} items, but contains ${elementCount} items`);
|
|
}
|
|
});
|
|
|
|
module.exports = pSome;
|
|
// TODO: Remove this for the next major release
|
|
module.exports.default = pSome;
|
|
|
|
module.exports.AggregateError = AggregateError;
|