Esempio n. 1
0
        public static bool TryProcess(CommandInputSpecification spec, TParseResult parseResult, out DefaultCommandInput <TParseResult> result, out IReadOnlyList <CommandInputProcessingIssue> processingIssues)
        {
            spec = spec ?? throw new ArgumentNullException(nameof(spec));

            List <CommandInputProcessingIssue> issues = null;
            List <InputElement> commandNameElements   = null;

            foreach (IReadOnlyList <string> commandName in spec.CommandName)
            {
                if (TryProcessCommandName(commandName, parseResult, out List <InputElement> nameElements, out issues))
                {
                    commandNameElements = nameElements;
                    break;
                }
            }

            if (commandNameElements is null)
            {
                result           = null;
                processingIssues = issues;
                return(false);
            }

            List <InputElement> arguments = new List <InputElement>();
            Dictionary <InputElement, InputElement> options = new Dictionary <InputElement, InputElement>();
            InputElement currentOption = null;
            CommandOptionSpecification currentOptionSpec = null;
            InputElement selectedElement = null;

            for (int i = spec.CommandName.Count; i < parseResult.Sections.Count; ++i)
            {
                //If we're not looking at an option name
                if (!parseResult.Sections[i].StartsWith(spec.OptionPreamble.ToString(), StringComparison.OrdinalIgnoreCase) || parseResult.IsQuotedSection(i))
                {
                    if (currentOption is null)
                    {
                        InputElement currentElement = new InputElement(CommandInputLocation.Argument, parseResult.Sections[i], parseResult.Sections[i], i);

                        if (i == parseResult.SelectedSection)
                        {
                            selectedElement = currentElement;
                        }

                        arguments.Add(currentElement);
                    }
                    else
                    {
                        //If the option isn't a defined one or it is and indicates that it accepts a value, add the section as an option value,
                        //  otherwise add it as an argument
                        if (currentOptionSpec?.AcceptsValue ?? true)
                        {
                            InputElement currentElement = new InputElement(currentOption, CommandInputLocation.OptionValue, parseResult.Sections[i], parseResult.Sections[i], i);

                            if (i == parseResult.SelectedSection)
                            {
                                selectedElement = currentElement;
                            }

                            options[currentOption] = currentElement;
                            currentOption          = null;
                            currentOptionSpec      = null;
                        }
                        else
                        {
                            InputElement currentElement = new InputElement(CommandInputLocation.Argument, parseResult.Sections[i], parseResult.Sections[i], i);

                            if (i == parseResult.SelectedSection)
                            {
                                selectedElement = currentElement;
                            }

                            arguments.Add(currentElement);
                        }
                    }
                }
                //If we are looking at an option name
                else
                {
                    //Otherwise, check to see whether the previous option had a required argument before committing it
                    if (currentOption is object)
                    {
                        options[currentOption] = null;

                        if (currentOptionSpec?.RequiresValue ?? false)
                        {
                            issues.Add(new CommandInputProcessingIssue(CommandInputProcessingIssueKind.MissingRequiredOptionInput, currentOption.Text));
                        }
                    }

                    CommandOptionSpecification optionSpec = spec.Options.FirstOrDefault(x => x.Forms.Any(y => string.Equals(y, parseResult.Sections[i], StringComparison.Ordinal)));

                    if (optionSpec is null)
                    {
                        issues.Add(new CommandInputProcessingIssue(CommandInputProcessingIssueKind.UnknownOption, parseResult.Sections[i]));
                    }

                    currentOption = new InputElement(CommandInputLocation.OptionName, parseResult.Sections[i], optionSpec?.Id, i);

                    if (i == parseResult.SelectedSection)
                    {
                        selectedElement = currentOption;
                    }

                    currentOptionSpec = optionSpec;
                }
            }

            //Clear any option in progress
            if (currentOption is object)
            {
                options[currentOption] = null;

                if (currentOptionSpec?.RequiresValue ?? false)
                {
                    issues.Add(new CommandInputProcessingIssue(CommandInputProcessingIssueKind.MissingRequiredOptionInput, currentOption.Text));
                }
            }

            //Check to make sure our argument count is in range, if not add an issue
            if (arguments.Count > spec.MaximumArguments || arguments.Count < spec.MinimumArguments)
            {
                issues.Add(new CommandInputProcessingIssue(CommandInputProcessingIssueKind.ArgumentCountOutOfRange, arguments.Count.ToString()));
            }

            //Build up the dictionary of options by normal form, then validate counts for every option in the spec
            Dictionary <string, IReadOnlyList <InputElement> > optionsByNormalForm = new Dictionary <string, IReadOnlyList <InputElement> >(StringComparer.Ordinal);

            foreach (KeyValuePair <InputElement, InputElement> entry in options)
            {
                if (entry.Key.NormalizedText is null)
                {
                    continue;
                }

                if (!optionsByNormalForm.TryGetValue(entry.Key.NormalizedText, out IReadOnlyList <InputElement> rawBucket))
                {
                    optionsByNormalForm[entry.Key.NormalizedText] = rawBucket = new List <InputElement>();
                }

                List <InputElement> bucket = (List <InputElement>)rawBucket;
                bucket.Add(entry.Value);
            }

            foreach (CommandOptionSpecification optionSpec in spec.Options)
            {
                if (!optionsByNormalForm.TryGetValue(optionSpec.Id, out IReadOnlyList <InputElement> values))
                {
                    optionsByNormalForm[optionSpec.Id] = values = new List <InputElement>();
                }

                if (values.Count < optionSpec.MinimumOccurrences || values.Count > optionSpec.MaximumOccurrences)
                {
                    issues.Add(new CommandInputProcessingIssue(CommandInputProcessingIssueKind.OptionUseCountOutOfRange, values.Count.ToString()));
                }
            }

            result           = new DefaultCommandInput <TParseResult>(commandNameElements, arguments, optionsByNormalForm, selectedElement);
            processingIssues = issues;
            return(issues.Count == 0);
        }
Esempio n. 2
0
 public CommandInputSpecificationBuilder WithOption(CommandOptionSpecification option)
 {
     _options.Add(option);
     return(this);
 }