diff --git a/README.md b/README.md index 9ad01a6e5..de31d6274 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# RSCG - 281 Examples of Roslyn Source Code Generators / 16 created by Microsoft / +# RSCG - 282 Examples of Roslyn Source Code Generators / 16 created by Microsoft / -The RSCG_Examples repository is a comprehensive documentation system that automatically processes and showcases 281 Roslyn Source Code Generator (RSCG) examples. The system transforms individual RSCG projects into structured documentation with code examples and cross-referenced content with a searchable website and code example exports. +The RSCG_Examples repository is a comprehensive documentation system that automatically processes and showcases 282 Roslyn Source Code Generator (RSCG) examples. The system transforms individual RSCG projects into structured documentation with code examples and cross-referenced content with a searchable website and code example exports. This system serves as both a learning resource for .NET developers interested in source generators and an automated pipeline for maintaining up-to-date documentation about the RSCG ecosystem -## Latest Update : 2026-08-21 => 21 August 2026 +## Latest Update : 2026-08-22 => 22 August 2026 If you want to see examples with code, please click ***[List V2](https://ignatandrei.github.io/RSCG_Examples/v2/docs/List-of-RSCG)*** @@ -24,8 +24,30 @@ If you want to be notified each time I add a new RSCG example , please click htt ## Content -Those are the 281 Roslyn Source Code Generators that I have tested you can see and download source code example. +Those are the 282 Roslyn Source Code Generators that I have tested you can see and download source code example. ( including 16 from Microsoft ) +### 282. [Clap.Net](https://ignatandrei.github.io/RSCG_Examples/v2/docs/Clap.Net) , in the [CommandLine](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#commandline) category + +Generated on : 2026-08-22 => 22 August 2026 + +
+ Expand + + + +Author: Simon Curtis + +Package Description + +Nuget: [https://www.nuget.org/packages/Clap.Net/](https://www.nuget.org/packages/Clap.Net/) + + +Link: [https://ignatandrei.github.io/RSCG_Examples/v2/docs/Clap.Net](https://ignatandrei.github.io/RSCG_Examples/v2/docs/Clap.Net) + +Source: [https://github.com/simon-curtis/Clap.Net](https://github.com/simon-curtis/Clap.Net) + +
+ ### 281. [EndpointHelpers](https://ignatandrei.github.io/RSCG_Examples/v2/docs/EndpointHelpers) , in the [MVC](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#mvc) category Generated on : 2026-08-21 => 21 August 2026 diff --git a/later.md b/later.md index 80b278e77..bf23de164 100644 --- a/later.md +++ b/later.md @@ -1,6 +1,6 @@ # Just later -## Latest Update : 2026-08-21 => 21 August 2026 +## Latest Update : 2026-08-22 => 22 August 2026 diff --git a/v2/.tours/Clap.Net.tour b/v2/.tours/Clap.Net.tour new file mode 100644 index 000000000..563b200bb --- /dev/null +++ b/v2/.tours/Clap.Net.tour @@ -0,0 +1,36 @@ + +{ + "$schema": "https://aka.ms/codetour-schema", + "title": "Clap.Net", + "steps": + [ + { + "file": "rscg_examples/Clap.Net/src/ConsoleDemo/ConsoleDemo.csproj", + "description": "First, we add Nuget [Clap.Net](https://www.nuget.org/packages/Clap.Net/) in csproj ", + "pattern": "Clap.Net" + } + + ,{ + "file": "rscg_examples/Clap.Net/src/ConsoleDemo/CmdForSum.cs", + "description": "File CmdForSum.cs ", + "pattern": "this is the code" + } + + ,{ + "file": "rscg_examples/Clap.Net/src/ConsoleDemo/Program.cs", + "description": "File Program.cs \r\n>> dotnet run --project rscg_examples/Clap.Net/src/ConsoleDemo/ConsoleDemo.csproj ", + "pattern": "this is the code" + } + + + ,{ + "file": "rscg_examples/Clap.Net/src/ConsoleDemo/obj/GX/Clap.Net/Clap.Net.ClapGenerator/CmdForSum.ParseMethod.g.cs", + "description": "Generated File 1 from 1 : CmdForSum.ParseMethod.g.cs ", + "line": 1 + } + + ], + + "ref": "main" + +} \ No newline at end of file diff --git a/v2/Generator/all.csv b/v2/Generator/all.csv index 466b83625..8d7bffebe 100644 --- a/v2/Generator/all.csv +++ b/v2/Generator/all.csv @@ -280,3 +280,4 @@ Nr,Key,Source,Category 279,ReflectionIT.DisposeGenerator, https://github.com/sonnemaf/ReflectionIT.DisposeGenerator,Disposer 280,serde, https://github.com/serdedotnet/serde,Serializer 281,EndpointHelpers, https://github.com/gumbarros/EndpointHelpers,MVC +282,Clap.Net, https://github.com/simon-curtis/Clap.Net,CommandLine diff --git a/v2/RSCGExamplesData/GeneratorDataRec.json b/v2/RSCGExamplesData/GeneratorDataRec.json index b43bd2343..f981bc517 100644 --- a/v2/RSCGExamplesData/GeneratorDataRec.json +++ b/v2/RSCGExamplesData/GeneratorDataRec.json @@ -1703,5 +1703,12 @@ "Category": 36, "dtStart": "2026-08-21T00:00:00", "show": true + }, + { + "ID":"Clap.Net", + "Category":32, + "dtStart": "2026-08-22T00:00:00", + "show": true } + ] \ No newline at end of file diff --git a/v2/book/examples/Clap.Net.html b/v2/book/examples/Clap.Net.html new file mode 100644 index 000000000..208199197 --- /dev/null +++ b/v2/book/examples/Clap.Net.html @@ -0,0 +1,59 @@ + +

RSCG nr 282 : Clap.Net

+ +

Info

+Nuget : https://www.nuget.org/packages/Clap.Net/ + +

You can find more details at : https://github.com/simon-curtis/Clap.Net

+ +

Author :Simon Curtis

+ +

Source: https://github.com/simon-curtis/Clap.Net

+ +

About

+ +Command line arguments parsing + +

+ How to use +

+

+ Add reference to the Clap.Net in the csproj +

+ + +

This was for me the starting code

+ +
+ I have coded the file Program.cs +
+ +
+ +
+ I have coded the file CmdForSum.cs +
+ +
+

And here are the generated files

+ +
+ The file generated is CmdForSum.ParseMethod.g.cs +
+ + +

+ You can download the code and this page as pdf from + + https://ignatandrei.github.io/RSCG_Examples/v2/docs/Clap.Net + +

+ + +

+ You can see the whole list at + + https://ignatandrei.github.io/RSCG_Examples/v2/docs/List-of-RSCG + +

+ diff --git a/v2/book/list.html b/v2/book/list.html index 63f68a176..a76b73702 100644 --- a/v2/book/list.html +++ b/v2/book/list.html @@ -17,7 +17,7 @@

-This is the list of 281 RSCG with examples => +This is the list of 282 RSCG with examples =>

@@ -1150,6 +1150,10 @@

+ + + +
281 EndpointHelpers
282Clap.Net
diff --git a/v2/book/pandocHTML.yaml b/v2/book/pandocHTML.yaml index 3f14a1f9d..448881e85 100644 --- a/v2/book/pandocHTML.yaml +++ b/v2/book/pandocHTML.yaml @@ -295,6 +295,7 @@ input-files: - examples/ReflectionIT.DisposeGenerator.html - examples/serde.html - examples/EndpointHelpers.html +- examples/Clap.Net.html # or you may use input-file: with a single value # defaults: diff --git a/v2/docFind.json b/v2/docFind.json index f175c0182..3a0098279 100644 --- a/v2/docFind.json +++ b/v2/docFind.json @@ -1684,5 +1684,11 @@ "category": "MVC", "href": "/RSCG_Examples/v2/docs/EndpointHelpers/", "body": "Source generators that add strongly-typed UrlHelper and LinkGenerator APIs for ASP.NET Core MVC controllers." + }, + { + "title": "Clap.Net", + "category": "CommandLine", + "href": "/RSCG_Examples/v2/docs/Clap.Net/", + "body": "Package Description" } ] \ No newline at end of file diff --git a/v2/rscg_examples/Clap.Net/description.json b/v2/rscg_examples/Clap.Net/description.json new file mode 100644 index 000000000..855a75d77 --- /dev/null +++ b/v2/rscg_examples/Clap.Net/description.json @@ -0,0 +1,22 @@ +{ + "generator":{ + "name":"Clap.Net", + "nuget":[ + "https://www.nuget.org/packages/Clap.Net/" + ], + "link":"https://github.com/simon-curtis/Clap.Net", + "author":"Simon Curtis", + "source":"https://github.com/simon-curtis/Clap.Net" + }, + "data":{ + "goodFor":["Command line arguments parsing"], + "csprojDemo":"ConsoleDemo.csproj", + "csFiles":["Program.cs","CmdForSum.cs"], + "excludeDirectoryGenerated":[""], + "includeAdditionalFiles":[""] + }, + "links":{ + "blog":"", + "video":"" + } +} \ No newline at end of file diff --git a/v2/rscg_examples/Clap.Net/nuget.txt b/v2/rscg_examples/Clap.Net/nuget.txt new file mode 100644 index 000000000..882e74f60 --- /dev/null +++ b/v2/rscg_examples/Clap.Net/nuget.txt @@ -0,0 +1 @@ +Package Description \ No newline at end of file diff --git a/v2/rscg_examples/Clap.Net/readme.txt b/v2/rscg_examples/Clap.Net/readme.txt new file mode 100644 index 000000000..abfad0fa2 --- /dev/null +++ b/v2/rscg_examples/Clap.Net/readme.txt @@ -0,0 +1,412 @@ +# Clap.Net + +**A modern, type-safe command-line argument parser for .NET using source generation.** + +Clap.Net brings the power and elegance of Rust's [clap](https://github.com/clap-rs/clap) library to the .NET ecosystem. Define your CLI with attributes and properties, and let the source generator handle the rest—no reflection, no runtime overhead, just clean, fast, generated code. + +## Why Clap.Net? + +**Zero Runtime Overhead** +Source generators produce parsing code at compile time. No reflection, no performance penalties—just pure, optimized C# code. + +**Type Safety First** +Your command-line interface is defined using strongly-typed classes and properties. Catch errors at compile time, not runtime. + +**Batteries Included** +Automatic help generation, version handling, environment variable fallback, subcommands, and rich argument types—all out of the box. + +**Developer Friendly** +Leverage C# language features like `required` properties, nullable types, and pattern matching. Your CLI definition is just normal C# code with a few attributes. + +## Quick Start + +### Installation + +```bash +dotnet add package Clap.Net +``` + +### Basic Example + +Define a command with a simple attribute: + +```csharp +using Clap.Net; + +[Command(Name = "greet", About = "A friendly greeter", Version = "1.0.0")] +public partial class GreetCommand +{ + [Arg(Short = 'n', Long = "name", Help = "The name to greet")] + public string Name { get; init; } = "World"; + + [Arg(Short = 'v', Long = "verbose")] + public bool Verbose { get; init; } + + public required string Message { get; init; } +} +``` + +Parse and use it: + +```csharp +var cmd = GreetCommand.Parse(args); +Console.WriteLine($"{cmd.Message}, {cmd.Name}!"); +if (cmd.Verbose) + Console.WriteLine("Verbose mode enabled."); +``` + +```bash +$ dotnet run -- "Hello" --name "Alice" -v +Hello, Alice! +Verbose mode enabled. + +$ dotnet run -- --help +# Displays auto-generated help text +``` + +## Complete Example with Subcommands + +Clap.Net makes complex CLIs easy to build and maintain: + +```csharp +using Clap.Net; + +namespace Clap.Examples; + +[Command(Name = "image-converter", About = "Convert and manage images")] +public partial class ImageConverter +{ + [Arg(Help = "The path of the image to convert")] + public required string Path { get; init; } + + [Arg(Help = "The destination path (default: .[new-ext])", Last = true)] + public string? DestinationPath { get; init; } + + [Arg(Short = 'e', Long = "extension", Help = "Target image format")] + public string? Extension { get; init; } + + [Arg(Short = 'v', Long = "verbose", Help = "Enable verbose output")] + public bool Verbose { get; set; } + + [Command] + public ImageConverterCommands? Command { get; init; } +} + +[SubCommand] +public partial class ImageConverterCommands +{ + [Command(About = "Show conversion history")] + public partial class History : ImageConverterCommands; + + [Command(About = "Publish converted images")] + public partial class Publish : ImageConverterCommands + { + [Arg(Help = "The URL to publish the image to")] + public required string[] UploadUrl { get; init; } + } +} +``` + +**Using the parser:** + +```csharp +var app = ImageConverter.Parse(args); + +switch (app.Command) +{ + case ImageConverterCommands.History: + Console.WriteLine("Showing conversion history..."); + break; + + case ImageConverterCommands.Publish publish: + Console.WriteLine($"Publishing to {string.Join(", ", publish.UploadUrl)}"); + break; + + default: + Console.WriteLine($"Converting {app.Path} to {app.Extension ?? "default format"}"); + break; +} +``` + +**Command-line usage:** + +```bash +# Basic conversion +$ dotnet run -- -v "~/Downloads/tree.png" "~/Downloads/tree.jpg" + +# With subcommand +$ dotnet run -- "~/Downloads/tree.png" -e "jpg" publish "https://yourdomain.com/upload" + +# Get help for subcommands +$ dotnet run -- publish --help +``` + +## Argument Validation + +Clap.Net supports the full `System.ComponentModel.DataAnnotations` validation framework, allowing you to validate argument values at parse time with clear error messages. + +### Built-in Validators + +Use standard .NET validation attributes to enforce constraints: + +```csharp +using System.ComponentModel.DataAnnotations; + +[Command(Name = "server", About = "Start a web server")] +public partial class ServerCommand +{ + [Arg(Long = "port")] + [Range(1, 65535, ErrorMessage = "Port must be between 1 and 65535")] + public required int Port { get; init; } + + [Arg(Long = "host")] + [RegularExpression(@"^[a-zA-Z0-9.-]+$", ErrorMessage = "Invalid hostname")] + public string Host { get; init; } = "localhost"; + + [Arg(Long = "email")] + [EmailAddress(ErrorMessage = "Invalid email address")] + public required string Email { get; init; } + + [Arg(Long = "username")] + [StringLength(20, MinimumLength = 5)] + [RegularExpression(@"^[a-zA-Z0-9_]+$", ErrorMessage = "Only letters, numbers, and underscores allowed")] + public required string Username { get; init; } +} +``` + +**Available validators:** +- `[Range(min, max)]` - Numeric range validation +- `[StringLength(max, MinimumLength = min)]` - String length constraints +- `[RegularExpression("pattern")]` - Regex pattern matching +- `[EmailAddress]`, `[Phone]`, `[Url]`, `[CreditCard]` - Format validators +- Multiple validators can be combined on a single property + +### Custom Validators + +Create your own validators by inheriting from `ValidationAttribute`: + +```csharp +public class PortRangeAttribute : ValidationAttribute +{ + public override bool IsValid(object? value) + { + if (value is int port) + return port >= 1 && port <= 65535; + return false; + } +} + +[Command] +public partial class MyApp +{ + [Arg(Long = "port")] + [PortRange(ErrorMessage = "Invalid port number")] + public required int Port { get; init; } +} +``` + +### Handling Validation Errors + +Validation failures return a `ParseError` with detailed messages: + +```csharp +var result = ServerCommand.TryParse(args); + +if (result.IsT3) // ParseError +{ + Console.Error.WriteLine(result.AsT3.Message); + // Output: "Validation failed for 'Port': Port must be between 1 and 65535" + return 1; +} + +var cmd = result.AsT0; +// Use validated command... +``` + +## Multi-Value Arguments + +Clap.Net provides flexible ways to accept multiple values for a single argument, with different behaviors depending on how you define your properties. + +### Array Arguments (Per-Flag Values) + +For **named arguments** with array types (`string[]`, `int[]`, etc.), each flag invocation captures **one value**. To collect multiple values, repeat the flag: + +```csharp +[Command] +public partial class BenchmarkCommand +{ + [Arg(Short = 't', Long = "test", Help = "Tests to run")] + public string[]? Tests { get; init; } + + // Positional array consumes all remaining positional values + public string[] Extensions { get; init; } = ["js", "ts"]; +} +``` + +**Usage:** +```bash +# Single value - Tests gets ["unit"], Extensions gets ["py", "go"] +$ app -t unit py go + +# Multiple values - repeat the flag for each value +$ app -t unit -t integration py go +# Tests gets ["unit", "integration"], Extensions gets ["py", "go"] + +# Without -t, all values go to positional +$ app py go js +# Tests is null/empty, Extensions gets ["py", "go", "js"] +``` + +**Key behavior:** +- Named array arguments: **One value per flag invocation** +- Positional array arguments: **Greedy - consumes all remaining positional values** +- This prevents named arrays from "stealing" values intended for positional arguments + +### Action.Append (Alternative Pattern) + +For collection types with `Action.Append`, the behavior is similar but uses `IEnumerable`: + +```csharp +[Command] +public partial class TagCommand +{ + [Arg(Short = 't', Long = "tag", Action = ArgAction.Append)] + public IEnumerable Tags { get; init; } = []; +} +``` + +**Usage:** +```bash +$ app -t "v1.0" -t "release" -t "stable" +# Tags gets ["v1.0", "release", "stable"] +``` + +### When to Use Each + +| Pattern | Type | Behavior | Use Case | +|---------|------|----------|----------| +| **Array** | `string[]` | One value per flag | Named args that need to work with positional args | +| **Action.Append** | `IEnumerable` | One value per flag | Named args only, more explicit about appending | +| **Positional Array** | `string[]` | Greedy (all remaining) | Variadic trailing arguments (like `files...`) | + +### Examples + +**File processor with filters and files:** +```csharp +[Command] +public partial class ProcessFiles +{ + [Arg(Short = 'e', Long = "exclude")] + public string[] ExcludePatterns { get; init; } = []; + + public string[] Files { get; init; } = []; // Positional +} + +// Usage: +$ app -e "*.tmp" -e "*.log" file1.txt file2.txt file3.txt +// ExcludePatterns: ["*.tmp", "*.log"] +// Files: ["file1.txt", "file2.txt", "file3.txt"] +``` + +**Test runner with specific tests and extensions:** +```csharp +[Command] +public partial class TestRunner +{ + [Arg(Short = 't')] + public string[]? Tests { get; init; } + + public string[] Extensions { get; init; } = ["js", "ts", "py"]; +} + +// Usage: +$ app -t unit -t integration go rb +// Tests: ["unit", "integration"] +// Extensions: ["go", "rb"] +``` + +## Key Features + +**Strongly-Typed Parsing** +Define your CLI interface using classes, properties, and attributes. Get compile-time safety and IntelliSense support. + +**Powerful Subcommands** +Create complex command hierarchies using nested classes. Each subcommand can have its own arguments and options. + +**Rich Argument Types** +Support for strings, numbers, bools, enums, arrays, and any type with `TryParse`. Custom parsing logic is straightforward. + +**Automatic Help Generation** +Help text is generated from your attributes and XML documentation comments. Use `--help` on any command or subcommand. + +**Environment Variable Fallback** +Options can fallback to environment variables when not provided on the command line. + +**Negatable Flags** +Boolean flags can be negated with `--no-*` syntax for flexible configuration. + +## Debugging Generated Code + +If you're troubleshooting source generation issues or want to inspect the generated parser code, add this to your `.csproj`: + +```xml + + true + bin/Generated + +``` + +Generated files will be written to `bin/Generated/`, allowing you to step through the parser logic and understand how arguments are processed. + +## Feature Roadmap + +Clap.Net aims for near feature-parity with clap-rs. Here's what's implemented and what's coming: + +### Implemented + +- **Commands** + - Root command definition with Name, About, and Version + - Subcommands with nested class hierarchies + - Automatic help text for all commands + +- **Arguments & Options** + - Short (`-v`) and long (`--verbose`) flags + - Positional arguments with order-based mapping + - Required vs optional arguments + - Environment variable fallback + - Default values via C# property initializers + - Multiple values (arrays and collections) + - TryParse support for custom types + - Custom parser functions via `ValueParser` attribute + - Argument actions (Set, Append, Count) + - Full `ValidationAttribute` support (Range, StringLength, RegularExpression, EmailAddress, custom validators) + +- **Flags** + - Boolean flags (presence/absence) + - Negatable flags (`--no-debug`) + +- **Help & Version** + - Automatic `--help` generation + - Automatic `--version` handling + - Custom help text from XML docs + +### Coming Soon + +- Argument value suggestions and completion +- More flexible argument ordering +- Improved error messages + +## Contributing + +Clap.Net is actively developed and there's plenty of work to do! Pull requests are welcome for: + +- Bug fixes and performance improvements +- New features from the roadmap +- Documentation and examples +- Test coverage + +Check out the [CLAUDE.md](./CLAUDE.md) file for architectural guidance and development patterns. + +## License + +MIT License - see [LICENSE](./LICENSE) for details diff --git a/v2/rscg_examples/Clap.Net/src/ConsoleDemo.slnx b/v2/rscg_examples/Clap.Net/src/ConsoleDemo.slnx new file mode 100644 index 000000000..d66776aa2 --- /dev/null +++ b/v2/rscg_examples/Clap.Net/src/ConsoleDemo.slnx @@ -0,0 +1,3 @@ + + + diff --git a/v2/rscg_examples/Clap.Net/src/ConsoleDemo/CmdForSum.cs b/v2/rscg_examples/Clap.Net/src/ConsoleDemo/CmdForSum.cs new file mode 100644 index 000000000..d013d95af --- /dev/null +++ b/v2/rscg_examples/Clap.Net/src/ConsoleDemo/CmdForSum.cs @@ -0,0 +1,19 @@ + +using Clap.Net; + +namespace ConsoleDemo; + +[Command(Name = "MakeSum")] +public partial class CmdForSum +{ + [Arg(Short = 'f', Long = "firstarg", Help = "first argument")] + public int x { get; set; } = 0; + + [Arg(Short = 's', Long = "secondarg", Help = "second argument")] + public int y { get; set; } = 0; + + public void MySum() + { + Console.WriteLine($"Hello, {x+y}!"); + } +} diff --git a/v2/rscg_examples/Clap.Net/src/ConsoleDemo/ConsoleDemo.csproj b/v2/rscg_examples/Clap.Net/src/ConsoleDemo/ConsoleDemo.csproj new file mode 100644 index 000000000..043c39e40 --- /dev/null +++ b/v2/rscg_examples/Clap.Net/src/ConsoleDemo/ConsoleDemo.csproj @@ -0,0 +1,17 @@ + + + + Exe + net10.0 + enable + enable + + + true + $(BaseIntermediateOutputPath)\GX + + + + + + diff --git a/v2/rscg_examples/Clap.Net/src/ConsoleDemo/Program.cs b/v2/rscg_examples/Clap.Net/src/ConsoleDemo/Program.cs new file mode 100644 index 000000000..ea4be36b1 --- /dev/null +++ b/v2/rscg_examples/Clap.Net/src/ConsoleDemo/Program.cs @@ -0,0 +1,7 @@ +using ConsoleDemo; + + +// --help +// -f 10 -s 20 +var cmd = CmdForSum.Parse(args); +cmd.MySum(); \ No newline at end of file diff --git a/v2/rscg_examples/Clap.Net/video.json b/v2/rscg_examples/Clap.Net/video.json new file mode 100644 index 000000000..4008ce435 --- /dev/null +++ b/v2/rscg_examples/Clap.Net/video.json @@ -0,0 +1,39 @@ +{ + "scriptName": "Clap.Net", + "steps": +[ + {"typeStep":"exec","arg":"clipchamp.exe launch"}, + {"typeStep":"text","arg": "Welcome to Roslyn Examples"}, + {"typeStep":"text","arg":"If you want to see more examples , see List Of RSCG"}, + {"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/List-of-RSCG"}, + {"typeStep":"text","arg": "My name is Andrei Ignat and I am deeply fond of Roslyn Source Code Generator. "}, + +{"typeStep":"text","arg": "Today I will present Clap.Net . Command line arguments parsing ."}, +{"typeStep":"browser","arg":"https://www.nuget.org/packages/Clap.Net/"}, +{"typeStep":"text","arg": "The whole example is here"}, +{"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/Clap.Net"}, +{"typeStep":"text","arg": "You can download the code from here"}, +{"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/Clap.Net#download-example-net--c-"}, +{"typeStep":"text","arg":"Here is the code downloaded "}, +{"typeStep":"exec","arg":"explorer.exe /select,D:\\gth\\RSCG_Examples\\v2\\Generator.sln"}, +{"typeStep":"text","arg": "So , let's start the project with Visual Studio Code "}, +{"typeStep":"stepvscode","arg": "-n D:\\gth\\RSCG_Examples\\v2"}, + +{"typeStep":"text","arg": "To use it ,you will put the Nuget Clap.Net into the csproj "}, + +{"typeStep":"stepvscode","arg": "-r -g D:\\gth\\RSCG_Examples\\v2\\rscg_examples\\Clap.Net\\src\\ConsoleDemo\\ConsoleDemo.csproj"}, + +{"typeStep":"text","arg": "And now I will show you an example of using Clap.Net"}, + +{"typeStep":"hide","arg": "now execute the tour in VSCode"}, +{"typeStep":"tour", "arg": "src/.tours/"}, +{"typeStep":"text","arg":" And I will execute the project"}, +{"typeStep":"showproj", "arg":"ConsoleDemo.csproj"}, +{"typeStep":"text","arg":" This concludes the project"}, +{"typeStep":"waitseconds","arg":"30"}, +{"typeStep":"text","arg": "Remember, you can download the code from here"}, +{"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/Clap.Net#download-example-net--c-", +SpeakTest=" "}, +{"typeStep":"waitseconds","arg":"30"}, +] +} diff --git a/v2/rscg_examples_site/docs/Authors/Simon_Curtis.md b/v2/rscg_examples_site/docs/Authors/Simon_Curtis.md new file mode 100644 index 000000000..16d475bb7 --- /dev/null +++ b/v2/rscg_examples_site/docs/Authors/Simon_Curtis.md @@ -0,0 +1,7 @@ +# Author : Simon Curtis + +Number RSCG: 1 + + + 1 [Clap.Net](/docs/Clap.Net) [![Nuget](https://img.shields.io/nuget/dt/Clap.Net?label=Clap.Net)](https://www.nuget.org/packages/Clap.Net/) ![GitHub Repo stars](https://img.shields.io/github/stars/simon-curtis/Clap.Net?style=social) 2026-08-22 + diff --git a/v2/rscg_examples_site/docs/Categories/CommandLine.md b/v2/rscg_examples_site/docs/Categories/CommandLine.md index 009c182ef..c9b4e19de 100644 --- a/v2/rscg_examples_site/docs/Categories/CommandLine.md +++ b/v2/rscg_examples_site/docs/Categories/CommandLine.md @@ -1,14 +1,16 @@

CommandLine

-Number RSCG: 5 +Number RSCG: 6 1 [ArgumentParsing](/docs/ArgumentParsing) [![Nuget](https://img.shields.io/nuget/dt/ArgumentParsing?label=ArgumentParsing)](https://www.nuget.org/packages/ArgumentParsing/) ![GitHub Repo stars](https://img.shields.io/github/stars/DoctorKrolic/ArgumentParsing?style=social) 2025-07-01 - 2 [CommandLine](/docs/CommandLine) [![Nuget](https://img.shields.io/nuget/dt/DotMake.CommandLine?label=DotMake.CommandLine)](https://www.nuget.org/packages/DotMake.CommandLine/) ![GitHub Repo stars](https://img.shields.io/github/stars/dotmake-build/command-line?style=social) 2024-02-11 + 2 [Clap.Net](/docs/Clap.Net) [![Nuget](https://img.shields.io/nuget/dt/Clap.Net?label=Clap.Net)](https://www.nuget.org/packages/Clap.Net/) ![GitHub Repo stars](https://img.shields.io/github/stars/simon-curtis/Clap.Net?style=social) 2026-08-22 - 3 [ConsoleAppFramework](/docs/ConsoleAppFramework) [![Nuget](https://img.shields.io/nuget/dt/ConsoleAppFramework?label=ConsoleAppFramework)](https://www.nuget.org/packages/ConsoleAppFramework/) ![GitHub Repo stars](https://img.shields.io/github/stars/Cysharp/ConsoleAppFramework?style=social) 2025-10-02 + 3 [CommandLine](/docs/CommandLine) [![Nuget](https://img.shields.io/nuget/dt/DotMake.CommandLine?label=DotMake.CommandLine)](https://www.nuget.org/packages/DotMake.CommandLine/) ![GitHub Repo stars](https://img.shields.io/github/stars/dotmake-build/command-line?style=social) 2024-02-11 - 4 [docopt.net](/docs/docopt.net) [![Nuget](https://img.shields.io/nuget/dt/docopt.net?label=docopt.net)](https://www.nuget.org/packages/docopt.net/) ![GitHub Repo stars](https://img.shields.io/github/stars/docopt/docopt.net?style=social) 2025-12-15 + 4 [ConsoleAppFramework](/docs/ConsoleAppFramework) [![Nuget](https://img.shields.io/nuget/dt/ConsoleAppFramework?label=ConsoleAppFramework)](https://www.nuget.org/packages/ConsoleAppFramework/) ![GitHub Repo stars](https://img.shields.io/github/stars/Cysharp/ConsoleAppFramework?style=social) 2025-10-02 - 5 [TeCLI](/docs/TeCLI) [![Nuget](https://img.shields.io/nuget/dt/TeCLI?label=TeCLI)](https://www.nuget.org/packages/TeCLI/) ![GitHub Repo stars](https://img.shields.io/github/stars/tyevco/TeCLI?style=social) 2025-11-07 + 5 [docopt.net](/docs/docopt.net) [![Nuget](https://img.shields.io/nuget/dt/docopt.net?label=docopt.net)](https://www.nuget.org/packages/docopt.net/) ![GitHub Repo stars](https://img.shields.io/github/stars/docopt/docopt.net?style=social) 2025-12-15 + + 6 [TeCLI](/docs/TeCLI) [![Nuget](https://img.shields.io/nuget/dt/TeCLI?label=TeCLI)](https://www.nuget.org/packages/TeCLI/) ![GitHub Repo stars](https://img.shields.io/github/stars/tyevco/TeCLI?style=social) 2025-11-07 \ No newline at end of file diff --git a/v2/rscg_examples_site/docs/Categories/_PrimitiveCommandLine.mdx b/v2/rscg_examples_site/docs/Categories/_PrimitiveCommandLine.mdx index e0120b5d9..5eef3bfad 100644 --- a/v2/rscg_examples_site/docs/Categories/_PrimitiveCommandLine.mdx +++ b/v2/rscg_examples_site/docs/Categories/_PrimitiveCommandLine.mdx @@ -2,13 +2,15 @@ 1 [ArgumentParsing](/docs/ArgumentParsing) [![Nuget](https://img.shields.io/nuget/dt/ArgumentParsing?label=ArgumentParsing)](https://www.nuget.org/packages/ArgumentParsing/) ![GitHub Repo stars](https://img.shields.io/github/stars/DoctorKrolic/ArgumentParsing?style=social) 2025-07-01 - 2 [CommandLine](/docs/CommandLine) [![Nuget](https://img.shields.io/nuget/dt/DotMake.CommandLine?label=DotMake.CommandLine)](https://www.nuget.org/packages/DotMake.CommandLine/) ![GitHub Repo stars](https://img.shields.io/github/stars/dotmake-build/command-line?style=social) 2024-02-11 + 2 [Clap.Net](/docs/Clap.Net) [![Nuget](https://img.shields.io/nuget/dt/Clap.Net?label=Clap.Net)](https://www.nuget.org/packages/Clap.Net/) ![GitHub Repo stars](https://img.shields.io/github/stars/simon-curtis/Clap.Net?style=social) 2026-08-22 - 3 [ConsoleAppFramework](/docs/ConsoleAppFramework) [![Nuget](https://img.shields.io/nuget/dt/ConsoleAppFramework?label=ConsoleAppFramework)](https://www.nuget.org/packages/ConsoleAppFramework/) ![GitHub Repo stars](https://img.shields.io/github/stars/Cysharp/ConsoleAppFramework?style=social) 2025-10-02 + 3 [CommandLine](/docs/CommandLine) [![Nuget](https://img.shields.io/nuget/dt/DotMake.CommandLine?label=DotMake.CommandLine)](https://www.nuget.org/packages/DotMake.CommandLine/) ![GitHub Repo stars](https://img.shields.io/github/stars/dotmake-build/command-line?style=social) 2024-02-11 - 4 [docopt.net](/docs/docopt.net) [![Nuget](https://img.shields.io/nuget/dt/docopt.net?label=docopt.net)](https://www.nuget.org/packages/docopt.net/) ![GitHub Repo stars](https://img.shields.io/github/stars/docopt/docopt.net?style=social) 2025-12-15 + 4 [ConsoleAppFramework](/docs/ConsoleAppFramework) [![Nuget](https://img.shields.io/nuget/dt/ConsoleAppFramework?label=ConsoleAppFramework)](https://www.nuget.org/packages/ConsoleAppFramework/) ![GitHub Repo stars](https://img.shields.io/github/stars/Cysharp/ConsoleAppFramework?style=social) 2025-10-02 - 5 [TeCLI](/docs/TeCLI) [![Nuget](https://img.shields.io/nuget/dt/TeCLI?label=TeCLI)](https://www.nuget.org/packages/TeCLI/) ![GitHub Repo stars](https://img.shields.io/github/stars/tyevco/TeCLI?style=social) 2025-11-07 + 5 [docopt.net](/docs/docopt.net) [![Nuget](https://img.shields.io/nuget/dt/docopt.net?label=docopt.net)](https://www.nuget.org/packages/docopt.net/) ![GitHub Repo stars](https://img.shields.io/github/stars/docopt/docopt.net?style=social) 2025-12-15 + + 6 [TeCLI](/docs/TeCLI) [![Nuget](https://img.shields.io/nuget/dt/TeCLI?label=TeCLI)](https://www.nuget.org/packages/TeCLI/) ![GitHub Repo stars](https://img.shields.io/github/stars/tyevco/TeCLI?style=social) 2025-11-07 ### See category diff --git a/v2/rscg_examples_site/docs/RSCG-Examples/Clap.Net.md b/v2/rscg_examples_site/docs/RSCG-Examples/Clap.Net.md new file mode 100644 index 000000000..f0d67026f --- /dev/null +++ b/v2/rscg_examples_site/docs/RSCG-Examples/Clap.Net.md @@ -0,0 +1,875 @@ +--- +sidebar_position: 2820 +title: 282 - Clap.Net +description: Command line arguments parsing +slug: /Clap.Net +--- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import TOCInline from '@theme/TOCInline'; +import SameCategory from '../Categories/_PrimitiveCommandLine.mdx'; + +# Clap.Net by Simon Curtis + + + + +## NuGet / site data +[![Nuget](https://img.shields.io/nuget/dt/Clap.Net?label=Clap.Net)](https://www.nuget.org/packages/Clap.Net/) +[![GitHub last commit](https://img.shields.io/github/last-commit/simon-curtis/Clap.Net?label=updated)](https://github.com/simon-curtis/Clap.Net) +![GitHub Repo stars](https://img.shields.io/github/stars/simon-curtis/Clap.Net?style=social) + +## Details + +### Info +:::info + +Name: **Clap.Net** + +Package Description + +Author: Simon Curtis + +NuGet: +*https://www.nuget.org/packages/Clap.Net/* + + +You can find more details at https://github.com/simon-curtis/Clap.Net + +Source: https://github.com/simon-curtis/Clap.Net + +::: + +### Author +:::note +Simon Curtis +![Alt text](https://github.com/simon-curtis.png) +::: + +## Original Readme +:::note + +### Clap.Net + +**A modern, type-safe command-line argument parser for .NET using source generation.** + +Clap.Net brings the power and elegance of Rust's [clap](https://github.com/clap-rs/clap) library to the .NET ecosystem. Define your CLI with attributes and properties, and let the source generator handle the rest—no reflection, no runtime overhead, just clean, fast, generated code. + +###### Why Clap.Net? + +**Zero Runtime Overhead** +Source generators produce parsing code at compile time. No reflection, no performance penalties—just pure, optimized C# code. + +**Type Safety First** +Your command-line interface is defined using strongly-typed classes and properties. Catch errors at compile time, not runtime. + +**Batteries Included** +Automatic help generation, version handling, environment variable fallback, subcommands, and rich argument types—all out of the box. + +**Developer Friendly** +Leverage C# language features like `required` properties, nullable types, and pattern matching. Your CLI definition is just normal C# code with a few attributes. + +###### Quick Start + +######### Installation + +```bash +dotnet add package Clap.Net +``` + +######### Basic Example + +Define a command with a simple attribute: + +```csharp +using Clap.Net; + +[Command(Name = "greet", About = "A friendly greeter", Version = "1.0.0")] +public partial class GreetCommand +{ + [Arg(Short = 'n', Long = "name", Help = "The name to greet")] + public string Name \{ get; init; \} = "World"; + + [Arg(Short = 'v', Long = "verbose")] + public bool Verbose \{ get; init; } + + public required string Message \{ get; init; } +} +``` + +Parse and use it: + +```csharp +var cmd = GreetCommand.Parse(args); +Console.WriteLine($"{cmd.Message}, {cmd.Name}!"); +if (cmd.Verbose) + Console.WriteLine("Verbose mode enabled."); +``` + +```bash +$ dotnet run -- "Hello" --name "Alice" -v +Hello, Alice! +Verbose mode enabled. + +$ dotnet run -- --help +### Displays auto-generated help text +``` + +###### Complete Example with Subcommands + +Clap.Net makes complex CLIs easy to build and maintain: + +```csharp +using Clap.Net; + +namespace Clap.Examples; + +[Command(Name = "image-converter", About = "Convert and manage images")] +public partial class ImageConverter +{ + [Arg(Help = "The path of the image to convert")] + public required string Path \{ get; init; } + + [Arg(Help = "The destination path (default: .[new-ext])", Last = true)] + public string? DestinationPath \{ get; init; } + + [Arg(Short = 'e', Long = "extension", Help = "Target image format")] + public string? Extension \{ get; init; } + + [Arg(Short = 'v', Long = "verbose", Help = "Enable verbose output")] + public bool Verbose \{ get; set; } + + [Command] + public ImageConverterCommands? Command \{ get; init; } +} + +[SubCommand] +public partial class ImageConverterCommands +{ + [Command(About = "Show conversion history")] + public partial class History : ImageConverterCommands; + + [Command(About = "Publish converted images")] + public partial class Publish : ImageConverterCommands + { + [Arg(Help = "The URL to publish the image to")] + public required string[] UploadUrl \{ get; init; } + } +} +``` + +**Using the parser:** + +```csharp +var app = ImageConverter.Parse(args); + +switch (app.Command) +{ + case ImageConverterCommands.History: + Console.WriteLine("Showing conversion history..."); + break; + + case ImageConverterCommands.Publish publish: + Console.WriteLine($"Publishing to {string.Join(", ", publish.UploadUrl)}"); + break; + + default: + Console.WriteLine($"Converting {app.Path} to {app.Extension ?? "default format"}"); + break; +} +``` + +**Command-line usage:** + +```bash +### Basic conversion +$ dotnet run -- -v "~/Downloads/tree.png" "~/Downloads/tree.jpg" + +### With subcommand +$ dotnet run -- "~/Downloads/tree.png" -e "jpg" publish "https://yourdomain.com/upload" + +### Get help for subcommands +$ dotnet run -- publish --help +``` + +###### Argument Validation + +Clap.Net supports the full `System.ComponentModel.DataAnnotations` validation framework, allowing you to validate argument values at parse time with clear error messages. + +######### Built-in Validators + +Use standard .NET validation attributes to enforce constraints: + +```csharp +using System.ComponentModel.DataAnnotations; + +[Command(Name = "server", About = "Start a web server")] +public partial class ServerCommand +{ + [Arg(Long = "port")] + [Range(1, 65535, ErrorMessage = "Port must be between 1 and 65535")] + public required int Port \{ get; init; } + + [Arg(Long = "host")] + [RegularExpression(@"^[a-zA-Z0-9.-]+$", ErrorMessage = "Invalid hostname")] + public string Host \{ get; init; \} = "localhost"; + + [Arg(Long = "email")] + [EmailAddress(ErrorMessage = "Invalid email address")] + public required string Email \{ get; init; } + + [Arg(Long = "username")] + [StringLength(20, MinimumLength = 5)] + [RegularExpression(@"^[a-zA-Z0-9_]+$", ErrorMessage = "Only letters, numbers, and underscores allowed")] + public required string Username \{ get; init; } +} +``` + +**Available validators:** +- `[Range(min, max)]` - Numeric range validation +- `[StringLength(max, MinimumLength = min)]` - String length constraints +- `[RegularExpression("pattern")]` - Regex pattern matching +- `[EmailAddress]`, `[Phone]`, `[Url]`, `[CreditCard]` - Format validators +- Multiple validators can be combined on a single property + +######### Custom Validators + +Create your own validators by inheriting from `ValidationAttribute`: + +```csharp +public class PortRangeAttribute : ValidationAttribute +{ + public override bool IsValid(object? value) + { + if (value is int port) + return port >= 1 && port <= 65535; + return false; + } +} + +[Command] +public partial class MyApp +{ + [Arg(Long = "port")] + [PortRange(ErrorMessage = "Invalid port number")] + public required int Port \{ get; init; } +} +``` + +######### Handling Validation Errors + +Validation failures return a `ParseError` with detailed messages: + +```csharp +var result = ServerCommand.TryParse(args); + +if (result.IsT3) // ParseError +{ + Console.Error.WriteLine(result.AsT3.Message); + // Output: "Validation failed for 'Port': Port must be between 1 and 65535" + return 1; +} + +var cmd = result.AsT0; +// Use validated command... +``` + +###### Multi-Value Arguments + +Clap.Net provides flexible ways to accept multiple values for a single argument, with different behaviors depending on how you define your properties. + +######### Array Arguments (Per-Flag Values) + +For **named arguments** with array types (`string[]`, `int[]`, etc.), each flag invocation captures **one value**. To collect multiple values, repeat the flag: + +```csharp +[Command] +public partial class BenchmarkCommand +{ + [Arg(Short = 't', Long = "test", Help = "Tests to run")] + public string[]? Tests \{ get; init; } + + // Positional array consumes all remaining positional values + public string[] Extensions \{ get; init; \} = ["js", "ts"]; +} +``` + +**Usage:** +```bash +### Single value - Tests gets ["unit"], Extensions gets ["py", "go"] +$ app -t unit py go + +### Multiple values - repeat the flag for each value +$ app -t unit -t integration py go +### Tests gets ["unit", "integration"], Extensions gets ["py", "go"] + +### Without -t, all values go to positional +$ app py go js +### Tests is null/empty, Extensions gets ["py", "go", "js"] +``` + +**Key behavior:** +- Named array arguments: **One value per flag invocation** +- Positional array arguments: **Greedy - consumes all remaining positional values** +- This prevents named arrays from "stealing" values intended for positional arguments + +######### Action.Append (Alternative Pattern) + +For collection types with `Action.Append`, the behavior is similar but uses `IEnumerable`: + +```csharp +[Command] +public partial class TagCommand +{ + [Arg(Short = 't', Long = "tag", Action = ArgAction.Append)] + public IEnumerable Tags \{ get; init; \} = []; +} +``` + +**Usage:** +```bash +$ app -t "v1.0" -t "release" -t "stable" +### Tags gets ["v1.0", "release", "stable"] +``` + +######### When to Use Each + +| Pattern | Type | Behavior | Use Case | +|---------|------|----------|----------| +| **Array** | `string[]` | One value per flag | Named args that need to work with positional args | +| **Action.Append** | `IEnumerable` | One value per flag | Named args only, more explicit about appending | +| **Positional Array** | `string[]` | Greedy (all remaining) | Variadic trailing arguments (like `files...`) | + +######### Examples + +**File processor with filters and files:** +```csharp +[Command] +public partial class ProcessFiles +{ + [Arg(Short = 'e', Long = "exclude")] + public string[] ExcludePatterns \{ get; init; \} = []; + + public string[] Files \{ get; init; \} = []; // Positional +} + +// Usage: +$ app -e "*.tmp" -e "*.log" file1.txt file2.txt file3.txt +// ExcludePatterns: ["*.tmp", "*.log"] +// Files: ["file1.txt", "file2.txt", "file3.txt"] +``` + +**Test runner with specific tests and extensions:** +```csharp +[Command] +public partial class TestRunner +{ + [Arg(Short = 't')] + public string[]? Tests \{ get; init; } + + public string[] Extensions \{ get; init; \} = ["js", "ts", "py"]; +} + +// Usage: +$ app -t unit -t integration go rb +// Tests: ["unit", "integration"] +// Extensions: ["go", "rb"] +``` + +###### Key Features + +**Strongly-Typed Parsing** +Define your CLI interface using classes, properties, and attributes. Get compile-time safety and IntelliSense support. + +**Powerful Subcommands** +Create complex command hierarchies using nested classes. Each subcommand can have its own arguments and options. + +**Rich Argument Types** +Support for strings, numbers, bools, enums, arrays, and any type with `TryParse`. Custom parsing logic is straightforward. + +**Automatic Help Generation** +Help text is generated from your attributes and XML documentation comments. Use `--help` on any command or subcommand. + +**Environment Variable Fallback** +Options can fallback to environment variables when not provided on the command line. + +**Negatable Flags** +Boolean flags can be negated with `--no-*` syntax for flexible configuration. + +###### Debugging Generated Code + +If you're troubleshooting source generation issues or want to inspect the generated parser code, add this to your `.csproj`: + +```xml + + true + bin/Generated + +``` + +Generated files will be written to `bin/Generated/`, allowing you to step through the parser logic and understand how arguments are processed. + +###### Feature Roadmap + +Clap.Net aims for near feature-parity with clap-rs. Here's what's implemented and what's coming: + +######### Implemented + +- **Commands** + - Root command definition with Name, About, and Version + - Subcommands with nested class hierarchies + - Automatic help text for all commands + +- **Arguments & Options** + - Short (`-v`) and long (`--verbose`) flags + - Positional arguments with order-based mapping + - Required vs optional arguments + - Environment variable fallback + - Default values via C# property initializers + - Multiple values (arrays and collections) + - TryParse support for custom types + - Custom parser functions via `ValueParser` attribute + - Argument actions (Set, Append, Count) + - Full `ValidationAttribute` support (Range, StringLength, RegularExpression, EmailAddress, custom validators) + +- **Flags** + - Boolean flags (presence/absence) + - Negatable flags (`--no-debug`) + +- **Help & Version** + - Automatic `--help` generation + - Automatic `--version` handling + - Custom help text from XML docs + +######### Coming Soon + +- Argument value suggestions and completion +- More flexible argument ordering +- Improved error messages + +###### Contributing + +Clap.Net is actively developed and there's plenty of work to do! Pull requests are welcome for: + +- Bug fixes and performance improvements +- New features from the roadmap +- Documentation and examples +- Test coverage + +Check out the [CLAUDE.md](https://github.com/simon-curtis/Clap.Net/CLAUDE.md) file for architectural guidance and development patterns. + +###### License + +MIT License - see [LICENSE](https://github.com/simon-curtis/Clap.Net/LICENSE) for details + + +::: + +### About +:::note + +Command line arguments parsing + + +::: + +## How to use + +### Example (source csproj, source files) + + + + + +This is the CSharp Project that references **Clap.Net** +```xml showLineNumbers {14} + + + + Exe + net10.0 + enable + enable + + + true + $(BaseIntermediateOutputPath)\GX + + + + + + + +``` + + + + + + This is the use of **Clap.Net** in *Program.cs* + +```csharp showLineNumbers +using ConsoleDemo; + + +// --help +// -f 10 -s 20 +var cmd = CmdForSum.Parse(args); +cmd.MySum(); +``` + + + + + This is the use of **Clap.Net** in *CmdForSum.cs* + +```csharp showLineNumbers + +using Clap.Net; + +namespace ConsoleDemo; + +[Command(Name = "MakeSum")] +public partial class CmdForSum +{ + [Arg(Short = 'f', Long = "firstarg", Help = "first argument")] + public int x \{ get; set; \} = 0; + + [Arg(Short = 's', Long = "secondarg", Help = "second argument")] + public int y \{ get; set; \} = 0; + + public void MySum() + { + Console.WriteLine($"Hello, {x+y}!"); + } +} + +``` + + + + +### Generated Files + +Those are taken from $(BaseIntermediateOutputPath)\GX + + + + +```csharp showLineNumbers +/* +* CAUTION! This code has been generated by the Clap.Net source generator and should not be edited. +* +* Name: MakeSum +* About: +* Long About: +*/ + +#nullable enable + +namespace ConsoleDemo; + +public partial class CmdForSum +{ + private const string HelpMessage = + """ + Usage: {{EXECUTABLE_NAME}} [OPTIONS] + + Options: + -f, --firstarg first argument + -s, --secondarg second argument + -h, --help Shows this help message + + """; + + public class CmdForSumParseResult + { + private enum ResultType \{ Success, Help, Version, Error } + + private readonly ResultType _type; + private readonly ConsoleDemo.CmdForSum? _command; + private readonly Clap.Net.Models.ShowHelp? _help; + private readonly Clap.Net.Models.ShowVersion? _version; + private readonly Clap.Net.Models.ParseError? _error; + + private CmdForSumParseResult(ConsoleDemo.CmdForSum command) + { + _type = ResultType.Success; + _command = command; + } + + private CmdForSumParseResult(Clap.Net.Models.ShowHelp help) + { + _type = ResultType.Help; + _help = help; + } + + private CmdForSumParseResult(Clap.Net.Models.ShowVersion version) + { + _type = ResultType.Version; + _version = version; + } + + private CmdForSumParseResult(Clap.Net.Models.ParseError error) + { + _type = ResultType.Error; + _error = error; + } + + public bool IsSuccess => _type == ResultType.Success; + public bool IsHelp => _type == ResultType.Help; + public bool IsVersion => _type == ResultType.Version; + public bool IsError => _type == ResultType.Error; + + public ConsoleDemo.CmdForSum Command => _command ?? throw new System.InvalidOperationException("Result is not Success"); + public Clap.Net.Models.ShowHelp Help => _help ?? throw new System.InvalidOperationException("Result is not Help"); + public Clap.Net.Models.ShowVersion Version => _version ?? throw new System.InvalidOperationException("Result is not Version"); + public Clap.Net.Models.ParseError Error => _error ?? throw new System.InvalidOperationException("Result is not Error"); + + public TNewParseResult ChangeType() where TNewParseResult : class + { + object? value = _type switch + { + ResultType.Success => _command, + ResultType.Help => _help, + ResultType.Version => _version, + ResultType.Error => _error, + _ => throw new System.InvalidOperationException("Unknown result type") + }; + + if (value is TNewParseResult result) + return result; + + throw new System.InvalidCastException( + $"Cannot cast {value?.GetType().FullName ?? "null"} to {typeof(TNewParseResult).FullName}"); + } + + public static implicit operator CmdForSumParseResult(ConsoleDemo.CmdForSum value) => new(value); + public static implicit operator CmdForSumParseResult(Clap.Net.Models.ShowHelp value) => new(value); + public static implicit operator CmdForSumParseResult(Clap.Net.Models.ShowVersion value) => new(value); + public static implicit operator CmdForSumParseResult(Clap.Net.Models.ParseError value) => new(value); + } + + public static ConsoleDemo.CmdForSum Parse(System.ReadOnlySpan args) + { + // Protect against DoS attacks with excessive argument counts + const int MaxTotalArguments = 50000; + if (args.Length > MaxTotalArguments) + { + throw new System.ArgumentException( + $"Total argument count ({args.Length}) exceeds maximum of {MaxTotalArguments}"); + } + + var tokens = Clap.Net.ArgsLexer.Lex(args); + return Parse(tokens); + } + + public static ConsoleDemo.CmdForSum Parse(System.ReadOnlySpan tokens) + { + var parseResult = TryParse(tokens); + + if (parseResult.IsSuccess) + return parseResult.Command; + + if (parseResult.IsVersion) + { + System.Console.WriteLine(parseResult.Version.Version); + System.Environment.Exit(0); + } + + if (parseResult.IsError) + { + DisplayError(parseResult.Error.Message, parseResult.Error.HelpMessage); + System.Environment.Exit(0); + } + + PrintHelpMessage(parseResult.Help.HelpMessage); + System.Environment.Exit(0); + + // Unreachable: all control paths above call Environment.Exit(0) + return default!; + } + + public static CmdForSumParseResult TryParse(System.ReadOnlySpan args) + { + var tokens = Clap.Net.ArgsLexer.Lex(args); + return TryParse(tokens); + } + + public static CmdForSumParseResult TryParse(System.ReadOnlySpan tokens) + { + if (tokens.Length > 0 && tokens[0] is Clap.Net.ShortFlag('h') or Clap.Net.LongFlag("help")) + { + return new Clap.Net.Models.ShowHelp(GetFormattedHelpMessage()); + } + + if (tokens.Length > 0 && tokens[0] is Clap.Net.ShortFlag('v') or Clap.Net.LongFlag("version")) + { + return new Clap.Net.Models.ShowVersion("1.0.0.0"); + } + + // Argument 'x' is a named argument + Clap.Net.Models.FieldValue @__clapgen_x = (System.Int32)0; + // Argument 'y' is a named argument + Clap.Net.Models.FieldValue @__clapgen_y = (System.Int32)0; + + var index = 0; + while (index < tokens.Length) + { + switch (tokens[index]) + { + // Handling CompoundFlag + case Clap.Net.CompoundFlag(var chars): + { + foreach (var c in chars) + { + switch (c) + { + case 'f': + { + @__clapgen_x = @__clapgen_x.Value + 1; + break; + } + case 's': + { + @__clapgen_y = @__clapgen_y.Value + 1; + break; + } + default: + { + return new Clap.Net.Models.ParseError($"Unexpected flag supplied in compound flags '{c}'", GetFormattedHelpMessage()); + } + } + } + index++; + break; + } + // Setting named argument 'ConsoleDemo.CmdForSum.x' + // action 'Set' + case Clap.Net.ShortFlag('f') or Clap.Net.LongFlag("firstarg"): + { + index++; + if (index >= tokens.Length || tokens[index] is not Clap.Net.ValueLiteral(var value)) + return new Clap.Net.Models.ParseError("Expected value to follow named arg 'x'", GetFormattedHelpMessage()); + + @__clapgen_x = TryParseOrThrow(value, int.TryParse, "integer"); + index++; + break; + } + + // Setting named argument 'ConsoleDemo.CmdForSum.y' + // action 'Set' + case Clap.Net.ShortFlag('s') or Clap.Net.LongFlag("secondarg"): + { + index++; + if (index >= tokens.Length || tokens[index] is not Clap.Net.ValueLiteral(var value)) + return new Clap.Net.Models.ParseError("Expected value to follow named arg 'y'", GetFormattedHelpMessage()); + + @__clapgen_y = TryParseOrThrow(value, int.TryParse, "integer"); + index++; + break; + } + + case var arg: + { + return new Clap.Net.Models.ParseError($"Unknown argument '{Clap.Net.TokenExtensions.Format(arg)}'", GetFormattedHelpMessage()); + } + } + } + + // No required fields + + return new ConsoleDemo.CmdForSum + { + x = @__clapgen_x.Value, + y = @__clapgen_y.Value, + }; + } + + public static void DisplayError(string message, string helpMessage) + { + var previousColour = System.Console.ForegroundColor; + System.Console.ForegroundColor = System.ConsoleColor.Red; + System.Console.WriteLine(message); + System.Console.ForegroundColor = previousColour; + System.Console.WriteLine(helpMessage); + } + + public static void PrintHelpMessage(string helpMessage) + { + System.Console.WriteLine(helpMessage); + } + + private static string GetFormattedHelpMessage() + { + var executableName = System.IO.Path.GetFileNameWithoutExtension(System.Environment.GetCommandLineArgs()[0]); + if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) + executableName += ".exe"; + return HelpMessage.Replace("{{EXECUTABLE_NAME}}", executableName); + } + + private delegate bool TryParseDelegate(string input, out T result); + + private static T TryParseOrThrow(string input, TryParseDelegate tryParse, string typeName) + { + if (tryParse(input, out var result)) + return result; + + throw new System.FormatException($"Failed to parse '{input}' as {typeName}"); + } + + private static T TryParseWithCustomParser(string input, System.Func parser) + { + try + { + return parser(input); + } + catch (System.Exception ex) + { + throw new System.FormatException($"Custom parser failed to parse '{input}': {ex.Message}", ex); + } + } + + private static object TryConvertOrThrow(string input, System.Type targetType, string typeName) + { + try + { + return System.Convert.ChangeType(input, targetType); + } + catch (System.Exception ex) + { + throw new System.FormatException($"Failed to convert '{input}' to {typeName}: {ex.Message}", ex); + } + } +} + +``` + + + + +## Useful + +### Download Example (.NET C#) + +:::tip + +[Download Example project Clap.Net ](/sources/Clap.Net.zip) + +::: + + +### Share Clap.Net + + + +https://ignatandrei.github.io/RSCG_Examples/v2/docs/Clap.Net + + + diff --git a/v2/rscg_examples_site/docs/RSCG-Examples/index.md b/v2/rscg_examples_site/docs/RSCG-Examples/index.md index 5b843b810..3cfc8efb8 100644 --- a/v2/rscg_examples_site/docs/RSCG-Examples/index.md +++ b/v2/rscg_examples_site/docs/RSCG-Examples/index.md @@ -1,7 +1,7 @@ --- sidebar_position: 30 -title: 281 RSCG list by category -description: 281 RSCG list by category +title: 282 RSCG list by category +description: 282 RSCG list by category slug: /rscg-examples --- @@ -307,7 +307,7 @@ import DocCardList from '@theme/DocCardList'; ## CommandLine
- Expand CommandLine =>examples:5 + Expand CommandLine =>examples:6 @@ -333,6 +333,11 @@ import DocCardList from '@theme/DocCardList'; [docopt.net](/docs/docopt.net) + + + +[Clap.Net](/docs/Clap.Net) +
@@ -1850,6 +1855,8 @@ flowchart LR; CommandLine--> docopt.net((docopt.net)) + CommandLine--> Clap.Net((Clap.Net)) + Console--> Figgle((Figgle)) Constructor--> AutoDeconstruct((AutoDeconstruct)) diff --git a/v2/rscg_examples_site/docs/about.md b/v2/rscg_examples_site/docs/about.md index 0a2b5ae30..87bcf3496 100644 --- a/v2/rscg_examples_site/docs/about.md +++ b/v2/rscg_examples_site/docs/about.md @@ -6,7 +6,7 @@ title: About ## Content You will find here code examples -of 281 Roslyn Source Code Generator (RSCG) +of 282 Roslyn Source Code Generator (RSCG) that can be useful for you. That means, you will write more elegant and concise code - even if the generators code is not always nice to look. ## Are those examples ready for production? diff --git a/v2/rscg_examples_site/docs/indexRSCG.md b/v2/rscg_examples_site/docs/indexRSCG.md index 1cb04f4f3..6dbc9e76e 100644 --- a/v2/rscg_examples_site/docs/indexRSCG.md +++ b/v2/rscg_examples_site/docs/indexRSCG.md @@ -7,9 +7,9 @@ slug: /List-of-RSCG import useBaseUrl from '@docusaurus/useBaseUrl'; -## 281 RSCG with examples in descending chronological order +## 282 RSCG with examples in descending chronological order -This is the list of 281 ( 16 from Microsoft) RSCG with examples +This is the list of 282 ( 16 from Microsoft) RSCG with examples [See by category](/docs/rscg-examples) [See as json](/exports/RSCG.json) [See as Excel](/exports/RSCG.xlsx) @@ -20,6 +20,7 @@ This is the list of 281 ( 16 from Microsoft) RSCG with examples | No | Name | Date | Category | | --------- | ----- | ---- | -------- | +|282| [Clap.Net by Simon Curtis ](/docs/Clap.Net)|2026-08-22 => 22 August 2026 | [CommandLine](/docs/Categories/CommandLine) | |281| [EndpointHelpers by Gustavo Mauricio de Barros ](/docs/EndpointHelpers)|2026-08-21 => 21 August 2026 | [MVC](/docs/Categories/MVC) | |280| [serde by Andy Gocke ](/docs/serde)|2026-08-20 => 20 August 2026 | [Serializer](/docs/Categories/Serializer) | |279| [ReflectionIT.DisposeGenerator by Fons Sonnemans ](/docs/ReflectionIT.DisposeGenerator)|2026-08-19 => 19 August 2026 | [Disposer](/docs/Categories/Disposer) | diff --git a/v2/rscg_examples_site/src/components/HomepageFeatures/index.js b/v2/rscg_examples_site/src/components/HomepageFeatures/index.js index 812833329..4fa2119b7 100644 --- a/v2/rscg_examples_site/src/components/HomepageFeatures/index.js +++ b/v2/rscg_examples_site/src/components/HomepageFeatures/index.js @@ -4,7 +4,7 @@ import styles from './styles.module.css'; const FeatureList = [ { -title: '281 Examples (16 from MSFT)', +title: '282 Examples (16 from MSFT)', Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default, description: ( <> diff --git a/v2/rscg_examples_site/static/exports/RSCG.json b/v2/rscg_examples_site/static/exports/RSCG.json index def113da3..d07b0d255 100644 --- a/v2/rscg_examples_site/static/exports/RSCG.json +++ b/v2/rscg_examples_site/static/exports/RSCG.json @@ -2249,6 +2249,14 @@ "Source": "https://github.com/gumbarros/EndpointHelpers", "Category": "MVC", "AddedOn": "2026-08-21T00:00:00" + }, + { + "Name": "Clap.Net", + "Link": "https://ignatandrei.github.io/RSCG_Examples/v2/docs/Clap.Net", + "NuGet": "https://www.nuget.org/packages/Clap.Net/", + "Source": "https://github.com/simon-curtis/Clap.Net", + "Category": "CommandLine", + "AddedOn": "2026-08-22T00:00:00" } ] } \ No newline at end of file diff --git a/v2/rscg_examples_site/static/exports/RSCG.xlsx b/v2/rscg_examples_site/static/exports/RSCG.xlsx index 410899a7f..aaab27310 100644 Binary files a/v2/rscg_examples_site/static/exports/RSCG.xlsx and b/v2/rscg_examples_site/static/exports/RSCG.xlsx differ diff --git a/v2/rscg_examples_site/static/sources/Clap.Net.zip b/v2/rscg_examples_site/static/sources/Clap.Net.zip new file mode 100644 index 000000000..092597876 Binary files /dev/null and b/v2/rscg_examples_site/static/sources/Clap.Net.zip differ