UNPKG

@daisugi/daisugi

Version:

Daisugi is a minimalist functional middleware engine.

337 lines (219 loc) โ€ข 7.16 kB
# @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> [![version](https://img.shields.io/npm/v/@daisugi/daisugi.svg)](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)