Skip to content

Commit

Permalink
Merge pull request #16 from QianMoXi/main
Browse files Browse the repository at this point in the history
Add support for tasks without the async keyword
  • Loading branch information
calacayir authored Apr 2, 2024
2 parents 7f9334c + a89875b commit cbd2e43
Show file tree
Hide file tree
Showing 9 changed files with 525 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ namespace DotMake.CommandLine.SourceGeneration
public class CliCommandAsDelegateInfo : CliSymbolInfo, IEquatable<CliCommandAsDelegateInfo>
{
private const string TaskFullName = "System.Threading.Tasks.Task";
private const string TaskIntFullName = "System.Threading.Tasks.Task<System.Int32>";
public static readonly string CliCommandAsDelegateFullName = "DotMake.CommandLine.CliCommandAsDelegate";

public CliCommandAsDelegateInfo(ISymbol symbol, SyntaxNode syntaxNode, SemanticModel semanticModel)
: base(symbol, syntaxNode, semanticModel)
{
Symbol = (IMethodSymbol)symbol;

if (Symbol.IsAsync)
if (Symbol.IsAsync || Symbol.ReturnType.ToCompareString() is TaskFullName or TaskIntFullName)
{
IsAsync = true;
ReturnsVoid = (Symbol.ReturnType.ToCompareString() == TaskFullName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace DotMake.CommandLine.SourceGeneration
public class CliCommandHandlerInfo : CliSymbolInfo, IEquatable<CliCommandHandlerInfo>
{
private const string TaskFullName = "System.Threading.Tasks.Task";
private const string TaskIntFullName = "System.Threading.Tasks.Task<System.Int32>";
private const string CliContextFullName = "DotMake.CommandLine.CliContext";
public const string DiagnosticName = "CLI command handler";

Expand All @@ -16,7 +17,7 @@ public CliCommandHandlerInfo(IMethodSymbol symbol, SyntaxNode syntaxNode, Semant
Symbol = symbol;
Parent = parent;

if (symbol.IsAsync)
if (symbol.IsAsync || (Symbol.Name == "RunAsync" && Symbol.ReturnType.ToCompareString() is TaskFullName or TaskIntFullName))
{
IsAsync = true;
ReturnsVoid = (symbol.ReturnType.ToCompareString() == TaskFullName);
Expand Down Expand Up @@ -77,9 +78,12 @@ private void Analyze()

public static bool HasCorrectName(IMethodSymbol symbol)
{
return symbol.IsAsync
? (symbol.Name == "RunAsync")
: (symbol.Name == "Run");
return symbol.Name switch
{
"Run" => true,
"RunAsync" => symbol.IsAsync || symbol.ReturnType.ToCompareString() is TaskFullName or TaskIntFullName,
_ => false
};
}

public void AppendCSharpCallString(CodeStringBuilder sb, string varCliContext = null)
Expand Down
26 changes: 26 additions & 0 deletions src/TestApp/Commands/TaskIntReturnCliCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma warning disable CS1591
using System;
using System.Threading.Tasks;
using DotMake.CommandLine;

namespace TestApp.Commands;

[CliCommand(Description = "A root cli command with async handler with Task<int> (return int)")]
public class TaskIntReturnCliCommand
{
[CliOption(Description = "Description for Option1")]
public string Option1 { get; set; } = "DefaultForOption1";

[CliArgument(Description = "Description for Argument1")]
public string Argument1 { get; set; }

public Task<int> RunAsync()
{
Console.WriteLine($@"Handler for '{GetType().FullName}' is run:");
Console.WriteLine($@"Value for {nameof(Option1)} property is '{Option1}'");
Console.WriteLine($@"Value for {nameof(Argument1)} property is '{Argument1}'");
Console.WriteLine();

return Task.FromResult(0);
}
}
26 changes: 26 additions & 0 deletions src/TestApp/Commands/TaskVoidReturnCliCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Threading.Tasks;
using DotMake.CommandLine;

namespace TestApp.Commands;

#pragma warning disable CS1591
[CliCommand(Description = "A root cli command with async handler with Task (return void)")]
public class TaskVoidReturnCliCommand
{
[CliOption(Description = "Description for Option1")]
public string Option1 { get; set; } = "DefaultForOption1";

[CliArgument(Description = "Description for Argument1")]
public string Argument1 { get; set; }

public Task RunAsync()
{
Console.WriteLine($@"Handler for '{GetType().FullName}' is run:");
Console.WriteLine($@"Value for {nameof(Option1)} property is '{Option1}'");
Console.WriteLine($@"Value for {nameof(Argument1)} property is '{Argument1}'");
Console.WriteLine();

return Task.Delay(1000);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// <auto-generated />
// Generated by DotMake.CommandLine.SourceGeneration v1.8.6.0
// Roslyn (Microsoft.CodeAnalysis) v4.900.24.12101
// Generation: 1

namespace TestApp.Commands.GeneratedCode
{
/// <inheritdoc />
public class TaskIntReturnCliCommandBuilder : DotMake.CommandLine.CliCommandBuilder
{
/// <inheritdoc />
public TaskIntReturnCliCommandBuilder()
{
DefinitionType = typeof(TestApp.Commands.TaskIntReturnCliCommand);
ParentDefinitionType = null;
NameCasingConvention = DotMake.CommandLine.CliNameCasingConvention.KebabCase;
NamePrefixConvention = DotMake.CommandLine.CliNamePrefixConvention.DoubleHyphen;
ShortFormPrefixConvention = DotMake.CommandLine.CliNamePrefixConvention.SingleHyphen;
ShortFormAutoGenerate = true;
}

private TestApp.Commands.TaskIntReturnCliCommand CreateInstance()
{
return new TestApp.Commands.TaskIntReturnCliCommand();
}

/// <inheritdoc />
public override System.CommandLine.CliCommand Build()
{
// Command for 'TaskIntReturnCliCommand' class
var rootCommand = new System.CommandLine.CliRootCommand()
{
Description = "A root cli command with async handler with Task<int> (return int)",
};

var defaultClass = CreateInstance();

// Option for 'Option1' property
var option0 = new System.CommandLine.CliOption<string>
(
"--option-1"
)
{
Description = "Description for Option1",
Required = false,
DefaultValueFactory = _ => defaultClass.Option1,
CustomParser = GetArgumentParser<string>
(
null
),
};
option0.Aliases.Add("-o");
rootCommand.Add(option0);

// Argument for 'Argument1' property
var argument0 = new System.CommandLine.CliArgument<string>
(
"argument-1"
)
{
Description = "Description for Argument1",
CustomParser = GetArgumentParser<string>
(
null
),
};
rootCommand.Add(argument0);

// Add nested or external registered children
foreach (var child in Children)
{
rootCommand.Add(child.Build());
}

Binder = (parseResult) =>
{
var targetClass = CreateInstance();

// Set the parsed or default values for the options
targetClass.Option1 = GetValueForOption(parseResult, option0);

// Set the parsed or default values for the arguments
targetClass.Argument1 = GetValueForArgument(parseResult, argument0);

// Set the values for the parent command accessors

return targetClass;
};

rootCommand.SetAction(async (parseResult, cancellationToken) =>
{
var targetClass = (TestApp.Commands.TaskIntReturnCliCommand) Bind(parseResult);

// Call the command handler
var cliContext = new DotMake.CommandLine.CliContext(parseResult, cancellationToken);
var exitCode = 0;
exitCode = await targetClass.RunAsync();
return exitCode;
});

return rootCommand;
}

[System.Runtime.CompilerServices.ModuleInitializerAttribute]
internal static void Initialize()
{
var commandBuilder = new TestApp.Commands.GeneratedCode.TaskIntReturnCliCommandBuilder();

// Register this command builder so that it can be found by the definition class
// and it can be found by the parent definition class if it's a nested/external child.
commandBuilder.Register();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// <auto-generated />
// Generated by DotMake.CommandLine.SourceGeneration v1.8.6.0
// Roslyn (Microsoft.CodeAnalysis) v4.900.24.12101
// Generation: 1

namespace TestApp.Commands.GeneratedCode
{
/// <inheritdoc />
public class TaskVoidReturnCliCommandBuilder : DotMake.CommandLine.CliCommandBuilder
{
/// <inheritdoc />
public TaskVoidReturnCliCommandBuilder()
{
DefinitionType = typeof(TestApp.Commands.TaskVoidReturnCliCommand);
ParentDefinitionType = null;
NameCasingConvention = DotMake.CommandLine.CliNameCasingConvention.KebabCase;
NamePrefixConvention = DotMake.CommandLine.CliNamePrefixConvention.DoubleHyphen;
ShortFormPrefixConvention = DotMake.CommandLine.CliNamePrefixConvention.SingleHyphen;
ShortFormAutoGenerate = true;
}

private TestApp.Commands.TaskVoidReturnCliCommand CreateInstance()
{
return new TestApp.Commands.TaskVoidReturnCliCommand();
}

/// <inheritdoc />
public override System.CommandLine.CliCommand Build()
{
// Command for 'TaskVoidReturnCliCommand' class
var rootCommand = new System.CommandLine.CliRootCommand()
{
Description = "A root cli command with async handler with Task (return void)",
};

var defaultClass = CreateInstance();

// Option for 'Option1' property
var option0 = new System.CommandLine.CliOption<string>
(
"--option-1"
)
{
Description = "Description for Option1",
Required = false,
DefaultValueFactory = _ => defaultClass.Option1,
CustomParser = GetArgumentParser<string>
(
null
),
};
option0.Aliases.Add("-o");
rootCommand.Add(option0);

// Argument for 'Argument1' property
var argument0 = new System.CommandLine.CliArgument<string>
(
"argument-1"
)
{
Description = "Description for Argument1",
CustomParser = GetArgumentParser<string>
(
null
),
};
rootCommand.Add(argument0);

// Add nested or external registered children
foreach (var child in Children)
{
rootCommand.Add(child.Build());
}

Binder = (parseResult) =>
{
var targetClass = CreateInstance();

// Set the parsed or default values for the options
targetClass.Option1 = GetValueForOption(parseResult, option0);

// Set the parsed or default values for the arguments
targetClass.Argument1 = GetValueForArgument(parseResult, argument0);

// Set the values for the parent command accessors

return targetClass;
};

rootCommand.SetAction(async (parseResult, cancellationToken) =>
{
var targetClass = (TestApp.Commands.TaskVoidReturnCliCommand) Bind(parseResult);

// Call the command handler
var cliContext = new DotMake.CommandLine.CliContext(parseResult, cancellationToken);
var exitCode = 0;
await targetClass.RunAsync();
return exitCode;
});

return rootCommand;
}

[System.Runtime.CompilerServices.ModuleInitializerAttribute]
internal static void Initialize()
{
var commandBuilder = new TestApp.Commands.GeneratedCode.TaskVoidReturnCliCommandBuilder();

// Register this command builder so that it can be found by the definition class
// and it can be found by the parent definition class if it's a nested/external child.
commandBuilder.Register();
}
}
}
Loading

0 comments on commit cbd2e43

Please sign in to comment.