Help us shape the future of Go! Take the 2026 Go Developer Survey

cli

package
v2.3.124 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 4, 2026 License: Apache-2.0 Imports: 24 Imported by: 0

README

CLI Package - Functional Wrappers for urfave/cli/v3

This package provides functional programming wrappers for the github.com/urfave/cli/v3 library, enabling Effect-based command actions and type-safe flag handling through Prisms.

Features

1. Effect-Based Command Actions

Transform CLI command actions into composable Effects that follow functional programming principles.

Key Functions
  • ToAction(effect CommandEffect) func(context.Context, *C.Command) error

    • Converts a CommandEffect into a standard urfave/cli Action function
    • Enables Effect-based command handlers to work with cli/v3 framework
  • FromAction(action func(context.Context, *C.Command) error) CommandEffect

    • Lifts existing cli/v3 action handlers into the Effect type
    • Allows gradual migration to functional style
  • MakeCommand(name, usage string, flags []C.Flag, effect CommandEffect) *C.Command

    • Creates a new Command with an Effect-based action
    • Convenience function combining command creation with Effect conversion
  • MakeCommandWithSubcommands(...) *C.Command

    • Creates a Command with subcommands and an Effect-based action
Example Usage
import (
    "context"
    
    E "github.com/IBM/fp-go/v2/effect"
    F "github.com/IBM/fp-go/v2/function"
    R "github.com/IBM/fp-go/v2/result"
    "github.com/IBM/fp-go/v2/cli"
    C "github.com/urfave/cli/v3"
)

// Define an Effect-based command action
processEffect := func(cmd *C.Command) E.Thunk[F.Void] {
    return func(ctx context.Context) E.IOResult[F.Void] {
        return func() R.Result[F.Void] {
            input := cmd.String("input")
            // Process input...
            return R.Of(F.Void{})
        }
    }
}

// Create command with Effect
command := cli.MakeCommand(
    "process",
    "Process input files",
    []C.Flag{
        &C.StringFlag{Name: "input", Usage: "Input file path"},
    },
    processEffect,
)

// Or convert existing action to Effect
existingAction := func(ctx context.Context, cmd *C.Command) error {
    // Existing logic...
    return nil
}
effect := cli.FromAction(existingAction)
2. Flag Type Prisms

Type-safe extraction and manipulation of CLI flags using Prisms from the optics package.

Available Prisms
  • StringFlagPrism() - Extract *C.StringFlag from C.Flag
  • IntFlagPrism() - Extract *C.IntFlag from C.Flag
  • BoolFlagPrism() - Extract *C.BoolFlag from C.Flag
  • Float64FlagPrism() - Extract *C.Float64Flag from C.Flag
  • DurationFlagPrism() - Extract *C.DurationFlag from C.Flag
  • TimestampFlagPrism() - Extract *C.TimestampFlag from C.Flag
  • StringSliceFlagPrism() - Extract *C.StringSliceFlag from C.Flag
  • IntSliceFlagPrism() - Extract *C.IntSliceFlag from C.Flag
  • Float64SliceFlagPrism() - Extract *C.Float64SliceFlag from C.Flag
  • UintFlagPrism() - Extract *C.UintFlag from C.Flag
  • Uint64FlagPrism() - Extract *C.Uint64Flag from C.Flag
  • Int64FlagPrism() - Extract *C.Int64Flag from C.Flag
Example Usage
import (
    O "github.com/IBM/fp-go/v2/option"
    "github.com/IBM/fp-go/v2/cli"
    C "github.com/urfave/cli/v3"
)

// Extract a StringFlag from a Flag interface
var flag C.Flag = &C.StringFlag{Name: "input", Value: "default"}
prism := cli.StringFlagPrism()

// Safe extraction returns Option
result := prism.GetOption(flag)
if O.IsSome(result) {
    strFlag := O.MonadFold(result, 
        func() *C.StringFlag { return nil },
        func(f *C.StringFlag) *C.StringFlag { return f },
    )
    // Use strFlag...
}

// Type mismatch returns None
var intFlag C.Flag = &C.IntFlag{Name: "count"}
result = prism.GetOption(intFlag)  // Returns None

// Convert back to Flag
strFlag := &C.StringFlag{Name: "output"}
flag = prism.ReverseGet(strFlag)

