@execution-flows/flow-compose

中文文档
0.3.0发布于 2026/04/24MPL-2.0TypeScriptCommonJS零依赖近 30 天下载 4160

A TypeScript implementation of Execution Flows using the Flow Compose pattern.

原始使用文档
文档目录11 节
  1. Installation
  2. Description
  3. Usage
  4. Basic Flow
  5. Flow with Arguments
  6. Composing Functions with Arguments
  7. Caching with flowProperty
  8. Caching a Composed Flow with Flow
  9. Contributing
  10. Community and Support
  11. License

@execution-flows/flow-compose

Installation

npm install @execution-flows/flow-compose

Description

At its core, flow-compose is a lightweight, functional dependency injection library that helps you manage complex execution flows by decoupling your functions from their dependencies.

It encourages a powerful pattern where every function in your codebase can be written as a nullary function—a function that takes no arguments. This means you can invoke any function from anywhere without worrying about how to provide the data or other functions it needs to run.

Instead of passing dependencies as arguments (a practice that often leads to "prop drilling"), functions simply declare what they need. This is achieved through the flow context.

The top-level flow function acts as a DI container. You provide it with a context object that holds all the functions and data required for the flow. When a function is executed, the flow automatically injects the dependencies it declared, making them available for use.

A key characteristic of this pattern is that everything is lazy-loaded by default. Since every dependency is wrapped in a function, nothing is evaluated until it is explicitly invoked. If a dependency is never called, its code is never executed, making the entire system highly efficient.

This results in highly composable, testable, and maintainable code.

Usage

The entire library exposes only four functions: flow, flowFunction, flowArgument, and flowProperty. These four functions can then be used to compose an execution flow of any complexity with the utmost clarity of which code requires what and how they get it.

Basic Flow

The flow and flowFunction constructs are the building blocks of this library.

import { flow, flowFunction } from "@execution-flows/flow-compose";
import type { FlowFunction } from "@execution-flows/flow-compose";

// A `flowFunction` is a unit of logic that can be used within a `flow`.
const greetHelloWorld = flowFunction(() => {
  console.log("Hello, World!");
});

// The `flow` function composes everything into a single, callable function.
const helloWorld = flow(
  // The first argument is the `context`, a map of named dependencies.
  { greet: greetHelloWorld },
  // The second argument is the `body` of the flow, which is also a `flowFunction`.
  flowFunction(({ greet }: { greet: FlowFunction<void> }) => {
    greet();
  }),
);

helloWorld(); // Outputs: "Hello, World!"

Flow with Arguments

You can use flowArgument to pass arguments to your flows at invocation time.

import { flow, flowFunction, flowArgument } from "@execution-flows/flow-compose";
import type { FlowFunction } from "@execution-flows/flow-compose";

// This `flowFunction` depends on `name`, which will be provided by a `flowArgument`.
const greetWithName = flowFunction(({ name }: { name: FlowFunction<string> }) => {
  console.log(`Hello, ${name()}!`);
});

const hello = flow(
  {
    // `flowArgument` marks `name` as a required runtime argument for the final flow.
    name: flowArgument<string>(),
    // The context maps the implementation `greetWithName` to the name `greet`.
    // Any `flowFunction` inside this flow can now request `greet` to get its dependency.
    greet: greetWithName,
  },
  flowFunction(({ greet }: { greet: FlowFunction<void> }) => {
    greet();
  }),
);

// The resulting `hello` function now expects an object with a `name` property.
hello({ name: "Ada" }); // Outputs: "Hello, Ada!"

Composing Functions with Arguments

A flowFunction can also provide a dependency that accepts arguments. This allows other functions in the flow to inject it and call it with different parameters, enabling more dynamic and reusable logic.

import { flow, flowFunction } from "@execution-flows/flow-compose";

// This `flowFunction` provides a dependency named `greetingBuilder`.
const greetingBuilder = flowFunction((): ((index: number) => string) => {
  // The dependency it provides is a function that takes an `index`.
  return (index: number) => {
    console.log(`Building greeting for index: ${index}`);
    return `Hello, World! - ${String(index)}`;
  };
});

// This `flowFunction` depends on `greeting`, which it expects to be a function.
const greetUsingGreeting = flowFunction(
  ({ greeting }: { greeting: (index: number) => string }): void => {
    // It can then call the injected function with different arguments.
    const greetingOne = greeting(11);
    const greetingTwo = greeting(13);
    console.log(greetingOne);
    console.log(greetingTwo);
  },
);

const helloWorld = flow(
  { greeting: greetingBuilder, greet: greetUsingGreeting },
  flowFunction(({ greet }: { greet: () => void }): void => {
    greet();
  }),
);

