effect-cli

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Effect CLI (v4)

Effect CLI (v4)

Build type-safe command-line applications with typed arguments, flags, subcommands, and dependency injection.
构建带有类型化参数、标志、子命令和依赖注入的类型安全命令行应用。

Import Pattern

导入方式

typescript
import { Argument, Command, Flag } from 'effect/unstable/cli';
Platform services and runtime for the entry point:
typescript
import { NodeRuntime, NodeServices } from '@effect/platform-node';
typescript
import { Argument, Command, Flag } from 'effect/unstable/cli';
用于入口点的平台服务和运行时:
typescript
import { NodeRuntime, NodeServices } from '@effect/platform-node';

Positional Arguments (Argument)

位置参数(Argument)

Positional arguments are parsed in order.
Argument.boolean
intentionally does not exist — use
Flag.boolean
or
Argument.choice("name", ["true", "false"])
instead.
位置参数按顺序解析。
Argument.boolean
是故意不提供的——请改用
Flag.boolean
Argument.choice("name", ["true", "false"])

Constructors

构造函数

typescript
import { Argument } from 'effect/unstable/cli';

Argument.string('name'); // string
Argument.integer('count'); // number (integer)
Argument.float('ratio'); // number (float)
Argument.date('deadline'); // Date
Argument.file('input'); // file path (string)
Argument.file('input', { mustExist: true }); // file path that must exist
Argument.directory('dir'); // directory path (string)
Argument.directory('dir', { mustExist: true }); // directory that must exist
Argument.path('target'); // any path (string)
Argument.choice('env', ['dev', 'staging', 'prod']); // constrained string union
Argument.choiceWithValue('level', [
	// choice with mapped values
	['debug', 0],
	['info', 1],
	['error', 3]
]);
Argument.redacted('secret'); // Redacted<string>
Argument.fileText('config'); // reads file content as string
Argument.fileSchema('config', MySchema); // reads and validates file via Schema
typescript
import { Argument } from 'effect/unstable/cli';

Argument.string('name'); // 字符串类型
Argument.integer('count'); // 数字类型(整数)
Argument.float('ratio'); // 数字类型(浮点数)
Argument.date('deadline'); // Date类型
Argument.file('input'); // 文件路径(字符串)
Argument.file('input', { mustExist: true }); // 必须存在的文件路径
Argument.directory('dir'); // 目录路径(字符串)
Argument.directory('dir', { mustExist: true }); // 必须存在的目录
Argument.path('target'); // 任意路径(字符串)
Argument.choice('env', ['dev', 'staging', 'prod']); // 受限的字符串联合类型
Argument.choiceWithValue('level', [
	// 带映射值的选项
	['debug', 0],
	['info', 1],
	['error', 3]
]);
Argument.redacted('secret'); // Redacted<string>类型
Argument.fileText('config'); // 读取文件内容为字符串
Argument.fileSchema('config', MySchema); // 通过Schema读取并验证文件

Combinators

组合器

typescript
import { Argument } from 'effect/unstable/cli';

// Description for help text
Argument.string('file').pipe(Argument.withDescription('Input file'));

// Default value
Argument.integer('port').pipe(Argument.withDefault(8080));

// Optional (returns Option<T>)
Argument.string('config').pipe(Argument.optional);

// Variadic (returns ReadonlyArray<T>)
Argument.string('files').pipe(Argument.variadic);
Argument.string('files').pipe(Argument.variadic({ min: 1 }));
Argument.string('files').pipe(Argument.variadic({ min: 1, max: 5 }));

// Cardinality shortcuts
Argument.string('files').pipe(Argument.atLeast(1));
Argument.string('files').pipe(Argument.atMost(5));
Argument.string('files').pipe(Argument.between(1, 5));

// Transform
Argument.integer('port').pipe(Argument.map((p) => `http://localhost:${p}`));

// Validate with Schema
Argument.string('input').pipe(Argument.withSchema(Schema.NonEmptyString));