Type Definitions

CommandEffect
type CommandEffect = E.Effect[*C.Command, F.Void]

A CommandEffect represents a CLI command action as an Effect. It takes a *C.Command as context and produces a result wrapped in the Effect monad.

The Effect structure is:

func(*C.Command) -> func(context.Context) -> func() -> Result[Void]

This allows for:

  • Composability: Effects can be composed using standard functional combinators
  • Testability: Pure functions are easier to test
  • Error Handling: Errors are explicitly represented in the Result type
  • Context Management: Context flows naturally through the Effect

Benefits

1. Functional Composition

Effects can be composed using standard functional programming patterns:

import (
    F "github.com/IBM/fp-go/v2/function"
    RRIOE "github.com/IBM/fp-go/v2/context/readerreaderioresult"
)

// Compose multiple effects
validateInput := func(cmd *C.Command) E.Thunk[F.Void] { /* ... */ }
processData := func(cmd *C.Command) E.Thunk[F.Void] { /* ... */ }
saveResults := func(cmd *C.Command) E.Thunk[F.Void] { /* ... */ }

// Chain effects together
pipeline := F.Pipe3(
    validateInput,
    RRIOE.Chain(func(F.Void) E.Effect[*C.Command, F.Void] { return processData }),
    RRIOE.Chain(func(F.Void) E.Effect[*C.Command, F.Void] { return saveResults }),
)
2. Type Safety

Prisms provide compile-time type safety when working with flags:

// Type-safe flag extraction
flags := []C.Flag{
    &C.StringFlag{Name: "input"},
    &C.IntFlag{Name: "count"},
}

for _, flag := range flags {
    // Safe extraction with pattern matching
    O.MonadFold(
        cli.StringFlagPrism().GetOption(flag),
        func() { /* Not a string flag */ },
        func(sf *C.StringFlag) { /* Handle string flag */ },
    )
}
3. Error Handling

Errors are explicitly represented in the Result type:

effect := func(cmd *C.Command) E.Thunk[F.Void] {
    return func(ctx context.Context) E.IOResult[F.Void] {
        return func() R.Result[F.Void] {
            if err := validateInput(cmd); err != nil {
                return R.Left[F.Void](err)  // Explicit error
            }
            return R.Of(F.Void{})  // Success
        }
    }
}
4. Testability

Pure functions are easier to test:

func TestCommandEffect(t *testing.T) {
    cmd := &C.Command{Name: "test"}
    effect := myCommandEffect(cmd)
    
    // Execute effect
    result := effect(context.Background())()
    
    // Assert on result
    assert.True(t, R.IsRight(result))
}

Migration Guide

From Standard Actions to Effects

Before:

command := &C.Command{
    Name: "process",
    Action: func(ctx context.Context, cmd *C.Command) error {
        input := cmd.String("input")
        // Process...
        return nil
    },
}

After:

effect := func(cmd *C.Command) E.Thunk[F.Void] {
    return func(ctx context.Context) E.IOResult[F.Void] {
        return func() R.Result[F.Void] {
            input := cmd.String("input")
            // Process...
            return R.Of(F.Void{})
        }
    }
}

command := cli.MakeCommand("process", "Process files", flags, effect)
Gradual Migration

You can mix both styles during migration:

// Wrap existing action
existingAction := func(ctx context.Context, cmd *C.Command) error {
    // Legacy code...
    return nil
}

// Use as Effect
effect := cli.FromAction(existingAction)
command := cli.MakeCommand("legacy", "Legacy command", flags, effect)

See Also

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ApplyCommand

func ApplyCommand() *C.Command

func BindCommand

func BindCommand() *C.Command

func BoolFlagPrism added in v2.2.20

func BoolFlagPrism() P.Prism[C.Flag, *C.BoolFlag]

BoolFlagPrism creates a Prism for extracting a BoolFlag from a Flag. This provides a type-safe way to work with boolean flags, handling type mismatches gracefully through the Option type.

Returns

  • A Prism[C.Flag, *C.BoolFlag] for safe BoolFlag extraction

Example Usage

prism := BoolFlagPrism()

// Extract BoolFlag from Flag
var flag C.Flag = &C.BoolFlag{Name: "verbose", Value: true}
result := prism.GetOption(flag)  // Some(*C.BoolFlag{...})

