SkillAgentSearch skills...

FluentArgs

FluentArgs is a library to parse command line arguments. It focuses on a very simple API and strong typing. It is able to generate a help view and proper error messages.

Install / Use

/learn @kutoga/FluentArgs
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Build Status

FluentArgs: Fluent Argument Parsing for .NET

<strong> Version: 0.9.7 </strong>

FluentArgs Logo

FluentArgs is an easy-to-use library that provides command line argument parsing. For all parameters it is possible to provide meta information (description, examples etc.) which might be used to auto-generate a simple help for the final application.

Why FluentArgs?

The API is optimized to be as readable and type-safe as possible. Therefore, anyone can learn how to use this library in just a few minutes.

How to install

Package Manager:

PM> Install-Package FluentArgs

.NET CLI:

> dotnet add package FluentArgs

Paket CLI:

> paket add FluentArgs

💡 Example: Parse simple arguments and flags

Given you want a program which supports png to jpeg conversion and you want to support calls like these:

  • myapp -i image.png -o image.jpeg -q 100
  • myapp --input image.png --quality 50 --output image.jpeg
  • myapp --input=image.png -q=50 --output image.jpeg
  • etc.

There's the code:

namespace Example
{
    using System;
    using System.Threading.Tasks;
    using FluentArgs;

    public static class Program
    {
        public static void Main(string[] args)
        {
            FluentArgsBuilder.New()
                .Parameter("-i", "--input").IsRequired()
                .Parameter("-o", "--output").IsRequired()
                .Parameter<ushort>("-q", "--quality")
                    .WithValidation(n => n >= 0 && n <= 100)
                    .IsOptionalWithDefault(50)
                .Call(quality => outputFile => inputFile =>
                {
                    /* ... */
                    Console.WriteLine($"Convert {inputFile} to {outputFile} with quality {quality}...");
                    /* ... */
                })
                .Parse(args);
        }
    }
}

You might wonder why the order of parameters for the Call-method are inverted. This is due to a limitation of the C#-programming language: If the order should be reversed, the number of parameters has to be limited to a fixed number. At least it is not obvious how something like variadic templates can be implemented.

You want to have a detailed help? Just annotate all parameters and call myapp -h or myapp --help. The help flag is added by the DefaultConfigs...-call. As you can see later, it is possible to disable the help flag, to use a different help flag name or to customize the help output. It is also possible use async code.

In general it is recommended to add DefaultConfigs() to the parser: It adds the help flags (which still might be overwritten) and some additional validations (see Example: Advanced configuration).

namespace Example
{
    using System;
    using System.Threading.Tasks;
    using FluentArgs;

    public static class Program
    {
        public static Task Main(string[] args)
        {
            return FluentArgsBuilder.New()
                .DefaultConfigsWithAppDescription("An app to convert png files to jpg files.")
                .Parameter("-i", "--input")
                    .WithDescription("Input png file")
                    .WithExamples("input.png")
                    .IsRequired()
                .Parameter("-o", "--output")
                    .WithDescription("Output jpg file")
                    .WithExamples("output.jpg")
                    .IsRequired()
                .Parameter<ushort>("-q", "--quality")
                    .WithDescription("Quality of the conversion")
                    .WithValidation(n => n >= 0 && n <= 100)
                    .IsOptionalWithDefault(50)
                .Call(quality => outputFile => inputFile =>
                {
                    /* ... */
                    Console.WriteLine($"Convert {inputFile} to {outputFile} with quality {quality}...");
                    /* ... */
                    return Task.CompletedTask;
                })
                .ParseAsync(args);
        }
    }
}

💡 Example: Parse positional and remaining arguments

Positional arguments without an explicit name might be used if the context defines their meaning. E.g. find --type f ./my_directory shall be parsed. An equivalent call is find ./my_directory --type f. The source directory is a positional argument.

Such arguments can be defined after all simple arguments and flags are defined:

<details> <summary>📃 Click here to see the code</summary>
namespace Example
{
    using System;
    using System.Threading.Tasks;
    using FluentArgs;

