sflow
Version:
sflow is a powerful and highly-extensible library designed for processing and manipulating streams of data effortlessly. Inspired by the functional programming paradigm, it provides a rich set of utilities for transforming streams, including chunking, fil
94 lines (88 loc) • 2.68 kB
JavaScript
//#region src/chunkIfs.ts
/** chunk items if condition is true */
function chunkIfs(predicate, { inclusive = false } = {}) {
const chunks = [];
let i = 0;
return new TransformStream({
transform: async (chunk, ctrl) => {
const cond = await predicate(chunk, i++, chunks);
if (!inclusive && !cond) {
if (chunks.length) ctrl.enqueue(chunks.splice(0, Infinity));
}
chunks.push(chunk);
if (!cond) ctrl.enqueue(chunks.splice(0, Infinity));
},
flush: async (ctrl) => {
if (chunks.length) ctrl.enqueue(chunks);
}
});
}
//#endregion
//#region src/maps.ts
function maps(fn, options) {
const concurrency = options?.concurrency ?? 1;
if (concurrency === 1) {
let i = 0;
return new TransformStream({ transform: async (chunk, ctrl) => {
const ret = fn(chunk, i++);
const val = ret instanceof Promise ? await ret : ret;
ctrl.enqueue(val);
} });
}
let i = 0;
const promises = [];
return new TransformStream({
transform: async (chunk, ctrl) => {
promises.push(fn(chunk, i++));
if (promises.length >= concurrency) ctrl.enqueue(await promises.shift());
},
flush: async (ctrl) => {
while (promises.length) ctrl.enqueue(await promises.shift());
}
});
}
//#endregion
//#region src/flatMaps.ts
function flatMaps(fn) {
let i = 0;
return new TransformStream({ transform: async (chunk, ctrl) => {
const ret = fn(chunk, i++);
(ret instanceof Promise ? await ret : ret).map((e) => ctrl.enqueue(e));
} });
}
//#endregion
//#region src/throughs.ts
/** pipe upstream through a transform stream */
const throughs = (arg) => {
if (!arg) return new TransformStream();
if (typeof arg !== "function") return throughs((s) => s.pipeThrough(arg));
const fn = arg;
const { writable, readable } = new TransformStream();
return {
writable,
readable: fn(readable)
};
};
//#endregion
//#region src/lines.ts
/** split string stream into lines stream, handy to concat LLM's tokens stream into line by line stream or split a long string by lines */
const lines = ({ EOL = "KEEP" } = {}) => {
const CRLFMap = {
KEEP: "$1",
LF: "\n",
CRLF: "\r\n",
NONE: ""
};
return throughs((r) => r.pipeThrough(flatMaps((s) => s.split(/(?<=\n)/g))).pipeThrough(chunkIfs((ch) => ch.indexOf("\n") === -1, { inclusive: true })).pipeThrough(maps((chunks) => chunks.join("").replace(/(\r?\n?)$/, CRLFMap[EOL]))));
};
//#endregion
//#region src/skips.ts
function skips(n = 1) {
return new TransformStream({ transform: async (chunk, ctrl) => {
if (n <= 0) ctrl.enqueue(chunk);
else n--;
} });
}
//#endregion
export { maps as a, flatMaps as i, lines as n, chunkIfs as o, throughs as r, skips as t };
//# sourceMappingURL=skips-o3ebh_7B.js.map