UNPKG

@onekuma/seq

Version:
309 lines (305 loc) 6.42 kB
'use strict'; const option = require('@onekuma/option'); class BaseSeq { } class Seq extends BaseSeq { constructor(forEach, done = false) { super(); this.forEach = forEach; this.done = done; } static of(...args) { return this.from(args); } static from(arr) { if (Array.isArray(arr)) { let i = 0; return new Seq((consume) => { if (i < arr.length) { consume(arr[i++]); return true; } else { return false; } }); } else { return new Seq((consume) => { const cur = arr.next(); if (!cur.done) { consume(cur.value); return true; } else { return false; } }); } } static range(...args) { if (args.length === 1 || args.length === 2) { const n = args[args.length - 1]; let i = args.length === 1 ? 0 : args[0]; return new Seq((consume) => { if (i < n) { consume(i++); return true; } else { return false; } }); } else { return Seq.of(); } } map(fn) { return new Seq((consume) => this.forEach((t) => consume(fn(t)))); } enumerate() { let i = 0; return this.map((e) => [i++, e]); } filter(predicate) { return new Seq((consume) => this.forEach((t) => predicate(t) && consume(t))); } filterDef() { return this.filter((e) => e !== void 0 && e !== null); } catch(handler) { return new Seq((consume) => { try { return this.forEach((t) => consume(t)); } catch (error) { handler && handler(error); return true; } }); } first() { let elem = option.Option.none(); this.forEach((t) => elem = option.Option.some(t)); return elem; } last() { let elem = option.Option.none(); while (this.forEach((t) => elem = option.Option.some(t))) ; return elem; } take(count) { let i = 0; return new Seq((consume) => { if (i < count) { i++; return this.forEach((t) => consume(t)); } else { return false; } }); } drop(count) { let i = 0; return new Seq( (consume) => this.forEach((t) => { if (i < count) { i++; } else { consume(t); } }) ); } static chain(...args) { if (args.length > 0) { return args[0].concat(...args.slice(1)); } else { return Seq.of(); } } concat(...args) { let i = 0; return new Seq((consume) => { while (this.forEach((t) => consume(t))) ; while (i < args.length) { let cont = args[i].forEach((t) => consume(t)); if (cont) { return true; } i++; } return false; }); } append(...args) { return this.concat(Seq.of(...args)); } *[Symbol.iterator]() { let elem = void 0; while (this.forEach((t) => elem = t)) { yield elem; } } async() { const it = this[Symbol.iterator](); return new AsyncSeq(async (consume) => { const cur = it.next(); if (!cur.done) { await consume(cur.value); return true; } else { return false; } }, this.done); } // API that closees this sequence reduce(reducer) { this.close(); let f = this.first(); if (f.isNone) return f; let acc = f.value; while (this.forEach((t) => acc = reducer(acc, t))) ; return option.Option.some(acc); } fold(initial, reducer) { this.close(); let acc = initial; while (this.forEach((t) => acc = reducer(acc, t))) ; return acc; } async parallel(fn) { const arr = this.toArray(); return await Promise.all(arr.map((el) => fn(el))); } toArray() { this.close(); const arr = []; while (this.forEach((t) => arr.push(t))) ; return arr; } close() { if (this.done) { throw new SeqError(); } this.done = true; } } class AsyncSeq extends BaseSeq { constructor(forEach, done = false) { super(); this.forEach = forEach; this.done = done; } static of(...args) { return this.from(args); } static from(arr) { return Seq.from(arr).async(); } map(fn) { return new AsyncSeq( async (consume) => await this.forEach(async (t) => await consume(await fn(t))) ); } filter(fn) { return new AsyncSeq( async (consume) => await this.forEach(async (t) => { if (await fn(t)) { await consume(t); } }) ); } // API that closees this sequence async toArray() { this.close(); const arr = []; while (await this.forEach(async (t) => { arr.push(t); })) ; return arr; } close() { if (this.done) { throw new SeqError(); } this.done = true; } } class SeqError extends Error { constructor() { super("This seq has been consumed"); } } function range(...args) { if (args.length === 1) { const n = Array.isArray(args[0]) ? args[0].length : args[0]; let i = 0; return new Seq((consume) => { if (i < n) { consume(i++); return true; } else { return false; } }); } else if (args.length === 2) { let i = args[0]; const n = args[1]; if (args[0] <= args[1]) { return new Seq((consume) => { if (i < n) { consume(i++); return true; } else { return false; } }); } else { return new Seq((consume) => { if (i > n) { consume(i--); return true; } else { return false; } }); } } else if (args.length === 3) { let i = args[0]; const n = args[1]; const step = args[2]; if (args[0] < args[1]) { return new Seq((consume) => { if (i < n) { consume(i); i += step; return true; } else { return false; } }); } else if (args[0] > args[1]) { return new Seq((consume) => { if (i > n) { consume(i); i -= step; return true; } else { return false; } }); } else { return Seq.of(); } } else { return Seq.of(); } } exports.AsyncSeq = AsyncSeq; exports.Seq = Seq; exports.SeqError = SeqError; exports.range = range;