// Fallback from env config
Argument.string('repo').pipe(
	Argument.withFallbackConfig(Config.string('REPOSITORY'))
);

// Fallback interactive prompt
Argument.string('name').pipe(
	Argument.withFallbackPrompt(Prompt.text({ message: 'Name' }))
);

// Custom metavar for help text
Argument.integer('port').pipe(Argument.withMetavar('PORT'));

// Filter with error message
Argument.integer('count').pipe(
	Argument.filter(
		(n) => n > 0,
		(n) => `Expected positive, got ${n}`
	)
);
typescript
import { Argument } from 'effect/unstable/cli';

// 帮助文本描述
Argument.string('file').pipe(Argument.withDescription('输入文件'));

// 默认值
Argument.integer('port').pipe(Argument.withDefault(8080));

// 可选参数(返回Option<T>)
Argument.string('config').pipe(Argument.optional);

// 可变参数(返回ReadonlyArray<T>)
Argument.string('files').pipe(Argument.variadic);
Argument.string('files').pipe(Argument.variadic({ min: 1 }));
Argument.string('files').pipe(Argument.variadic({ min: 1, max: 5 }));

// 数量快捷方式
Argument.string('files').pipe(Argument.atLeast(1));
Argument.string('files').pipe(Argument.atMost(5));
Argument.string('files').pipe(Argument.between(1, 5));

// 转换
Argument.integer('port').pipe(Argument.map((p) => `http://localhost:${p}`));

// 使用Schema验证
Argument.string('input').pipe(Argument.withSchema(Schema.NonEmptyString));

// 从环境配置回退
Argument.string('repo').pipe(
	Argument.withFallbackConfig(Config.string('REPOSITORY'))
);

// 回退到交互式提示
Argument.string('name').pipe(
	Argument.withFallbackPrompt(Prompt.text({ message: '名称' }))
);

// 帮助文本的自定义元变量
Argument.integer('port').pipe(Argument.withMetavar('PORT'));

// 带错误信息的过滤
Argument.integer('count').pipe(
	Argument.filter(
		(n) => n > 0,
		(n) => `期望值为正数,实际得到 ${n}`
	)
);

Named Flags (Flag)

命名标志(Flag)

Flags are named options with
--name
or
-alias
syntax.
标志是使用
--name
-alias
语法的命名选项。

Constructors

构造函数

typescript
import { Flag } from 'effect/unstable/cli';

Flag.boolean('verbose'); // --verbose / --no-verbose
Flag.string('config'); // --config value
Flag.integer('port'); // --port 8080
Flag.float('rate'); // --rate 3.14
Flag.date('since'); // --since 2024-01-01
Flag.file('input'); // --input file.txt
Flag.file('input', { mustExist: true }); // file must exist
Flag.directory('output'); // --output ./dist
Flag.path('config-path'); // --config-path /etc/app
Flag.choice('env', ['dev', 'staging', 'prod']); // --env dev
Flag.choiceWithValue('log-level', [
	// choice with mapped values
	['debug', 'Debug' as const],
	['info', 'Info' as const],
	['error', 'Error' as const]
]);
Flag.redacted('password'); // Redacted<string>
Flag.fileText('config-file'); // reads file content
Flag.fileParse('config'); // reads and parses file (auto-detects format)
Flag.fileSchema('config', MySchema); // reads and validates via Schema
Flag.keyValuePair('env'); // --env FOO=bar → Record<string, string>
typescript
import { Flag } from 'effect/unstable/cli';

Flag.boolean('verbose'); // --verbose / --no-verbose
Flag.string('config'); // --config 取值
Flag.integer('port'); // --port 8080
Flag.float('rate'); // --rate 3.14
Flag.date('since'); // --since 2024-01-01
Flag.file('input'); // --input file.txt
Flag.file('input', { mustExist: true }); // 必须存在的文件
Flag.directory('output'); // --output ./dist
Flag.path('config-path'); // --config-path /etc/app
Flag.choice('env', ['dev', 'staging', 'prod']); // --env dev
Flag.choiceWithValue('log-level', [
	// 带映射值的选项
	['debug', 'Debug' as const],
	['info', 'Info' as const],
	['error', 'Error' as const]
]);
Flag.redacted('password'); // Redacted<string>类型
Flag.fileText('config-file'); // 读取文件内容
Flag.fileParse('config'); // 读取并解析文件(自动检测格式)
Flag.fileSchema('config', MySchema); // 通过Schema读取并验证
Flag.keyValuePair('env'); // --env FOO=bar → Record<string, string>

