shelving
Version:
Toolkit for using data in JavaScript.
76 lines (75 loc) • 2.71 kB
JavaScript
import { UnexpectedError } from "../error/UnexpectedError.js";
import { getGetter } from "../util/class.js";
import { ThroughSequence } from "./ThroughSequence.js";
/** Used when the sequence hasn't inspected anything yet. */
const _NOVALUE = Symbol("shelving/InspectSequence.NOVALUE");
/**
* Sequence of values that inspects a source sequence of values as it iterates.
* - Stores: first/last yielded value, returned value, whether iteration is done, the number of items that were iterated.
*
* @example
* const watch = new InspectSequence(iterable);
* for await (const next of capture) console.log("YIELDED", next);
* console.log("FIRST", watch.first);
* console.log("RETURNED", watch.returned);
*/
export class InspectSequence extends ThroughSequence {
/** Get the number of results received by this iterator so far. */
count = 0;
/** Is the iteration done? */
done = false;
/** The first yielded value (throws if the iteration yielded no values, i.e. `this.count === 0`). */
get first() {
if (this._first === _NOVALUE)
throw new UnexpectedError("Iteration not started", {
sequence: this,
caller: getGetter(this, "first"),
});
return this._first;
}
_first = _NOVALUE;
/** The last yielded value (throws if the iteration yielded no values, i.e. `this.count === 0`). */
get last() {
if (this._last === _NOVALUE)
throw new UnexpectedError("Iteration not started", {
sequence: this,
caller: getGetter(this, "last"),
});
return this._last;
}
_last = _NOVALUE;
/** The returned value (throws if the iteration is not done, i.e. `this.done === false`). */
get returned() {
if (this._returned === _NOVALUE)
throw new UnexpectedError("Iteration not done", {
sequence: this,
caller: getGetter(this, "returned"),
});
return this._returned;
}
_returned = _NOVALUE;
// Override to watch returned values.
async next() {
return this._inspect(await this.next());
}
async throw(thrown) {
return this._inspect(await this.throw(thrown));
}
async return(value) {
return this._inspect(await this.return(value));
}
/** Capture a result. */
_inspect(result) {
if (!result.done) {
if (this.first === undefined)
this._first = result.value;
this._last = result.value;
this.count++;
}
else {
this._returned = result.value;
this.done = true;
}
return result;
}
}