/// <summary> /// Attempts to resolve a valid parsed input to a registered command /// </summary> /// <param name="input">The valid parsed input</param> /// <returns>A resolved command</returns> public ResolvedCommand Resolve(ParsedInput input) { // is input valid if (!input.IsValid) { throw new CommandResolutionException(input, "The provided input is invalid and cannot be resolved"); } // does cmd exist var cmdInfo = _registry.Commands.FirstOrDefault(c => c.Name.Equals(input.GetCommandElement().Value, StringComparison.OrdinalIgnoreCase)); if (cmdInfo == null) { return(new ResolvedCommand(input, CommandResolutionErrorType.CommandNotFound)); } // begin to accumulate errors var errors = new List <ResolveCommandError>(); // capture argument errors - unknown arguments, options with values var inputMap = new Dictionary <ArgumentInfo, ParsedInputElement>(); foreach (var node in input.Elements.Where(n => n.ElementType == InputElementType.ArgumentName || n.ElementType == InputElementType.ArgumentAlias)) { var argInfo = node.ElementType == InputElementType.ArgumentName ? cmdInfo.Arguments.SingleOrDefault(p => p.Name.Equals(node.Value, StringComparison.OrdinalIgnoreCase)) : cmdInfo.Arguments.SingleOrDefault(p => p.Alias.Equals(node.Value.Single())); CaptureArgumentErrors( errors, argInfo, node); if (argInfo != null) { if (!inputMap.ContainsKey(argInfo)) { inputMap.Add(argInfo, node); } else { errors.Add(new ResolveCommandError { Type = CommandResolutionErrorType.DuplicateArgument, Element = node, Message = $"Arguments \"{node.Raw}\" and \"{inputMap[argInfo].Raw}\" resolve the same argument property." }); } } } return(new ResolvedCommand(input, cmdInfo, new ReadOnlyDictionary <ArgumentInfo, ParsedInputElement>(inputMap), errors)); }
public async Task <int> Run(string inputStr) { try { // create new cancellation token source _currentCancellationTokenSource = new CancellationTokenSource(); // ensure only one execution at a time if (IsRunning) { throw new InvalidOperationException("Another command is already executing"); } IsRunning = true; // parse input var input = new ParsedInput(inputStr); if (!input.IsValid) { // process input parsing errors foreach (var err in input.Errors) { switch (err.Type) { case ParsedInputValidationErrorType.NoCommandElement: _interface.WriterCollection.Error.WriteLine("Invalid input :: no command element defined"); break; case ParsedInputValidationErrorType.InvalidAlias: _interface.WriterCollection.Error.WriteLine($"Invalid alisas :: [{err.Element.StartPosition}] {err.Element.Raw} - {err.Message}"); break; default: throw new ArgumentOutOfRangeException($"Value \"{err.Type}\" not defined for switch."); } } // list unexpected values foreach (var elem in input.Elements.Where(e => e.ElementType == InputElementType.Unexpected)) { _interface.WriterCollection.Error.WriteLine($"Unexpected element :: [{elem.StartPosition}] {elem.Raw}"); } return((int)ExecutionReturnCode.UnexpectedElements); } // resolve command var resCmd = _resolver.Resolve(input); if (!resCmd.IsValid) { foreach (var err in resCmd.Errors) { switch (err.Type) { case CommandResolutionErrorType.CommandNotFound: _interface.WriterCollection.Error.WriteLine($"Command, \"{input.GetCommandElement().Value}\" not found"); break; case CommandResolutionErrorType.ArgumentNotFound: case CommandResolutionErrorType.UnexpectedValue: case CommandResolutionErrorType.DuplicateArgument: _interface.WriterCollection.Error.WriteLine($"{err.Message} :: [{err.Element.StartPosition}] {err.Element.Raw}"); break; default: throw new ArgumentOutOfRangeException($"Value \"{err.Type}\" not defined for switch."); } } return((int)ExecutionReturnCode.CommandResolutionError); } // activate and execute return(await ExecuteCommand(_activator.Activate(resCmd))); } finally { IsRunning = false; _currentCancellationTokenSource.Dispose(); } }