{"id":37038470,"url":"https://github.com/flyingpie/declarative-command-line","last_synced_at":"2026-01-14T04:34:34.110Z","repository":{"id":65672208,"uuid":"588745695","full_name":"flyingpie/declarative-command-line","owner":"flyingpie","description":"Attribute-driven layer on top of System.CommandLine to make the most common use cases easier to set up.","archived":false,"fork":false,"pushed_at":"2025-12-25T12:05:53.000Z","size":158,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-12-27T00:09:02.155Z","etag":null,"topics":["command-line","dotnet"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/flyingpie.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-01-13T22:14:40.000Z","updated_at":"2025-12-25T12:05:55.000Z","dependencies_parsed_at":"2024-12-14T22:23:34.661Z","dependency_job_id":"f04f376e-903c-4fa2-ae02-77ae1755efa9","html_url":"https://github.com/flyingpie/declarative-command-line","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/flyingpie/declarative-command-line","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flyingpie%2Fdeclarative-command-line","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flyingpie%2Fdeclarative-command-line/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flyingpie%2Fdeclarative-command-line/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flyingpie%2Fdeclarative-command-line/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/flyingpie","download_url":"https://codeload.github.com/flyingpie/declarative-command-line/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flyingpie%2Fdeclarative-command-line/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28409528,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T01:52:23.358Z","status":"online","status_checked_at":"2026-01-14T02:00:06.678Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["command-line","dotnet"],"created_at":"2026-01-14T04:34:33.548Z","updated_at":"2026-01-14T04:34:34.091Z","avatar_url":"https://github.com/flyingpie.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Declarative Command Line\r\n\r\n[![WTQ CI](https://github.com/flyingpie/declarative-command-line/actions/workflows/ci.yml/badge.svg)](https://github.com/flyingpie/declarative-command-line/actions/workflows/ci.yml)\r\n\r\n[![Nuget](https://img.shields.io/nuget/vpre/DeclarativeCommandLine.svg)](https://nuget.org/packages/DeclarativeCommandLine)\r\n\r\nAttribute-driven layer on top of [System.CommandLine](https://github.com/dotnet/command-line-api) to make the most common use cases easier to set up.\r\n\r\n## Minimalistic Example\r\n\r\nA minimal example, using DI to instantiate command objects:\r\n\r\n### Add NuGet Packages\r\n\r\n2 packages are needed:\r\n- [DeclarativeCommandLine](https://www.nuget.org/packages/DeclarativeCommandLine): Contains attributes used to decorate commands, options and arguments;\r\n- [DeclarativeCommandLine.Generator](https://www.nuget.org/packages/DeclarativeCommandLine.Generator): The source generator that actually constructs the System.CommandLine client code. Only used on compile time.\r\n\r\n```xml\r\n\u003cItemGroup\u003e\r\n  \u003cPackageReference Include=\"DeclarativeCommandLine\" Version=\"2.0.4\" /\u003e\r\n  \u003cPackageReference Include=\"DeclarativeCommandLine.Generator\" Version=\"2.0.4\" /\u003e\r\n  \u003cPackageReference Include=\"Microsoft.Extensions.DependencyInjection\" Version=\"9.0.9\"/\u003e\r\n\u003c/ItemGroup\u003e\r\n```\r\n\r\n### Program.cs\r\n\r\n```cs\r\nusing DeclarativeCommandLine;\r\nusing Microsoft.Extensions.DependencyInjection;\r\n\r\nnamespace MyApp;\r\n\r\n[Command(Description = \"Math commands\")]\r\npublic class AppRootCommand\r\n{\r\n}\r\n\r\n[Command(Description = \"Add 2 numbers\", Parent = typeof(AppRootCommand))]\r\npublic class AddCommand : ICommand\r\n{\r\n    [Option(Required = true)]\r\n    public int ValueA { get; set; }\r\n\r\n    [Option(Required = true)]\r\n    public int ValueB { get; set; }\r\n\r\n    public void Execute()\r\n    {\r\n        Console.WriteLine($\"A={ValueA} + {ValueB} = {ValueA + ValueB}\");\r\n    }\r\n}\r\n\r\npublic static class Program\r\n{\r\n    public static int Main(string[] args)\r\n    {\r\n        var p = new ServiceCollection()\r\n            .AddTransient\u003cAppRootCommand\u003e()\r\n            .AddTransient\u003cAddCommand\u003e()\r\n            .BuildServiceProvider();\r\n\r\n        return new CommandBuilder()\r\n            .Build(t =\u003e p.GetRequiredService(t))\r\n            .Parse(args)\r\n            .Invoke();\r\n    }\r\n}\r\n```\r\n\r\n### Result\r\n\r\n```bash\r\n$ ./myapp\r\nRequired command was not provided.\r\n\r\nDescription:\r\n\r\nUsage:\r\n  myapp [command] [options]\r\n\r\nOptions:\r\n  -?, -h, --help  Show help and usage information\r\n  --version       Show version information\r\n\r\nCommands:\r\n  add\r\n```\r\n\r\n```bash\r\n$ ./myapp add\r\nOption '--value-a' is required.\r\nOption '--value-b' is required.\r\n\r\nDescription:\r\n\r\nUsage:\r\n  myapp add [options]\r\n\r\nOptions:\r\n  --value-a \u003cvalue-a\u003e (REQUIRED)\r\n  --value-b \u003cvalue-b\u003e (REQUIRED)\r\n  -?, -h, --help                  Show help and usage information\r\n```\r\n\r\n```bash\r\n$ ./myapp add --value-a 20 --value-b 22\r\nA=20 + 22 = 42\r\n```\r\n\r\n### Generated\r\n\r\nThis is what the source generator has written, based on the attribute-annotated classes:\r\n\r\n```cs\r\n/// \u003cauto-generated/\u003e\r\nusing DeclarativeCommandLine;\r\nusing System;\r\nusing System.CommandLine;\r\n\r\nnamespace MyApp\r\n{\r\n    public partial class CommandBuilder\r\n    {\r\n        public virtual RootCommand Build(Func\u003cType, object\u003e serviceProvider)\r\n        {\r\n            var cmd1 = new RootCommand();\r\n            cmd1.Hidden = false;\r\n            // global::MyApp.AddCommand\r\n            {\r\n                var cmd2 = new Command(\"add\");\r\n                cmd1.Add(cmd2);\r\n                cmd2.Hidden = false;\r\n                // Option --value-a\r\n                var opt3 = new Option\u003cInt32\u003e(\"--value-a\");\r\n                {\r\n                    cmd2.Add(opt3);\r\n                    opt3.Description = \"\";\r\n                    opt3.Hidden = false;\r\n                    opt3.Required = true;\r\n                }\r\n                // Option --value-b\r\n                var opt4 = new Option\u003cInt32\u003e(\"--value-b\");\r\n                {\r\n                    cmd2.Add(opt4);\r\n                    opt4.Description = \"\";\r\n                    opt4.Hidden = false;\r\n                    opt4.Required = true;\r\n                }\r\n                cmd2.SetAction(async (parseResult, ct) =\u003e\r\n                {\r\n                    var cmd2Inst = (global::MyApp.AddCommand)serviceProvider(typeof(global::MyApp.AddCommand));\r\n                    cmd2Inst.ValueA = parseResult.GetValue(opt3);\r\n                    cmd2Inst.ValueB = parseResult.GetValue(opt4);\r\n\r\n                    if (cmd2Inst is IAsyncCommandWithParseResult cmd2001)\r\n                    {\r\n                        await cmd2001.ExecuteAsync(parseResult, ct).ConfigureAwait(false);\r\n                    }\r\n                \r\n                    if (cmd2Inst is IAsyncCommand cmd2002)\r\n                    {\r\n                        await cmd2002.ExecuteAsync(ct).ConfigureAwait(false);\r\n                    }\r\n                \r\n                    if (cmd2Inst is ICommand cmd2003)\r\n                    {\r\n                        cmd2003.Execute();\r\n                    }\r\n                });\r\n\r\n            }\r\n            return cmd1;\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n## Progress\r\n\r\n### Command\r\n\r\n- [x] Action\r\n- [x] Aliases\r\n- [x] Arguments\r\n- [x] Description\r\n- [x] Hidden\r\n- [x] Name\r\n- [x] Options\r\n- [x] Subcommands\r\n- [ ] Completions\r\n- [ ] TreatUnmatchedTokensAsErrors\r\n- [ ] Validators\r\n\r\n### Arguments\r\n\r\n- [x] AcceptOnlyFromAmong\r\n- [x] Default\r\n- [x] Description\r\n- [x] Name\r\n- [ ] AcceptLegalFileNamesOnly\r\n- [ ] AcceptLegalFilePathsOnly\r\n- [ ] Arity\r\n- [ ] Completions\r\n- [ ] HelpName\r\n- [ ] Hidden\r\n- [ ] Validators\r\n\r\n### Directives\r\n\r\n- [ ] dir.Description\r\n- [ ] dir.Hidden\r\n- [ ] dir.Name\r\n\r\n### Option\r\n\r\n- [x] opt.AcceptOnlyFromAmong\r\n- [x] opt.Aliases\r\n- [x] opt.DefaultValueFactory\r\n- [x] opt.Description\r\n- [x] opt.Hidden\r\n- [x] opt.Name\r\n- [x] opt.Required\r\n- [ ] opt.AcceptLegalFileNamesOnly\r\n- [ ] opt.AcceptLegalFilePathsOnly\r\n- [ ] opt.AllowMultipleArgumentsPerToken\r\n- [ ] opt.Arity\r\n- [ ] opt.Completions\r\n- [ ] opt.HelpName\r\n- [ ] opt.Recursive\r\n- [ ] opt.Validators","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflyingpie%2Fdeclarative-command-line","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fflyingpie%2Fdeclarative-command-line","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflyingpie%2Fdeclarative-command-line/lists"}