Combinators

组合器

typescript
import { Flag } from 'effect/unstable/cli';

// Alias
Flag.boolean('verbose').pipe(Flag.withAlias('v')); // --verbose or -v

// Description
Flag.string('config').pipe(Flag.withDescription('Path to config file'));

// Default value (makes flag optional with fallback)
Flag.integer('port').pipe(Flag.withDefault(3000));

// Optional (returns Option<T>)
Flag.string('token').pipe(Flag.optional);

// Custom metavar for help
Flag.string('db-url').pipe(Flag.withMetavar('URL')); // --db-url URL

// Repetition
Flag.string('tag').pipe(Flag.atLeast(1)); // --tag a --tag b
Flag.string('warning').pipe(Flag.atMost(3));
Flag.string('host').pipe(Flag.between(1, 3));

// Transform
Flag.integer('port').pipe(Flag.map((p) => `http://localhost:${p}`));

// Validate with Schema
Flag.string('email').pipe(Flag.withSchema(EmailSchema));

// Filter
Flag.integer('port').pipe(
	Flag.filter(
		(p) => p >= 1 && p <= 65535,
		(p) => `Port ${p} out of range`
	)
);

// Fallback from env config
Flag.boolean('verbose').pipe(
	Flag.withFallbackConfig(Config.boolean('VERBOSE'))
);

// Fallback interactive prompt
Flag.string('name').pipe(
	Flag.withFallbackPrompt(Prompt.text({ message: 'Name' }))
);
typescript
import { Flag } from 'effect/unstable/cli';

// 别名
Flag.boolean('verbose').pipe(Flag.withAlias('v')); // --verbose 或 -v

// 描述
Flag.string('config').pipe(Flag.withDescription('配置文件路径'));

// 默认值(使标志变为可选并带有回退值)
Flag.integer('port').pipe(Flag.withDefault(3000));

// 可选参数(返回Option<T>)
Flag.string('token').pipe(Flag.optional);

// 帮助文本的自定义元变量
Flag.string('db-url').pipe(Flag.withMetavar('URL')); // --db-url URL

// 重复参数
Flag.string('tag').pipe(Flag.atLeast(1)); // --tag a --tag b
Flag.string('warning').pipe(Flag.atMost(3));
Flag.string('host').pipe(Flag.between(1, 3));

// 转换
Flag.integer('port').pipe(Flag.map((p) => `http://localhost:${p}`));

// 使用Schema验证
Flag.string('email').pipe(Flag.withSchema(EmailSchema));

// 过滤
Flag.integer('port').pipe(
	Flag.filter(
		(p) => p >= 1 && p <= 65535,
		(p) => `端口 ${p} 超出范围`
	)
);

// 从环境配置回退
Flag.boolean('verbose').pipe(
	Flag.withFallbackConfig(Config.boolean('VERBOSE'))
);

// 回退到交互式提示
Flag.string('name').pipe(
	Flag.withFallbackPrompt(Prompt.text({ message: '名称' }))
);

Commands

命令

Creating Commands

创建命令

Command.make
accepts a name, optional config object, and optional handler:
typescript
import { Console, Effect } from 'effect';
import { Argument, Command, Flag } from 'effect/unstable/cli';

// Simple command (no config, no handler)
const version = Command.make('version');

// Command with config (no handler yet)
const deploy = Command.make('deploy', {
	env: Flag.string('env'),
	force: Flag.boolean('force'),
	files: Argument.string('files').pipe(Argument.variadic)
});

