UNPKG

stream-chain

Version:

Chain functions, generators, Node streams, and Web streams into a pipeline with backpressure support.

181 lines (158 loc) 4.54 kB
// @ts-self-types="./defs.d.ts" const none = Symbol.for('object-stream.none'); const stop = Symbol.for('object-stream.stop'); const finalSymbol = Symbol.for('object-stream.final'); const manySymbol = Symbol.for('object-stream.many'); const flushSymbol = Symbol.for('object-stream.flush'); const fListSymbol = Symbol.for('object-stream.fList'); const finalValue = value => ({[finalSymbol]: 1, value}); const many = values => ({[manySymbol]: 1, values}); const isFinalValue = o => o && o[finalSymbol] === 1; const isMany = o => o && o[manySymbol] === 1; const isFlushable = o => o && o[flushSymbol] === 1; const isFunctionList = o => o && o[fListSymbol] === 1; const getFinalValue = o => o.value; const getManyValues = o => o.values; const getFunctionList = o => o.fList; const flushable = (write, final = null) => { const fn = final ? value => (value === none ? final() : write(value)) : write; fn[flushSymbol] = 1; return fn; }; const setFunctionList = (o, fns) => { o.fList = fns; o[fListSymbol] = 1; return o; }; const clearFunctionList = o => { delete o.fList; delete o[fListSymbol]; return o; }; class Stop extends Error {} const toMany = value => value === none ? many([]) : value && value[manySymbol] === 1 ? value : many([value]); const normalizeMany = o => { if (o?.[manySymbol] === 1) { switch (o.values.length) { case 0: return none; case 1: return o.values[0]; } } return o; }; const combineMany = (...args) => { const values = []; for (let i = 0; i < args.length; ++i) { const a = args[i]; if (a === none) continue; if (a?.[manySymbol] === 1) { values.push(...a.values); } else { values.push(a); } } return many(values); }; const combineManyMut = (a, ...args) => { const values = a === none ? [] : a?.[manySymbol] === 1 ? a.values : [a]; for (let i = 0; i < args.length; ++i) { const b = args[i]; if (b === none) continue; if (b?.[manySymbol] === 1) { values.push(...b.values); } else { values.push(b); } } return many(values); }; // --------------------------------------------------------------------------- // Stream type guards (shape-based). Live in defs.js so the symmetric // is*WebStream and is*NodeStream are co-located and reachable from any // subpath. Neither path imports `node:stream` — both are duck-typed: // // - Web: ReadableStream has `getReader`, WritableStream has `getWriter` // (Node streams expose neither). // - Node: streams expose `.pipe` / `.write` / `.on` plus the private // `_readableState` / `_writableState` markers (Web streams expose none). // // Node guard logic is taken from // https://github.com/nodejs/node/blob/master/lib/internal/streams/utils.js // --------------------------------------------------------------------------- const isReadableWebStream = x => !!( x && typeof x === 'object' && typeof x.getReader === 'function' && typeof x.pipeTo === 'function' ); const isWritableWebStream = x => !!( x && typeof x === 'object' && typeof x.getWriter === 'function' && typeof x.abort === 'function' ); const isDuplexWebStream = x => !!( x && typeof x === 'object' && isReadableWebStream(x.readable) && isWritableWebStream(x.writable) ); const isReadableNodeStream = obj => obj && typeof obj.pipe === 'function' && typeof obj.on === 'function' && (!obj._writableState || (typeof obj._readableState === 'object' ? obj._readableState.readable : null) !== false) && (!obj._writableState || obj._readableState); const isWritableNodeStream = obj => obj && typeof obj.write === 'function' && typeof obj.on === 'function' && (!obj._readableState || (typeof obj._writableState === 'object' ? obj._writableState.writable : null) !== false); const isDuplexNodeStream = obj => obj && typeof obj.pipe === 'function' && obj._readableState && typeof obj.on === 'function' && typeof obj.write === 'function'; // old aliases const final = finalValue; export { none, stop, Stop, finalSymbol, finalValue, final, isFinalValue, getFinalValue, manySymbol, many, isMany, getManyValues, flushSymbol, flushable, isFlushable, fListSymbol, isFunctionList, getFunctionList, setFunctionList, clearFunctionList, toMany, normalizeMany, combineMany, combineManyMut, isReadableWebStream, isWritableWebStream, isDuplexWebStream, isReadableNodeStream, isWritableNodeStream, isDuplexNodeStream };