@raini/pipes is a set of composable blocks called Pipelines. Pipelines are lazy and do not get invoked until they are forked with process method.
Pipelines are Monoids and can be concatenated with other Pipelines using p.concat which allows joining separate sets of composed functions.
- Composition of functions via pipe
- Helper pipe methods, e.g. pipeTaporextendPipe
- Implements Semigroup (holds associativity) with p.concat
- Implements Monoid (holds right identity and left identity) with p.concatandP.empty
- PromisePipeline allows abstracting from using Promises in composed functions - promisePipeline.processreturns the only Promise to work with
- Can be used both in Node and in browsers (transpiled to ES5)
npm i -S @raini/pipesimport { PromisePipeline } from "@raini/pipes"
import * as rl from "readline"
const addSpaceIfMissing = (q: string): string => (q.endsWith(" ") ? q : q.concat(" "))
const toObject = (q: string) => ({ q })
const createReadLine = () => ({ rl: rl.createInterface(process.stdin, process.stdout) })
const askQuestionAsync = ({ rl, q }) => new Promise((res) => rl.question(q, (a: string) => res(a)))
const applyGreenColor = (x: string) => `\x1b[32m${x}\x1b[0m`
const log = console.log
const exit = () => process.exit(0)
PromisePipeline.of(addSpaceIfMissing)
  .pipe(toObject)
  .pipeExtend(createReadLine) // Extend argument object with return value
  .pipe(askQuestionAsync)
  .pipe(applyGreenColor)
  .pipeTap(log) // Execute function on the argument and return the argument
  .process(() => "What is the answer to life, the universe and everything?")
  .then(exit)- pipeP is equivalent to PromisePipeline.empty().pipe
- pipeExtendP is equivalent to PromisePipeline.empty().pipeExtend
- pipeTapP is equivalent to PromisePipeline.empty().pipeTap
import { SyncPipeline } from "@raini/pipes"
const isOdd = (num: number) => num % 2 == 0
const negate = <T>(f: (x: T) => any) => (x: T) => !f(x)
const filterOutOddNumbers = (nums: number[]) => nums.filter(negate(isOdd))
const multiplyBy2 = (num: number) => num * 2
const multiplyItemsBy2 = (nums: number[]) => nums.map(multiplyBy2)
const log = console.log
const result = SyncPipeline.of(filterOutOddNumbers)
  .pipeTap(log) // [ 1, 3, 5 ]
  .pipe(multiplyItemsBy2)
  .process(() => [1, 2, 3, 4, 5])
log(result) // [ 2, 6, 10 ]
// A fun thing using pipeExtend (instead of pipe) for multiplying items by 2
const result2 = SyncPipeline.of(filterOutOddNumbers)
  .pipeTap(log) // [ 1, 3, 5 ]
  .pipeExtend(multiplyItemsBy2)
  .process(() => [1, 2, 3, 4, 5])
log(result2) // [ 1, 3, 5, 2, 6, 10 ]- pipe is equivalent to SyncPipeline.empty().pipe
- pipeExtend is equivalent to SyncPipeline.empty().pipeExtend
- pipeTap is equivalent to SyncPipeline.empty().pipeTap