Scal.Interpreting.Commands 1.0.4

There is a newer version of this package available.
See the version list below for details.
dotnet add package Scal.Interpreting.Commands --version 1.0.4
                    
NuGet\Install-Package Scal.Interpreting.Commands -Version 1.0.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Scal.Interpreting.Commands" Version="1.0.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Scal.Interpreting.Commands" Version="1.0.4" />
                    
Directory.Packages.props
<PackageReference Include="Scal.Interpreting.Commands" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Scal.Interpreting.Commands --version 1.0.4
                    
#r "nuget: Scal.Interpreting.Commands, 1.0.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Scal.Interpreting.Commands@1.0.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Scal.Interpreting.Commands&version=1.0.4
                    
Install as a Cake Addin
#tool nuget:?package=Scal.Interpreting.Commands&version=1.0.4
                    
Install as a Cake Tool

Scal.Interpreting.Commands

A lightweight, deterministic command-line interpreter for DotNet with attribute-based validation and type conversion.

Unlike reflection-heavy or attribute-mandatory CLI frameworks, Scal.Interpreting.Commands prioritizes deterministic resolution and minimal dependencies.

Motivation

Philosophy

  • simple deterministic grammar: verb (noun) (arguments)
  • case-insensitive
  • dash-tolerant but dash-agnostic
  • accept abbreviations but detect collisions
  • bulletproof and predictable behavior

Technical features

  • verb/noun definition by attributes or Pascal-case naming convention
  • strongly-typed command instantiation
  • validation via DataAnnotations
  • TypeConverter support
  • contextual help generation
  • dependency-free
  • DI-agnostic construction
  • .Net 8.0 LTS compatible (console or ASP.NET)
  • lightweight (425 lines in total including comments, 4 classes and 2 extensions)

Syntax

CommandLine-ebnf

Usage example

dotnet add package Scal.Interpreting.Commands

Example of a program accepting as List Image Name=abc command

[DataContract(Name = "CliArgs")]
[Description("Cli arguments interpreter example")]
public abstract class Program
{
    private static async Task<int> Main(string[] args)
    {
        var interpretation = new CommandLineInterpreter().Interpret<Program>(args);
        if (interpretation.Command is null) {
            interpretation.Feedback(Console.WriteLine);
            return 1;
        }
        interpretation.Feedback(Console.WriteLine, showHelp: false);
        return await interpretation.Command.ExecuteAsync();
    }

    public abstract Task<int> ExecuteAsync();

    [Description("List the images")]
    [DataContract(Namespace = "List", Name = "Image")]
    public class ListImage : Program
    {
        [Description("The image name pattern")]
        [Required]
        [MinLength(1)]
        public string Name { get; set; } = string.Empty;

        [Description("The image type Id")]
        [Range(1, 9)]
        public int TypeId { get; set; } = 1;

        public override Task<int> ExecuteAsync()
        {
            Console.WriteLine("Simulate {0} {1}", nameof(ListImage), this.Name);
            return Task.FromResult(0);
        }
    }
}

Mention that:

  • the Program itself is an abstract with just an entrypoint and the ExecuteAsync contract
  • commands are classes deriving from Program containg the methods you desire (ExecuteAsync in the example)
  • it is derived in a ListImage class that is instantiated
  • I choose to output the feedback without help in case of success which shows the program title

Executing it with List Image Name=abc or L I N=abc gives:

CliArgs Cli arguments interpreter example
Simulate ListImage abc

Help

Executing the program without parameter will output this with the accepted abbreviations in parentheses:

CliArgs Cli arguments interpreter example
*** : Usage: verb (noun) (parameters)
  List     Image            List the images (L I)
    TypeId                  The image type Id (T)
    Name                    The image name pattern (N)

Validation using DataAnnotations attributes or your custom attributes

Executing it with:

CliArgs.exe List Image Name= Type=10
or
CliArgs.exe L I N= T=10

gives:

CliArgs Cli arguments interpreter example
*** TypeId: The field TypeId must be between 1 and 9.
*** Name: The Name field is required.
  List     Image            List the images (L I)
    TypeId                  The image type Id (T)
    Name                    The image name pattern (N)

New ListImport command without attribute

When adding a new command List Import to the same program:

    public class ListImportWithoutParameter : Program
    {
        public override Task<int> ExecuteAsync()
        {
            Console.WriteLine("Simulate {0}", nameof(ListImportWithoutParameter));
            return Task.FromResult(0);
        }
    }

Mention that:

  • The class does not require any attribute and VerbNoun is extracted using the first two words of the class name Pascal-casing
  • Acronyms such as XML or HTTP will be split into individual letters unless explicitly configured using attributes, e.g. a ListXMLFile will be interpreted as List X by convention. In such a case, use a DataContract attribute to clarify your intent.
  • The abbreviations now become l ima for List Image and l imp for List Import as those are the minimum required to prevent ambiguity.

