diff --git a/src/System.CommandLine.Subsystems.Tests/ErrorReportingFunctionalTests.cs b/src/System.CommandLine.Subsystems.Tests/ErrorReportingFunctionalTests.cs index 47e4808c1..b9deabd18 100644 --- a/src/System.CommandLine.Subsystems.Tests/ErrorReportingFunctionalTests.cs +++ b/src/System.CommandLine.Subsystems.Tests/ErrorReportingFunctionalTests.cs @@ -56,9 +56,9 @@ public void Help_display_can_be_disabled() var result = rootCommand.Parse("oops", config); - if (result.Action is ParseErrorAction parseError) + if (result.Action is CliDiagnosticAction CliDiagnostic) { - parseError.ShowHelp = false; + CliDiagnostic.ShowHelp = false; } result.Invoke(); diff --git a/src/System.CommandLine.Subsystems.Tests/ErrorReportingSubsystemTests.cs b/src/System.CommandLine.Subsystems.Tests/ErrorReportingSubsystemTests.cs index 1ce30a942..b8284a71b 100644 --- a/src/System.CommandLine.Subsystems.Tests/ErrorReportingSubsystemTests.cs +++ b/src/System.CommandLine.Subsystems.Tests/ErrorReportingSubsystemTests.cs @@ -1,9 +1,9 @@ // Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System.CommandLine.Parsing; using FluentAssertions; using Xunit; -using System.CommandLine.Parsing; namespace System.CommandLine.Subsystems.Tests; @@ -12,8 +12,8 @@ public class ErrorReportingSubsystemTests [Fact] public void Report_when_single_error_writes_to_console_hack() { - var error = new ParseError("a sweet error message"); - var errors = new List { error }; + var error = new CliDiagnostic(new("", "", "a sweet error message", CliDiagnosticSeverity.Warning, null), []); + var errors = new List { error }; var errorSubsystem = new ErrorReportingSubsystem(); var consoleHack = new ConsoleHack().RedirectToBuffer(true); @@ -25,9 +25,9 @@ public void Report_when_single_error_writes_to_console_hack() [Fact] public void Report_when_multiple_error_writes_to_console_hack() { - var error = new ParseError("a sweet error message"); - var anotherError = new ParseError("another sweet error message"); - var errors = new List { error, anotherError }; + var error = new CliDiagnostic(new("", "", "a sweet error message", CliDiagnosticSeverity.Warning, null), []); + var anotherError = new CliDiagnostic(new("", "", "another sweet error message", CliDiagnosticSeverity.Warning, null), []); + var errors = new List { error, anotherError }; var errorSubsystem = new ErrorReportingSubsystem(); var consoleHack = new ConsoleHack().RedirectToBuffer(true); @@ -39,7 +39,7 @@ public void Report_when_multiple_error_writes_to_console_hack() [Fact] public void Report_when_no_errors_writes_nothing_to_console_hack() { - var errors = new List { }; + var errors = new List { }; var errorSubsystem = new ErrorReportingSubsystem(); var consoleHack = new ConsoleHack().RedirectToBuffer(true); @@ -53,7 +53,7 @@ public void Report_when_no_errors_writes_nothing_to_console_hack() [InlineData("-non_existant_option")] public void GetIsActivated_GivenInvalidInput_SubsystemIsActive(string input) { - var rootCommand = new CliRootCommand {new CliOption("-v")}; + var rootCommand = new CliRootCommand { new CliOption("-v") }; var configuration = new CliConfiguration(rootCommand); var errorSubsystem = new ErrorReportingSubsystem(); IReadOnlyList args = [""]; diff --git a/src/System.CommandLine.Subsystems/ErrorReportingSubsystem.cs b/src/System.CommandLine.Subsystems/ErrorReportingSubsystem.cs index 27f43ab9f..039e70021 100644 --- a/src/System.CommandLine.Subsystems/ErrorReportingSubsystem.cs +++ b/src/System.CommandLine.Subsystems/ErrorReportingSubsystem.cs @@ -33,7 +33,7 @@ public override void Execute(PipelineResult pipelineResult) pipelineResult.SetSuccess(); } - public void Report(ConsoleHack consoleHack, IReadOnlyList errors) + public void Report(ConsoleHack consoleHack, IReadOnlyList errors) { ConsoleHelpers.ResetTerminalForegroundColor(); ConsoleHelpers.SetTerminalForegroundRed(); diff --git a/src/System.CommandLine.Subsystems/PipelineResult.cs b/src/System.CommandLine.Subsystems/PipelineResult.cs index cb1763c3d..8af9b55ed 100644 --- a/src/System.CommandLine.Subsystems/PipelineResult.cs +++ b/src/System.CommandLine.Subsystems/PipelineResult.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.CommandLine.Parsing; @@ -9,8 +9,8 @@ namespace System.CommandLine; public class PipelineResult { // TODO: Try to build workflow so it is illegal to create this without a ParseResult - private readonly List errors = []; - private ValueProvider valueProvider { get; } + private readonly List errors = []; + private ValueProvider valueProvider { get; } public PipelineResult(ParseResult parseResult, string rawInput, Pipeline? pipeline, ConsoleHack? consoleHack = null) { @@ -44,7 +44,7 @@ public PipelineResult(ParseResult parseResult, string rawInput, Pipeline? pipeli => ParseResult.GetValueResult(valueSymbol); - public void AddErrors(IEnumerable errors) + public void AddErrors(IEnumerable errors) { if (errors is not null) { @@ -52,10 +52,10 @@ public void AddErrors(IEnumerable errors) } } - public void AddError(ParseError error) + public void AddError(CliDiagnostic error) => errors.Add(error); - public IEnumerable GetErrors(bool excludeParseErrors = false) + public IEnumerable GetErrors(bool excludeParseErrors = false) => excludeParseErrors || ParseResult is null ? errors : ParseResult.Errors.Concat(errors); diff --git a/src/System.CommandLine.Subsystems/Validation/InclusiveGroupValidator.cs b/src/System.CommandLine.Subsystems/Validation/InclusiveGroupValidator.cs index 6c8a1c28e..961b4538a 100644 --- a/src/System.CommandLine.Subsystems/Validation/InclusiveGroupValidator.cs +++ b/src/System.CommandLine.Subsystems/Validation/InclusiveGroupValidator.cs @@ -44,9 +44,9 @@ public override void Validate(CliCommandResult commandResult, // TODO: Rework to allow localization var pluralToBe = "are"; var singularToBe = "is"; - validationContext.AddError(new ParseError( $"The members {string.Join(", ", groupMembers.Select(m => m.Name))} " + - $"must all be used if one is used. {string.Join(", ", missingMembers.Select(m => m.Name))} " + - $"{(missingMembers.Skip(1).Any() ? pluralToBe : singularToBe)} missing.")); + validationContext.AddError(new CliDiagnostic(new("", "", "The members {groupMembers} " + + "must all be used if one is used. {missingMembers} " + + "{toBe} missing.", severity: CliDiagnosticSeverity.Error, null), [string.Join(", ", groupMembers.Select(m => m.Name)), string.Join(", ", missingMembers.Select(m => m.Name)), (missingMembers.Skip(1).Any() ? pluralToBe : singularToBe)])); } } } diff --git a/src/System.CommandLine.Subsystems/Validation/RangeValidator.cs b/src/System.CommandLine.Subsystems/Validation/RangeValidator.cs index cfab72a18..5f0e682a4 100644 --- a/src/System.CommandLine.Subsystems/Validation/RangeValidator.cs +++ b/src/System.CommandLine.Subsystems/Validation/RangeValidator.cs @@ -24,9 +24,7 @@ public override void Validate(object? value, CliValueSymbol valueSymbol, } if (valueCondition.MustHaveValidator) { - validationContext.AddError(new ParseError($"Range validator missing for {valueSymbol.Name}")); + validationContext.AddError(new CliDiagnostic(new("", "", "Range validator missing for {valueSymbol}", severity: CliDiagnosticSeverity.Error, null), [valueSymbol.Name], cliSymbolResult: valueResult)); } } - - } diff --git a/src/System.CommandLine.Subsystems/Validation/ValidationContext.cs b/src/System.CommandLine.Subsystems/Validation/ValidationContext.cs index 3f22a1228..93c8bfe22 100644 --- a/src/System.CommandLine.Subsystems/Validation/ValidationContext.cs +++ b/src/System.CommandLine.Subsystems/Validation/ValidationContext.cs @@ -3,7 +3,6 @@ using System.CommandLine.Parsing; using System.CommandLine.ValueSources; -using static System.Runtime.InteropServices.JavaScript.JSType; namespace System.CommandLine.Validation; @@ -24,7 +23,7 @@ internal ValidationContext(PipelineResult pipelineResult, ValidationSubsystem va /// Adds an error to the PipelineContext. /// /// The to add - public void AddError(ParseError error) + public void AddError(CliDiagnostic error) => pipelineResult.AddError(error); /// diff --git a/src/System.CommandLine.Subsystems/Validation/Validator.cs b/src/System.CommandLine.Subsystems/Validation/Validator.cs index e33f732c1..e8d64e4a2 100644 --- a/src/System.CommandLine.Subsystems/Validation/Validator.cs +++ b/src/System.CommandLine.Subsystems/Validation/Validator.cs @@ -31,11 +31,11 @@ internal Validator(string name, Type valueConditionType, params Type[] moreValue /// /// This method needs to be evolved as we replace ParseError with CliError /// - protected static List AddValidationError(ref List? parseErrors, string message, IEnumerable errorValues) + protected static List AddValidationError(ref List? parseErrors, string message, IEnumerable errorValues) { // TODO: Review the handling of errors. They are currently transient and returned by the Validate method, and to avoid allocating in the case of no errors (the common case) this method is used. This adds complexity to creating a new validator. - parseErrors ??= new List(); - parseErrors.Add(new ParseError(message)); + parseErrors ??= new List(); + parseErrors.Add(new CliDiagnostic(new("", "", message, severity: CliDiagnosticSeverity.Error, null), [])); return parseErrors; } diff --git a/src/System.CommandLine.Subsystems/ValidationSubsystem.cs b/src/System.CommandLine.Subsystems/ValidationSubsystem.cs index 00e44e997..1ae38a131 100644 --- a/src/System.CommandLine.Subsystems/ValidationSubsystem.cs +++ b/src/System.CommandLine.Subsystems/ValidationSubsystem.cs @@ -81,7 +81,8 @@ private void ValidateValue(CliValueSymbol valueSymbol, ValidationContext validat var value = validationContext.GetValue(valueSymbol); var valueResult = validationContext.GetValueResult(valueSymbol); - do { + do + { ValidateValueCondition(value, valueSymbol, valueResult, enumerator.Current, validationContext); } while (enumerator.MoveNext()); } @@ -123,9 +124,9 @@ private void ValidateValueCondition(object? value, CliValueSymbol valueSymbol, C { if (condition.MustHaveValidator) { - validationContext.AddError(new ParseError($"{valueSymbol.Name} must have {condition.Name} validator.")); + validationContext.AddError(new CliDiagnostic(new("", "", "{valueSymbol} must have {condition} validator.", severity: CliDiagnosticSeverity.Error, null), [valueSymbol.Name, condition.Name], cliSymbolResult: valueResult)); } - return; + return; } validator.Validate(value, valueSymbol, valueResult, condition, validationContext); @@ -169,7 +170,7 @@ private void ValidateCommandCondition(CliCommandResult commandResult, CommandCon { if (condition.MustHaveValidator) { - validationContext.AddError(new ParseError($"{commandResult.Command.Name} must have {condition.Name} validator.")); + validationContext.AddError(new CliDiagnostic(new("", "", "{commandResult} must have {condition} validator.", severity: CliDiagnosticSeverity.Error, null), [commandResult.Command.Name, condition.Name])); } return; } diff --git a/src/System.CommandLine.Subsystems/ValueConditions/Range.cs b/src/System.CommandLine.Subsystems/ValueConditions/Range.cs index 2d029e5e8..70bb2c07f 100644 --- a/src/System.CommandLine.Subsystems/ValueConditions/Range.cs +++ b/src/System.CommandLine.Subsystems/ValueConditions/Range.cs @@ -40,8 +40,8 @@ internal Range(ValueSource? lowerBound, ValueSource? upperBound, RangeBoun LowerBound = lowerBound; UpperBound = upperBound; RangeBound = rangeBound; - } - + } + /// public void Validate(object? value, CliValueSymbol valueSymbol, @@ -59,7 +59,7 @@ public void Validate(object? value, && validationContext.TryGetTypedValue(LowerBound, out var lowerValue) && comparableValue.CompareTo(lowerValue) < 0) { - validationContext.AddError(new ParseError($"The value for '{valueSymbol.Name}' is below the lower bound of {LowerBound}")); + validationContext.AddError(new CliDiagnostic(new("", "", "The value for '{valueSymbol}' is below the lower bound of {lowerBound}", severity: CliDiagnosticSeverity.Error, null), [valueSymbol.Name, LowerBound], cliSymbolResult: valueResult)); } @@ -67,7 +67,7 @@ public void Validate(object? value, && validationContext.TryGetTypedValue(UpperBound, out var upperValue) && comparableValue.CompareTo(upperValue) > 0) { - validationContext.AddError(new ParseError($"The value for '{valueSymbol.Name}' is above the upper bound of {UpperBound}")); + validationContext.AddError(new CliDiagnostic(new("", "", "The value for '{valueSymbol}' is above the upper bound of {upperBound}", severity: CliDiagnosticSeverity.Error, null), [valueSymbol.Name, UpperBound], cliSymbolResult: valueResult)); } } diff --git a/src/System.CommandLine/ParseResult.cs b/src/System.CommandLine/ParseResult.cs index 569615481..3e91bf1ba 100644 --- a/src/System.CommandLine/ParseResult.cs +++ b/src/System.CommandLine/ParseResult.cs @@ -3,9 +3,6 @@ using System.Collections.Generic; using System.CommandLine.Parsing; -using System.Linq; -using System.Threading.Tasks; -using System.Threading; namespace System.CommandLine { @@ -39,7 +36,7 @@ internal ParseResult( */ // TODO: unmatched tokens // List? unmatchedTokens, - List? errors, + List? errors, // TODO: commandLineText should be string array string? commandLineText = null //, // TODO: invocation @@ -82,12 +79,11 @@ internal ParseResult( // TODO: unmatched tokens // _unmatchedTokens = unmatchedTokens is null ? Array.Empty() : unmatchedTokens; - Errors = errors is not null ? errors : Array.Empty(); + Errors = errors is not null ? errors : Array.Empty(); } public CliSymbol? GetSymbolByName(string name, bool valuesOnly = false) { - symbolLookupByName ??= new SymbolLookupByName(this); return symbolLookupByName.TryGetSymbol(name, out var symbol, valuesOnly: valuesOnly) ? symbol diff --git a/src/System.CommandLine/Parsing/CliArgumentResultInternal.cs b/src/System.CommandLine/Parsing/CliArgumentResultInternal.cs index 8c59a3edb..11e0e47ef 100644 --- a/src/System.CommandLine/Parsing/CliArgumentResultInternal.cs +++ b/src/System.CommandLine/Parsing/CliArgumentResultInternal.cs @@ -138,9 +138,9 @@ public void OnlyTake(int numberOfTokens) public override string ToString() => $"{nameof(CliArgumentResultInternal)} {Argument.Name}: {string.Join(" ", Tokens.Select(t => $"<{t.Value}>"))}"; /// - internal override void AddError(string errorMessage) + internal override void AddError(string errorMessage, CliValueResult valueResult) { - SymbolResultTree.AddError(new CliDiagnostic(new("", "", errorMessage, CliDiagnosticSeverity.Warning, null), [], symbolResult: AppliesToPublicSymbolResult)); + SymbolResultTree.AddError(new CliDiagnostic(new("", "", errorMessage, CliDiagnosticSeverity.Warning, null), [], cliSymbolResult: valueResult)); _conversionResult = ArgumentConversionResult.Failure(this, errorMessage, ArgumentConversionResultType.Failed); } @@ -170,6 +170,8 @@ private ArgumentConversionResult ValidateAndConvert(bool useValidators) } } */ + // TODO: defaults + /* if (Parent!.UseDefaultValueFor(this)) { var defaultValue = Argument.GetDefaultValue(this); @@ -177,6 +179,7 @@ private ArgumentConversionResult ValidateAndConvert(bool useValidators) // default value factory provided by the user might report an error, which sets _conversionResult return _conversionResult ?? ArgumentConversionResult.Success(this, defaultValue); } + */ if (Argument.ConvertArguments is null) { @@ -218,7 +221,7 @@ ArgumentConversionResult ReportErrorIfNeeded(ArgumentConversionResult result) { if (result.Result >= ArgumentConversionResultType.Failed) { - SymbolResultTree.AddError(new CliDiagnostic(new("ArgumentConversionResultTypeFailed", "Type Conversion Failed", result.ErrorMessage!, CliDiagnosticSeverity.Warning, null), [], symbolResult: AppliesToPublicSymbolResult)); + SymbolResultTree.AddError(new CliDiagnostic(new("ArgumentConversionResultTypeFailed", "Type Conversion Failed", result.ErrorMessage!, CliDiagnosticSeverity.Warning, null), [], cliSymbolResult: ValueResult)); } return result; diff --git a/src/System.CommandLine/Parsing/CliCommandResultInternal.cs b/src/System.CommandLine/Parsing/CliCommandResultInternal.cs index 36413e3c2..486194317 100644 --- a/src/System.CommandLine/Parsing/CliCommandResultInternal.cs +++ b/src/System.CommandLine/Parsing/CliCommandResultInternal.cs @@ -84,7 +84,7 @@ internal void Validate(bool completeValidation) if (Command.HasSubcommands) { SymbolResultTree.InsertFirstError( - new CliDiagnostic(new("validateSubCommandError", "Validation Error", LocalizationResources.RequiredCommandWasNotProvided(), CliDiagnosticSeverity.Warning, null), [], symbolResult: this)); + new CliDiagnostic(new("validateSubCommandError", "Validation Error", LocalizationResources.RequiredCommandWasNotProvided(), CliDiagnosticSeverity.Warning, null), [], valueResult: )); } // TODO: validators diff --git a/src/System.CommandLine/Parsing/CliDiagnostic.cs b/src/System.CommandLine/Parsing/CliDiagnostic.cs index 8328683f7..f8605ee78 100644 --- a/src/System.CommandLine/Parsing/CliDiagnostic.cs +++ b/src/System.CommandLine/Parsing/CliDiagnostic.cs @@ -1,7 +1,8 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; namespace System.CommandLine.Parsing; @@ -11,6 +12,7 @@ namespace System.CommandLine.Parsing; * https://github.com/mhutch/MonoDevelop.MSBuildEditor/blob/main/MonoDevelop.MSBuild/Analysis/MSBuildDiagnosticDescriptor.cs * https://github.com/dotnet/roslyn/blob/main/src/Compilers/Core/Portable/Diagnostic/DiagnosticDescriptor.cs * https://github.com/dotnet/roslyn/blob/main/src/Compilers/Core/Portable/Diagnostic/Diagnostic.cs + * https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/sarif-v2.1.0-errata01-os-complete.html#_Toc141791086 */ internal static class ParseDiagnostics { @@ -27,7 +29,7 @@ internal static class ParseDiagnostics public sealed class CliDiagnosticDescriptor { - public CliDiagnosticDescriptor(string id, string title, string messageFormat, CliDiagnosticSeverity severity, string? helpUri) + public CliDiagnosticDescriptor(string id, string title, [StringSyntax(StringSyntaxAttribute.CompositeFormat)] string messageFormat, CliDiagnosticSeverity severity, string? helpUri) { Id = id; Title = title; @@ -38,6 +40,7 @@ public CliDiagnosticDescriptor(string id, string title, string messageFormat, Cl public string Id { get; } public string Title { get; } + [StringSyntax(StringSyntaxAttribute.CompositeFormat)] public string MessageFormat { get; } public CliDiagnosticSeverity Severity { get; } public string? HelpUri { get; } @@ -65,19 +68,18 @@ public sealed class CliDiagnostic /// Contains information about the error. /// The arguments to be passed to the in the . /// Properties to be associated with the diagnostic. - /// The symbol result detailing the symbol that failed to parse and the tokens involved. + /// Contains information about a single value entered. /// The location of the error. public CliDiagnostic( CliDiagnosticDescriptor descriptor, object?[]? messageArgs, ImmutableDictionary? properties = null, - SymbolResult? symbolResult = null, + CliSymbolResult? cliSymbolResult = null, Location? location = null) { Descriptor = descriptor; MessageArgs = messageArgs; Properties = properties; - SymbolResult = symbolResult; } /// @@ -101,10 +103,7 @@ public string Message public object?[]? MessageArgs { get; } - /// - /// Gets the symbol result detailing the symbol that failed to parse and the tokens involved. - /// - public SymbolResult? SymbolResult { get; } + public CliSymbolResult? CliSymbolResult { get; } /// public override string ToString() => Message; diff --git a/src/System.CommandLine/Parsing/CliSymbolResultInternal.cs b/src/System.CommandLine/Parsing/CliSymbolResultInternal.cs index 68e134a81..4a679578c 100644 --- a/src/System.CommandLine/Parsing/CliSymbolResultInternal.cs +++ b/src/System.CommandLine/Parsing/CliSymbolResultInternal.cs @@ -64,7 +64,8 @@ public IEnumerable Errors /// Adds an error message for this symbol result to it's parse tree. /// /// Setting an error will cause the parser to indicate an error for the user and prevent invocation of the command line. - internal virtual void AddError(string errorMessage) => SymbolResultTree.AddError(new CliDiagnostic(new("", "", errorMessage, severity: CliDiagnosticSeverity.Error, null), [], symbolResult: this)); + internal virtual void AddError(string errorMessage, CliValueResult valueResult) => + SymbolResultTree.AddError(new CliDiagnostic(new("", "", errorMessage, severity: CliDiagnosticSeverity.Error, null), [], cliSymbolResult: valueResult)); /// /// Finds a result for the specific argument anywhere in the parse tree, including parent and child symbol results. /// diff --git a/src/System.CommandLine/Parsing/ParseOperation.cs b/src/System.CommandLine/Parsing/ParseOperation.cs index 3c941ecf9..50185de4a 100644 --- a/src/System.CommandLine/Parsing/ParseOperation.cs +++ b/src/System.CommandLine/Parsing/ParseOperation.cs @@ -76,7 +76,7 @@ internal ParseResult Parse() { if (_symbolResultTree.ErrorCount > 0) { - _primaryAction = new ParseErrorAction(); + _primaryAction = new CliDiagnosticAction(); } } */ diff --git a/src/System.CommandLine/Parsing/SymbolResultTree.cs b/src/System.CommandLine/Parsing/SymbolResultTree.cs index d053c1c61..1a6b3aeb9 100644 --- a/src/System.CommandLine/Parsing/SymbolResultTree.cs +++ b/src/System.CommandLine/Parsing/SymbolResultTree.cs @@ -8,7 +8,7 @@ namespace System.CommandLine.Parsing internal sealed class SymbolResultTree : Dictionary { private readonly CliCommand _rootCommand; - internal List? Errors; + internal List? Errors; // TODO: unmatched tokens /* internal List? UnmatchedTokens; @@ -29,7 +29,9 @@ internal SymbolResultTree( for (var i = 0; i < tokenizeErrors.Count; i++) { - Errors.Add(new CliDiagnostic(new("", "", tokenizeErrors[i], CliDiagnosticSeverity.Warning, null), [])); + Errors.Add(new CliDiagnostic(new("", "", + tokenizeErrors[i], CliDiagnosticSeverity.Warning, null), [], + cliSymbolResult: null)); } } } @@ -81,8 +83,8 @@ internal IReadOnlyDictionary BuildValueResultDictiona return dict; } - internal void AddError(CliDiagnostic parseError) => (Errors ??= new()).Add(parseError); - internal void InsertFirstError(CliDiagnostic parseError) => (Errors ??= new()).Insert(0, parseError); + internal void AddError(CliDiagnostic CliDiagnostic) => (Errors ??= new()).Add(CliDiagnostic); + internal void InsertFirstError(CliDiagnostic CliDiagnostic) => (Errors ??= new()).Insert(0, CliDiagnostic); internal void AddUnmatchedToken(CliToken token, CliCommandResultInternal commandResult, CliCommandResultInternal rootCommandResult) { @@ -98,75 +100,10 @@ internal void AddUnmatchedToken(CliToken token, CliCommandResultInternal command } */ - AddError(new CliDiagnostic(new("", "", LocalizationResources.UnrecognizedCommandOrArgument(token.Value), CliDiagnosticSeverity.Warning, null), [], symbolResult: commandResult)); + AddError(new CliDiagnostic(new("", "", LocalizationResources.UnrecognizedCommandOrArgument(token.Value), CliDiagnosticSeverity.Warning, null), [])); /* - } - - public SymbolResult? GetResult(string name) - { - if (_symbolsByName is null) - { - _symbolsByName = new(); - PopulateSymbolsByName(_rootCommand); } */ } - -// TODO: symbolsbyname - this is inefficient -// results for some values may not be queried at all, dependent on other options -// so we could avoid using their value factories and adding them to the dictionary -// could we sort by name allowing us to do a binary search instead of allocating a dictionary? -// could we add codepaths that query for specific kinds of symbols so they don't have to search all symbols? - private void PopulateSymbolsByName(CliCommand command) - { - if (command.HasArguments) - { - for (var i = 0; i < command.Arguments.Count; i++) - { - AddToSymbolsByName(command.Arguments[i]); - } - } - - if (command.HasOptions) - { - for (var i = 0; i < command.Options.Count; i++) - { - AddToSymbolsByName(command.Options[i]); - } - } - - if (command.HasSubcommands) - { - for (var i = 0; i < command.Subcommands.Count; i++) - { - var childCommand = command.Subcommands[i]; - AddToSymbolsByName(childCommand); - PopulateSymbolsByName(childCommand); - } - } - - // TODO: Explore removing closure here - void AddToSymbolsByName(CliSymbol symbol) - { - if (_symbolsByName!.TryGetValue(symbol.Name, out var node)) - { - if (symbol.Name == node.Symbol.Name && - symbol.FirstParent?.Symbol is { } parent && - parent == node.Symbol.FirstParent?.Symbol) - { - throw new InvalidOperationException($"Command {parent.Name} has more than one child named \"{symbol.Name}\"."); - } - - _symbolsByName[symbol.Name] = new(symbol) - { - Next = node - }; - } - else - { - _symbolsByName[symbol.Name] = new(symbol); - } - } - } } }