// Command with config and inline handler
const greet = Command.make(
	'greet',
	{
		name: Argument.string('name').pipe(
			Argument.withDescription('Person to greet')
		),
		times: Flag.integer('times').pipe(Flag.withDefault(1))
	},
	Effect.fn(function* ({ name, times }) {
		for (let i = 0; i < times; i++) {
			yield* Console.log(`Hello, ${name}!`);
		}
	})
);
Command.make
接受名称、可选配置对象和可选处理函数:
typescript
import { Console, Effect } from 'effect';
import { Argument, Command, Flag } from 'effect/unstable/cli';

// 简单命令(无配置,无处理函数)
const version = Command.make('version');

// 带配置的命令(暂未设置处理函数)
const deploy = Command.make('deploy', {
	env: Flag.string('env'),
	force: Flag.boolean('force'),
	files: Argument.string('files').pipe(Argument.variadic)
});

// 带配置和内联处理函数的命令
const greet = Command.make(
	'greet',
	{
		name: Argument.string('name').pipe(
			Argument.withDescription('要问候的人')
		),
		times: Flag.integer('times').pipe(Flag.withDefault(1))
	},
	Effect.fn(function* ({ name, times }) {
		for (let i = 0; i < times; i++) {
			yield* Console.log(`你好,${name}!`);
		}
	})
);

Handler Pattern

处理函数模式

Handlers use
Effect.fn
with a generator that destructures the config:
typescript
const cmd = Command.make(
	'deploy',
	{
		env: Flag.choice('env', ['dev', 'staging', 'prod']),
		dryRun: Flag.boolean('dry-run')
	},
	Effect.fn(function* ({ env, dryRun }) {
		if (dryRun) {
			yield* Console.log(`Would deploy to ${env}`);
		} else {
			yield* Console.log(`Deploying to ${env}...`);
		}
	})
);
Alternatively, add a handler later with
Command.withHandler
:
typescript
const cmd = Command.make('greet', {
	name: Flag.string('name')
}).pipe(Command.withHandler(({ name }) => Console.log(`Hello, ${name}!`)));
处理函数使用
Effect.fn
和生成器函数,解构配置对象:
typescript
const cmd = Command.make(
	'deploy',
	{
		env: Flag.choice('env', ['dev', 'staging', 'prod']),
		dryRun: Flag.boolean('dry-run')
	},
	Effect.fn(function* ({ env, dryRun }) {
		if (dryRun) {
			yield* Console.log(`将部署到 ${env}`);
		} else {
			yield* Console.log(`正在部署到 ${env}...`);
		}
	})
);
或者,稍后使用
Command.withHandler
添加处理函数:
typescript
const cmd = Command.make('greet', {
	name: Flag.string('name')
}).pipe(Command.withHandler(({ name }) => Console.log(`你好,${name}!`)));

Command Metadata

命令元数据

typescript
Command.make('deploy', config, handler).pipe(
	Command.withDescription('Deploy the application'),
	Command.withShortDescription('Deploy app'), // used in subcommand listings
	Command.withAlias('d'), // alternate name
	Command.withExamples([
		{
			command: 'myapp deploy --env prod',
			description: 'Deploy to production'
		},
		{ command: 'myapp deploy --env dev --dry-run', description: 'Dry run' }
	])
);
typescript
Command.make('deploy', config, handler).pipe(
	Command.withDescription('部署应用'),
	Command.withShortDescription('部署应用'), // 用于子命令列表
	Command.withAlias('d'), // 备用名称
	Command.withExamples([
		{
			command: 'myapp deploy --env prod',
			description: '部署到生产环境'
		},
		{ command: 'myapp deploy --env dev --dry-run', description: '试运行' }
	])
);

Nested Config

嵌套配置