    public static class Program
    {
        public static Task Main(string[] args)
        {
            return FluentArgsBuilder.New()
                .DefaultConfigsWithAppDescription("List files and / or subdirectories")
                .Parameter<char>("-t", "--type")
                    .WithDescription("List entry type (e.g. f=file, d=directory)")
                    .IsOptionalWithDefault('d')
                .PositionalArgument()
                    .WithDescription("The source directory")
                    .IsRequired()
                .Call(sourceDirectory => type =>
                {
                    /* ... */
                    Console.WriteLine($"Find all {type} filesystem entries in the directory {sourceDirectory}");
                    /* ... */
                    return Task.CompletedTask;
                })
                .ParseAsync(args);
        }
    }
}
</details>

It is no problem to define multiple positional arguments:

<details> <summary>📃 Click here to see the code</summary>
namespace Example
{
    using System;
    using System.Threading.Tasks;
    using FluentArgs;

    public static class Program
    {
        public static Task Main(string[] args)
        {
            return FluentArgsBuilder.New()
                .PositionalArgument().IsRequired()
                .PositionalArgument<int>().IsRequired()
                .PositionalArgument<bool>().IsOptionalWithDefault(false)
                .Call(p3 => p2 => p1 =>
                {
                    /* ... */
                    Console.WriteLine($"First parameter: {p1}");
                    Console.WriteLine($"Second parameter: {p2}");
                    Console.WriteLine($"Third parameter: {p3}");
                    /* ... */
                    return Task.CompletedTask;
                })
                .ParseAsync(args);
        }
    }
}
</details>

It is also possible to parse all remaining arguments. E.g., if calls like rm -f file1 file2 file should be supported (with an arbitrary number of files), this can be achieved by the following code:

<details> <summary>📃 Click here to see the code</summary>
namespace Example
{
    using System;
    using System.Threading.Tasks;
    using FluentArgs;

    public static class Program
    {
        public static Task Main(string[] args)
        {
            return FluentArgsBuilder.New()
                .Flag("-f")
                    .WithDescription("Force to delete a file")
                .LoadRemainingArguments()
                    .WithDescription("All files which should be deleted")
                .Call(files => f =>
                {
                    /* ... */
                    Console.WriteLine($"f-Flag: {f}");
                    Console.WriteLine($"Files: {string.Join(", ", files)}");
                    /* ... */
                    return Task.CompletedTask;
                })
                .ParseAsync(args);
        }
    }
}
</details>

💡 Example: Parse conditional arguments / commands

Conditional arguments allow to control the argument parsing flow. E.g., the requirements for our CLI is the following:

  • If the flag -v (or --version) is given, the program version should be print (independent of all other parameters)
  • If the flag -u (or --update) is given, an update should be downloaded and installed
    • An optional parameter -s (or --source) defines the update source
  • Otherwise the program takes it first two positional arguments and prints their sum: myapp 1 2 should print 1+2=3

The following code fulfills this specifications:

<details> <summary>📃 Click here to see the code</summary>
namespace Example
{
    using System;
    using System.Threading.Tasks;
    using FluentArgs;

    public static class Program
    {
        public static void Main(string[] args)
        {
            FluentArgsBuilder.New()
                .WithApplicationDescription("A simple calculator: add two numbers")
                .Given.Flag("-v", "--version").Then(() =>
                {
                    /* ... */
                    Console.WriteLine("Program version: 2.0");
                    /* ... */
                })
                .Given.Flag("-u", "--update").Then(b => b
                    .Parameter<Uri>("-s", "--source")
                        .WithDescription("Update source url")
                        .IsOptionalWithDefault(new Uri("http://my-update-server.com/update.zip"))
                    .Call(uri =>
                    {
                        /* ... */
                        Console.WriteLine($"Install update from {uri}...");
                        /* ... */
                    }))
                .PositionalArgument<int>()
                    .WithDescription("The first number")
                    .IsRequired()
                .PositionalArgument<int>()
                    .WithDescription("the second number")
                    .IsRequired()
                .Call(n2 => n1 =>
                {
                    /* ... */
                    Console.WriteLine($"{n1}+{n2}={n1 + n2}");
          
View on GitHub
GitHub Stars41
CategoryDevelopment
Updated1mo ago
Forks3

Languages

C#

Security Score

95/100

Audited on Feb 17, 2026

No findings