doddle
Version:
Tiny yet feature-packed (async) iteration toolkit.
125 lines • 4.19 kB
JavaScript
import { pull } from "../doddle/index.js";
import { checkSeqInputValue, chk, gotAsyncIteratorInSyncContext, loadCheckers } from "../errors/error.js";
import { _iter, isArrayLike, isInt, isIterable, isNextable, isThenable } from "../utils.js";
import { Seq, SeqOperator } from "./seq.class.js";
export function seq(input) {
input = checkSeqInputValue(input);
if (isNextable(input)) {
return seq(() => input).cache();
}
if (isIterable(input) || isArrayLike(input)) {
return seq(() => input);
}
return SeqOperator(input, function* seq(input) {
const invoked = typeof input === "function" ? input() : input;
let pulled = pull(invoked);
if (isArrayLike(pulled)) {
for (const key of Object.keys(pulled)) {
if (isInt(+key)) {
yield pull(pulled[+key]);
}
}
return;
}
if (isIterable(pulled)) {
pulled = _iter(pulled);
}
for (let item = pulled.next(); !item.done; item = pulled.next()) {
if (isThenable(item)) {
gotAsyncIteratorInSyncContext();
}
yield pull(item.value);
}
pulled.return?.();
});
}
/**
* Tools for creating {@link Seq} instances.
*
* @category Create
* @example
* seq.range(0, 10) // { 0 .. 10 }
* seq.iterate(5, i => i * 2) // { 0, 2, 4, 6, 8 }
*/
(function (seq) {
/**
* Creates a {@link Seq} of items by iterating a projection function.
*
* @param count Number of items to iterate
* @param projection Function that receives the index and returns the item for that index.
* @returns A {@link Seq} of the generated items.
*/
function iterate(count, projection) {
const c = chk(iterate);
c.count(count);
c.projection(projection);
return seq(function* () {
for (let i = 0; i < count; i++) {
yield projection(i);
}
});
}
seq.iterate = iterate;
/**
* Creates a {@link Seq} from the own, enumerable, string key-value pairs of an object, evaluated
* lazily.
*
* @template Object Type of the source object.
* @param source Source object to create the {@link Seq} from.
* @returns A {@link Seq} of key-value pairs from the source object.
*/
function fromObject(source) {
const c = chk(fromObject);
c.source(source);
return seq(() => Object.keys(source)).map(key => [key, source[key]]);
}
seq.fromObject = fromObject;
/**
* Creates a {@link Seq} of numbers in the specified range.
*
* @param start Starting number of the range.
* @param end Ending number of the range (exclusive).
* @param size Step size for the range. Defaults to 1.
* @returns A {@link Seq} of numbers in the specified range.
*/
function range(start, end, size = 1) {
const c = chk(range);
c.size(size);
c.start(start);
c.end(end);
const direction = Math.sign(end - start);
return seq(function* range() {
for (let i = start; direction * i < direction * end; i += direction * size) {
yield i;
}
});
}
seq.range = range;
/**
* Checks if the provided input is a {@link Seq}.
*
* @template T Type of items in the {@link Seq}.
* @param input Input to check.
* @returns `true` if the input is a {@link Seq}, otherwise `false`.
*/
function is(input) {
return input instanceof Seq;
}
seq.is = is;
/**
* Creates a {@link Seq} that throws an error when iterated.
*
* @param thrower Function that returns the error to throw.
* @returns A {@link Seq} that throws the specified error when iterated.
*/
function throws(thrower) {
thrower = chk(throws).thrower(thrower);
return SeqOperator(thrower, function* throws(input) {
const result = input();
throw result;
});
}
seq.throws = throws;
})(seq || (seq = {}));
loadCheckers(seq);
//# sourceMappingURL=seq.ctor.js.map