⚠️ Please note that abbreviations should never be used is scripts or documentation for many reasons (clarity, newbie-friendly), including the fact that they may change by adding new commands.

Verb-only command

You may define a verb-only command by creating a one-word class like Cleanup, or by specifying a Namespace in a DataContract without Name:

    public class Cleanup : Program
    {
        public override Task<int> ExecuteAsync()
        {
            Console.WriteLine("Simulate {0}", nameof(Cleanup));
            return Task.FromResult(0);
        }
    }

Type converter and custom validation

Custom type converter and custom validation may be used:

    public class SomeCommand : Program
    {
        [TypeConverter(typeof(YourTypeConverter))]
        [YourCustomValidation]
        [Required]
        public YourType Reference { get; set; }

        public override Task<int> ExecuteAsync()
        {
            Console.WriteLine("Simulate {0} {1}", nameof(SomeCommand), this.Reference);
            return Task.FromResult(0);
        }
    }

Factory constructor

You may provide a factory delegate to integrate with your preferred DI framework:

var interpreter = new CommandLineInterpreter(
    factory: type => MyContainer.Resolve(type));

If no factory delegate is provided, Activator is used:

... = Activator.CreateInstance(type);

Examples

To view examples, see the tests models: by convention, by annotation and with type converter.

Thanks

Thanks to Dan (aka ChatGPT) for they advices and making doubts disappear.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.5 0 2/23/2026
1.0.4 0 2/23/2026

# Change Log

<a name="1.0.4"></a>
## [1.0.4](https://www.github.com/Scal-Human/Scal.Interpreting.Commands/releases/tag/v1.0.4) (2026-02-23)

<a name="1.0.3"></a>
## [1.0.3](https://www.github.com/Scal-Human/Scal.Interpreting.Commands/releases/tag/v1.0.3) (2026-02-23)

<a name="1.0.2"></a>
## [1.0.2](https://www.github.com/Scal-Human/Scal.Interpreting.Commands/releases/tag/v1.0.2) (2026-02-23)

<a name="1.0.1"></a>
## [1.0.1](https://www.github.com/Scal-Human/Scal.Interpreting.Commands/releases/tag/v1.0.1) (2026-02-23)

### Documentation

* Adjust ReadMe ([38b90a4](https://www.github.com/Scal-Human/Scal.Interpreting.Commands/commit/38b90a4d2e98991d35f955d40936e85af805510d))
* Align tags with GitHub ([a3828ef](https://www.github.com/Scal-Human/Scal.Interpreting.Commands/commit/a3828ef3a1de6fd6bbbd4f3e9a84127acc904c1c))
* ChangeLog in PackageReleaseNotes ([d36de6e](https://www.github.com/Scal-Human/Scal.Interpreting.Commands/commit/d36de6e1cbf15b5aee114ce40ee26e00721d2cb0))
* Description and tags refinement ([6ffbee4](https://www.github.com/Scal-Human/Scal.Interpreting.Commands/commit/6ffbee44b628d38fccfea2024888ed2fce3c5b00))
* Documentation changes including ebnf, move ChangeLog to root ([3738fe0](https://www.github.com/Scal-Human/Scal.Interpreting.Commands/commit/3738fe08057987649d5f3bf4ff5056854c33dd08))
* ReadMe corrections ([49876ba](https://www.github.com/Scal-Human/Scal.Interpreting.Commands/commit/49876ba8024c774b40db85cc11b04a00ebc37eac))
* Tags ([bb75e38](https://www.github.com/Scal-Human/Scal.Interpreting.Commands/commit/bb75e38ab66e5d803f4d328f8d31225b87442169))
* Use ChangeLog content as PackageReleaseNotes ([9fd3f1c](https://www.github.com/Scal-Human/Scal.Interpreting.Commands/commit/9fd3f1cb326471b79a3768bd7466c19128a36774))
* **ChangeLog:** Remove pre-v1 changes ([003ecbf](https://www.github.com/Scal-Human/Scal.Interpreting.Commands/commit/003ecbfd67334deec566bc2394d44962ddba4025))
* **Versionize:** Default configuration ([6a12c3b](https://www.github.com/Scal-Human/Scal.Interpreting.Commands/commit/6a12c3b3ecf87a2b11d75928eaf8a4385f42fe46))

### Small Changes

* Use Versionize 2.5.0 ([e650607](https://www.github.com/Scal-Human/Scal.Interpreting.Commands/commit/e650607b31dbe4cf3fdf4aa159d43003131a29df))

<a name="1.0.0"></a>
## [1.0.0](https://www.github.com/Scal-Human/Scal.Interpreting.Commands/releases/tag/v1.0.0) (2026-02-18)

### Breaking Changes

* Bump v1 ([88d1af8](https://www.github.com/Scal-Human/Scal.Interpreting.Commands/commit/88d1af83ba1397645bfbf3322513fe66790c68b9))