diff --git a/.changeset/beige-mice-hide.md b/.changeset/beige-mice-hide.md
new file mode 100644
index 0000000..1da06be
--- /dev/null
+++ b/.changeset/beige-mice-hide.md
@@ -0,0 +1,5 @@
+---
+"@effect/cli": patch
+---
+
+Made `Command`, `Option`, `Args` and `Primitive` pipeable
diff --git a/src/Args.ts b/src/Args.ts
index 60ce109..37ca9d5 100644
--- a/src/Args.ts
+++ b/src/Args.ts
@@ -8,6 +8,7 @@ import type { ValidationError } from "@effect/cli/ValidationError"
import type { Chunk, NonEmptyChunk } from "@effect/data/Chunk"
import type { Either } from "@effect/data/Either"
import type { Option } from "@effect/data/Option"
+import type { Pipeable } from "@effect/data/Pipeable"
import type { NonEmptyReadonlyArray } from "@effect/data/ReadonlyArray"
import type { Effect } from "@effect/io/Effect"
@@ -29,7 +30,7 @@ export type ArgsTypeId = typeof ArgsTypeId
* @since 1.0.0
* @category models
*/
-export interface Args extends Args.Variance {}
+export interface Args extends Args.Variance, Pipeable {}
/**
* @since 1.0.0
diff --git a/src/Command.ts b/src/Command.ts
index bf245de..dc6e43a 100644
--- a/src/Command.ts
+++ b/src/Command.ts
@@ -13,6 +13,7 @@ import type { Either } from "@effect/data/Either"
import type { HashMap } from "@effect/data/HashMap"
import type { HashSet } from "@effect/data/HashSet"
import type { Option } from "@effect/data/Option"
+import type { Pipeable } from "@effect/data/Pipeable"
import type { NonEmptyReadonlyArray } from "@effect/data/ReadonlyArray"
import type { Effect } from "@effect/io/Effect"
@@ -38,7 +39,7 @@ export type CommandTypeId = typeof CommandTypeId
* @since 1.0.0
* @category models
*/
-export interface Command extends Command.Variance {}
+export interface Command extends Command.Variance, Pipeable {}
/**
* @since 1.0.0
diff --git a/src/Options.ts b/src/Options.ts
index baa9c4d..dca4fb2 100644
--- a/src/Options.ts
+++ b/src/Options.ts
@@ -10,6 +10,7 @@ import type { Chunk, NonEmptyChunk } from "@effect/data/Chunk"
import type { Either } from "@effect/data/Either"
import type { HashMap } from "@effect/data/HashMap"
import type { Option } from "@effect/data/Option"
+import type { Pipeable } from "@effect/data/Pipeable"
import type { NonEmptyReadonlyArray } from "@effect/data/ReadonlyArray"
import type { Effect } from "@effect/io/Effect"
@@ -29,7 +30,7 @@ export type OptionsTypeId = typeof OptionsTypeId
* @since 1.0.0
* @category models
*/
-export interface Options extends Options.Variance {}
+export interface Options extends Options.Variance, Pipeable {}
/**
* @since 1.0.0
diff --git a/src/Primitive.ts b/src/Primitive.ts
index eafa0a5..c8e2f4f 100644
--- a/src/Primitive.ts
+++ b/src/Primitive.ts
@@ -4,6 +4,7 @@
import type { Span } from "@effect/cli/HelpDoc/Span"
import * as internal from "@effect/cli/internal/primitive"
import type { Option } from "@effect/data/Option"
+import type { Pipeable } from "@effect/data/Pipeable"
import type { NonEmptyReadonlyArray } from "@effect/data/ReadonlyArray"
import type { Effect } from "@effect/io/Effect"
@@ -37,7 +38,7 @@ export declare namespace Primitive {
* @since 1.0.0
* @category models
*/
- export interface Variance {
+ export interface Variance extends Pipeable {
readonly [PrimitiveTypeId]: {
readonly _A: (_: never) => A
}
diff --git a/src/internal/args.ts b/src/internal/args.ts
index ae90f4b..56e2bd5 100644
--- a/src/internal/args.ts
+++ b/src/internal/args.ts
@@ -12,6 +12,7 @@ import * as Chunk from "@effect/data/Chunk"
import * as Either from "@effect/data/Either"
import { dual } from "@effect/data/Function"
import * as Option from "@effect/data/Option"
+import { pipeArguments } from "@effect/data/Pipeable"
import * as ReadonlyArray from "@effect/data/ReadonlyArray"
import type { NonEmptyReadonlyArray } from "@effect/data/ReadonlyArray"
import * as Effect from "@effect/io/Effect"
@@ -31,6 +32,9 @@ export type Op = Args.Args & Body & {
const proto = {
[ArgsTypeId]: {
_A: (_: never) => _
+ },
+ pipe() {
+ return pipeArguments(this, arguments)
}
}
diff --git a/src/internal/command.ts b/src/internal/command.ts
index 72e6adb..985e46f 100644
--- a/src/internal/command.ts
+++ b/src/internal/command.ts
@@ -21,6 +21,7 @@ import { dual, pipe } from "@effect/data/Function"
import * as HashMap from "@effect/data/HashMap"
import * as HashSet from "@effect/data/HashSet"
import * as Option from "@effect/data/Option"
+import { pipeArguments } from "@effect/data/Pipeable"
import * as ReadonlyArray from "@effect/data/ReadonlyArray"
import type { NonEmptyReadonlyArray } from "@effect/data/ReadonlyArray"
import * as Effect from "@effect/io/Effect"
@@ -41,6 +42,9 @@ const proto = {
[CommandTypeId]: {
_ArgsType: (_: never) => _,
_OptionsType: (_: never) => _
+ },
+ pipe() {
+ return pipeArguments(this, arguments)
}
}
diff --git a/src/internal/options.ts b/src/internal/options.ts
index 691fddd..96f4bf9 100644
--- a/src/internal/options.ts
+++ b/src/internal/options.ts
@@ -16,6 +16,7 @@ import { dual, pipe } from "@effect/data/Function"
import * as HashMap from "@effect/data/HashMap"
import * as Option from "@effect/data/Option"
import * as Order from "@effect/data/Order"
+import { pipeArguments } from "@effect/data/Pipeable"
import type { Predicate } from "@effect/data/Predicate"
import * as RA from "@effect/data/ReadonlyArray"
import * as Effect from "@effect/io/Effect"
@@ -35,6 +36,9 @@ export type Op = Options.Options & Body &
const proto = {
[OptionsTypeId]: {
_A: (_: never) => _
+ },
+ pipe() {
+ return pipeArguments(this, arguments)
}
}
diff --git a/src/internal/primitive.ts b/src/internal/primitive.ts
index d698d70..03cee9e 100644
--- a/src/internal/primitive.ts
+++ b/src/internal/primitive.ts
@@ -3,6 +3,7 @@ import * as span from "@effect/cli/internal/helpDoc/span"
import type * as Primitive from "@effect/cli/Primitive"
import { dual, pipe } from "@effect/data/Function"
import * as Option from "@effect/data/Option"
+import { pipeArguments } from "@effect/data/Pipeable"
import type { NonEmptyReadonlyArray } from "@effect/data/ReadonlyArray"
import * as Effect from "@effect/io/Effect"
@@ -16,6 +17,9 @@ export const PrimitiveTypeId: Primitive.PrimitiveTypeId = Symbol.for(
const proto = {
[PrimitiveTypeId]: {
_A: (_: never) => _
+ },
+ pipe() {
+ return pipeArguments(this, arguments)
}
}
diff --git a/test/Command.ts b/test/Command.ts
index 213cfbc..4f966f2 100644
--- a/test/Command.ts
+++ b/test/Command.ts
@@ -64,7 +64,7 @@ describe.concurrent("Command", () => {
Effect.gen(function*($) {
const config = CliConfig.defaultConfig
const args = ["log"]
- const command = pipe(Command.make("remote"), Command.orElse(Command.make("log")))
+ const command = Command.make("remote").pipe(Command.orElse(Command.make("log")))
const result = yield* $(Command.parse(command, args, config))
const expected = { name: "log", options: void 0, args: void 0 }
expect(result).toEqual(CommandDirective.userDefined([], expected))
@@ -97,8 +97,7 @@ describe.concurrent("Command", () => {
}))
describe.concurrent("Subcommands - no options or arguments", () => {
- const git = pipe(
- Command.make("git", { options: Options.alias(Options.boolean("verbose"), "v") }),
+ const git = Command.make("git", { options: Options.boolean("verbose").pipe(Options.alias("v")) }).pipe(
Command.subcommands([Command.make("remote"), Command.make("log")])
)
@@ -155,13 +154,11 @@ describe.concurrent("Command", () => {
})
describe.concurrent("Subcommands - with options and arguments", () => {
- const rebaseOptions = pipe(
- Options.boolean("i"),
- Options.zip(Options.withDefault(Options.text("empty"), "drop"))
+ const rebaseOptions = Options.boolean("i").pipe(
+ Options.zip(Options.text("empty").pipe(Options.withDefault("drop")))
)
const rebaseArgs = Args.zip(Args.text(), Args.text())
- const git = pipe(
- Command.make("git"),
+ const git = Command.make("git").pipe(
Command.subcommands([
Command.make("rebase", { options: rebaseOptions, args: rebaseArgs })
])
@@ -212,11 +209,9 @@ describe.concurrent("Command", () => {
})
describe.concurrent("Subcommands - nested", () => {
- const command = pipe(
- Command.make("command"),
+ const command = Command.make("command").pipe(
Command.subcommands([
- pipe(
- Command.make("sub"),
+ Command.make("sub").pipe(
Command.subcommands([Command.make("subsub", { options: Options.boolean("i"), args: Args.text() })])
)
])
diff --git a/test/Options.ts b/test/Options.ts
index 64d55a4..bb27227 100644
--- a/test/Options.ts
+++ b/test/Options.ts
@@ -68,7 +68,7 @@ describe.concurrent("Options", () => {
it.effect("validates a text option", () =>
Effect.gen(function*($) {
const config = CliConfig.defaultConfig
- const option = Options.alias(Options.text("firstName"), "f")
+ const option = Options.text("firstName").pipe(Options.alias("f"))
const result = yield* $(Options.validate(option, ["--firstName", "John"], config))
expect(result).toEqual([[], "John"])
}))
@@ -76,7 +76,7 @@ describe.concurrent("Options", () => {
it.effect("validates a text option with an alternative format", () =>
Effect.gen(function*($) {
const config = CliConfig.defaultConfig
- const option = Options.alias(Options.text("firstName"), "f")
+ const option = Options.text("firstName").pipe(Options.alias("f"))
const result = yield* $(Options.validate(option, ["--firstName=John"], config))
expect(result).toEqual([[], "John"])
}))
@@ -84,7 +84,7 @@ describe.concurrent("Options", () => {
it.effect("validates a text option with an alias", () =>
Effect.gen(function*($) {
const config = CliConfig.defaultConfig
- const option = Options.alias(Options.text("firstName"), "f")
+ const option = Options.text("firstName").pipe(Options.alias("f"))
const result = yield* $(Options.validate(option, ["-f", "John"], config))
expect(result).toEqual([[], "John"])
}))
@@ -100,7 +100,7 @@ describe.concurrent("Options", () => {
it.effect("validates an option and returns the remainder", () =>
Effect.gen(function*($) {
const config = CliConfig.defaultConfig
- const option = Options.alias(Options.text("firstName"), "f")
+ const option = Options.text("firstName").pipe(Options.alias("f"))
const args = ["--firstName", "John", "--lastName", "Doe"]
const result = yield* $(Options.validate(option, args, config))
expect(result).toEqual([["--lastName", "Doe"], "John"])
@@ -109,7 +109,7 @@ describe.concurrent("Options", () => {
it.effect("validates an option and returns the remainder with different ordering", () =>
Effect.gen(function*($) {
const config = CliConfig.defaultConfig
- const option = Options.alias(Options.text("firstName"), "f")
+ const option = Options.text("firstName").pipe(Options.alias("f"))
const args = ["--bar", "baz", "--firstName", "John", "--lastName", "Doe"]
const result = yield* $(Options.validate(option, args, config))
expect(result).toEqual([["--bar", "baz", "--lastName", "Doe"], "John"])
@@ -118,7 +118,7 @@ describe.concurrent("Options", () => {
it.effect("does not validate when no valid values are passed", () =>
Effect.gen(function*($) {
const config = CliConfig.defaultConfig
- const option = Options.alias(Options.text("firstName"), "f")
+ const option = Options.text("firstName").pipe(Options.alias("f"))
const args = ["--lastName", "Doe"]
const result = yield* $(Effect.either(Options.validate(option, args, config)))
expect(result).toEqual(Either.left(ValidationError.missingValue(HelpDoc.p(Span.error(
@@ -129,7 +129,7 @@ describe.concurrent("Options", () => {
it.effect("does not validate when an option is passed without a corresponding value", () =>
Effect.gen(function*($) {
const config = CliConfig.defaultConfig
- const option = Options.alias(Options.text("firstName"), "f")
+ const option = Options.text("firstName").pipe(Options.alias("f"))
const args = ["--firstName"]
const result = yield* $(Effect.either(Options.validate(option, args, config)))
expect(result).toEqual(Either.left(ValidationError.invalidValue(HelpDoc.p(
@@ -184,7 +184,7 @@ describe.concurrent("Options", () => {
it.effect("validates an unsupplied optional option", () =>
Effect.gen(function*($) {
const config = CliConfig.defaultConfig
- const option = Options.optional(Options.integer("age"))
+ const option = Options.integer("age").pipe(Options.optional)
const result = yield* $(Options.validate(option, [], config))
expect(result).toEqual([[], Option.none()])
}))
@@ -192,7 +192,7 @@ describe.concurrent("Options", () => {
it.effect("validates an unsupplied optional option with remainder", () =>
Effect.gen(function*($) {
const config = CliConfig.defaultConfig
- const option = Options.optional(Options.integer("age"))
+ const option = Options.integer("age").pipe(Options.optional)
const args = ["--bar", "baz"]
const result = yield* $(Options.validate(option, args, config))
expect(result).toEqual([args, Option.none()])
@@ -201,7 +201,7 @@ describe.concurrent("Options", () => {
it.effect("validates a supplied optional option", () =>
Effect.gen(function*($) {
const config = CliConfig.defaultConfig
- const option = Options.optional(Options.integer("age"))
+ const option = Options.integer("age").pipe(Options.optional)
const args = ["--age", "20"]
const result = yield* $(Options.validate(option, args, config))
expect(result).toEqual([[], Option.some(20)])
@@ -210,7 +210,7 @@ describe.concurrent("Options", () => {
it.effect("validates a supplied optional option with remainder", () =>
Effect.gen(function*($) {
const config = CliConfig.defaultConfig
- const option = Options.optional(Options.integer("age"))
+ const option = Options.integer("age").pipe(Options.optional)
const args = ["--firstName", "John", "--age", "20", "--lastName", "Doe"]
const result = yield* $(Options.validate(option, args, config))
expect(result).toEqual([["--firstName", "John", "--lastName", "Doe"], Option.some(20)])
@@ -245,7 +245,7 @@ describe.concurrent("Options", () => {
it.effect("validate provides a suggestion if a provided option with a default is close to a specified option", () =>
Effect.gen(function*($) {
const config = CliConfig.defaultConfig
- const option = Options.withDefault(Options.text("firstName"), "Jack")
+ const option = Options.text("firstName").pipe(Options.withDefault("Jack"))
const args = ["--firstme", "Alice"]
const result = yield* $(Effect.flip(Options.validate(option, args, config)))
expect(result).toEqual(ValidationError.invalidValue(HelpDoc.p(Span.error(
@@ -300,8 +300,7 @@ describe.concurrent("Options", () => {
it.effect("orElse - invalid option provided with a default", () =>
Effect.gen(function*($) {
const config = CliConfig.defaultConfig
- const option = pipe(
- Options.integer("min"),
+ const option = Options.integer("min").pipe(
Options.orElse(Options.integer("max")),
Options.withDefault(0)
)