@reactivex/ix-esnext-esm
Version:
The Interactive Extensions for JavaScript
297 lines (295 loc) • 9.11 kB
JavaScript
import { bindCallback } from '../util/bindcallback.js';
import { identityAsync } from '../util/identity.js';
import { isReadableNodeStream, isWritableNodeStream, isIterable, isAsyncIterable, isArrayLike, isIterator, isPromise, isObservable, } from '../util/isiterable.js';
import { toLength } from '../util/tolength.js';
import { AbortError, throwIfAborted } from '../aborterror.js';
/**
* This class serves as the base for all operations which support [Symbol.asyncIterator].
*/
export class AsyncIterableX {
/** @nocollapse */
async forEach(projection, thisArg, signal) {
const source = signal ? new WithAbortAsyncIterable(this, signal) : this;
let i = 0;
for await (const item of source) {
await projection.call(thisArg, item, i++, signal);
}
}
pipe(...args) {
let i = -1;
const n = args.length;
let acc = this;
while (++i < n) {
acc = args[i](AsyncIterableX.as(acc));
}
return acc;
}
/** @nocollapse */
static from(source, selector = identityAsync, thisArg) {
const fn = bindCallback(selector, thisArg, 2);
if (isIterable(source) || isAsyncIterable(source)) {
return new FromAsyncIterable(source, fn);
}
if (isPromise(source)) {
return new FromPromiseIterable(source, fn);
}
if (isObservable(source)) {
return new FromObservableAsyncIterable(source, fn);
}
if (isArrayLike(source)) {
return new FromArrayIterable(source, fn);
}
if (isIterator(source)) {
return new FromAsyncIterable({ [Symbol.asyncIterator]: () => source }, fn);
}
throw new TypeError('Input type not supported');
}
/**
* Converts the input into an async-iterable sequence.
*
* @param {*} source The source to convert to an async-iterable sequence.
* @returns {AsyncIterableX<*>} An async-iterable containing the input.
*/
/** @nocollapse */
static as(source) {
if (source instanceof AsyncIterableX) {
return source;
}
if (typeof source === 'string') {
return new FromArrayIterable([source], identityAsync);
}
if (isIterable(source) || isAsyncIterable(source)) {
return new FromAsyncIterable(source, identityAsync);
}
if (isPromise(source)) {
return new FromPromiseIterable(source, identityAsync);
}
if (isObservable(source)) {
return new FromObservableAsyncIterable(source, identityAsync);
}
if (isArrayLike(source)) {
return new FromArrayIterable(source, identityAsync);
}
return new FromArrayIterable([source], identityAsync);
}
}
AsyncIterableX.prototype[Symbol.toStringTag] = 'AsyncIterableX';
Object.defineProperty(AsyncIterableX, Symbol.hasInstance, {
writable: true,
configurable: true,
value(inst) {
return !!(inst && inst[Symbol.toStringTag] === 'AsyncIterableX');
},
});
const ARRAY_VALUE = 'value';
const ARRAY_ERROR = 'error';
/** @ignore */
/** @ignore */
export class AsyncSink {
_ended;
_values;
_resolvers;
constructor() {
this._ended = false;
this._values = [];
this._resolvers = [];
}
[Symbol.asyncIterator]() {
return this;
}
write(value) {
this._push({ type: ARRAY_VALUE, value });
}
error(error) {
this._push({ type: ARRAY_ERROR, error });
}
_push(item) {
if (this._ended) {
throw new Error('AsyncSink already ended');
}
if (this._resolvers.length > 0) {
const { resolve, reject } = this._resolvers.shift();
if (item.type === ARRAY_ERROR) {
reject(item.error);
}
else {
resolve({ done: false, value: item.value });
}
}
else {
this._values.push(item);
}
}
next() {
if (this._values.length > 0) {
const { type, value, error } = this._values.shift();
if (type === ARRAY_ERROR) {
return Promise.reject(error);
}
else {
return Promise.resolve({ done: false, value });
}
}
if (this._ended) {
return Promise.resolve({ done: true });
}
return new Promise((resolve, reject) => {
this._resolvers.push({ resolve, reject });
});
}
end() {
while (this._resolvers.length > 0) {
this._resolvers.shift().resolve({ done: true });
}
this._ended = true;
}
}
/** @ignore */
export class FromArrayIterable extends AsyncIterableX {
_source;
_selector;
constructor(source, selector) {
super();
this._source = source;
this._selector = selector;
}
async *[Symbol.asyncIterator]() {
let i = 0;
const length = toLength(this._source.length);
while (i < length) {
yield await this._selector(this._source[i], i++);
}
}
}
/** @ignore */
export class FromAsyncIterable extends AsyncIterableX {
_source;
_selector;
constructor(source, selector) {
super();
this._source = source;
this._selector = selector;
}
async *[Symbol.asyncIterator](signal) {
let i = 0;
if (signal && this._source instanceof AsyncIterableX) {
for await (const item of new WithAbortAsyncIterable(this._source, signal)) {
yield await this._selector(item, i++);
}
}
else {
throwIfAborted(signal);
for await (const item of this._source) {
throwIfAborted(signal);
const value = await this._selector(item, i++);
throwIfAborted(signal);
yield value;
}
}
}
}
/** @ignore */
export class FromPromiseIterable extends AsyncIterableX {
_source;
_selector;
constructor(source, selector) {
super();
this._source = source;
this._selector = selector;
}
async *[Symbol.asyncIterator]() {
const item = await this._source;
yield await this._selector(item, 0);
}
}
/** @ignore */
export class FromObservableAsyncIterable extends AsyncIterableX {
_observable;
_selector;
constructor(observable, selector) {
super();
this._observable = observable;
this._selector = selector;
}
async *[Symbol.asyncIterator](signal) {
throwIfAborted(signal);
const sink = new AsyncSink();
const subscription = this._observable.subscribe({
next(value) {
sink.write(value);
},
error(err) {
sink.error(err);
},
complete() {
sink.end();
},
});
function onAbort() {
sink.error(new AbortError());
}
if (signal) {
signal.addEventListener('abort', onAbort);
}
let i = 0;
try {
for (let next; !(next = await sink.next()).done;) {
throwIfAborted(signal);
yield await this._selector(next.value, i++);
}
}
finally {
if (signal) {
signal.removeEventListener('abort', onAbort);
}
subscription.unsubscribe();
}
}
}
class WithAbortAsyncIterable {
_source;
_signal;
constructor(source, signal) {
this._source = source;
this._signal = signal;
}
[Symbol.asyncIterator]() {
// @ts-ignore
return this._source[Symbol.asyncIterator](this._signal);
}
}
try {
((isBrowser) => {
if (isBrowser) {
return;
}
AsyncIterableX.prototype['pipe'] = nodePipe;
const readableOpts = (x, opts = x._writableState || { objectMode: true }) => opts;
function nodePipe(...args) {
let i = -1;
let end;
const n = args.length;
let prev = this;
let next;
while (++i < n) {
next = args[i];
if (typeof next === 'function') {
prev = next(AsyncIterableX.as(prev));
}
else if (isWritableNodeStream(next)) {
({ end = true } = args[i + 1] || {});
// prettier-ignore
return isReadableNodeStream(prev) ? prev.pipe(next, { end }) :
AsyncIterableX.as(prev).toNodeStream(readableOpts(next)).pipe(next, { end });
}
}
return prev;
}
})(typeof window === 'object' && typeof document === 'object' && document.nodeType === 9);
}
catch (e) {
/* */
}
export const as = AsyncIterableX.as;
export const from = AsyncIterableX.from;
//# sourceMappingURL=asynciterablex.js.map