Config objects can be nested for organization:
typescript
const deploy = Command.make('deploy', {
	environment: Flag.string('env'),
	server: {
		host: Flag.string('host').pipe(Flag.withDefault('localhost')),
		port: Flag.integer('port').pipe(Flag.withDefault(3000))
	},
	files: Argument.string('files').pipe(Argument.variadic)
});
// Handler receives: { environment: string, server: { host: string, port: number }, files: ReadonlyArray<string> }
配置对象可以嵌套以实现组织化:
typescript
const deploy = Command.make('deploy', {
	environment: Flag.string('env'),
	server: {
		host: Flag.string('host').pipe(Flag.withDefault('localhost')),
		port: Flag.integer('port').pipe(Flag.withDefault(3000))
	},
	files: Argument.string('files').pipe(Argument.variadic)
});
// 处理函数接收:{ environment: string, server: { host: string, port: number }, files: ReadonlyArray<string> }

Subcommands

子命令

Basic Subcommands

基础子命令

typescript
const app = Command.make('app');

const init = Command.make(
	'init',
	{},
	Effect.fn(function* () {
		yield* Console.log('Initializing...');
	})
);

const build = Command.make(
	'build',
	{
		target: Flag.choice('target', ['web', 'node'])
	},
	Effect.fn(function* ({ target }) {
		yield* Console.log(`Building for ${target}`);
	})
);

app.pipe(
	Command.withSubcommands([init, build]),
	Command.run({ version: '1.0.0' }),
	Effect.provide(NodeServices.layer),
	NodeRuntime.runMain
);
// Usage: app init | app build --target web
typescript
const app = Command.make('app');

const init = Command.make(
	'init',
	{},
	Effect.fn(function* () {
		yield* Console.log('初始化中...');
	})
);

const build = Command.make(
	'build',
	{
		target: Flag.choice('target', ['web', 'node'])
	},
	Effect.fn(function* ({ target }) {
		yield* Console.log(`${target} 构建`);
	})
);

app.pipe(
	Command.withSubcommands([init, build]),
	Command.run({ version: '1.0.0' }),
	Effect.provide(NodeServices.layer),
	NodeRuntime.runMain
);
// 使用方式: app init | app build --target web

Shared Parent Flags

共享父标志

Use
Command.withSharedFlags
to define flags on a parent that are available to all subcommands. Subcommands access parent config by yielding the parent command:
typescript
const tasks = Command.make('tasks').pipe(
	Command.withSharedFlags({
		workspace: Flag.string('workspace').pipe(
			Flag.withAlias('w'),
			Flag.withDefault('personal')
		),
		verbose: Flag.boolean('verbose').pipe(Flag.withAlias('v'))
	})
);

const create = Command.make(
	'create',
	{
		title: Argument.string('title'),
		priority: Flag.choice('priority', ['low', 'normal', 'high']).pipe(
			Flag.withDefault('normal')
		)
	},
	Effect.fn(function* ({ title, priority }) {
		// Access parent config by yielding the parent command
		const root = yield* tasks;
		if (root.verbose) {
			yield* Console.log(`workspace=${root.workspace} action=create`);
		}
		yield* Console.log(
			`Created "${title}" in ${root.workspace} with ${priority} priority`
		);
	})
).pipe(
	Command.withDescription('Create a task'),
	Command.withExamples([
		{
			command: 'tasks create "Ship 4.0" --priority high',
			description: 'Create a high-priority task'
		}
	])
);

const list = Command.make(
	'list',
	{
		status: Flag.choice('status', ['open', 'done', 'all']).pipe(
			Flag.withDefault('open')
		),
		json: Flag.boolean('json')
	},
	Effect.fn(function* ({ status, json }) {
		const root = yield* tasks;
		if (json) {
			yield* Console.log(
				JSON.stringify({ workspace: root.workspace, status }, null, 2)
			);
		} else {
			yield* Console.log(`Listing ${status} tasks in ${root.workspace}`);
		}
	})
).pipe(Command.withDescription('List tasks'), Command.withAlias('ls'));

