Skip to content

Commit 68126c5

Browse files
committed
Added .editorconfig file and normalized tabs to spaces
Visual Studio messes with tabs and spaces due to default setting "adaptive formatting". Adding .editorconfig file forces the indent rules and then running "dotnet format whitespace" command fixed all files in the solution.
1 parent 854ccb2 commit 68126c5

File tree

76 files changed

+5442
-5374
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+5442
-5374
lines changed

docs/README.md

Lines changed: 97 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
# DotMake Command-Line
44

5-
Declarative syntax for [System.CommandLine](https://github.com/dotnet/command-line-api) via attributes for easy, fast, strongly-typed (no reflection) usage. Includes a source generator which automagically converts your classes to CLI commands and properties to CLI options or CLI arguments. Supports [trimming](https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trim-self-contained) an [AOT compilation](https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=net7%2Cwindows#limitations-of-native-aot-deployment) !
6-
75
System.CommandLine is a very good parser but you need a lot of boilerplate code to get going and the API is hard to discover. This becomes complicated to newcomers and also you would have a lot of ugly code in your `Program.cs` to maintain. What if you had an easy class-based layer combined with a good parser?
86

7+
DotMake.CommandLine is a library which provides declarative syntax for [System.CommandLine](https://github.com/dotnet/command-line-api) via attributes for easy, fast, strongly-typed (no reflection) usage. The library includes includes a source generator which automagically converts your classes to CLI commands and properties to CLI options or CLI arguments. Supports [trimming](https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trim-self-contained) and [AOT compilation](https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/?tabs=net7%2Cwindows#limitations-of-native-aot-deployment) !
8+
99
[![Nuget](https://img.shields.io/nuget/v/DotMake.CommandLine?style=for-the-badge&logo=nuget)](https://www.nuget.org/packages/DotMake.CommandLine)
1010

1111
## Getting started
@@ -38,19 +38,19 @@ using DotMake.CommandLine;
3838
[CliCommand(Description = "A root cli command")]
3939
public class RootCliCommand
4040
{
41-
[CliOption(Description = "Description for Option1")]
42-
public string Option1 { get; set; } = "DefaultForOption1";
41+
[CliOption(Description = "Description for Option1")]
42+
public string Option1 { get; set; } = "DefaultForOption1";
4343

44-
[CliArgument(Description = "Description for Argument1")]
45-
public string Argument1 { get; set; } = "DefaultForArgument1";
44+
[CliArgument(Description = "Description for Argument1")]
45+
public string Argument1 { get; set; } = "DefaultForArgument1";
4646

47-
public void Run()
48-
{
49-
Console.WriteLine($@"Handler for '{GetType().FullName}' is run:");
50-
Console.WriteLine($@"Value for {nameof(Option1)} property is '{Option1}'");
51-
Console.WriteLine($@"Value for {nameof(Argument1)} property is '{Argument1}'");
52-
Console.WriteLine();
53-
}
47+
public void Run()
48+
{
49+
Console.WriteLine($@"Handler for '{GetType().FullName}' is run:");
50+
Console.WriteLine($@"Value for {nameof(Option1)} property is '{Option1}'");
51+
Console.WriteLine($@"Value for {nameof(Argument1)} property is '{Argument1}'");
52+
Console.WriteLine();
53+
}
5454
}
5555
```
5656
In Program.cs, add this single line:
@@ -67,17 +67,17 @@ To handle exceptions, you just use a try-catch block:
6767
```c#
6868
try
6969
{
70-
Cli.Run<RootCliCommand>(args);
70+
Cli.Run<RootCliCommand>(args);
7171
}
7272
catch (Exception e)
7373
{
74-
Console.WriteLine(@"Exception in main: {0}", e.Message);
74+
Console.WriteLine(@"Exception in main: {0}", e.Message);
7575
}
7676
```
7777
System.CommandLine, by default overtakes your exceptions that are thrown in command handlers (even if you don't set an exception handler explicitly) but DotMake.CommandLine, by default allows the exceptions to pass through. However if you wish, you can easily use an exception handler by using `configureBuilder` delegate parameter like this:
7878
```c#
7979
Cli.Run<RootCliCommand>(args, builder =>
80-
builder.UseExceptionHandler((e, context) => Console.WriteLine(@"Exception in command handler: {0}", e.Message))
80+
builder.UseExceptionHandler((e, context) => Console.WriteLine(@"Exception in command handler: {0}", e.Message))
8181
);
8282
```
8383
### Summary
@@ -116,7 +116,8 @@ Cli.Run<RootCliCommand>(args, builder =>
116116
The signatures which return int value, sets the ExitCode of the app.
117117
- Call `Cli.Run<>` or`Cli.RunAsync<>` method with your class name to run your CLI app (see [Cli](https://dotmake.build/api/html/T_DotMake_CommandLine_Cli.htm) docs for more info).
118118
119-
---
119+
## Model binding
120+
120121
When the command handler is run, the properties for CLI options and arguments will be already populated
121122
and bound from values passed in the command-line. If no matching value is passed, the property will have its default value.
122123

@@ -148,7 +149,8 @@ Value for Option1 property is 'NewValueForOption1'
148149
Value for Argument1 property is 'NewValueForArgument1'
149150
```
150151

151-
---
152+
## Help output
153+
152154
When you run the app via `TestApp.exe -?` or `dotnet run -- -?`, you see this usage help:
153155
```console
154156
Description:
@@ -169,13 +171,13 @@ Note, how command/option/argument names, descriptions and default values are aut
169171

170172
By default, command/option/argument names are generated as follows;
171173
- First the following suffixes are stripped out from class and property names:
172-
- For commands:
173-
"RootCliCommand", "RootCommand", "SubCliCommand", "SubCommand", "CliCommand", "Command", "Cli"
174-
- For options:
175-
"RootCommandOption", "SubCliCommandOption", "SubCommandOption", "CliCommandOption", "CommandOption", "CliOption", "Option"
176-
- For arguments:
177-
"RootCliCommandArgument", "RootCommandArgument", "SubCliCommandArgument", "SubCommandArgument", "CliCommandArgument", "CommandArgument", "CliArgument", "Argument"
178-
174+
- For commands:
175+
"RootCliCommand", "RootCommand", "SubCliCommand", "SubCommand", "CliCommand", "Command", "Cli"
176+
- For options:
177+
"RootCommandOption", "SubCliCommandOption", "SubCommandOption", "CliCommandOption", "CommandOption", "CliOption", "Option"
178+
- For arguments:
179+
"RootCliCommandArgument", "RootCommandArgument", "SubCliCommandArgument", "SubCommandArgument", "CliCommandArgument", "CommandArgument", "CliArgument", "Argument"
180+
179181
- Then the names are converted to **kebab-case**, this can be changed by setting `NameCasingConvention` property of the `CliCommand` attribute to one of the following values:
180182
- `CliNameCasingConvention.None`
181183
- `CliNameCasingConvention.LowerCase`
@@ -200,26 +202,26 @@ using System;
200202
using DotMake.CommandLine;
201203

202204
[CliCommand(
203-
Description = "A cli command with snake_case name casing and forward slash prefix conventions",
204-
NameCasingConvention = CliNameCasingConvention.SnakeCase,
205-
NamePrefixConvention = CliNamePrefixConvention.ForwardSlash,
206-
ShortFormPrefixConvention = CliNamePrefixConvention.ForwardSlash
205+
Description = "A cli command with snake_case name casing and forward slash prefix conventions",
206+
NameCasingConvention = CliNameCasingConvention.SnakeCase,
207+
NamePrefixConvention = CliNamePrefixConvention.ForwardSlash,
208+
ShortFormPrefixConvention = CliNamePrefixConvention.ForwardSlash
207209
)]
208210
public class RootCliCommand
209211
{
210-
[CliOption(Description = "Description for Option1")]
211-
public string Option1 { get; set; } = "DefaultForOption1";
212+
[CliOption(Description = "Description for Option1")]
213+
public string Option1 { get; set; } = "DefaultForOption1";
212214

213-
[CliArgument(Description = "Description for Argument1")]
214-
public string Argument1 { get; set; } = "DefaultForArgument1";
215+
[CliArgument(Description = "Description for Argument1")]
216+
public string Argument1 { get; set; } = "DefaultForArgument1";
215217

216-
public void Run()
217-
{
218-
Console.WriteLine($@"Handler for '{GetType().FullName}' is run:");
219-
Console.WriteLine($@"Value for {nameof(Option1)} property is '{Option1}'");
220-
Console.WriteLine($@"Value for {nameof(Argument1)} property is '{Argument1}'");
221-
Console.WriteLine();
222-
}
218+
public void Run()
219+
{
220+
Console.WriteLine($@"Handler for '{GetType().FullName}' is run:");
221+
Console.WriteLine($@"Value for {nameof(Option1)} property is '{Option1}'");
222+
Console.WriteLine($@"Value for {nameof(Argument1)} property is '{Argument1}'");
223+
Console.WriteLine();
224+
}
223225
}
224226
```
225227
When you run the app via `TestApp.exe -?` or `dotnet run -- -?`, you see this usage help:
@@ -263,55 +265,55 @@ Defining sub-commands in DotMake.Commandline is very easy. We simply use nested
263265
[CliCommand(Description = "A root cli command with nested children")]
264266
public class WithNestedChildrenCliCommand
265267
{
266-
[CliOption(Description = "Description for Option1")]
267-
public string Option1 { get; set; } = "DefaultForOption1";
268+
[CliOption(Description = "Description for Option1")]
269+
public string Option1 { get; set; } = "DefaultForOption1";
268270

269-
[CliArgument(Description = "Description for Argument1")]
270-
public string Argument1 { get; set; } = "DefaultForArgument1";
271+
[CliArgument(Description = "Description for Argument1")]
272+
public string Argument1 { get; set; } = "DefaultForArgument1";
271273

272-
public void Run()
273-
{
274-
Console.WriteLine($@"Handler for '{GetType().FullName}' is run:");
275-
Console.WriteLine($@"Value for {nameof(Option1)} property is '{Option1}'");
276-
Console.WriteLine($@"Value for {nameof(Argument1)} property is '{Argument1}'");
277-
Console.WriteLine();
278-
}
274+
public void Run()
275+
{
276+
Console.WriteLine($@"Handler for '{GetType().FullName}' is run:");
277+
Console.WriteLine($@"Value for {nameof(Option1)} property is '{Option1}'");
278+
Console.WriteLine($@"Value for {nameof(Argument1)} property is '{Argument1}'");
279+
Console.WriteLine();
280+
}
279281

280-
[CliCommand(Description = "A nested level 1 sub-command")]
281-
public class Level1SubCliCommand
282-
{
283-
[CliOption(Description = "Description for Option1")]
284-
public string Option1 { get; set; } = "DefaultForOption1";
282+
[CliCommand(Description = "A nested level 1 sub-command")]
283+
public class Level1SubCliCommand
284+
{
285+
[CliOption(Description = "Description for Option1")]
286+
public string Option1 { get; set; } = "DefaultForOption1";
285287

286-
[CliArgument(Description = "Description for Argument1")]
287-
public string Argument1 { get; set; } = "DefaultForArgument1";
288+
[CliArgument(Description = "Description for Argument1")]
289+
public string Argument1 { get; set; } = "DefaultForArgument1";
288290

289-
public void Run()
290-
{
291-
Console.WriteLine($@"Handler for '{GetType().FullName}' is run:");
292-
Console.WriteLine($@"Value for {nameof(Option1)} property is '{Option1}'");
293-
Console.WriteLine($@"Value for {nameof(Argument1)} property is '{Argument1}'");
294-
Console.WriteLine();
295-
}
291+
public void Run()
292+
{
293+
Console.WriteLine($@"Handler for '{GetType().FullName}' is run:");
294+
Console.WriteLine($@"Value for {nameof(Option1)} property is '{Option1}'");
295+
Console.WriteLine($@"Value for {nameof(Argument1)} property is '{Argument1}'");
296+
Console.WriteLine();
297+
}
296298

297-
[CliCommand(Description = "A nested level 2 sub-command")]
298-
public class Level2SubCliCommand
299-
{
300-
[CliOption(Description = "Description for Option1")]
301-
public string Option1 { get; set; } = "DefaultForOption1";
299+
[CliCommand(Description = "A nested level 2 sub-command")]
300+
public class Level2SubCliCommand
301+
{
302+
[CliOption(Description = "Description for Option1")]
303+
public string Option1 { get; set; } = "DefaultForOption1";
302304

303-
[CliArgument(Description = "Description for Argument1")]
304-
public string Argument1 { get; set; } = "DefaultForArgument1";
305+
[CliArgument(Description = "Description for Argument1")]
306+
public string Argument1 { get; set; } = "DefaultForArgument1";
305307

306-
public void Run()
307-
{
308-
Console.WriteLine($@"Handler for '{GetType().FullName}' is run:");
309-
Console.WriteLine($@"Value for {nameof(Option1)} property is '{Option1}'");
310-
Console.WriteLine($@"Value for {nameof(Argument1)} property is '{Argument1}'");
311-
Console.WriteLine();
312-
}
313-
}
314-
}
308+
public void Run()
309+
{
310+
Console.WriteLine($@"Handler for '{GetType().FullName}' is run:");
311+
Console.WriteLine($@"Value for {nameof(Option1)} property is '{Option1}'");
312+
Console.WriteLine($@"Value for {nameof(Argument1)} property is '{Argument1}'");
313+
Console.WriteLine();
314+
}
315+
}
316+
}
315317
}
316318
```
317319
Just make sure you apply `CliCommand` attribute to the nested classes as well.
@@ -322,25 +324,25 @@ Another way to create hierarchy between commands, especially if you want to use
322324
[CliCommand(Description = "A root cli command")]
323325
public class RootCliCommand
324326
{
325-
[CliOption(Description = "Description for Option1")]
326-
public string Option1 { get; set; } = "DefaultForOption1";
327+
[CliOption(Description = "Description for Option1")]
328+
public string Option1 { get; set; } = "DefaultForOption1";
327329

328-
[CliArgument(Description = "Description for Argument1")]
329-
public string Argument1 { get; set; } = "DefaultForArgument1";
330+
[CliArgument(Description = "Description for Argument1")]
331+
public string Argument1 { get; set; } = "DefaultForArgument1";
330332

331-
public void Run()
332-
{
333-
Console.WriteLine($@"Handler for '{GetType().FullName}' is run:");
334-
Console.WriteLine($@"Value for {nameof(Option1)} property is '{Option1}'");
335-
Console.WriteLine($@"Value for {nameof(Argument1)} property is '{Argument1}'");
336-
Console.WriteLine();
337-
}
333+
public void Run()
334+
{
335+
Console.WriteLine($@"Handler for '{GetType().FullName}' is run:");
336+
Console.WriteLine($@"Value for {nameof(Option1)} property is '{Option1}'");
337+
Console.WriteLine($@"Value for {nameof(Argument1)} property is '{Argument1}'");
338+
Console.WriteLine();
339+
}
338340
}
339341

340342
[CliCommand(
341-
Name = "Level1External",
342-
Description = "An external level 1 sub-command",
343-
Parent = typeof(RootCliCommand)
343+
Name = "Level1External",
344+
Description = "An external level 1 sub-command",
345+
Parent = typeof(RootCliCommand)
344346
)]
345347
public class ExternalLevel1SubCliCommand
346348
{

src/.editorconfig

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Version: 4.1.1 (Using https://semver.org/)
2+
# Updated: 2022-05-23
3+
# See https://github.com/RehanSaeed/EditorConfig/releases for release notes.
4+
# See https://github.com/RehanSaeed/EditorConfig for updates to this file.
5+
# See http://EditorConfig.org for more information about .editorconfig files.
6+
7+
##########################################
8+
# Common Settings
9+
##########################################
10+
11+
# This file is the top-most EditorConfig file
12+
root = true
13+
14+
# All Files
15+
[*]
16+
charset = utf-8
17+
indent_style = space
18+
indent_size = 4
19+
insert_final_newline = true
20+
trim_trailing_whitespace = true
21+
22+
##########################################
23+
# File Extension Settings
24+
##########################################
25+
26+
# Visual Studio Solution Files
27+
[*.sln]
28+
indent_style = tab
29+
30+
# Visual Studio XML Project Files
31+
[*.{csproj,vbproj,vcxproj.filters,proj,projitems,shproj}]
32+
indent_size = 2
33+
34+
# XML Configuration Files
35+
[*.{xml,config,props,targets,nuspec,resx,ruleset,vsixmanifest,vsct}]
36+
indent_size = 2
37+
38+
# JSON Files
39+
[*.{json,json5,webmanifest}]
40+
indent_size = 2
41+
42+
# YAML Files
43+
[*.{yml,yaml}]
44+
indent_size = 2
45+
46+
# Markdown Files
47+
[*.{md,mdx}]
48+
trim_trailing_whitespace = false
49+
50+
# Web Files
51+
[*.{htm,html,js,jsm,ts,tsx,cjs,cts,ctsx,mjs,mts,mtsx,css,sass,scss,less,pcss,svg,vue}]
52+
indent_size = 2
53+
54+
# Batch Files
55+
[*.{cmd,bat}]
56+
end_of_line = crlf
57+
58+
# Bash Files
59+
[*.sh]
60+
end_of_line = lf
61+
62+
# Makefiles
63+
[Makefile]
64+
indent_style = tab

src/Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<!-- https://learn.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props#generateassemblyinfo -->
5-
<VersionPrefix>1.2.0</VersionPrefix>
5+
<VersionPrefix>1.2.1</VersionPrefix>
66
<Product>DotMake Command-Line</Product>
77
<Company>DotMake</Company>
88
<!-- Copyright is also used for NuGet metadata -->

0 commit comments

Comments
 (0)