https://github.com/orlowdev/or-pipets
Typed pipeable interface for imperative sequences in FP.
https://github.com/orlowdev/or-pipets
Last synced: about 1 year ago
JSON representation
Typed pipeable interface for imperative sequences in FP.
- Host: GitHub
- URL: https://github.com/orlowdev/or-pipets
- Owner: orlowdev
- License: mit
- Created: 2020-09-11T10:39:48.000Z (almost 6 years ago)
- Default Branch: main
- Last Pushed: 2023-01-06T14:24:57.000Z (over 3 years ago)
- Last Synced: 2025-03-16T13:37:31.073Z (about 1 year ago)
- Language: TypeScript
- Size: 1.68 MB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 9
-
Metadata Files:
- Readme: readme.md
- Contributing: .github/contributing.md
- Funding: .github/funding.yml
- License: license.md
- Code of conduct: .github/code_of_conduct.md
- Codeowners: .github/codeowners
- Security: .github/security.md
Awesome Lists containing this project
README
# ||pipets



[](https://codeclimate.com/github/orlovedev/or-pipets/maintainability)
[](https://codecov.io/gh/orlovedev/or-pipets)
[](https://bundlephobia.com/result?p=or-pipets)
[](https://github.com/xojs/xo)
[](https://github.com/prettier/prettier)
[](https://github.com/orlovedev/or-release)
Typed pipeable interface for imperative sequences in FP.
This package provides two constructs - `Pipe` and `AsyncPipe`. `AsyncPipe` provides the same methods as `Pipe` but its methods (except for `.concat`) end with **P**, e.g. `.pipeP` instead of `.pipe`. This is done to distinguish in the code when a `Pipe` transforms to an `AsyncPipe`.
- `Pipe.of(func)` and `AsyncPipe.of(asyncFunc)` wrap a function into pipe or async pipe accordingly
- `Pipe.from(...funcs)` and `AsyncPipe.from(...asyncFuncs)` wrap multiple functions
- `Pipe.empty()` and `AsyncPipe.empty()` create empty pipes
- `pipe.pipe(func)` extends the sequence with a function
- `.pipeTap(func)` extends the sequence with a function. The function will be executed but the pipe will ignore its return value and preserve previous context instead
- `.pipeExtend(func)` extends the sequence with a function. The function will be executed and the return value will be merged with the previous context. _Should only be used with objects_
- `a.concat(b)` creates a new pipe that contains sequences of both pipes. If either `a` or `b` is an `AsyncPipe`, an `AsyncPipe` is returned, no matter what another pipe was.
## Installation
```sh
yarn add or-pipets
```
or
```sh
npm i -S or-pipets
```
## Examples
### Bored
Suggests you ideas in case you get bored.
```typescript
import { EventEmitter } from 'events'
// You also need node-fetch for this to work
import fetch, { Response } from 'node-fetch'
import { AsyncPipe } from 'or-pipets'
const emitter = new EventEmitter()
const getJson = async (response: Response) => response.json()
const boredPipe = AsyncPipe.of(() => 'https://www.boredapi.com/api/activity')
.pipeTapP(() => console.log('Searching for activities... 🤔'))
.pipeP(fetch)
.pipeP(getJson)
.pipeP((json: { activity: string }) => json.activity)
.pipeTapP(() => console.log('Found one 🎉'))
.pipeP((activity) => ` 💡 ${activity}`)
.pipeP(console.log)
emitter.on('bored', boredPipe.processP)
setTimeout(() => emitter.emit('bored'), 300)
```
### Add 10
Adds 10 to the number you provide as a CLI argument.
```typescript
import { Pipe } from 'or-pipets'
// Start with removing the first two strings in the argv
Pipe.of((argv: string[]) => argv.slice(2))
// .pipeTap executes provided function but the return value is
// ignored - the argument is passed to the next function instead
// Log the context to console
.pipeTap((x) => console.log('>>>', x))
// Get the first item in the array and parse a number, 0 if NaN
.pipe(([numberString]) => Number.parseInt(numberString, 10) || 0)
// Log the context to console
.pipeTap((x) => console.log('>>>', x))
// Add 10
.pipe((number) => number + 10)
// Log the result to console
.pipe((result) => console.log(`🧮 ${result}`))
// Pass argv to the context of the Pipe
.process(process.argv)
```
### Welcome to localhost
Welcomes you to localhost:3000.
```typescript
import * as express from 'express'
import { Pipe } from 'or-pipets'
const app = express()
interface ICtx {
request: express.Request
response: express.Response
}
// Here we start with Pipe.empty() because our first function returns
// void. If we pass it to Pipe.of, it will pass nothing to the first
// pipeExtend and the code will fail. This is because pipeExtend
// manages saving previous context, not the Pipe itself.
const getSlashPipeline = Pipe.empty()
.pipeExtend(({ response }) => response.setHeader('X-Powered-By', 'Express with Pipe'))
// Puts the value of the Host header to the context
.pipeExtend(({ request }) => ({ host: request.header('host') ?? '🤔' }))
// Creates the response string with the host
.pipeExtend(({ host }) => ({ responseBody: `Welcome to ${host}!` }))
// Wraps the response string into h1
.pipeExtend(({ responseBody }) => ({ responseBody: `
${responseBody}
` }))
// Sends the response
.pipe(({ response, responseBody }) => response.send(responseBody))
app.get('/', (request, response) => getSlashPipeline.process({ request, response }))
app.listen(3000, () => {
console.log(`Example app listening on port 3000`)
})
```