Skip to content

Commit cbd2e43

Browse files
authored
Merge pull request #16 from QianMoXi/main
Add support for tasks without the async keyword
2 parents 7f9334c + a89875b commit cbd2e43

File tree

9 files changed

+525
-5
lines changed

9 files changed

+525
-5
lines changed

src/DotMake.CommandLine.SourceGeneration/CliCommandAsDelegateInfo.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@ namespace DotMake.CommandLine.SourceGeneration
1111
public class CliCommandAsDelegateInfo : CliSymbolInfo, IEquatable<CliCommandAsDelegateInfo>
1212
{
1313
private const string TaskFullName = "System.Threading.Tasks.Task";
14+
private const string TaskIntFullName = "System.Threading.Tasks.Task<System.Int32>";
1415
public static readonly string CliCommandAsDelegateFullName = "DotMake.CommandLine.CliCommandAsDelegate";
1516

1617
public CliCommandAsDelegateInfo(ISymbol symbol, SyntaxNode syntaxNode, SemanticModel semanticModel)
1718
: base(symbol, syntaxNode, semanticModel)
1819
{
1920
Symbol = (IMethodSymbol)symbol;
2021

21-
if (Symbol.IsAsync)
22+
if (Symbol.IsAsync || Symbol.ReturnType.ToCompareString() is TaskFullName or TaskIntFullName)
2223
{
2324
IsAsync = true;
2425
ReturnsVoid = (Symbol.ReturnType.ToCompareString() == TaskFullName);

src/DotMake.CommandLine.SourceGeneration/CliCommandHandlerInfo.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ namespace DotMake.CommandLine.SourceGeneration
77
public class CliCommandHandlerInfo : CliSymbolInfo, IEquatable<CliCommandHandlerInfo>
88
{
99
private const string TaskFullName = "System.Threading.Tasks.Task";
10+
private const string TaskIntFullName = "System.Threading.Tasks.Task<System.Int32>";
1011
private const string CliContextFullName = "DotMake.CommandLine.CliContext";
1112
public const string DiagnosticName = "CLI command handler";
1213

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

19-
if (symbol.IsAsync)
20+
if (symbol.IsAsync || (Symbol.Name == "RunAsync" && Symbol.ReturnType.ToCompareString() is TaskFullName or TaskIntFullName))
2021
{
2122
IsAsync = true;
2223
ReturnsVoid = (symbol.ReturnType.ToCompareString() == TaskFullName);
@@ -77,9 +78,12 @@ private void Analyze()
7778

7879
public static bool HasCorrectName(IMethodSymbol symbol)
7980
{
80-
return symbol.IsAsync
81-
? (symbol.Name == "RunAsync")
82-
: (symbol.Name == "Run");
81+
return symbol.Name switch
82+
{
83+
"Run" => true,
84+
"RunAsync" => symbol.IsAsync || symbol.ReturnType.ToCompareString() is TaskFullName or TaskIntFullName,
85+
_ => false
86+
};
8387
}
8488

8589
public void AppendCSharpCallString(CodeStringBuilder sb, string varCliContext = null)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#pragma warning disable CS1591
2+
using System;
3+
using System.Threading.Tasks;
4+
using DotMake.CommandLine;
5+
6+
namespace TestApp.Commands;
7+
8+
[CliCommand(Description = "A root cli command with async handler with Task<int> (return int)")]
9+
public class TaskIntReturnCliCommand
10+
{
11+
[CliOption(Description = "Description for Option1")]
12+
public string Option1 { get; set; } = "DefaultForOption1";
13+
14+
[CliArgument(Description = "Description for Argument1")]
15+
public string Argument1 { get; set; }
16+
17+
public Task<int> RunAsync()
18+
{
19+
Console.WriteLine($@"Handler for '{GetType().FullName}' is run:");
20+
Console.WriteLine($@"Value for {nameof(Option1)} property is '{Option1}'");
21+
Console.WriteLine($@"Value for {nameof(Argument1)} property is '{Argument1}'");
22+
Console.WriteLine();
23+
24+
return Task.FromResult(0);
25+
}
26+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using DotMake.CommandLine;
4+
5+
namespace TestApp.Commands;
6+
7+
#pragma warning disable CS1591
8+
[CliCommand(Description = "A root cli command with async handler with Task (return void)")]
9+
public class TaskVoidReturnCliCommand
10+
{
11+
[CliOption(Description = "Description for Option1")]
12+
public string Option1 { get; set; } = "DefaultForOption1";
13+
14+
[CliArgument(Description = "Description for Argument1")]
15+
public string Argument1 { get; set; }
16+
17+
public Task RunAsync()
18+
{
19+
Console.WriteLine($@"Handler for '{GetType().FullName}' is run:");
20+
Console.WriteLine($@"Value for {nameof(Option1)} property is '{Option1}'");
21+
Console.WriteLine($@"Value for {nameof(Argument1)} property is '{Argument1}'");
22+
Console.WriteLine();
23+
24+
return Task.Delay(1000);
25+
}
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// <auto-generated />
2+
// Generated by DotMake.CommandLine.SourceGeneration v1.8.6.0
3+
// Roslyn (Microsoft.CodeAnalysis) v4.900.24.12101
4+
// Generation: 1
5+
6+
namespace TestApp.Commands.GeneratedCode
7+
{
8+
/// <inheritdoc />
9+
public class TaskIntReturnCliCommandBuilder : DotMake.CommandLine.CliCommandBuilder
10+
{
11+
/// <inheritdoc />
12+
public TaskIntReturnCliCommandBuilder()
13+
{
14+
DefinitionType = typeof(TestApp.Commands.TaskIntReturnCliCommand);
15+
ParentDefinitionType = null;
16+
NameCasingConvention = DotMake.CommandLine.CliNameCasingConvention.KebabCase;
17+
NamePrefixConvention = DotMake.CommandLine.CliNamePrefixConvention.DoubleHyphen;
18+
ShortFormPrefixConvention = DotMake.CommandLine.CliNamePrefixConvention.SingleHyphen;
19+
ShortFormAutoGenerate = true;
20+
}
21+
22+
private TestApp.Commands.TaskIntReturnCliCommand CreateInstance()
23+
{
24+
return new TestApp.Commands.TaskIntReturnCliCommand();
25+
}
26+
27+
/// <inheritdoc />
28+
public override System.CommandLine.CliCommand Build()
29+
{
30+
// Command for 'TaskIntReturnCliCommand' class
31+
var rootCommand = new System.CommandLine.CliRootCommand()
32+
{
33+
Description = "A root cli command with async handler with Task<int> (return int)",
34+
};
35+
36+
var defaultClass = CreateInstance();
37+
38+
// Option for 'Option1' property
39+
var option0 = new System.CommandLine.CliOption<string>
40+
(
41+
"--option-1"
42+
)
43+
{
44+
Description = "Description for Option1",
45+
Required = false,
46+
DefaultValueFactory = _ => defaultClass.Option1,
47+
CustomParser = GetArgumentParser<string>
48+
(
49+
null
50+
),
51+
};
52+
option0.Aliases.Add("-o");
53+
rootCommand.Add(option0);
54+
55+
// Argument for 'Argument1' property
56+
var argument0 = new System.CommandLine.CliArgument<string>
57+
(
58+
"argument-1"
59+
)
60+
{
61+
Description = "Description for Argument1",
62+
CustomParser = GetArgumentParser<string>
63+
(
64+
null
65+
),
66+
};
67+
rootCommand.Add(argument0);
68+
69+
// Add nested or external registered children
70+
foreach (var child in Children)
71+
{
72+
rootCommand.Add(child.Build());
73+
}
74+
75+
Binder = (parseResult) =>
76+
{
77+
var targetClass = CreateInstance();
78+
79+
// Set the parsed or default values for the options
80+
targetClass.Option1 = GetValueForOption(parseResult, option0);
81+
82+
// Set the parsed or default values for the arguments
83+
targetClass.Argument1 = GetValueForArgument(parseResult, argument0);
84+
85+
// Set the values for the parent command accessors
86+
87+
return targetClass;
88+
};
89+
90+
rootCommand.SetAction(async (parseResult, cancellationToken) =>
91+
{
92+
var targetClass = (TestApp.Commands.TaskIntReturnCliCommand) Bind(parseResult);
93+
94+
// Call the command handler
95+
var cliContext = new DotMake.CommandLine.CliContext(parseResult, cancellationToken);
96+
var exitCode = 0;
97+
exitCode = await targetClass.RunAsync();
98+
return exitCode;
99+
});
100+
101+
return rootCommand;
102+
}
103+
104+
[System.Runtime.CompilerServices.ModuleInitializerAttribute]
105+
internal static void Initialize()
106+
{
107+
var commandBuilder = new TestApp.Commands.GeneratedCode.TaskIntReturnCliCommandBuilder();
108+
109+
// Register this command builder so that it can be found by the definition class
110+
// and it can be found by the parent definition class if it's a nested/external child.
111+
commandBuilder.Register();
112+
}
113+
}
114+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// <auto-generated />
2+
// Generated by DotMake.CommandLine.SourceGeneration v1.8.6.0
3+
// Roslyn (Microsoft.CodeAnalysis) v4.900.24.12101
4+
// Generation: 1
5+
6+
namespace TestApp.Commands.GeneratedCode
7+
{
8+
/// <inheritdoc />
9+
public class TaskVoidReturnCliCommandBuilder : DotMake.CommandLine.CliCommandBuilder
10+
{
11+
/// <inheritdoc />
12+
public TaskVoidReturnCliCommandBuilder()
13+
{
14+
DefinitionType = typeof(TestApp.Commands.TaskVoidReturnCliCommand);
15+
ParentDefinitionType = null;
16+
NameCasingConvention = DotMake.CommandLine.CliNameCasingConvention.KebabCase;
17+
NamePrefixConvention = DotMake.CommandLine.CliNamePrefixConvention.DoubleHyphen;
18+
ShortFormPrefixConvention = DotMake.CommandLine.CliNamePrefixConvention.SingleHyphen;
19+
ShortFormAutoGenerate = true;
20+
}
21+
22+
private TestApp.Commands.TaskVoidReturnCliCommand CreateInstance()
23+
{
24+
return new TestApp.Commands.TaskVoidReturnCliCommand();
25+
}
26+
27+
/// <inheritdoc />
28+
public override System.CommandLine.CliCommand Build()
29+
{
30+
// Command for 'TaskVoidReturnCliCommand' class
31+
var rootCommand = new System.CommandLine.CliRootCommand()
32+
{
33+
Description = "A root cli command with async handler with Task (return void)",
34+
};
35+
36+
var defaultClass = CreateInstance();
37+
38+
// Option for 'Option1' property
39+
var option0 = new System.CommandLine.CliOption<string>
40+
(
41+
"--option-1"
42+
)
43+
{
44+
Description = "Description for Option1",
45+
Required = false,
46+
DefaultValueFactory = _ => defaultClass.Option1,
47+
CustomParser = GetArgumentParser<string>
48+
(
49+
null
50+
),
51+
};
52+
option0.Aliases.Add("-o");
53+
rootCommand.Add(option0);
54+
55+
// Argument for 'Argument1' property
56+
var argument0 = new System.CommandLine.CliArgument<string>
57+
(
58+
"argument-1"
59+
)
60+
{
61+
Description = "Description for Argument1",
62+
CustomParser = GetArgumentParser<string>
63+
(
64+
null
65+
),
66+
};
67+
rootCommand.Add(argument0);
68+
69+
// Add nested or external registered children
70+
foreach (var child in Children)
71+
{
72+
rootCommand.Add(child.Build());
73+
}
74+
75+
Binder = (parseResult) =>
76+
{
77+
var targetClass = CreateInstance();
78+
79+
// Set the parsed or default values for the options
80+
targetClass.Option1 = GetValueForOption(parseResult, option0);
81+
82+
// Set the parsed or default values for the arguments
83+
targetClass.Argument1 = GetValueForArgument(parseResult, argument0);
84+
85+
// Set the values for the parent command accessors
86+
87+
return targetClass;
88+
};
89+
90+
rootCommand.SetAction(async (parseResult, cancellationToken) =>
91+
{
92+
var targetClass = (TestApp.Commands.TaskVoidReturnCliCommand) Bind(parseResult);
93+
94+
// Call the command handler
95+
var cliContext = new DotMake.CommandLine.CliContext(parseResult, cancellationToken);
96+
var exitCode = 0;
97+
await targetClass.RunAsync();
98+
return exitCode;
99+
});
100+
101+
return rootCommand;
102+
}
103+
104+
[System.Runtime.CompilerServices.ModuleInitializerAttribute]
105+
internal static void Initialize()
106+
{
107+
var commandBuilder = new TestApp.Commands.GeneratedCode.TaskVoidReturnCliCommandBuilder();
108+
109+
// Register this command builder so that it can be found by the definition class
110+
// and it can be found by the parent definition class if it's a nested/external child.
111+
commandBuilder.Register();
112+
}
113+
}
114+
}

0 commit comments

Comments
 (0)