func Commands

func Commands() []*C.Command

func ContextReaderIOEitherCommand

func ContextReaderIOEitherCommand() *C.Command

func DICommand

func DICommand() *C.Command

func DurationFlagPrism added in v2.2.20

func DurationFlagPrism() P.Prism[C.Flag, *C.DurationFlag]

DurationFlagPrism creates a Prism for extracting a DurationFlag from a Flag. This provides a type-safe way to work with duration flags, handling type mismatches gracefully through the Option type.

Returns

  • A Prism[C.Flag, *C.DurationFlag] for safe DurationFlag extraction

Example Usage

prism := DurationFlagPrism()

// Extract DurationFlag from Flag
var flag C.Flag = &C.DurationFlag{Name: "timeout", Value: 30 * time.Second}
result := prism.GetOption(flag)  // Some(*C.DurationFlag{...})

func EitherCommand

func EitherCommand() *C.Command

func Float64FlagPrism added in v2.2.20

func Float64FlagPrism() P.Prism[C.Flag, *C.Float64Flag]

Float64FlagPrism creates a Prism for extracting a Float64Flag from a Flag. This provides a type-safe way to work with float64 flags, handling type mismatches gracefully through the Option type.

Returns

  • A Prism[C.Flag, *C.Float64Flag] for safe Float64Flag extraction

Example Usage

prism := Float64FlagPrism()

// Extract Float64Flag from Flag
var flag C.Flag = &C.Float64Flag{Name: "ratio", Value: 0.5}
result := prism.GetOption(flag)  // Some(*C.Float64Flag{...})

func Float64SliceFlagPrism added in v2.2.20

func Float64SliceFlagPrism() P.Prism[C.Flag, *C.Float64SliceFlag]

Float64SliceFlagPrism creates a Prism for extracting a Float64SliceFlag from a Flag. This provides a type-safe way to work with float64 slice flags, handling type mismatches gracefully through the Option type.

Returns

  • A Prism[C.Flag, *C.Float64SliceFlag] for safe Float64SliceFlag extraction

Example Usage

prism := Float64SliceFlagPrism()

// Extract Float64SliceFlag from Flag
var flag C.Flag = &C.Float64SliceFlag{Name: "ratios"}
result := prism.GetOption(flag)  // Some(*C.Float64SliceFlag{...})

func IOCommand

func IOCommand() *C.Command

func IOEitherCommand

func IOEitherCommand() *C.Command

func IOOptionCommand

func IOOptionCommand() *C.Command

func IdentityCommand

func IdentityCommand() *C.Command

func Int64FlagPrism added in v2.2.20

func Int64FlagPrism() P.Prism[C.Flag, *C.Int64Flag]

Int64FlagPrism creates a Prism for extracting an Int64Flag from a Flag. This provides a type-safe way to work with int64 flags, handling type mismatches gracefully through the Option type.

Returns

  • A Prism[C.Flag, *C.Int64Flag] for safe Int64Flag extraction

Example Usage

prism := Int64FlagPrism()

// Extract Int64Flag from Flag
var flag C.Flag = &C.Int64Flag{Name: "offset"}
result := prism.GetOption(flag)  // Some(*C.Int64Flag{...})

func IntFlagPrism added in v2.2.20

func IntFlagPrism() P.Prism[C.Flag, *C.IntFlag]

IntFlagPrism creates a Prism for extracting an IntFlag from a Flag. This provides a type-safe way to work with integer flags, handling type mismatches gracefully through the Option type.

Returns

  • A Prism[C.Flag, *C.IntFlag] for safe IntFlag extraction

Example Usage

prism := IntFlagPrism()

// Extract IntFlag from Flag
var flag C.Flag = &C.IntFlag{Name: "count", Value: 10}
result := prism.GetOption(flag)  // Some(*C.IntFlag{...})

func IntSliceFlagPrism added in v2.2.20

func IntSliceFlagPrism() P.Prism[C.Flag, *C.IntSliceFlag]

IntSliceFlagPrism creates a Prism for extracting an IntSliceFlag from a Flag. This provides a type-safe way to work with int slice flags, handling type mismatches gracefully through the Option type.