tasks.pipe(
	Command.withSubcommands([create, list]),
	Command.run({ version: '1.0.0' }),
	Effect.provide(NodeServices.layer),
	NodeRuntime.runMain
);
// Usage: tasks --workspace team-a list --status open
// Usage: tasks create "Ship 4.0" --priority high
// Usage: tasks ls --json
使用
Command.withSharedFlags
在父命令上定义所有子命令都可用的标志。子命令通过生成父命令来访问父配置:
typescript
const tasks = Command.make('tasks').pipe(
	Command.withSharedFlags({
		workspace: Flag.string('workspace').pipe(
			Flag.withAlias('w'),
			Flag.withDefault('personal')
		),
		verbose: Flag.boolean('verbose').pipe(Flag.withAlias('v'))
	})
);

const create = Command.make(
	'create',
	{
		title: Argument.string('title'),
		priority: Flag.choice('priority', ['low', 'normal', 'high']).pipe(
			Flag.withDefault('normal')
		)
	},
	Effect.fn(function* ({ title, priority }) {
		// 通过生成父命令访问父配置
		const root = yield* tasks;
		if (root.verbose) {
			yield* Console.log(`workspace=${root.workspace} action=create`);
		}
		yield* Console.log(
			`${root.workspace} 中创建了 "${title}",优先级为 ${priority}`
		);
	})
).pipe(
	Command.withDescription('创建任务'),
	Command.withExamples([
		{
			command: 'tasks create "Ship 4.0" --priority high',
			description: '创建高优先级任务'
		}
	])
);

const list = Command.make(
	'list',
	{
		status: Flag.choice('status', ['open', 'done', 'all']).pipe(
			Flag.withDefault('open')
		),
		json: Flag.boolean('json')
	},
	Effect.fn(function* ({ status, json }) {
		const root = yield* tasks;
		if (json) {
			yield* Console.log(
				JSON.stringify({ workspace: root.workspace, status }, null, 2)
			);
		} else {
			yield* Console.log(`列出 ${root.workspace} 中状态为 ${status} 的任务`);
		}
	})
).pipe(Command.withDescription('列出任务'), Command.withAlias('ls'));

tasks.pipe(
	Command.withSubcommands([create, list]),
	Command.run({ version: '1.0.0' }),
	Effect.provide(NodeServices.layer),
	NodeRuntime.runMain
);
// 使用方式: tasks --workspace team-a list --status open
// 使用方式: tasks create "Ship 4.0" --priority high
// 使用方式: tasks ls --json

Grouped Subcommands

分组子命令

typescript
app.pipe(
	Command.withSubcommands([
		init,
		{ group: 'Development', commands: [build, test] },
		{ group: 'Deployment', commands: [deploy, rollback] }
	])
);
typescript
app.pipe(
	Command.withSubcommands([
		init,
		{ group: '开发', commands: [build, test] },
		{ group: '部署', commands: [deploy, rollback] }
	])
);

Dependency Injection

依赖注入

Provide a Layer

提供Layer

typescript
const deploy = Command.make(
	'deploy',
	{
		env: Flag.string('env')
	},
	Effect.fn(function* ({ env }) {
		const fs = yield* FileSystem.FileSystem;
		// ...
	})
).pipe(Command.provide(FileSystemLive));

// Layer can depend on parsed input
Command.provide((config) =>
	config.env === 'local' ? LocalFsLayer : RemoteFsLayer
);
typescript
const deploy = Command.make(
	'deploy',
	{
		env: Flag.string('env')
	},
	Effect.fn(function* ({ env }) {
		const fs = yield* FileSystem.FileSystem;
		// ...
	})
).pipe(Command.provide(FileSystemLive));

// Layer可以依赖解析后的输入
Command.provide((config) =>
	config.env === 'local' ? LocalFsLayer : RemoteFsLayer
);

Provide a Service

提供服务

typescript
Command.provideSync(MyService, makeMyService());
Command.provideEffect(MyService, Effect.succeed(makeMyService()));

// Can depend on parsed input
Command.provideSync(MyService, (config) => makeMyService(config.env));
typescript
Command.provideSync(MyService, makeMyService());
Command.provideEffect(MyService, Effect.succeed(makeMyService()));

