@daisugi/daisugi
Version:
Daisugi is a minimalist functional middleware engine.
337 lines (219 loc) โข 7.16 kB
Markdown
# @daisugi/daisugi
<p align="center">
<img alt="daisugi" src="https://user-images.githubusercontent.com/22574/125201112-fc787f00-e26d-11eb-8e70-569dbd6997e0.png" width="170">
</p>
<p align="center">
Daisugi is a minimalist functional middleware engine.
</p>
[](https://www.npmjs.com/package/@daisugi/daisugi)
This project is part of the [@daisugi](https://github.com/daisugiland/daisugi) monorepo.
Well tested. | Without any external code dependencies and small size.
Daisugi was created with the purpose of organizing your code in an understandable execution pipeline.
## โจ Features
- ๐ก Minimal size overhead ([details](https://bundlephobia.com/result?p=@daisugi/daisugi))
- โก๏ธ Written in TypeScript
- ๐ฆ Uses only trusted dependencies
- ๐จ Powerful and agnostic to your code
- ๐งช Well-tested
- ๐ค Used in production
- ๐ Supports both ES Modules and CommonJS
## ๐ Usage
```js
import { Daisugi } from '@daisugi/daisugi';
const { sequenceOf } = new Daisugi();
function addName(arg) {
return `${arg} John`;
}
function addLastName(arg) {
return `${arg} Doe.`;
}
const handler = sequenceOf([addName, addLastName]);
handler('Hi');
// Hi John Doe.
```
## ๐ Table of Contents
- [@daisugi/daisugi](#daisugidaisugi)
- [โจ Features](#-features)
- [๐ Usage](#-usage)
- [๐ Table of Contents](#-table-of-contents)
- [๐ฆ Installation](#-installation)
- [๐ Downstream and Downstream/Upstream](#-downstream-and-downstreamupstream)
- [Downstream](#downstream)
- [Cascading (Downstream/Upstream)](#cascading-downstreamupstream)
- [๐ Synchronous and Asynchronous](#-synchronous-and-asynchronous)
- [๐๏ธ Nesting](#๏ธ-nesting)
- [๐ Flow Control](#-flow-control)
- [Example: Stopping Propagation](#example-stopping-propagation)
- [Example: Failing with an Error](#example-failing-with-an-error)
- [๐ข Multiple Arguments](#-multiple-arguments)
- [๐ง Extendable](#-extendable)
- [๐ฏ Goal](#-goal)
- [๐ Etymology](#-etymology)
- [๐ Other Projects](#-other-projects)
- [๐ License](#-license)
[:top: Back to top](#-table-of-contents)
## ๐ฆ Installation
Using npm:
```sh
npm install @daisugi/daisugi
```
Using pnpm:
```sh
pnpm install @daisugi/daisugi
```
[:top: Back to top](#-table-of-contents)
## ๐ Downstream and Downstream/Upstream
Daisugi allows both sequential execution (downstream) and cascading (downstream/upstream) flows.
### Downstream
Perform sequential executions like traditional pipes using simple functions (handlers).
```js
import { Daisugi } from '@daisugi/daisugi';
const { sequenceOf } = new Daisugi();
function addName(arg) {
return `${arg} John.`;
}
sequenceOf([addName])('Hi');
// Hi John.
```
### Cascading (Downstream/Upstream)
Yield downstream and then flow control back upstream, often used in middleware (similar to [Koa](https://github.com/koajs/koa)). To achieve cascading, provide the `injectToolkit` property in the function's metadata (`meta`), which instructs Daisugi to include a toolkit with flow utilities (`next`, `nextWith`) as the last argument.
```js
import { Daisugi } from '@daisugi/daisugi';
const { sequenceOf } = new Daisugi();
function addName(arg, toolkit) {
arg.value = `${arg.value} John`;
return toolkit.next;
}
addName.meta = {
injectToolkit: true,
};
function addLastName(arg) {
return `${arg.value} Doe.`;
}
sequenceOf([addName])({ value: 'Hi' });
// 'Hi John.'
```
By default, the downstream type is used. You can switch to cascading for more complex behaviors (e.g., tracing, logging) or mix both types within the same sequence.
[:top: Back to top](#-table-of-contents)
## ๐ Synchronous and Asynchronous
Daisugi supports both synchronous and asynchronous handlers.
```js
import { Daisugi } from '@daisugi/daisugi';
const { sequenceOf } = new Daisugi();
async function waitForName(arg, toolkit) {
return await toolkit.next;
}
waitForName.meta = {
injectToolkit: true,
};
async function addName(arg) {
return `${arg} John.`;
}
await sequenceOf([waitForName, addName])('Hi');
// Hi John.
```
[:top: Back to top](#-table-of-contents)
## ๐๏ธ Nesting
Daisugi allows you to nest sequences within each other as each sequence is simply another handler.
```js
import { Daisugi } from '@daisugi/daisugi';
const { sequenceOf } = new Daisugi();
function addName(arg) {
return `${arg} John`;
}
function addLastName(arg) {
return `${arg} Doe.`;
}
sequenceOf([addName, sequenceOf([addLastName])])('Hi');
// Hi John Doe.
```
[:top: Back to top](#-table-of-contents)
## ๐ Flow Control
Daisugi gives you control over the data flow with static methods:
- `stopPropagationWith`: Stops and exits the current sequence.
- `failWith`: Stops execution and exits from all sequences.
### Example: Stopping Propagation
```js
import { Daisugi } from '@daisugi/daisugi';
const { sequenceOf } = new Daisugi();
function addName(arg) {
return Daisugi.stopPropagationWith(`${arg} John.`);
}
function addLastName(arg) {
return `${arg} Doe.`;
}
sequenceOf([addName, addLastName])('Hi');
// Hi John.
```
### Example: Failing with an Error
```js
import { Daisugi } from '@daisugi/daisugi';
const { sequenceOf } = new Daisugi();
function addName(arg) {
return Daisugi.failWith(`${arg} John`);
}
function addLastName(arg) {
return `${arg} Doe.`;
}
const response = sequenceOf([addName, addLastName])('Hi');
// response.getError().value === 'Hi John'
```
[:top: Back to top](#-table-of-contents)
## ๐ข Multiple Arguments
Handlers in Daisugi can receive multiple arguments, including `nextWith` among others.
```js
import { Daisugi } from '@daisugi/daisugi';
const { sequenceOf } = new Daisugi();
function addName(arg1, arg2, arg3) {
return `${arg1} ${arg2} ${arg3}.`;
}
sequenceOf([addName])('Hi', 'John', 'Doe');
// Hi John Doe.
```
[:top: Back to top](#-table-of-contents)
## ๐ง Extendable
Daisugi allows you to extend handlers at execution time or during initialization using decorators.
```js
import { Daisugi } from '@daisugi/daisugi';
function decorator(handler) {
return function addName(arg) {
handler(`${arg} ${handler.meta.arg}`);
};
}
const { sequenceOf } = new Daisugi([decorator]);
function addLastName(arg) {
return `${arg} Doe.`;
}
addLastName.meta = {
arg: 'John',
};
sequenceOf([addLastName])('Hi');
// Hi John Doe.
```
[:top: Back to top](#-table-of-contents)
## ๐ฏ Goal
Daisugi's goal is to keep the core simple while extending its functionality through provided tools.
[:top: Back to top](#-table-of-contents)
## ๐ Etymology
Daisugi is a Japanese forestry technique developed in the 14th century, where cedar trees are pruned to produce uniformly straight, knot-free lumber.
More info: [Twitter](https://twitter.com/wrathofgnon/status/1250287741247426565)
[:top: Back to top](#-table-of-contents)
## ๐ Other Projects
[Meet the ecosystem](../../README.md)
[:top: Back to top](#-table-of-contents)
## ๐ License
[MIT](../../LICENSE)