CLI: Add explicit per-command argument overrides (#41478)

David Bennett committed Sep 1, 2026 at 11:15 UTC 2dbe9953723e03f987b34bd1f5138dbf39238012
48 files changed +193 -146
src/windows/wslc/arguments/Argument.cpp
+9 -15
@@ -28,28 +28,22 @@ using namespace std::literals;
28 namespace wsl::windows::wslc {
29 using namespace wsl::windows::wslc::execution;
30
31 -// This is the main Argument creation method, allowing overrides of the default properties of arguments.
32 -// The ArgType has some core characteristic, such as the Kind, Name, and Alias. If these
33 -// need to be changed, it is recommended to create a new ArgType in ArgumentDefinitions.h. If the argument
34 -// just needs a different description, it can be overridden in the desc, or if you need it to be required,
35 -// or to allow multiple uses within a command, then those properties can be set using the Create
36 -// function below inside the command. In this way all arguments default to "1" use and not required, and
37 -// this can only be changed in the command's GetArguments function, so the defaults are always clear and
38 -// consistent. Visibility can also be overridden and is defaulted to "Help".
39 -Argument Argument::Create(ArgType type, std::optional<bool> required, std::optional<argument::Limit> limit, std::optional<std::wstring> desc)
31 +Argument Argument::Create(ArgType type, ArgumentOverrides overrides)
32 {
33 + WI_ASSERT(!overrides.Name.has_value() || overrides.Name->size() >= 2);
34 +
35 switch (type)
36 {
43 -#define WSLC_ARG_CREATE_CASE(EnumName, Name, Alias, ArgumentKind, ConvertedType, Desc) \
37 +#define WSLC_ARG_CREATE_CASE(EnumName, DefaultName, DefaultAlias, ArgumentKind, ConvertedType, DefaultDesc) \
38 case ArgType::EnumName: \
39 return Argument{ \
40 type, \
47 - L##Name, \
48 - Alias, \
49 - desc.has_value() ? std::move(desc.value()) : std::wstring(Desc), \
41 + overrides.Name.has_value() ? std::move(overrides.Name.value()) : std::wstring{L##DefaultName}, \
42 + overrides.Alias.has_value() ? std::move(overrides.Alias.value()) : std::wstring{DefaultAlias}, \
43 + overrides.Desc.has_value() ? std::move(overrides.Desc.value()) : std::wstring(DefaultDesc), \
44 ArgumentKind, \
51 - required.value_or(DefaultRequired), \
52 - limit.value_or(DefaultLimit)};
45 + overrides.Required.value_or(Argument::DefaultRequired), \
46 + overrides.Limit.value_or(Argument::DefaultLimit)};
47
48 WSLC_ARGUMENTS(WSLC_ARG_CREATE_CASE)
49 #undef WSLC_ARG_CREATE_CASE
src/windows/wslc/arguments/Argument.h
+17 -10
@@ -14,7 +14,9 @@ Abstract:
14 #pragma once
15 #include "ArgMap.h"
16
17 +#include <optional>
18 #include <string>
19 +#include <utility>
20
21 #define WSLC_CLI_ARG_ID_CHAR L'-'
22 #define WSLC_CLI_ARG_ID_STRING L"-"
@@ -26,6 +28,15 @@ Abstract:
28 using namespace wsl::windows::wslc::argument;
29
30 namespace wsl::windows::wslc {
31 +struct ArgumentOverrides
32 +{
33 + std::optional<std::wstring> Name;
34 + std::optional<std::wstring> Alias;
35 + std::optional<bool> Required;
36 + std::optional<argument::Limit> Limit;
37 + std::optional<std::wstring> Desc;
38 +};
39 +
40 // An argument to a command.
41 struct Argument
42 {
@@ -37,13 +48,13 @@ struct Argument
48 // Full constructor with all parameters
49 Argument(
50 ArgType argType,
40 - const std::wstring& name,
41 - const std::wstring& alias,
42 - const std::wstring& desc,
51 + std::wstring name,
52 + std::wstring alias,
53 + std::wstring desc,
54 argument::Kind kind = DefaultKind,
55 bool required = DefaultRequired,
56 argument::Limit limit = DefaultLimit) :
46 - m_argType(argType), m_name(name), m_alias(alias), m_desc(desc), m_type(kind), m_required(required), m_limit(limit)
57 + m_argType(argType), m_name(std::move(name)), m_desc(std::move(desc)), m_alias(std::move(alias)), m_required(required), m_type(kind), m_limit(limit)
58 {
59 }
60
@@ -53,12 +64,8 @@ struct Argument
64 Argument(Argument&&) = default;
65 Argument& operator=(Argument&&) = default;
66
56 - // Creates an argument with optional overrides for table defaults
57 - static Argument Create(
58 - ArgType type,
59 - std::optional<bool> required = std::nullopt,
60 - std::optional<argument::Limit> limit = std::nullopt,
61 - std::optional<std::wstring> desc = std::nullopt);
67 + // Creates an argument using its table defaults and any command-specific overrides.
68 + static Argument Create(ArgType type, ArgumentOverrides overrides = {});
69
70 // Gets the argument usage string in the format of "-alias,--name" or just "--name" if no alias.
71 std::wstring GetUsageString() const;
src/windows/wslc/arguments/ArgumentDefinitions.h
+5 -6
@@ -13,12 +13,11 @@ Abstract:
13 --*/
14 #pragma once
15
16 -// Here is where base argument types are defined, with their name, alias, kind, and default description.
17 -// The description can be overridden by commands if a particular command needs a different description but otherwise the
18 -// same argument type definition. The ArgType enum and the mapping of ArgType to data type are generated from this X-Macro, so all
19 -// arguments must be defined here to be used in the system. The arguments defined here are the basis for all commands,
20 -// but not all arguments need to be used by all commands, and additional properties of the arguments can be set in the command's
21 -// GetArguments function when creating the Argument with Argument::Create.
16 +// Here is where base argument types are defined, with their default name, default alias, kind, conversion type, and
17 +// default description. Commands can override the name, alias, required state, limit, and description. The ArgType enum,
18 +// kind, and conversion type remain fixed. The ArgType enum and the mapping of ArgType to data type are generated from
19 +// this X-Macro, so all arguments must be defined here to be used in the system. The arguments defined here are the basis
20 +// for all commands, but not all arguments need to be used by all commands.
21
22 // The Kind determines the data type:
23 // - Kind::Flag -> bool
src/windows/wslc/commands/ContainerAttachCommand.cpp
+1 -1
@@ -28,7 +28,7 @@ namespace wsl::windows::wslc {
28 std::vector<Argument> ContainerAttachCommand::GetArguments() const
29 {
30 return {
31 - Argument::Create(ArgType::ContainerId, true),
31 + Argument::Create(ArgType::ContainerId, {.Required = true}),
32 };
33 }
34
src/windows/wslc/commands/ContainerCpCommand.cpp
+2 -2
@@ -16,8 +16,8 @@ std::vector<Argument> ContainerCpCommand::GetArguments() const
16 {
17 return {
18 Argument::Create(ArgType::Archive),
19 - Argument::Create(ArgType::Source, true, std::nullopt, Localization::WSLCCLI_CpSourceArgDescription()),
20 - Argument::Create(ArgType::Target, true, std::nullopt, Localization::WSLCCLI_CpTargetArgDescription()),
19 + Argument::Create(ArgType::Source, {.Required = true, .Desc = Localization::WSLCCLI_CpSourceArgDescription()}),
20 + Argument::Create(ArgType::Target, {.Required = true, .Desc = Localization::WSLCCLI_CpTargetArgDescription()}),
21 };
22 }
23
src/windows/wslc/commands/ContainerCreateCommand.cpp
+15 -15
@@ -28,19 +28,19 @@ std::vector<Argument> ContainerCreateCommand::GetArguments() const
28 {
29 // clang-format off
30 return {
31 - Argument::Create(ArgType::ImageId, true),
31 + Argument::Create(ArgType::ImageId, {.Required = true}),
32 Argument::Create(ArgType::Command),
33 Argument::Create(ArgType::ForwardArgs),
34 Argument::Create(ArgType::CIDFile),
35 Argument::Create(ArgType::Cpus),
36 - Argument::Create(ArgType::DNS, false, Limit::Unlimited),
36 + Argument::Create(ArgType::DNS, {.Limit = Limit::Unlimited}),
37 // Argument::Create(ArgType::DNSDomain),
38 - Argument::Create(ArgType::DNSOption, false, Limit::Unlimited),
39 - Argument::Create(ArgType::DNSSearch, false, Limit::Unlimited),
38 + Argument::Create(ArgType::DNSOption, {.Limit = Limit::Unlimited}),
39 + Argument::Create(ArgType::DNSSearch, {.Limit = Limit::Unlimited}),
40 Argument::Create(ArgType::Domainname),
41 Argument::Create(ArgType::Entrypoint),
42 - Argument::Create(ArgType::Env, false, Limit::Unlimited),
43 - Argument::Create(ArgType::EnvFile, false, Limit::Unlimited),
42 + Argument::Create(ArgType::Env, {.Limit = Limit::Unlimited}),
43 + Argument::Create(ArgType::EnvFile, {.Limit = Limit::Unlimited}),
44 // Argument::Create(ArgType::GroupId),
45 Argument::Create(ArgType::Gpus),
46 Argument::Create(ArgType::HealthCmd),
@@ -50,17 +50,17 @@ std::vector<Argument> ContainerCreateCommand::GetArguments() const
50 Argument::Create(ArgType::HealthTimeout),
51 Argument::Create(ArgType::Hostname),
52 Argument::Create(ArgType::Interactive),
53 - Argument::Create(ArgType::IpAddress, false),
54 - Argument::Create(ArgType::Label, false, Limit::Unlimited),
53 + Argument::Create(ArgType::IpAddress),
54 + Argument::Create(ArgType::Label, {.Limit = Limit::Unlimited}),
55 Argument::Create(ArgType::Memory),
56 - Argument::Create(ArgType::Mount, false, Limit::Unlimited),
56 + Argument::Create(ArgType::Mount, {.Limit = Limit::Unlimited}),
57 Argument::Create(ArgType::Name),
58 - Argument::Create(ArgType::Network, false, Limit::Unlimited),
59 - Argument::Create(ArgType::NetworkAlias, false, Limit::Unlimited),
58 + Argument::Create(ArgType::Network, {.Limit = Limit::Unlimited}),
59 + Argument::Create(ArgType::NetworkAlias, {.Limit = Limit::Unlimited}),
60 // Argument::Create(ArgType::NoDNS),
61 // Argument::Create(ArgType::Progress),
62 Argument::Create(ArgType::NoHealthcheck),
63 - Argument::Create(ArgType::Publish, false, Limit::Unlimited),
63 + Argument::Create(ArgType::Publish, {.Limit = Limit::Unlimited}),
64 Argument::Create(ArgType::PublishAll),
65 Argument::Create(ArgType::Pull),
66 Argument::Create(ArgType::Remove),
@@ -68,11 +68,11 @@ std::vector<Argument> ContainerCreateCommand::GetArguments() const
68 Argument::Create(ArgType::ShmSize),
69 Argument::Create(ArgType::StopSignal),
70 Argument::Create(ArgType::StopTimeout),
71 - Argument::Create(ArgType::TMPFS, false, Limit::Unlimited),
71 + Argument::Create(ArgType::TMPFS, {.Limit = Limit::Unlimited}),
72 Argument::Create(ArgType::TTY),
73 - Argument::Create(ArgType::Ulimit, false, Limit::Unlimited),
73 + Argument::Create(ArgType::Ulimit, {.Limit = Limit::Unlimited}),
74 Argument::Create(ArgType::User),
75 - Argument::Create(ArgType::Volume, false, Limit::Unlimited),
75 + Argument::Create(ArgType::Volume, {.Limit = Limit::Unlimited}),
76 // Argument::Create(ArgType::Virtual),
77 Argument::Create(ArgType::WorkDir),
78 };
src/windows/wslc/commands/ContainerExecCommand.cpp
+5 -5
@@ -27,12 +27,12 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> ContainerExecCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::ContainerId, true),
31 - Argument::Create(ArgType::Command, true),
32 - Argument::Create(ArgType::ForwardArgs, std::nullopt, std::nullopt, Localization::WSLCCLI_ContainerExecForwardArgsDescription()),
30 + Argument::Create(ArgType::ContainerId, {.Required = true}),
31 + Argument::Create(ArgType::Command, {.Required = true}),
32 + Argument::Create(ArgType::ForwardArgs, {.Desc = Localization::WSLCCLI_ContainerExecForwardArgsDescription()}),
33 Argument::Create(ArgType::Detach),
34 - Argument::Create(ArgType::Env, false, Limit::Unlimited),
35 - Argument::Create(ArgType::EnvFile, false, Limit::Unlimited),
34 + Argument::Create(ArgType::Env, {.Limit = Limit::Unlimited}),
35 + Argument::Create(ArgType::EnvFile, {.Limit = Limit::Unlimited}),
36 Argument::Create(ArgType::Interactive),
37 Argument::Create(ArgType::TTY),
38 Argument::Create(ArgType::User),
src/windows/wslc/commands/ContainerExportCommand.cpp
+2 -2
@@ -27,8 +27,8 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> ContainerExportCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::ContainerId, true),
31 - Argument::Create(ArgType::Output, std::nullopt, std::nullopt, Localization::WSLCCLI_ContainerExportOutputArgDescription()),
30 + Argument::Create(ArgType::ContainerId, {.Required = true}),
31 + Argument::Create(ArgType::Output, {.Desc = Localization::WSLCCLI_ContainerExportOutputArgDescription()}),
32 };
33 }
34
src/windows/wslc/commands/ContainerInspectCommand.cpp
+1 -1
@@ -27,7 +27,7 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> ContainerInspectCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::ContainerId, true, Limit::Unlimited),
30 + Argument::Create(ArgType::ContainerId, {.Required = true, .Limit = Limit::Unlimited}),
31 Argument::Create(ArgType::InspectFormat),
32 };
33 }
src/windows/wslc/commands/ContainerKillCommand.cpp
+1 -1
@@ -27,7 +27,7 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> ContainerKillCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::ContainerId, true, Limit::Unlimited),
30 + Argument::Create(ArgType::ContainerId, {.Required = true, .Limit = Limit::Unlimited}),
31 Argument::Create(ArgType::Signal),
32 };
33 }
src/windows/wslc/commands/ContainerListCommand.cpp
+1 -1
@@ -29,7 +29,7 @@ std::vector<Argument> ContainerListCommand::GetArguments() const
29 {
30 return {
31 Argument::Create(ArgType::All),
32 - Argument::Create(ArgType::Filter, false, Limit::Unlimited),
32 + Argument::Create(ArgType::Filter, {.Limit = Limit::Unlimited}),
33 Argument::Create(ArgType::Format),
34 Argument::Create(ArgType::Last),
35 Argument::Create(ArgType::Latest),
src/windows/wslc/commands/ContainerLogsCommand.cpp
+1 -1
@@ -27,7 +27,7 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> ContainerLogsCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::ContainerId, true),
30 + Argument::Create(ArgType::ContainerId, {.Required = true}),
31 Argument::Create(ArgType::Follow),
32 Argument::Create(ArgType::Tail),
33 Argument::Create(ArgType::Timestamps),
src/windows/wslc/commands/ContainerRemoveCommand.cpp
+1 -1
@@ -27,7 +27,7 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> ContainerRemoveCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::ContainerId, true, Limit::Unlimited),
30 + Argument::Create(ArgType::ContainerId, {.Required = true, .Limit = Limit::Unlimited}),
31 Argument::Create(ArgType::Force),
32 Argument::Create(ArgType::Volumes),
33 };
src/windows/wslc/commands/ContainerRunCommand.cpp
+15 -15
@@ -28,20 +28,20 @@ std::vector<Argument> ContainerRunCommand::GetArguments() const
28 {
29 // clang-format off
30 return {
31 - Argument::Create(ArgType::ImageId, true),
31 + Argument::Create(ArgType::ImageId, {.Required = true}),
32 Argument::Create(ArgType::Command),
33 Argument::Create(ArgType::ForwardArgs),
34 Argument::Create(ArgType::CIDFile),
35 Argument::Create(ArgType::Cpus),
36 Argument::Create(ArgType::Detach),
37 - Argument::Create(ArgType::DNS, false, Limit::Unlimited),
37 + Argument::Create(ArgType::DNS, {.Limit = Limit::Unlimited}),
38 // Argument::Create(ArgType::DNSDomain),
39 - Argument::Create(ArgType::DNSOption, false, Limit::Unlimited),
40 - Argument::Create(ArgType::DNSSearch, false, Limit::Unlimited),
39 + Argument::Create(ArgType::DNSOption, {.Limit = Limit::Unlimited}),
40 + Argument::Create(ArgType::DNSSearch, {.Limit = Limit::Unlimited}),
41 Argument::Create(ArgType::Domainname),
42 Argument::Create(ArgType::Entrypoint),
43 - Argument::Create(ArgType::Env, false, Limit::Unlimited),
44 - Argument::Create(ArgType::EnvFile, false, Limit::Unlimited),
43 + Argument::Create(ArgType::Env, {.Limit = Limit::Unlimited}),
44 + Argument::Create(ArgType::EnvFile, {.Limit = Limit::Unlimited}),
45 Argument::Create(ArgType::Gpus),
46 Argument::Create(ArgType::HealthCmd),
47 Argument::Create(ArgType::HealthInterval),
@@ -50,17 +50,17 @@ std::vector<Argument> ContainerRunCommand::GetArguments() const
50 Argument::Create(ArgType::HealthTimeout),
51 Argument::Create(ArgType::Hostname),
52 Argument::Create(ArgType::Interactive),
53 - Argument::Create(ArgType::IpAddress, false),
54 - Argument::Create(ArgType::Label, false, Limit::Unlimited),
53 + Argument::Create(ArgType::IpAddress),
54 + Argument::Create(ArgType::Label, {.Limit = Limit::Unlimited}),
55 Argument::Create(ArgType::Memory),
56 - Argument::Create(ArgType::Mount, false, Limit::Unlimited),
56 + Argument::Create(ArgType::Mount, {.Limit = Limit::Unlimited}),
57 Argument::Create(ArgType::Name),
58 - Argument::Create(ArgType::Network, false, Limit::Unlimited),
59 - Argument::Create(ArgType::NetworkAlias, false, Limit::Unlimited),
58 + Argument::Create(ArgType::Network, {.Limit = Limit::Unlimited}),
59 + Argument::Create(ArgType::NetworkAlias, {.Limit = Limit::Unlimited}),
60 // Argument::Create(ArgType::NoDNS),
61 // Argument::Create(ArgType::Progress),
62 Argument::Create(ArgType::NoHealthcheck),
63 - Argument::Create(ArgType::Publish, false, Limit::Unlimited),
63 + Argument::Create(ArgType::Publish, {.Limit = Limit::Unlimited}),
64 Argument::Create(ArgType::PublishAll),
65 Argument::Create(ArgType::Pull),
66 Argument::Create(ArgType::Remove),
@@ -68,11 +68,11 @@ std::vector<Argument> ContainerRunCommand::GetArguments() const
68 Argument::Create(ArgType::ShmSize),
69 Argument::Create(ArgType::StopSignal),
70 Argument::Create(ArgType::StopTimeout),
71 - Argument::Create(ArgType::TMPFS, false, Limit::Unlimited),
71 + Argument::Create(ArgType::TMPFS, {.Limit = Limit::Unlimited}),
72 Argument::Create(ArgType::TTY),
73 - Argument::Create(ArgType::Ulimit, false, Limit::Unlimited),
73 + Argument::Create(ArgType::Ulimit, {.Limit = Limit::Unlimited}),
74 Argument::Create(ArgType::User),
75 - Argument::Create(ArgType::Volume, false, Limit::Unlimited),
75 + Argument::Create(ArgType::Volume, {.Limit = Limit::Unlimited}),
76 // Argument::Create(ArgType::Virtual),
77 Argument::Create(ArgType::WorkDir),
78 };
src/windows/wslc/commands/ContainerStartCommand.cpp
+1 -1
@@ -27,7 +27,7 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> ContainerStartCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::ContainerId, true),
30 + Argument::Create(ArgType::ContainerId, {.Required = true}),
31 Argument::Create(ArgType::Attach),
32 Argument::Create(ArgType::Interactive), // NYI
33 };
src/windows/wslc/commands/ContainerStatsCommand.cpp
+1 -1
@@ -26,7 +26,7 @@ namespace wsl::windows::wslc {
26 std::vector<Argument> ContainerStatsCommand::GetArguments() const
27 {
28 return {
29 - Argument::Create(ArgType::ContainerId, false, Limit::Unlimited),
29 + Argument::Create(ArgType::ContainerId, {.Limit = Limit::Unlimited}),
30 Argument::Create(ArgType::All),
31 Argument::Create(ArgType::Format),
32 Argument::Create(ArgType::NoTrunc),
src/windows/wslc/commands/ContainerStopCommand.cpp
+2 -2
@@ -27,8 +27,8 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> ContainerStopCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::ContainerId, true, Limit::Unlimited),
31 - Argument::Create(ArgType::Signal, std::nullopt, std::nullopt, Localization::WSLCCLI_ContainerStopSignalArgDescription()),
30 + Argument::Create(ArgType::ContainerId, {.Required = true, .Limit = Limit::Unlimited}),
31 + Argument::Create(ArgType::Signal, {.Desc = Localization::WSLCCLI_ContainerStopSignalArgDescription()}),
32 Argument::Create(ArgType::Time),
33 };
34 }
src/windows/wslc/commands/ImageBuildCommand.cpp
+6 -6
@@ -27,18 +27,18 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> ImageBuildCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::Path, true),
31 - Argument::Create(ArgType::BuildArg, false, Limit::Unlimited),
30 + Argument::Create(ArgType::Path, {.Required = true}),
31 + Argument::Create(ArgType::BuildArg, {.Limit = Limit::Unlimited}),
32 Argument::Create(ArgType::BuildPull),
33 Argument::Create(ArgType::BuildTarget),
34 Argument::Create(ArgType::File),
35 Argument::Create(ArgType::IidFile),
36 - Argument::Create(ArgType::BuildLabel, false, Limit::Unlimited),
36 + Argument::Create(ArgType::BuildLabel, {.Limit = Limit::Unlimited}),
37 Argument::Create(ArgType::NoCache),
38 - Argument::Create(ArgType::BuildOutput, false, std::nullopt, Localization::WSLCCLI_BuildOutputArgDescription()),
38 + Argument::Create(ArgType::BuildOutput, {.Desc = Localization::WSLCCLI_BuildOutputArgDescription()}),
39 Argument::Create(ArgType::Progress),
40 - Argument::Create(ArgType::Secret, false, Limit::Unlimited),
41 - Argument::Create(ArgType::Tag, false, Limit::Unlimited),
40 + Argument::Create(ArgType::Secret, {.Limit = Limit::Unlimited}),
41 + Argument::Create(ArgType::Tag, {.Limit = Limit::Unlimited}),
42 Argument::Create(ArgType::Verbose),
43 };
44 }
src/windows/wslc/commands/ImageImportCommand.cpp
+1 -1
@@ -27,7 +27,7 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> ImageImportCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::ImportFile, true),
30 + Argument::Create(ArgType::ImportFile, {.Required = true}),
31 Argument::Create(ArgType::ImageId),
32 Argument::Create(ArgType::NoTrunc),
33 };
src/windows/wslc/commands/ImageInspectCommand.cpp
+1 -1
@@ -28,7 +28,7 @@ namespace wsl::windows::wslc {
28 std::vector<Argument> ImageInspectCommand::GetArguments() const
29 {
30 return {
31 - Argument::Create(ArgType::ImageId, true, Limit::Unlimited),
31 + Argument::Create(ArgType::ImageId, {.Required = true, .Limit = Limit::Unlimited}),
32 Argument::Create(ArgType::InspectFormat),
33 };
34 }
src/windows/wslc/commands/ImageListCommand.cpp
+1 -1
@@ -28,7 +28,7 @@ namespace wsl::windows::wslc {
28 std::vector<Argument> ImageListCommand::GetArguments() const
29 {
30 return {
31 - Argument::Create(ArgType::Filter, false, Limit::Unlimited),
31 + Argument::Create(ArgType::Filter, {.Limit = Limit::Unlimited}),
32 Argument::Create(ArgType::Format),
33 Argument::Create(ArgType::NoTrunc),
34 Argument::Create(ArgType::Quiet),
src/windows/wslc/commands/ImagePruneCommand.cpp
+2 -2
@@ -28,8 +28,8 @@ namespace wsl::windows::wslc {
28 std::vector<Argument> ImagePruneCommand::GetArguments() const
29 {
30 return {
31 - Argument::Create(ArgType::All, std::nullopt, std::nullopt, Localization::WSLCCLI_ImagePruneAllArgDescription()),
32 - Argument::Create(ArgType::Filter, false, Limit::Unlimited),
31 + Argument::Create(ArgType::All, {.Desc = Localization::WSLCCLI_ImagePruneAllArgDescription()}),
32 + Argument::Create(ArgType::Filter, {.Limit = Limit::Unlimited}),
33 };
34 }
35
src/windows/wslc/commands/ImagePullCommand.cpp
+2 -2
@@ -27,8 +27,8 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> ImagePullCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::ImageId, true),
31 - Argument::Create(ArgType::Quiet, std::nullopt, std::nullopt, Localization::WSLCCLI_PullQuietArgDescription()),
30 + Argument::Create(ArgType::ImageId, {.Required = true}),
31 + Argument::Create(ArgType::Quiet, {.Desc = Localization::WSLCCLI_PullQuietArgDescription()}),
32 // Argument::Create(ArgType::Scheme),
33 // Argument::Create(ArgType::Progress),
34 };
src/windows/wslc/commands/ImagePushCommand.cpp
+1 -1
@@ -27,7 +27,7 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> ImagePushCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::ImageId, true),
30 + Argument::Create(ArgType::ImageId, {.Required = true}),
31 };
32 }
33
src/windows/wslc/commands/ImageRemoveCommand.cpp
+1 -1
@@ -28,7 +28,7 @@ namespace wsl::windows::wslc {
28 std::vector<Argument> ImageRemoveCommand::GetArguments() const
29 {
30 return {
31 - Argument::Create(ArgType::ImageId, true, Limit::Unlimited),
31 + Argument::Create(ArgType::ImageId, {.Required = true, .Limit = Limit::Unlimited}),
32 Argument::Create(ArgType::ImageForce),
33 Argument::Create(ArgType::NoPrune),
34 };
src/windows/wslc/commands/ImageSaveCommand.cpp
+1 -1
@@ -27,7 +27,7 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> ImageSaveCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::ImageId, true, Limit::Unlimited),
30 + Argument::Create(ArgType::ImageId, {.Required = true, .Limit = Limit::Unlimited}),
31 Argument::Create(ArgType::Output),
32 };
33 }
src/windows/wslc/commands/ImageTagCommand.cpp
+2 -2
@@ -27,8 +27,8 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> ImageTagCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::Source, true),
31 - Argument::Create(ArgType::Target, true),
30 + Argument::Create(ArgType::Source, {.Required = true}),
31 + Argument::Create(ArgType::Target, {.Required = true}),
32 };
33 }
34
src/windows/wslc/commands/InspectCommand.cpp
+1 -1
@@ -22,7 +22,7 @@ namespace wsl::windows::wslc {
22 std::vector<Argument> InspectCommand::GetArguments() const
23 {
24 return {
25 - Argument::Create(ArgType::ObjectId, true, Limit::Unlimited),
25 + Argument::Create(ArgType::ObjectId, {.Required = true, .Limit = Limit::Unlimited}),
26 Argument::Create(ArgType::Type),
27 Argument::Create(ArgType::InspectFormat),
28 };
src/windows/wslc/commands/NetworkConnectCommand.cpp
+7 -7
@@ -27,13 +27,13 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> NetworkConnectCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::NetworkName, true),
31 - Argument::Create(ArgType::ContainerId, true),
32 - Argument::Create(ArgType::DriverOpt, false, Limit::Unlimited),
33 - Argument::Create(ArgType::IpAddress, false),
34 - Argument::Create(ArgType::Link, false, Limit::Unlimited),
35 - Argument::Create(ArgType::LinkLocalIp, false, Limit::Unlimited),
36 - Argument::Create(ArgType::NetworkAlias, false, Limit::Unlimited),
30 + Argument::Create(ArgType::NetworkName, {.Required = true}),
31 + Argument::Create(ArgType::ContainerId, {.Required = true}),
32 + Argument::Create(ArgType::DriverOpt, {.Limit = Limit::Unlimited}),
33 + Argument::Create(ArgType::IpAddress),
34 + Argument::Create(ArgType::Link, {.Limit = Limit::Unlimited}),
35 + Argument::Create(ArgType::LinkLocalIp, {.Limit = Limit::Unlimited}),
36 + Argument::Create(ArgType::NetworkAlias, {.Limit = Limit::Unlimited}),
37 };
38 }
39
src/windows/wslc/commands/NetworkCreateCommand.cpp
+4 -4
@@ -27,10 +27,10 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> NetworkCreateCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::NetworkName, true),
31 - Argument::Create(ArgType::Driver, std::nullopt, std::nullopt, Localization::WSLCCLI_NetworkDriverOptionDescription()),
32 - Argument::Create(ArgType::Options, false, Limit::Unlimited),
33 - Argument::Create(ArgType::Label, false, Limit::Unlimited, Localization::WSLCCLI_NetworkLabelArgDescription()),
30 + Argument::Create(ArgType::NetworkName, {.Required = true}),
31 + Argument::Create(ArgType::Driver, {.Desc = Localization::WSLCCLI_NetworkDriverOptionDescription()}),
32 + Argument::Create(ArgType::Options, {.Limit = Limit::Unlimited}),
33 + Argument::Create(ArgType::Label, {.Limit = Limit::Unlimited, .Desc = Localization::WSLCCLI_NetworkLabelArgDescription()}),
34 Argument::Create(ArgType::Gateway),
35 Argument::Create(ArgType::Internal),
36 Argument::Create(ArgType::IpRange),
src/windows/wslc/commands/NetworkDisconnectCommand.cpp
+2 -2
@@ -27,8 +27,8 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> NetworkDisconnectCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::NetworkName, true),
31 - Argument::Create(ArgType::ContainerId, true),
30 + Argument::Create(ArgType::NetworkName, {.Required = true}),
31 + Argument::Create(ArgType::ContainerId, {.Required = true}),
32 };
33 }
34
src/windows/wslc/commands/NetworkInspectCommand.cpp
+1 -1
@@ -27,7 +27,7 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> NetworkInspectCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::NetworkName, true, Limit::Unlimited),
30 + Argument::Create(ArgType::NetworkName, {.Required = true, .Limit = Limit::Unlimited}),
31 Argument::Create(ArgType::InspectFormat),
32 };
33 }
src/windows/wslc/commands/NetworkListCommand.cpp
+2 -2
@@ -27,10 +27,10 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> NetworkListCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::Filter, false, Limit::Unlimited),
30 + Argument::Create(ArgType::Filter, {.Limit = Limit::Unlimited}),
31 Argument::Create(ArgType::Format),
32 Argument::Create(ArgType::NoTrunc),
33 - Argument::Create(ArgType::Quiet, false, std::nullopt, Localization::WSLCCLI_NetworkListQuietArgDesc()),
33 + Argument::Create(ArgType::Quiet, {.Desc = Localization::WSLCCLI_NetworkListQuietArgDesc()}),
34 };
35 }
36
src/windows/wslc/commands/NetworkPruneCommand.cpp
+1 -1
@@ -27,7 +27,7 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> NetworkPruneCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::Filter, false, Limit::Unlimited),
30 + Argument::Create(ArgType::Filter, {.Limit = Limit::Unlimited}),
31 };
32 }
33
src/windows/wslc/commands/NetworkRemoveCommand.cpp
+2 -2
@@ -27,8 +27,8 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> NetworkRemoveCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::NetworkName, true, Limit::Unlimited),
31 - Argument::Create(ArgType::Force, std::nullopt, std::nullopt, Localization::WSLCCLI_NetworkForceArgDescription()),
30 + Argument::Create(ArgType::NetworkName, {.Required = true, .Limit = Limit::Unlimited}),
31 + Argument::Create(ArgType::Force, {.Desc = Localization::WSLCCLI_NetworkForceArgDescription()}),
32 };
33 }
34
src/windows/wslc/commands/SessionEnterCommand.cpp
+2 -2
@@ -26,8 +26,8 @@ namespace wsl::windows::wslc {
26 std::vector<Argument> SessionEnterCommand::GetArguments() const
27 {
28 return {
29 - Argument::Create(ArgType::StoragePath, true),
30 - Argument::Create(ArgType::Name, std::nullopt, std::nullopt, Localization::WSLCCLI_SessionEnterNameArgDescription()),
29 + Argument::Create(ArgType::StoragePath, {.Required = true}),
30 + Argument::Create(ArgType::Name, {.Desc = Localization::WSLCCLI_SessionEnterNameArgDescription()}),
31 };
32 }
33
src/windows/wslc/commands/SessionListCommand.cpp
+1 -1
@@ -25,7 +25,7 @@ namespace wsl::windows::wslc {
25 std::vector<Argument> SessionListCommand::GetArguments() const
26 {
27 return {
28 - Argument::Create(ArgType::Verbose, std::nullopt, std::nullopt, Localization::WSLCCLI_SessionListVerboseArgDescription()),
28 + Argument::Create(ArgType::Verbose, {.Desc = Localization::WSLCCLI_SessionListVerboseArgDescription()}),
29 };
30 }
31
src/windows/wslc/commands/SessionRunCommand.cpp
+2 -2
@@ -25,8 +25,8 @@ namespace wsl::windows::wslc {
25 std::vector<Argument> SessionRunCommand::GetArguments() const
26 {
27 return {
28 - Argument::Create(ArgType::Command, true),
29 - Argument::Create(ArgType::ForwardArgs, std::nullopt, std::nullopt, Localization::WSLCCLI_SessionRunForwardArgsDescription()),
28 + Argument::Create(ArgType::Command, {.Required = true}),
29 + Argument::Create(ArgType::ForwardArgs, {.Desc = Localization::WSLCCLI_SessionRunForwardArgsDescription()}),
30 };
31 }
32
src/windows/wslc/commands/VolumeCreateCommand.cpp
+2 -2
@@ -29,8 +29,8 @@ std::vector<Argument> VolumeCreateCommand::GetArguments() const
29 return {
30 Argument::Create(ArgType::VolumeName),
31 Argument::Create(ArgType::Driver),
32 - Argument::Create(ArgType::Options, false, Limit::Unlimited),
33 - Argument::Create(ArgType::Label, false, Limit::Unlimited),
32 + Argument::Create(ArgType::Options, {.Limit = Limit::Unlimited}),
33 + Argument::Create(ArgType::Label, {.Limit = Limit::Unlimited}),
34 };
35 }
36
src/windows/wslc/commands/VolumeInspectCommand.cpp
+1 -1
@@ -27,7 +27,7 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> VolumeInspectCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::VolumeName, true, Limit::Unlimited),
30 + Argument::Create(ArgType::VolumeName, {.Required = true, .Limit = Limit::Unlimited}),
31 Argument::Create(ArgType::InspectFormat),
32 };
33 }
src/windows/wslc/commands/VolumeListCommand.cpp
+2 -2
@@ -27,9 +27,9 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> VolumeListCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::Filter, false, Limit::Unlimited),
30 + Argument::Create(ArgType::Filter, {.Limit = Limit::Unlimited}),
31 Argument::Create(ArgType::Format),
32 - Argument::Create(ArgType::Quiet, false, std::nullopt, Localization::WSLCCLI_VolumeListQuietArgDesc()),
32 + Argument::Create(ArgType::Quiet, {.Desc = Localization::WSLCCLI_VolumeListQuietArgDesc()}),
33 };
34 }
35
src/windows/wslc/commands/VolumePruneCommand.cpp
+2 -2
@@ -27,8 +27,8 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> VolumePruneCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::All, std::nullopt, std::nullopt, Localization::WSLCCLI_VolumePruneAllArgDescription()),
31 - Argument::Create(ArgType::Filter, false, Limit::Unlimited),
30 + Argument::Create(ArgType::All, {.Desc = Localization::WSLCCLI_VolumePruneAllArgDescription()}),
31 + Argument::Create(ArgType::Filter, {.Limit = Limit::Unlimited}),
32 };
33 }
34
src/windows/wslc/commands/VolumeRemoveCommand.cpp
+2 -2
@@ -27,8 +27,8 @@ namespace wsl::windows::wslc {
27 std::vector<Argument> VolumeRemoveCommand::GetArguments() const
28 {
29 return {
30 - Argument::Create(ArgType::VolumeName, true, Limit::Unlimited),
31 - Argument::Create(ArgType::Force, std::nullopt, std::nullopt, Localization::WSLCCLI_VolumeForceArgDescription()),
30 + Argument::Create(ArgType::VolumeName, {.Required = true, .Limit = Limit::Unlimited}),
31 + Argument::Create(ArgType::Force, {.Desc = Localization::WSLCCLI_VolumeForceArgDescription()}),
32 };
33 }
34
test/windows/wslc/ParserTestCases.h
+10 -10
@@ -55,21 +55,21 @@ inline std::vector<wsl::windows::wslc::Argument> GetArgumentsForSet(ArgumentSet
55 {
56 case ArgumentSet::Run:
57 return {
58 - Argument::Create(ArgType::ImageId, true), // Required positional argument
59 - Argument::Create(ArgType::Command, false), // Optional positional argument
60 - Argument::Create(ArgType::ForwardArgs, false),
58 + Argument::Create(ArgType::ImageId, {.Required = true}), // Required positional argument
59 + Argument::Create(ArgType::Command), // Optional positional argument
60 + Argument::Create(ArgType::ForwardArgs),
61 Argument::Create(ArgType::Help),
62 Argument::Create(ArgType::Interactive),
63 Argument::Create(ArgType::Verbose),
64 Argument::Create(ArgType::Remove),
65 Argument::Create(ArgType::Signal),
66 Argument::Create(ArgType::Time),
67 - Argument::Create(ArgType::Publish, false, Limit::Unlimited), // Not required, unlimited.
67 + Argument::Create(ArgType::Publish, {.Limit = Limit::Unlimited}), // Not required, unlimited.
68 };
69
70 case ArgumentSet::List:
71 return {
72 - Argument::Create(ArgType::ContainerId, false, Limit::Unlimited), // Optional positional
72 + Argument::Create(ArgType::ContainerId, {.Limit = Limit::Unlimited}), // Optional positional
73 Argument::Create(ArgType::Help),
74 Argument::Create(ArgType::Verbose),
75 };
@@ -78,17 +78,17 @@ inline std::vector<wsl::windows::wslc::Argument> GetArgumentsForSet(ArgumentSet
78 // Mirrors ImageBuildCommand::GetArguments() so the parser tests exercise the
79 // real `wslc build` option set (notably the --progress value option).
80 return {
81 - Argument::Create(ArgType::Path, true), // Required positional (build context path)
82 - Argument::Create(ArgType::BuildArg, false, Limit::Unlimited),
81 + Argument::Create(ArgType::Path, {.Required = true}), // Required positional (build context path)
82 + Argument::Create(ArgType::BuildArg, {.Limit = Limit::Unlimited}),
83 Argument::Create(ArgType::BuildPull),
84 Argument::Create(ArgType::BuildTarget),
85 Argument::Create(ArgType::File),
86 - Argument::Create(ArgType::Label, false, Limit::Unlimited),
86 + Argument::Create(ArgType::Label, {.Limit = Limit::Unlimited}),
87 Argument::Create(ArgType::NoCache),
88 Argument::Create(ArgType::Output),
89 Argument::Create(ArgType::Progress),
90 - Argument::Create(ArgType::Secret, false, Limit::Unlimited),
91 - Argument::Create(ArgType::Tag, false, Limit::Unlimited),
90 + Argument::Create(ArgType::Secret, {.Limit = Limit::Unlimited}),
91 + Argument::Create(ArgType::Tag, {.Limit = Limit::Unlimited}),
92 Argument::Create(ArgType::Verbose),
93 Argument::Create(ArgType::Help),
94 };
test/windows/wslc/WSLCCLIArgumentUnitTests.cpp
+19
@@ -69,6 +69,25 @@ class WSLCCLIArgumentUnitTests
69 VERIFY_ARE_EQUAL(ArgType::Verbose, withArgument.Arguments().front().Type());
70 }
71
72 + TEST_METHOD(ArgumentCreate_DefaultsAndOverrides)
73 + {
74 + const auto defaults = Argument::Create(ArgType::Quiet);
75 + VERIFY_ARE_EQUAL(std::wstring{L"quiet"}, defaults.Name());
76 + VERIFY_ARE_EQUAL(std::wstring{L"q"}, defaults.Alias());
77 +
78 + const auto noAlias = Argument::Create(ArgType::Quiet, {.Alias = NO_ALIAS});
79 + VERIFY_IS_TRUE(noAlias.Alias().empty());
80 + VERIFY_ARE_EQUAL(defaults.Description(), noAlias.Description());
81 +
82 + const auto overrides = Argument::Create(
83 + ArgType::Filter, {.Name = L"where", .Alias = L"x", .Required = true, .Limit = Limit::Unlimited, .Desc = L"Custom description"});
84 + VERIFY_ARE_EQUAL(std::wstring{L"where"}, overrides.Name());
85 + VERIFY_ARE_EQUAL(std::wstring{L"x"}, overrides.Alias());
86 + VERIFY_IS_TRUE(overrides.Required());
87 + VERIFY_ARE_EQUAL(Limit::Unlimited, overrides.Limit());
88 + VERIFY_ARE_EQUAL(std::wstring{L"Custom description"}, overrides.Description());
89 + }
90 +
91 // Test: Verify Argument::Create() successfully creates arguments for all ArgType enum values
92 TEST_METHOD(ArgumentCreate_AllArguments)
93 {
test/windows/wslc/WSLCCLICommandUnitTests.cpp
+7
@@ -316,6 +316,13 @@ class WSLCCLICommandUnitTests
316
317 // Check name collision between distinct ArgTypes.
318 const auto& name = arg.Name();
319 + if (name.size() < 2)
320 + {
321 + VERIFY_FAIL(
322 + std::format(L"Command '{}' uses invalid long-form name '--{}' for ArgType '{}'", commandFullName, name, ArgTypeName(arg.Type()))
323 + .c_str());
324 + }
325 +
326 auto [nameIt, nameInserted] = seenNames.emplace(name, arg.Type());
327 if (!nameInserted)
328 {
test/windows/wslc/WSLCCLIExecutionUnitTests.cpp
+1 -1
@@ -58,7 +58,7 @@ class WSLCCLIExecutionUnitTests
58 {
59 RootCommand command;
60 ArgMap args;
61 - const std::vector<Argument> definitions{Argument::Create(ArgType::Password, true)};
61 + const std::vector<Argument> definitions{Argument::Create(ArgType::Password, {.Required = true})};
62
63 try
64 {
test/windows/wslc/WSLCCLIParserUnitTests.cpp
+24 -3
@@ -361,7 +361,7 @@ class WSLCCLIParserUnitTests
361
362 // Pass 2: full mode with the subcommand's argument set.
363 std::vector<Argument> subDefs = {
364 - Argument::Create(ArgType::ImageId, true),
364 + Argument::Create(ArgType::ImageId, {.Required = true}),
365 Argument::Create(ArgType::Signal),
366 };
367 ArgMap subArgs;
@@ -558,7 +558,8 @@ class WSLCCLIParserUnitTests
558 // Unlimited value args are exempt from last-wins: every CLI occurrence accumulates.
559 TEST_METHOD(UnlimitedValueOnCli_Accumulates)
560 {
561 - ArgMap args = ParseFlags(L"wslc --publish 80:80 --publish 443:443", {Argument::Create(ArgType::Publish, false, Limit::Unlimited)});
561 + ArgMap args =
562 + ParseFlags(L"wslc --publish 80:80 --publish 443:443", {Argument::Create(ArgType::Publish, {.Limit = Limit::Unlimited})});
563
564 VERIFY_ARE_EQUAL(2u, args.Count(ArgType::Publish));
565 }
@@ -653,7 +654,8 @@ class WSLCCLIParserUnitTests
654 TEST_METHOD(Flag_SpaceSeparatedValue_StaysPositional)
655 {
656 ArgMap args = ParseFlags(
656 - L"wslc --verbose true", {Argument::Create(ArgType::Verbose), Argument::Create(ArgType::ContainerId, false, Limit::Unlimited)});
657 + L"wslc --verbose true",
658 + {Argument::Create(ArgType::Verbose), Argument::Create(ArgType::ContainerId, {.Limit = Limit::Unlimited})});
659
660 VERIFY_IS_TRUE(args.Contains(ArgType::Verbose));
661 VERIFY_IS_TRUE(args.GetValue<ArgType::Verbose>());
@@ -684,6 +686,25 @@ class WSLCCLIParserUnitTests
686 VERIFY_IS_FALSE(ParseFlags(L"wslc -q=false", {Argument::Create(ArgType::Quiet)}).GetValue<ArgType::Quiet>());
687 }
688
689 + TEST_METHOD(AliasOverride_ControlsCommandAlias)
690 + {
691 + const std::vector<Argument> customAlias{Argument::Create(ArgType::Quiet, {.Alias = L"x"})};
692 + VERIFY_IS_TRUE(ParseFlags(L"wslc -x", customAlias).GetValue<ArgType::Quiet>());
693 + VERIFY_THROWS(ParseFlags(L"wslc -q", customAlias), ArgumentException);
694 +
695 + const std::vector<Argument> noAlias{Argument::Create(ArgType::Quiet, {.Alias = NO_ALIAS})};
696 + VERIFY_IS_TRUE(ParseFlags(L"wslc --quiet", noAlias).GetValue<ArgType::Quiet>());
697 + VERIFY_THROWS(ParseFlags(L"wslc -q", noAlias), ArgumentException);
698 + }
699 +
700 + TEST_METHOD(NameOverride_ControlsCommandName)
701 + {
702 + const std::vector<Argument> definitions{Argument::Create(ArgType::Quiet, {.Name = L"silent"})};
703 + VERIFY_IS_TRUE(ParseFlags(L"wslc --silent", definitions).GetValue<ArgType::Quiet>());
704 + VERIFY_IS_TRUE(ParseFlags(L"wslc -q", definitions).GetValue<ArgType::Quiet>());
705 + VERIFY_THROWS(ParseFlags(L"wslc --quiet", definitions), ArgumentException);
706 + }
707 +
708 // Docker-parity single-letter forms ("t"/"T"/"f"/"F") are honored on the alias form too.
709 TEST_METHOD(Flag_AliasShortBooleanForms)
710 {