示例#1
0
    private void ValidateMember(IMemberSchema memberSchema, object?convertedValue)
    {
        var errors = new List <BindingValidationError>();

        foreach (var validatorType in memberSchema.ValidatorTypes)
        {
            var validator = (IBindingValidator)_typeActivator.CreateInstance(validatorType);
            var error     = validator.Validate(convertedValue);

            if (error is not null)
            {
                errors.Add(error);
            }
        }

        if (errors.Any())
        {
            throw CliFxException.UserError(
                      $"{memberSchema.GetKind()} {memberSchema.GetFormattedIdentifier()} has been provided with an invalid value." +
                      Environment.NewLine +
                      "Error(s):" +
                      Environment.NewLine +
                      errors.Select(e => "- " + e.Message).JoinToString(Environment.NewLine)
                      );
        }
    }
示例#2
0
    private object?ConvertMember(IMemberSchema memberSchema, IReadOnlyList <string> rawValues)
    {
        var targetType = memberSchema.Property.Type;

        try
        {
            // Non-scalar
            var enumerableUnderlyingType = targetType.TryGetEnumerableUnderlyingType();
            if (targetType != typeof(string) && enumerableUnderlyingType is not null)
            {
                return(ConvertMultiple(memberSchema, rawValues, targetType, enumerableUnderlyingType));
            }

            // Scalar
            if (rawValues.Count <= 1)
            {
                return(ConvertSingle(memberSchema, rawValues.SingleOrDefault(), targetType));
            }
        }
        catch (Exception ex) when(ex is not CliFxException)  // don't wrap CliFxException
        {
            // We use reflection-based invocation which can throw TargetInvocationException.
            // Unwrap these exceptions to provide a more user-friendly error message.
            var errorMessage = ex is TargetInvocationException invokeEx
                ? invokeEx.InnerException?.Message ?? invokeEx.Message
                : ex.Message;

            throw CliFxException.UserError(
                      $"{memberSchema.GetKind()} {memberSchema.GetFormattedIdentifier()} cannot be set from provided argument(s):" +
                      Environment.NewLine +
                      rawValues.Select(v => '<' + v + '>').JoinToString(" ") +
                      Environment.NewLine +
                      $"Error: {errorMessage}",
                      ex
                      );
        }

        // Mismatch (scalar but too many values)
        throw CliFxException.UserError(
                  $"{memberSchema.GetKind()} {memberSchema.GetFormattedIdentifier()} expects a single argument, but provided with multiple:" +
                  Environment.NewLine +
                  rawValues.Select(v => '<' + v + '>').JoinToString(" ")
                  );
    }
示例#3
0
    private void BindOptions(CommandInput commandInput, CommandSchema commandSchema, ICommand commandInstance)
    {
        // Ensure there are no unrecognized options and that all required options are set
        var remainingOptionInputs          = commandInput.Options.ToList();
        var remainingRequiredOptionSchemas = commandSchema.Options.Where(o => o.IsRequired).ToList();

        foreach (var optionSchema in commandSchema.Options)
        {
            var optionInputs = commandInput
                               .Options
                               .Where(o => optionSchema.MatchesIdentifier(o.Identifier))
                               .ToArray();

            var environmentVariableInput = commandInput
                                           .EnvironmentVariables
                                           .FirstOrDefault(e => optionSchema.MatchesEnvironmentVariable(e.Name));

            // Direct input
            if (optionInputs.Any())
            {
                var rawValues = optionInputs.SelectMany(o => o.Values).ToArray();

                BindMember(optionSchema, commandInstance, rawValues);

                // Required options require at least one value to be set
                if (rawValues.Any())
                {
                    remainingRequiredOptionSchemas.Remove(optionSchema);
                }
            }
            // Environment variable
            else if (environmentVariableInput is not null)
            {
                var rawValues = optionSchema.Property.IsScalar()
                    ? new[] { environmentVariableInput.Value }
                    : environmentVariableInput.SplitValues();

                BindMember(optionSchema, commandInstance, rawValues);

                // Required options require at least one value to be set
                if (rawValues.Any())
                {
                    remainingRequiredOptionSchemas.Remove(optionSchema);
                }
            }
            // No input - skip
            else
            {
                continue;
            }

            remainingOptionInputs.RemoveRange(optionInputs);
        }

        if (remainingOptionInputs.Any())
        {
            throw CliFxException.UserError(
                      "Unrecognized option(s):" +
                      Environment.NewLine +
                      remainingOptionInputs
                      .Select(o => o.GetFormattedIdentifier())
                      .JoinToString(", ")
                      );
        }

        if (remainingRequiredOptionSchemas.Any())
        {
            throw CliFxException.UserError(
                      "Missing required option(s):" +
                      Environment.NewLine +
                      remainingRequiredOptionSchemas
                      .Select(o => o.GetFormattedIdentifier())
                      .JoinToString(", ")
                      );
        }
    }
示例#4
0
    private void BindParameters(CommandInput commandInput, CommandSchema commandSchema, ICommand commandInstance)
    {
        // Ensure there are no unexpected parameters and that all parameters are provided
        var remainingParameterInputs          = commandInput.Parameters.ToList();
        var remainingRequiredParameterSchemas = commandSchema.Parameters.Where(p => p.IsRequired).ToList();

        var position = 0;

        foreach (var parameterSchema in commandSchema.Parameters.OrderBy(p => p.Order))
        {
            // Break when there are no remaining inputs
            if (position >= commandInput.Parameters.Count)
            {
                break;
            }

            // Scalar - take one input at the current position
            if (parameterSchema.Property.IsScalar())
            {
                var parameterInput = commandInput.Parameters[position];

                var rawValues = new[] { parameterInput.Value };
                BindMember(parameterSchema, commandInstance, rawValues);

                position++;

                remainingParameterInputs.Remove(parameterInput);
            }
            // Non-scalar - take all remaining inputs starting from the current position
            else
            {
                var parameterInputs = commandInput.Parameters.Skip(position).ToArray();

                var rawValues = parameterInputs.Select(p => p.Value).ToArray();
                BindMember(parameterSchema, commandInstance, rawValues);

                position += parameterInputs.Length;

                remainingParameterInputs.RemoveRange(parameterInputs);
            }

            remainingRequiredParameterSchemas.Remove(parameterSchema);
        }

        if (remainingParameterInputs.Any())
        {
            throw CliFxException.UserError(
                      "Unexpected parameter(s):" +
                      Environment.NewLine +
                      remainingParameterInputs
                      .Select(p => p.GetFormattedIdentifier())
                      .JoinToString(" ")
                      );
        }

        if (remainingRequiredParameterSchemas.Any())
        {
            throw CliFxException.UserError(
                      "Missing required parameter(s):" +
                      Environment.NewLine +
                      remainingRequiredParameterSchemas
                      .Select(o => o.GetFormattedIdentifier())
                      .JoinToString(" ")
                      );
        }
    }