Returns

  • A Prism[C.Flag, *C.IntSliceFlag] for safe IntSliceFlag extraction

Example Usage

prism := IntSliceFlagPrism()

// Extract IntSliceFlag from Flag
var flag C.Flag = &C.IntSliceFlag{Name: "ports"}
result := prism.GetOption(flag)  // Some(*C.IntSliceFlag{...})

func LensCommand

func LensCommand() *C.Command

LensCommand creates the CLI command for lens generation.

Two modes are supported:

  1. Annotation mode (default): scans Go files in --dir for structs annotated with "fp-go:Lens" and generates lenses for them.

  2. Type-name mode (--type flag, following the stringer convention): accepts a comma-separated list of struct names and optional package patterns as positional arguments (default "."). Uses go/packages for full type resolution — generics, external field types, and struct tags are all handled correctly without requiring source annotations.

deprecated

func MakeCommand added in v2.2.20

func MakeCommand(
	name string,
	usage string,
	flags []C.Flag,
	effect CommandEffect,
) *C.Command

MakeCommand creates a new Command with an Effect-based action. This is a convenience function that combines command creation with Effect conversion.

Parameters

  • name: The command name
  • usage: The command usage description
  • flags: The command flags
  • effect: The CommandEffect to use as the action

Returns

  • A *C.Command configured with the Effect-based action

Example Usage

cmd := MakeCommand(
    "process",
    "Process data files",
    []C.Flag{
        &C.StringFlag{Name: "input", Usage: "Input file"},
    },
    func(cmd *C.Command) E.Thunk[F.Void] {
        return func(ctx context.Context) E.IOResult[F.Void] {
            return func() R.Result[F.Void] {
                input := cmd.String("input")
                // Process input...
                return R.Of(F.Void{})
            }
        }
    },
)

func MakeCommandWithSubcommands added in v2.2.20

func MakeCommandWithSubcommands(
	name string,
	usage string,
	flags []C.Flag,
	commands []*C.Command,
	effect CommandEffect,
) *C.Command

MakeCommandWithSubcommands creates a new Command with subcommands and an Effect-based action.

Parameters

  • name: The command name
  • usage: The command usage description
  • flags: The command flags
  • commands: The subcommands
  • effect: The CommandEffect to use as the action

Returns

  • A *C.Command configured with subcommands and the Effect-based action

Example Usage

cmd := MakeCommandWithSubcommands(
    "app",
    "Application commands",
    []C.Flag{},
    []*C.Command{subCmd1, subCmd2},
    defaultEffect,
)

func OptionCommand

func OptionCommand() *C.Command

func PipeCommand

func PipeCommand() *C.Command

func ReaderCommand

func ReaderCommand() *C.Command

func ReaderIOEitherCommand

func ReaderIOEitherCommand() *C.Command

func StringFlagPrism added in v2.2.20

func StringFlagPrism() P.Prism[C.Flag, *C.StringFlag]

StringFlagPrism creates a Prism for extracting a StringFlag from a Flag. This provides a type-safe way to work with string flags, handling type mismatches gracefully through the Option type.

The prism's GetOption attempts to cast a Flag to *C.StringFlag. If the cast succeeds, it returns Some(*C.StringFlag); if it fails, it returns None.

The prism's ReverseGet converts a *C.StringFlag back to a Flag.

Returns

  • A Prism[C.Flag, *C.StringFlag] for safe StringFlag extraction

Example Usage

prism := StringFlagPrism()

// Extract StringFlag from Flag
var flag C.Flag = &C.StringFlag{Name: "input", Value: "default"}
result := prism.GetOption(flag)  // Some(*C.StringFlag{...})

// Type mismatch returns None
var intFlag C.Flag = &C.IntFlag{Name: "count"}
result = prism.GetOption(intFlag)  // None[*C.StringFlag]()

// Convert back to Flag
strFlag := &C.StringFlag{Name: "output"}
flag = prism.ReverseGet(strFlag)

func StringSliceFlagPrism added in v2.2.20

func StringSliceFlagPrism() P.Prism[C.Flag, *C.StringSliceFlag]

StringSliceFlagPrism creates a Prism for extracting a StringSliceFlag from a Flag. This provides a type-safe way to work with string slice flags, handling type mismatches gracefully through the Option type.

