Previous

Release v0.10.0 - Command Resolver and Double Dash raw args

Current

Release v0.11.0 - Too much to summarise

Release v0.11.0 - Too much to summarise

The latest release of JCLI has been released, featuring a massive amount of changes, tweaks, features, and a brand new comprehensive README.

Special thanks to andrey-zherikov for all of the support he's provided.

Changelog

Most changes are explained in the new README.

The following changes were implemented:

  1. README - A new large, comprehensive README has been created.
  2. Breaking - The @CommandDefault UDA has been introduced. The old way of making default commands is now deprecated.
  3. Breaking - Arg binders and validators now have to use the new Result type.
  4. Breaking - Arg validators now require the use of @ArgValidator.
  5. Feature - The @CommandArgGroup UDA has been introduced, allowing arguments to be organised into groups within a command's help text.
  6. Feature - Settings can now be passed into CommandLineInterface, including an app name to show within error and help text.
  7. Feature - Introduced a Result type.
  8. Feature - Added the top-level package jcli that publically imports jaster.cli.
  9. Feature - Add built-in validators @PreValidate and @PostValidate, allowing a more fluent but limited style of validation.
  10. Feature - The @ArgBindWith UDA has been introduced, so that specific arguments can be bound in a specific way.
  11. Feature - Introduce the CommandArgAction enum, which allows customisation of how an argument is parsed. Currently .default_ and .count.
  12. Change - Bash completion is now opt-in, and JCLI no longer requires the -J flag for non-dub users.
  13. Change - Version JCLI_BinderCompilerErrors has been removed as the ArgBinder will no longer mask compiler errors.
  14. Change - Github Actions now triggers on pull requests, and uses the official dlang action.
  15. Change - Detection of multiple default commands has moved to a compile-time check, instead of a runtime one.
  16. Change - Failure to find an appropriate binder in ArgBinder.bind now creates a compile-time error, instead of a runtime one.
  17. Tweak - core.d has been restructured (again).
  18. Tweak - binder.d has been restructured.
  19. Tweak - Unnamed positional arguments are given the default name of "VALUE" instead of being invisible.
  20. Tweak - The usage string has been changed into a more standard format.
  21. Tweak - Most error messages and help texts have been improved.

CommandDefault UDA

Previously to create a default command the user had to provide a null name: @Command(null, "description").

Having a special, unclear meaning to null, as well as forcing the user to even pass null in the first place, was not a wise idea.

So now the syntax is simply: @CommandDefault("description").

Arg validators and binders now have to use the new Result type

Arg binders before this version were defined similar to below:

@ArgBinderFunc
void numberBinder(T)(string arg, ref scope T value)
{
    import std.conv : to;

    value = arg.to!T; // Exceptions are caught and provided as an error message.
}

Now however, we have the new Result type, so arg binders are now defined as:

@ArgBinderFunc
Result!T numberBinder(T)(string arg)
if(isNumeric!T)
{
    import std.conv : to;

    try return Result!T.success(arg.to!T);
    catch(ConvException ex)
        return Result!T.failure(ex.msg);
}

Similarly arg validators used to be defined as:

struct IsEven
{
    // onPreValidate shown for completion, doesn't make logical sense for this validator though.
    bool onPreValidate(string arg, ref string error)
    {
        error = arg~" is not an even number."
        return arg.to!int() % 2 == 0;
    }

    bool onValidate(T)(T value, ref string error)
    if(isNumeric!T)
    {
        error = arg.to!string() ~ " is not an even number."
        return value % 2 == 0;
    }
}

As of this release, the above validator would now look like:

struct IsEven
{
    Result!void onPreValidate(string arg)
    {
        return (arg.to!int() % 2 == 0)
        ? Result!void.success()
        : Result!void.failure(arg~" is not an even number.");
    }

    Result!void onValidate(T)(T value)
    {
        // Alternative way to write the above.
        return Result!void.failureIf(
            value % 2 != 0, // Condition
            value.to!string ~ " is not an even number" // Error Message if condition is true.
        )
    }
}

ArgValidator UDA

Arg validator types must now be decorated with the @ArgValidator UDA. This is to solve certain ambiguity issues, as well as make it possible to provide better error messages.

Issues

During the development of this version I discovered a possible compiler frontend bug, filed as issue #21377.

Contributors ❤️

The following people (other than myself) have contributed to this release of JCLI:

  • andrey-zherikov - Helped either directly or indirectly with every part of this release.

Previous

Release v0.10.0 - Command Resolver and Double Dash raw args

Current

Release v0.11.0 - Too much to summarise