helloWorld();
// Outputs:
// Building greeting for index: 11
// Building greeting for index: 13
// Hello, World! - 11
// Hello, World! - 13

Caching with flowProperty

Use flowProperty to create a dependency whose result is cached within a single invocation of the flow. This is useful for expensive operations that might be accessed multiple times.

import { flow, flowFunction, flowProperty } from "@execution-flows/flow-compose";
import type { FlowFunction } from "@execution-flows/flow-compose";

// `flowProperty` is a shorthand for a `flowFunction` with caching enabled.
// The inner function will only be executed once per flow run.
const greetingHelloWorld = flowProperty((): string => {
  console.log("Generating greeting...");
  return "Hello, World!";
});

const greetUsingGreeting = flowFunction(
  ({ greeting }: { greeting: FlowFunction<string> }): void => {
    // Accessing `greeting` multiple times...
    const greetingOnce = greeting();
    const greetingTwice = greeting();
    // ...does not re-run the original function.
    console.log(greetingOnce);
    console.log(greetingTwice);
  },
);

const helloWorld = flow(
  { greeting: greetingHelloWorld, greet: greetUsingGreeting },
  flowFunction(({ greet }: { greet: FlowFunction<void> }): void => {
    greet();
  }),
);

helloWorld();
// Outputs:
// Generating greeting...
// Hello, World!
// Hello, World!

Caching a Composed Flow with Flow

You can cache the result of an entire composed flow across multiple calls using the Flow function decorator.

import { flow, flowFunction, Flow } from "@execution-flows/flow-compose";
import type { FlowFunction } from "@execution-flows/flow-compose";

const greetingHelloWorld = flowFunction((): string => {
  console.log("Generating greeting...");
  return "Hello, World!";
});

// This is a standard composed flow.
const helloWorldGreeting = flow(
  { greeting: greetingHelloWorld },
  flowFunction(({ greeting }: { greeting: FlowFunction<string> }): string => {
    return greeting();
  }),
);

const greetUsingGreeting = flowFunction(
  ({ greeting }: { greeting: FlowFunction<string> }): void => {
    greeting();
  },
);

// The `Flow` function wraps another flow and applies options.
// Here, we cache the result of `helloWorldGreeting`.
const helloWorld = flow(
  { greeting: Flow(helloWorldGreeting, { cached: true }), greet: greetUsingGreeting },
  flowFunction(({ greet }: { greet: FlowFunction<void> }): void => {
    // `greet` will be called twice...
    greet();
    greet();
    // ...but the underlying `helloWorldGreeting` flow will only run once.
  }),
);

helloWorld();
// Outputs:
// Generating greeting...

Contributing

Contributions are what make the open-source community such an amazing place to learn, inspire, and create. We welcome contributions of all kinds!

If you have a suggestion for a new feature, find a bug, or see an opportunity to improve the documentation, please feel free to open an issue.

Pull requests are also greatly appreciated.

Community and Support

Have a question or want to share an idea? The best place to start a conversation is by opening an issue on GitHub. We'd love to hear from you!

License

@execution-flows/flow-compose is open-source software licensed under the MPL-2.0.

版本与发布记录

@execution-flows/flow-compose 共发布 6 个版本,首次发布于 2026/03/22;过去 12 个月发布了 6 个版本。

版本发布日期距今
0.3.0latest2026/04/246 个月前
0.2.02026/04/087 个月前
0.1.02026/04/087 个月前
0.1.0-dev1dev2026/04/087 个月前
0.0.22026/04/077 个月前
0.0.12026/03/227 个月前

关于 @execution-flows/flow-compose 的常见问题

@execution-flows/flow-compose 是什么?

A TypeScript implementation of Execution Flows using the Flow Compose pattern.

如何安装 @execution-flows/flow-compose?

在项目目录运行 npm install @execution-flows/flow-compose,或使用 pnpm add / yarn add / bun add。

@execution-flows/flow-compose 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@execution-flows/flow-compose 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@execution-flows/flow-compose 可以商用吗?

@execution-flows/flow-compose 使用 MPL-2.0 许可。弱 Copyleft:可以商用,也可以和闭源代码一起使用;但如果分发时修改了 MPL 授权的文件,这些文件的修改需以 MPL 开源。以上为概括,不构成法律意见,请以许可原文为准。

@execution-flows/flow-compose 的下载量有多少?

根据 npm 官方下载统计,@execution-flows/flow-compose 在 2026/10/14 – 2026/11/12 这 30 天内被下载 4,160 次,日均约 139 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@execution-flows/flow-compose 还在维护吗?

最新版本 0.3.0 发布于 2026/04/24(6 个月前);至今共发布 6 个版本,其中过去 12 个月发布了 6 个;首次发布于 2026/03/22。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。