diff --git a/CliFx/Domain/CommandArgumentSchema.cs b/CliFx/Domain/CommandArgumentSchema.cs index 0aa4fbf..0cd0cff 100644 --- a/CliFx/Domain/CommandArgumentSchema.cs +++ b/CliFx/Domain/CommandArgumentSchema.cs @@ -19,7 +19,7 @@ namespace CliFx.Domain public Type? ConverterType { get; } - private readonly Type[]? _validators; + public readonly Type[]? ValidatorTypes; protected CommandArgumentSchema(PropertyInfo? property, string? description, Type? converterType = null, Type[]? validators = null) { @@ -27,7 +27,7 @@ namespace CliFx.Domain Description = description; ConverterType = converterType; - _validators = validators; + ValidatorTypes = validators; } private Type? TryGetEnumerableArgumentUnderlyingType() => @@ -140,7 +140,7 @@ namespace CliFx.Domain { var value = Convert(values); - if (_validators.NotEmpty()) + if (ValidatorTypes.NotEmpty()) Validate(value); Property?.SetValue(command, value); @@ -171,9 +171,9 @@ namespace CliFx.Domain return; var failed = new List(); - foreach (var validator in _validators!) + foreach (var validator in ValidatorTypes!) { - var result = validator.InstanceOf().Validate(value!); + var result = validator.CreateInstance().Validate(value!); if (result.IsValid) continue; diff --git a/CliFx/Domain/CommandOptionSchema.cs b/CliFx/Domain/CommandOptionSchema.cs index dc342f4..941a23f 100644 --- a/CliFx/Domain/CommandOptionSchema.cs +++ b/CliFx/Domain/CommandOptionSchema.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; @@ -26,8 +25,8 @@ namespace CliFx.Domain bool isRequired, string? description, Type? converterType = null, - Type[]? validators = null) - : base(property, description, converterType, validators) + Type[]? validatorTypes = null) + : base(property, description, converterType, validatorTypes) { Name = name; ShortName = shortName; @@ -110,9 +109,9 @@ namespace CliFx.Domain internal partial class CommandOptionSchema { public static CommandOptionSchema HelpOption { get; } = - new CommandOptionSchema(null, "help", 'h', null, false, "Shows help text.", null); + new CommandOptionSchema(null, "help", 'h', null, false, "Shows help text.", converterType: null, validatorTypes: null); public static CommandOptionSchema VersionOption { get; } = - new CommandOptionSchema(null, "version", null, null, false, "Shows version information.", null); + new CommandOptionSchema(null, "version", null, null, false, "Shows version information.", converterType: null, validatorTypes: null); } } \ No newline at end of file diff --git a/CliFx/Domain/CommandParameterSchema.cs b/CliFx/Domain/CommandParameterSchema.cs index 7aa556e..814c8d6 100644 --- a/CliFx/Domain/CommandParameterSchema.cs +++ b/CliFx/Domain/CommandParameterSchema.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Text; @@ -19,8 +18,8 @@ namespace CliFx.Domain string name, string? description, Type? converterType = null, - Type[]? validators = null) - : base(property, description, converterType, validators) + Type[]? validatorTypes = null) + : base(property, description, converterType, validatorTypes) { Order = order; Name = name; diff --git a/CliFx/Domain/RootSchema.cs b/CliFx/Domain/RootSchema.cs index 431bc43..98fff68 100644 --- a/CliFx/Domain/RootSchema.cs +++ b/CliFx/Domain/RootSchema.cs @@ -126,6 +126,18 @@ namespace CliFx.Domain invalidConverterParameters ); } + + var invalidValidatorParameters = command.Parameters + .Where(p => p.ValidatorTypes != null && !p.ValidatorTypes.All(x => x.Implements(typeof(IArgumentValueValidator)))) + .ToArray(); + + if (invalidValidatorParameters.Any()) + { + throw CliFxException.ParametersWithInvalidValidators( + command, + invalidValidatorParameters + ); + } } private static void ValidateOptions(CommandSchema command) @@ -208,6 +220,18 @@ namespace CliFx.Domain invalidConverterOptions ); } + + var invalidValidatorOptions = command.Options + .Where(o => o.ValidatorTypes != null && !o.ValidatorTypes.All(x => x.Implements(typeof(IArgumentValueValidator)))) + .ToArray(); + + if (invalidValidatorOptions.Any()) + { + throw CliFxException.OptionsWithInvalidValidators( + command, + invalidValidatorOptions + ); + } } private static void ValidateCommands(IReadOnlyList commands) diff --git a/CliFx/Exceptions/CliFxException.cs b/CliFx/Exceptions/CliFxException.cs index cb3075f..8535621 100644 --- a/CliFx/Exceptions/CliFxException.cs +++ b/CliFx/Exceptions/CliFxException.cs @@ -185,6 +185,19 @@ Specified converter must implement {typeof(IArgumentValueConverter).FullName}."; return new CliFxException(message.Trim()); } + internal static CliFxException ParametersWithInvalidValidators( + CommandSchema command, + IReadOnlyList invalidParameters) + { + var message = $@" +Command '{command.Type.FullName}' is invalid because it contains {invalidParameters.Count} parameter(s) with invalid value validators: +{invalidParameters.JoinToString(Environment.NewLine)} + +Specified validator(s) must inherit from {typeof(ArgumentValueValidator<>).FullName}."; + + return new CliFxException(message.Trim()); + } + internal static CliFxException OptionsWithNoName( CommandSchema command, IReadOnlyList invalidOptions) @@ -269,6 +282,19 @@ Specified converter must implement {typeof(IArgumentValueConverter).FullName}."; return new CliFxException(message.Trim()); } + + internal static CliFxException OptionsWithInvalidValidators( + CommandSchema command, + IReadOnlyList invalidOptions) + { + var message = $@" +Command '{command.Type.FullName}' is invalid because it contains {invalidOptions.Count} option(s) with invalid validators: +{invalidOptions.JoinToString(Environment.NewLine)} + +Specified validators must inherit from {typeof(IArgumentValueValidator).FullName}."; + + return new CliFxException(message.Trim()); + } } // End-user-facing exceptions