Returns

  • A Prism[C.Flag, *C.StringSliceFlag] for safe StringSliceFlag extraction

Example Usage

prism := StringSliceFlagPrism()

// Extract StringSliceFlag from Flag
var flag C.Flag = &C.StringSliceFlag{Name: "tags"}
result := prism.GetOption(flag)  // Some(*C.StringSliceFlag{...})

func TimestampFlagPrism added in v2.2.20

func TimestampFlagPrism() P.Prism[C.Flag, *C.TimestampFlag]

TimestampFlagPrism creates a Prism for extracting a TimestampFlag from a Flag. This provides a type-safe way to work with timestamp flags, handling type mismatches gracefully through the Option type.

Returns

  • A Prism[C.Flag, *C.TimestampFlag] for safe TimestampFlag extraction

Example Usage

prism := TimestampFlagPrism()

// Extract TimestampFlag from Flag
var flag C.Flag = &C.TimestampFlag{Name: "created"}
result := prism.GetOption(flag)  // Some(*C.TimestampFlag{...})

func ToAction added in v2.2.20

func ToAction(effect CommandEffect) func(context.Context, *C.Command) error

ToAction converts a CommandEffect into a standard urfave/cli Action function. This allows Effect-based command handlers to be used with the cli/v3 framework.

The conversion process:

  1. Takes the Effect which expects a *C.Command context
  2. Executes it with the provided command
  3. Runs the resulting IO operation
  4. Converts the Result to either nil (success) or error (failure)

Parameters

  • effect: The CommandEffect to convert

Returns

  • A function compatible with C.Command.Action signature

Example Usage

effect := func(cmd *C.Command) E.Thunk[F.Void] {
    return func(ctx context.Context) E.IOResult[F.Void] {
        return func() R.Result[F.Void] {
            // Command logic here
            return R.Of(F.Void{})
        }
    }
}
action := ToAction(effect)
command := &C.Command{
    Name: "example",
    Action: action,
}

func TupleCommand

func TupleCommand() *C.Command

func Uint64FlagPrism added in v2.2.20

func Uint64FlagPrism() P.Prism[C.Flag, *C.Uint64Flag]

Uint64FlagPrism creates a Prism for extracting a Uint64Flag from a Flag. This provides a type-safe way to work with uint64 flags, handling type mismatches gracefully through the Option type.

Returns

  • A Prism[C.Flag, *C.Uint64Flag] for safe Uint64Flag extraction

Example Usage

prism := Uint64FlagPrism()

// Extract Uint64Flag from Flag
var flag C.Flag = &C.Uint64Flag{Name: "size"}
result := prism.GetOption(flag)  // Some(*C.Uint64Flag{...})

func UintFlagPrism added in v2.2.20

func UintFlagPrism() P.Prism[C.Flag, *C.UintFlag]

UintFlagPrism creates a Prism for extracting a UintFlag from a Flag. This provides a type-safe way to work with unsigned integer flags, handling type mismatches gracefully through the Option type.

Returns

  • A Prism[C.Flag, *C.UintFlag] for safe UintFlag extraction

Example Usage

prism := UintFlagPrism()

// Extract UintFlag from Flag
var flag C.Flag = &C.UintFlag{Name: "workers", Value: 4}
result := prism.GetOption(flag)  // Some(*C.UintFlag{...})

Types

type CommandEffect added in v2.2.20

type CommandEffect = E.Effect[*C.Command, F.Void]

CommandEffect represents a CLI command action as an Effect. The Effect takes a *C.Command as context and produces a result.

func FromAction added in v2.2.20

func FromAction(action func(context.Context, *C.Command) error) CommandEffect

FromAction converts a standard urfave/cli Action function into a CommandEffect. This allows existing cli/v3 action handlers to be lifted into the Effect type.

The conversion process:

  1. Takes a standard action function (context.Context, *C.Command) -> error
  2. Wraps it in the Effect structure
  3. Converts the error result to a Result type

Parameters

  • action: The standard cli/v3 action function to convert

Returns

  • A CommandEffect that wraps the original action

Example Usage

standardAction := func(ctx context.Context, cmd *C.Command) error {
    // Existing command logic
    return nil
}
effect := FromAction(standardAction)
// Now can be composed with other Effects

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL