JSSoft.Commands 7.0.0-pr.19

This is a prerelease version of JSSoft.Commands.
There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package JSSoft.Commands --version 7.0.0-pr.19                
NuGet\Install-Package JSSoft.Commands -Version 7.0.0-pr.19                
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="JSSoft.Commands" Version="7.0.0-pr.19" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add JSSoft.Commands --version 7.0.0-pr.19                
#r "nuget: JSSoft.Commands, 7.0.0-pr.19"                
#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.
// Install JSSoft.Commands as a Cake Addin
#addin nuget:?package=JSSoft.Commands&version=7.0.0-pr.19&prerelease

// Install JSSoft.Commands as a Cake Tool
#tool nuget:?package=JSSoft.Commands&version=7.0.0-pr.19&prerelease                

commands

Summary

Parses a string to set a value to a specified property or invoke a specified method.

Like Terminal or Powershell, it provides a REPL environment to provide a command-based development environment.

Requirements

dotnet sdk 8.0.100 or later
c# 12

Clone

git clone https://github.com/s2quake/commands.git

Build - NET 8.0

dotnet build

Other Framework Build

# net7.0
dotnet build -p:TargetFrameworks=net7.0 --framework net7.0

# netcoreapp3.1
dotnet build -p:TargetFrameworks=netcoreapp3.1 --framework netcoreapp3.1

# netstandard2.1
dotnet build -p:TargetFrameworks=netstandard2.1 --framework netstandard2.1

# net481
dotnet build -p:TargetFrameworks=net481 --framework net481

Run Examples

# Run the property settings example project
dotnet run --project JSSoft.Commands.Parse --framework net8.0 -- --help

# Run the method call example project
dotnet run --project JSSoft.Commands.Invoke --framework net8.0 -- --help

# Run the CommandContext Execution example Project
dotnet run --project JSSoft.Commands.Sets --framework net8.0 -- --help

# Run the CommandContext Execution Example Project in the REPL environment
dotnet run --project JSSoft.Commands.Repl --framework net8.0

# Run the CommandContext Execution Example Project with Avalonia UI
dotnet run --project JSSoft.Commands.AppUI --framework net8.0

Parse

This is the most basic way to parse the command. Provides a function to set a value for a specified property.

var settings = new Settings();
var parser = new CommandParser(settings);
parser.Parse(args);

See the JSSoft.Commands.Parse project

Invoke

As an extension of Parse, it provides the ability to call a specified method by parsing the command.

var commands = new Commands();
var invoker = new CommandInvoker(commands);
invoker.Invoke(args);

See the JSSoft.Commands.Invoke project

CommandContext

It provides various functions to manage and process more commands.

var commands = new ICommand[]
{
    new LoginCommand(),
    new LogoutCommand(),
    new ExitCommand()
};
var commandContext = new CommandContext(commands);
commandContext.Execute(args);

or 

await commandContext.ExecuteAsync(args);

See the JSSoft.Commands.Sets project

It can be combined with user input such as EditBox, TextBox, InputText to build a console or REPL-like environment.

var commands = new ICommand[]
{
    new LoginCommand(),
    new LogoutCommand(),
    new ExitCommand()
};
var commandContext = new CommandContext(commands);
var terminal = new SystemTerminal(commandContext);
await terminal.StartAsync(CancellationToken.None);

See the JSSoft.Commands.Repl project

Property

Required argument definition

To define the value required for command syntax, define CommandPropertyRequired in the property.

[CommandPropertyRequired]
public string Value1 { get; set; } = string.Empty;

[CommandPropertyRequired]
public int Value2 { get; set; }
"value"   // error! value for Value2 does not exists.
3         // format error!
"value" 3 // Value1 is "value", Value2 is 3

You can set default values ​​like this: If there is no value in the command syntax, it is replaced with the default value.

[CommandPropertyRequired]
public string Value1 { get; set; } = string.Empty;

[CommandPropertyRequired(DefaultValue = 1)]
public int Value2 { get; set; }
"value" 2 // Value1 is "value", Value2 is 2
"value"   // Value1 is "value", Value2 is 1

Explicit required argument definition

An explicit required argument indicates that the command syntax must have a value, but must include a switch statement, such as --value "2".

[CommandPropertyRequired]
public string Value1 { get; set; } = string.Empty;

[CommandPropertyExplicitRequired]
public int Value2 { get; set; }
"value"            // error!
"value" 2          // error!
"value" --value2   // error!
"value" --value2 3 // Value1 is "value", Value2 is 3
--value2 3 "value" // Value1 is "value", Value2 is 3

In order to use the default values ​​of explicit required arguments, the command syntax must include a switch statement such as --value.

[CommandPropertyRequired]
public string Value1 { get; set; } = string.Empty;

[CommandPropertyExplicitRequired(DefaultValue = 1)]
public int Value2 { get; set; }
"value"            // error!
"value" 2          // error!
"value" --value2   // Value1 is "value", Value2 is 1
"value" --value2 3 // Value1 is "value", Value2 is 3
--value2 3 "value" // Value1 is "value", Value2 is 3
--value2 "value"   // error! "value" is not int

Optional argument definition

The optional argument can be set whether or not to use a value using a switch statement.

[CommandProperty]
public string Value { get; set; } = string.Empty;
--value      // error
--value text // value is "text"

To use the default, the command syntax must include a switch statement such as --value.

[CommandProperty(DefaultValue = "1")]
public string Value { get; set; } = string.Empty;
--value      // value is "1"
--value text // value is "text"

A bool type switch statement that does not use a value should be defined as follows.

[CommandPropertySwitch]
public bool Switch { get; set; }

Variable arguments definition

Variable arguments represent the values ​​of the remaining arguments that were not parsed in the command syntax.

The property type of a variable arguments must be an array and must be defined for only one property.

[CommandPropertyArray]
public string[] Values { get; set; } = Array.Empty<string>();
-- value1 value2 value3 "value4"

Method

Method definition

To execute an attribute method through command syntax, you must define a CommandMethod in the method as follows.

Each parameter of the method is automatically defined as a required argument.

[CommandMethod]
public void Save(string message)
{
}
save "message"

If you want to additionally define optional arguments in the method, you can use CommandMethodProperty and add the name of the property defined as CommandProperty.

[CommandMethod]
[CommandMethodProperty("Value")]
public void Save(string message)
{
}
save "comment"
save "comment" --value text

You can use params as below as a variable arguments.

[CommandMethod]
public void Save(string message, params string[] args)
{
}
save "comment"
save "comment" -- "1" "text" "string"

Enable or Disable Method

Define the properties by prefixing "Can" to the method name as shown below.

public bool Can{MethodName} { get; }

example:

public bool CanSave => true;

Static properties and methods

Properties and methods defined as static can be included in the object and used.

static class GlobalSettings
{
    [CommandProperty]
    public static string ID { get; set; } = string.Empty;

    [CommandProperty]
    public static string Password { get; set; }
}

[CommandStaticProperty(typeof(GlobalSettings))]
class Settings
{
}
static class StaticCommand
{
    [CommandMethod]
    [CommandMethodProperty(nameof(Value))]
    public static void List()
    {
    }

    [CommandProperty]
    public static int Value { get; set; }
}

[CommandStaticMethod(typeof(StaticCommand))]
class Commands
{
}

Naming

The property and method names defined as CommandProperty and CommandMethod are changed to kebab-case (spinal-case, Train-Case, Lisp-case).

Property name example

Property name Changed property name
Value --value
Message --message
IsLocked --is-locked

When using a name and a short name

[CommandProperty("custom-value", 'v')]
public string Value { get; set; } = string.Empty;
--custom-value or -v

When using only short names

[CommandProperty('v')]
public string Value { get; set; } = string.Empty;
-v

When using a short name and a default name

[CommandProperty('v', AllowName = true)]
public string Value { get; set; } = string.Empty;
-v or --value

Method name example

Method name Changed method name
Save save
LockTable lock-table

You can also set the method name yourself.

[CommandMethod("save")]
public void Save(string message)
{
}

Command

You can define commands in the CommandContext.

class ExitCommand : CommandBase
{
    [CommandPropertyRequired(DefaultValue = 0)]
    public int ExitCode { get; set; }

    protected override void OnExecute()
    {
        Environment.Exit(ExitCode);
    }
}
exit
exit 0

SubCommand

You can define commands that have subcommands in CommandContext.

class UserCommand : CommandMethodBase
{
    [CommandMethod]
    [CommandMethodProperty(nameof(Message))]
    public void Create(string userID)
    {
    }

    [CommandMethod]
    public void Delete(string userID)
    {
    }

    [CommandMethod]
    public void List()
    {
    }

    [CommandProperty]
    public string Message { get; set; }
}
user create "user1"
user create "user1" --message "new user"
user delete "user1"
user list

SubCommand extension

By implementing a partial class, you can add subcommand to the already implemented command.

[PartialCommand]
class UserPartialCommand : CommandMethodBase
{
    public UserPartialCommand()
        : base("user")
    {
    }

    [CommandMethod]
    public void SendMessage(string userID, string message)
    {
    }
}

SubCommand AsyncMethod

You can use asynchronous methods, as shown in the example below. The parameters CancellationToken and IProgress<ProgressInfo> are optional, but should always be the last declaration.

For more information, see the Choosing the overloads to provide topic in the TAP.

The name of an asynchronous method is used without the suffix Async.

class UserCommand : CommandMethodBase
{
    [CommandMethod]
    public Task Invoke1Async()
    {
        return Task.CompletedTask;
    }

    [CommandMethod]
    public Task Invoke2Async(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }

    [CommandMethod]
    public Task Invoke3Async(IProgress<ProgressInfo> progress)
    {
        return Task.CompletedTask;
    }

    [CommandMethod]
    public Task Invoke4Async(CancellationToken cancellationToken, IProgress<ProgressInfo> progress)
    {
        return Task.CompletedTask;
    }
}

License

Released under the MIT License.

Copyright (c) 2024 Jeesu Choi

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  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. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.1

    • No dependencies.
  • net6.0

    • No dependencies.
  • net7.0

    • No dependencies.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
7.0.0-pr.42 93 10/5/2024
7.0.0-pr.41 39 9/23/2024
7.0.0-pr.40 98 9/18/2024
7.0.0-pr.39 48 9/18/2024
7.0.0-pr.38 46 9/18/2024
7.0.0-pr.37 46 9/18/2024
7.0.0-pr.36 55 9/16/2024
7.0.0-pr.35 48 9/16/2024
7.0.0-pr.34 46 9/16/2024
7.0.0-pr.33 48 9/15/2024
7.0.0-pr.32 48 9/14/2024
7.0.0-pr.31 61 9/14/2024
7.0.0-pr.30 50 9/6/2024
7.0.0-pr.29 41 9/6/2024
7.0.0-pr.28 41 9/4/2024
7.0.0-pr.27 40 9/2/2024
7.0.0-pr.26 47 9/1/2024
7.0.0-pr.25 47 8/31/2024
7.0.0-pr.24 69 8/24/2024
7.0.0-pr.23 71 8/22/2024
7.0.0-pr.22 63 8/13/2024
7.0.0-pr.21 57 7/26/2024
7.0.0-pr.20 53 7/25/2024
7.0.0-pr.19 53 7/24/2024
7.0.0-pr.18 50 7/23/2024
7.0.0-pr.17 46 7/23/2024
6.0.2-pr.16 59 7/21/2024
6.0.2-pr.15 66 7/21/2024
6.0.2-pr.13 57 7/5/2024
6.0.1 494 5/31/2024
6.0.0 113 5/29/2024