// 可以依赖解析后的输入
Command.provideSync(MyService, (config) => makeMyService(config.env));

Running Commands

运行命令

Command.run
is a pipeable combinator that reads args from Stdio. Provide platform services and execute with the runtime:
typescript
import { NodeRuntime, NodeServices } from '@effect/platform-node';
import { Effect } from 'effect';
import { Command, Flag } from 'effect/unstable/cli';

const myCommand = Command.make(
	'myapp',
	{
		name: Flag.string('name')
	},
	Effect.fn(function* ({ name }) {
		yield* Console.log(`Hello, ${name}!`);
	})
);

// Entry point pattern
myCommand.pipe(
	Command.run({ version: '1.0.0' }),
	Effect.provide(NodeServices.layer),
	NodeRuntime.runMain
);
Auto-generates
--help
and
--version
flags.
Command.run
是一个可管道化的组合器,从标准输入读取参数。提供平台服务并通过运行时执行:
typescript
import { NodeRuntime, NodeServices } from '@effect/platform-node';
import { Effect } from 'effect';
import { Command, Flag } from 'effect/unstable/cli';

const myCommand = Command.make(
	'myapp',
	{
		name: Flag.string('name')
	},
	Effect.fn(function* ({ name }) {
		yield* Console.log(`你好,${name}!`);
	})
);

// 入口点模式
myCommand.pipe(
	Command.run({ version: '1.0.0' }),
	Effect.provide(NodeServices.layer),
	NodeRuntime.runMain
);
自动生成
--help
--version
标志。

Testing with Explicit Args

使用显式参数测试

Use
Command.runWith
to pass args directly (useful in tests):
typescript
const run = Command.runWith(myCommand, { version: '1.0.0' });
// run(["--name", "Alice"]) => Effect<void, ...>
使用
Command.runWith
直接传入参数(在测试中很有用):
typescript
const run = Command.runWith(myCommand, { version: '1.0.0' });
// run(["--name", "Alice"]) => Effect<void, ...>

Key Patterns

核心模式

  1. Argument
    = positional,
    Flag
    = named
    — No
    Argument.boolean
    ; use
    Flag.boolean
    for toggles
  2. Handlers use
    Effect.fn
    Effect.fn(function*({ ...config }) { ... })
  3. Parent access via yield
    const root = yield* parentCommand
    inside subcommand handlers
  4. Shared flags
    Command.withSharedFlags
    on parent; only flags allowed (no arguments)
  5. Pipeable
    Command.run
    command.pipe(Command.run({version}), Effect.provide(NodeServices.layer), NodeRuntime.runMain)
  6. Platform services required
    Command.run
    requires
    FileSystem
    ,
    Path
    ,
    Terminal
    ,
    Stdio
    ; provide via
    NodeServices.layer
  7. All combinators are dual — Work both as
    pipe(Flag.withAlias("v"))
    and
    Flag.withAlias(flag, "v")
  1. Argument
    = 位置参数,
    Flag
    = 命名参数
    — 没有
    Argument.boolean
    ;使用
    Flag.boolean
    实现开关功能
  2. 处理函数使用
    Effect.fn
    Effect.fn(function*({ ...config }) { ... })
  3. 通过生成器访问父命令 — 在子命令处理函数中使用
    const root = yield* parentCommand
  4. 共享标志 — 在父命令上使用
    Command.withSharedFlags
    ;仅允许标志(不支持位置参数)
  5. 可管道化的
    Command.run
    command.pipe(Command.run({version}), Effect.provide(NodeServices.layer), NodeRuntime.runMain)
  6. 需要平台服务
    Command.run
    需要
    FileSystem
    Path
    Terminal
    Stdio
    ;通过
    NodeServices.layer
    提供
  7. 所有组合器都是双模式的 — 既可以作为
    pipe(Flag.withAlias("v"))
    使用,也可以作为
    Flag.withAlias(flag, "v")
    使用