Sweet Pipeline
is a flexible and powerful pipeline package for JavaScript/TypeScript, inspired by the Laravel pipeline design pattern. It enables you to define a simple sequential flow of processes leveraging on functional programming
principles, making it easy to build complex workflows with a clear and readable structure.
Node 16 + is required.
To get the latest version of Sweet-Pipeline, simply install it
npm install sweet-pipeline
Processes which are referred to as pipes
in the pipeline are callable functions
, closures
or anything that can be invoked.
To begin require it at the top.
import { Pipeline } from "sweet-pipeline"
The basic idea behind the pipeline
is to send data through a series of steps. Each step (or "pipe") modifies the data and passes it to the next step.
const pipeline = new Pipeline<number>();
const result = await pipeline
.send(1) // The initial data
.through([
(value) => value + 1, // First step: Add 1
(value) => value * 2, // Second step: Multiply by 2
])
.then(result => {
console.log(result); // Output: 4 (1 + 1 = 2, 2 * 2 = 4)
});
A pipe
is a function that processes the data in the pipeline. Each pipe receives the data (passable
) and can either return a value directly or a Promise
.
A function that takes the current passable object and a next function. The next function calls the next pipe.
(value) => value + 1
export const addOnePipe: (value: number) => Promise<number> = async (value) => {
return value + 1; // Add 1 and return the result
};
An object with a handle
method that follows the same signature as the function pipe.
const pipeObject = {
handle: (value) => value * 2,
};
export class MultiplyByTwoPipe {
async handle(value: number): Promise<number> {
return value * 2; // Multiply by 2 and return the result
}
}
An object/class with a handle
method that follows the same signature as the function pipe can be passed.
const pipeline = new Pipeline<number>();
const result = await pipeline
.send(1) // The initial data
.through([
addOnePipe, // First step: Add 1 (Function)
new MultiplyByTwoPipe(), // Second step: Multiply by 2 (Class)
])
.then(result => {
console.log(result); // Output: 4 (1 + 1 = 2, 2 * 2 = 4)
});
You can use async
pipes that return promises
. The pipeline will wait
for the promise to resolve before passing the result to the next pipe.
const result = await new Pipeline<number>()
.send(1)
.through([
async (value) => value + 1, // First step: Add 1 (async)
async (value) => value * 2, // Second step: Multiply by 2 (async)
])
.then(result => console.log(result)); // Output: 4
You can break
out of the pipeline early by using the .break()
method. If a pipe returns true
for the break
condition, the pipeline will stop processing further pipes.
const result = await new Pipeline<number>()
.send(1)
.through([
(value) => value + 1, // First step: Add 1
(value) => value * 2, // Second step: Multiply by 2
])
.break(true) // Stop after the first pipe
.then(result => console.log(result)); // Output: 2 (1 + 1)
The then
method allows you to specify the final step in the pipeline after all pipes have been executed. This is where you define the ultimate result you want to achieve after passing through the pipeline.
const result = await new Pipeline<number>()
.send(1)
.through([
(value) => value + 1, // Add 1
(value) => value * 2, // Multiply by 2
])
.then(result => {
console.log(result); // Output: 4
return result * 2; // You can also return a value for further chaining
})
.then(console.log); // Output: 8
Sets the initial data (passable
) that will be passed through the pipeline
.
pipeline.send(10);
Sets the pipes (steps) that will transform the data. This can be an array of pipes, which can be functions
or objects
with a handle
method
pipeline.through([
(value) => value + 1,
(value) => value * 2,
]);
Executes the pipeline
and returns the final result. Pipes are reduced into a single composed function that calls each pipe in sequence. The destination is the final step of the pipeline.
const result = await pipeline.then(value => value + 5);
While Sweet Pipeline
follows many functional programming
principles—such as immutability, first-class functions, composition, and higher-order functions—it doesn't enforce pure functional programming strictly. It still allows for impure functions (if the user decides to use them), and side effects can be introduced in the pipes. However, if used correctly with pure functions, the package aligns well with functional programming principles
Please see CHANGELOG for more information what has changed recently.
Please see CONTRIBUTING for details.
If you discover any security related issues, please email [email protected]
instead of using the issue tracker.
- Find me on
Website.
Github.
X (Twitter).
Linkedin.
The MIT License (MIT). Please see License File for more information.