Ookii.CommandLine 4.0

When I released version 3.0 of Ookii.CommandLine last year, I wasn't expecting to have another major release so soon. I still had some ideas for new features, like supporting automatic aliases based on prefixes of command line arguments, but they'd only warrant minor revisions.

But then, I started reading about .Net source generators, and I thought, that's something I could use. Ookii.CommandLine used reflection to determine the command line arguments at runtime, so a source generator would be able to do the same job at compile time. That would make it faster, make the library trim-friendly, and allow me to emit warnings and errors for unsupported argument settings, define positional arguments based on the order of the class members rather than explicit numbers, and extract default values from property initializers.

Ookii.CommandLine 4.0 now gives you that option. You can apply the GeneratedParserAttribute to any class that defines command line arguments, and the parser will be generated at compile time.

partial class MyArguments
    [CommandLineArgument(IsPositional = true)]
    [Description("A required positional argument.")]
    public required string Required { get; set; }

    [CommandLineArgument(IsPositional = true)]
    [Description("An optional positional argument.")]
    public int Optional { get; set; } = 42;

    [Description("An argument that can only be supplied by name.")]
    public DateTime Named { get; set; }

    [Description("A switch argument, which doesn't require a value.")]
    public bool Switch { get; set; }

That still might not have warranted a major version bump, if trimming hadn't been a goal. Ookii.CommandLine relied on the TypeConverter class to convert argument values from strings to their defined type, and I soon discovered that determining the right TypeConverter for any type at compile time wasn't really possible, and calling TypeDescriptor.GetConverter() at runtime was inherently not compatible with trimming an application. I guess this is why System.CommandLine limits their supported types to just a chosen handful, and everything else requires custom converters.

The solution was ArgumentConverter, a new way to convert argument values, that replaces TypeConverter. Not only is it trim-friendly, it also enables converting arguments using ReadOnlySpan<char>, which means that the parser can avoid allocating strings when splitting arguments provided like -Name:value, another performance improvement.

However, it does mean that any command line arguments classes that relied on a TypeConverter will no longer function correctly without modifications, so the major version needed to change again. While I was at it, I made a few other breaking changes, the biggest of which was probably the removal of constructor parameters as a way to define command line arguments. Now, properties and methods are your only choice. I was never a big fan of the way constructor parameters worked, and how clumsy it was to add attributes to them. They were already de-emphasized in the documentation, and were mostly left over from version 1.0 (sadly lost to time), where they were the only way to define positional arguments. The work needed to support them with source generation meant they ended up on the chopping block this time.

For these and other breaking changes, check the migration guide. As with version 3.0, most users probably won't need to make many changes.

Besides source generation and new argument converters, Ookii.CommandLine 4.0 gives you plenty of other goodness, including the aforementioned automatic prefix aliases, support for C# 11 required properties, a new attribute for value descriptions that allows for localization, canceling parsing with success and access the remaining arguments afterwards, support for nested subcommands, source link integration, and more.

See the change log for everything that's new.

Get it on NuGet or GitHub. You can also try out the parser or subcommands on .Net Fiddle.

Categories: Software, Programming
Posted on: 2023-07-20 20:07 UTC.


No comments here...

Add comment

Comments are closed for this post. Sorry.

Latest posts




RSS Subscribe