Skip to content

Commit ddf0a2a

Browse files
Rebasing on powderhouse
1 parent 05bd9eb commit ddf0a2a

17 files changed

+121
-178
lines changed

src/System.CommandLine.Subsystems.Tests/ErrorReportingFunctionalTests.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ public void Help_display_can_be_disabled()
5656
5757
var result = rootCommand.Parse("oops", config);
5858
59-
if (result.Action is ParseErrorAction parseError)
59+
if (result.Action is CliDiagnosticAction CliDiagnostic)
6060
{
61-
parseError.ShowHelp = false;
61+
CliDiagnostic.ShowHelp = false;
6262
}
6363
6464
result.Invoke();

src/System.CommandLine.Subsystems.Tests/ErrorReportingSubsystemTests.cs

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// Copyright (c) .NET Foundation and contributors. All rights reserved.
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

4+
using System.CommandLine.Parsing;
45
using FluentAssertions;
56
using Xunit;
6-
using System.CommandLine.Parsing;
77

88
namespace System.CommandLine.Subsystems.Tests;
99

@@ -12,8 +12,8 @@ public class ErrorReportingSubsystemTests
1212
[Fact]
1313
public void Report_when_single_error_writes_to_console_hack()
1414
{
15-
var error = new ParseError("a sweet error message");
16-
var errors = new List<ParseError> { error };
15+
var error = new CliDiagnostic(new("", "", "a sweet error message", CliDiagnosticSeverity.Warning, null), []);
16+
var errors = new List<CliDiagnostic> { error };
1717
var errorSubsystem = new ErrorReportingSubsystem();
1818
var consoleHack = new ConsoleHack().RedirectToBuffer(true);
1919

@@ -25,9 +25,9 @@ public void Report_when_single_error_writes_to_console_hack()
2525
[Fact]
2626
public void Report_when_multiple_error_writes_to_console_hack()
2727
{
28-
var error = new ParseError("a sweet error message");
29-
var anotherError = new ParseError("another sweet error message");
30-
var errors = new List<ParseError> { error, anotherError };
28+
var error = new CliDiagnostic(new("", "", "a sweet error message", CliDiagnosticSeverity.Warning, null), []);
29+
var anotherError = new CliDiagnostic(new("", "", "another sweet error message", CliDiagnosticSeverity.Warning, null), []);
30+
var errors = new List<CliDiagnostic> { error, anotherError };
3131
var errorSubsystem = new ErrorReportingSubsystem();
3232
var consoleHack = new ConsoleHack().RedirectToBuffer(true);
3333

@@ -39,7 +39,7 @@ public void Report_when_multiple_error_writes_to_console_hack()
3939
[Fact]
4040
public void Report_when_no_errors_writes_nothing_to_console_hack()
4141
{
42-
var errors = new List<ParseError> { };
42+
var errors = new List<CliDiagnostic> { };
4343
var errorSubsystem = new ErrorReportingSubsystem();
4444
var consoleHack = new ConsoleHack().RedirectToBuffer(true);
4545

@@ -53,7 +53,7 @@ public void Report_when_no_errors_writes_nothing_to_console_hack()
5353
[InlineData("-non_existant_option")]
5454
public void GetIsActivated_GivenInvalidInput_SubsystemIsActive(string input)
5555
{
56-
var rootCommand = new CliRootCommand {new CliOption<bool>("-v")};
56+
var rootCommand = new CliRootCommand { new CliOption<bool>("-v") };
5757
var configuration = new CliConfiguration(rootCommand);
5858
var errorSubsystem = new ErrorReportingSubsystem();
5959
IReadOnlyList<string> args = [""];

src/System.CommandLine.Subsystems/ErrorReportingSubsystem.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public override void Execute(PipelineResult pipelineResult)
3333
pipelineResult.SetSuccess();
3434
}
3535

36-
public void Report(ConsoleHack consoleHack, IReadOnlyList<ParseError> errors)
36+
public void Report(ConsoleHack consoleHack, IReadOnlyList<CliDiagnostic> errors)
3737
{
3838
ConsoleHelpers.ResetTerminalForegroundColor();
3939
ConsoleHelpers.SetTerminalForegroundRed();

src/System.CommandLine.Subsystems/PipelineResult.cs

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation and contributors. All rights reserved.
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

44
using System.CommandLine.Parsing;
@@ -9,8 +9,8 @@ namespace System.CommandLine;
99
public class PipelineResult
1010
{
1111
// TODO: Try to build workflow so it is illegal to create this without a ParseResult
12-
private readonly List<ParseError> errors = [];
13-
private ValueProvider valueProvider { get; }
12+
private readonly List<CliDiagnostic> errors = [];
13+
private ValueProvider valueProvider { get; }
1414

1515
public PipelineResult(ParseResult parseResult, string rawInput, Pipeline? pipeline, ConsoleHack? consoleHack = null)
1616
{
@@ -44,18 +44,18 @@ public PipelineResult(ParseResult parseResult, string rawInput, Pipeline? pipeli
4444
=> ParseResult.GetValueResult(valueSymbol);
4545

4646

47-
public void AddErrors(IEnumerable<ParseError> errors)
47+
public void AddErrors(IEnumerable<CliDiagnostic> errors)
4848
{
4949
if (errors is not null)
5050
{
5151
this.errors.AddRange(errors);
5252
}
5353
}
5454

55-
public void AddError(ParseError error)
55+
public void AddError(CliDiagnostic error)
5656
=> errors.Add(error);
5757

58-
public IEnumerable<ParseError> GetErrors(bool excludeParseErrors = false)
58+
public IEnumerable<CliDiagnostic> GetErrors(bool excludeParseErrors = false)
5959
=> excludeParseErrors || ParseResult is null
6060
? errors
6161
: ParseResult.Errors.Concat(errors);

src/System.CommandLine.Subsystems/Validation/InclusiveGroupValidator.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ public override void Validate(CliCommandResult commandResult,
4444
// TODO: Rework to allow localization
4545
var pluralToBe = "are";
4646
var singularToBe = "is";
47-
validationContext.AddError(new ParseError( $"The members {string.Join(", ", groupMembers.Select(m => m.Name))} " +
48-
$"must all be used if one is used. {string.Join(", ", missingMembers.Select(m => m.Name))} " +
49-
$"{(missingMembers.Skip(1).Any() ? pluralToBe : singularToBe)} missing."));
47+
validationContext.AddError(new CliDiagnostic(new("", "", $"The members {string.Join(", ", groupMembers.Select(m => m.Name))} " +
48+
$"must all be used if one is used. {string.Join(", ", missingMembers.Select(m => m.Name))} " +
49+
$"{(missingMembers.Skip(1).Any() ? pluralToBe : singularToBe)} missing.", severity: CliDiagnosticSeverity.Error, null), []));
5050
}
5151
}
5252
}

src/System.CommandLine.Subsystems/Validation/RangeValidator.cs

+1-3
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,7 @@ public override void Validate(object? value, CliValueSymbol valueSymbol,
2424
}
2525
if (valueCondition.MustHaveValidator)
2626
{
27-
validationContext.AddError(new ParseError($"Range validator missing for {valueSymbol.Name}"));
27+
validationContext.AddError(new CliDiagnostic(new("", "", $"Range validator missing for {valueSymbol.Name}", severity: CliDiagnosticSeverity.Error, null), [], cliSymbolResult: valueResult));
2828
}
2929
}
30-
31-
3230
}

src/System.CommandLine.Subsystems/Validation/ValidationContext.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
using System.CommandLine.Parsing;
55
using System.CommandLine.ValueSources;
6-
using static System.Runtime.InteropServices.JavaScript.JSType;
76

87
namespace System.CommandLine.Validation;
98

@@ -24,7 +23,7 @@ internal ValidationContext(PipelineResult pipelineResult, ValidationSubsystem va
2423
/// Adds an error to the PipelineContext.
2524
/// </summary>
2625
/// <param name="error">The <see cref="ParseError"/> to add</param>
27-
public void AddError(ParseError error)
26+
public void AddError(CliDiagnostic error)
2827
=> pipelineResult.AddError(error);
2928

3029
/// <summary>

src/System.CommandLine.Subsystems/Validation/Validator.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ internal Validator(string name, Type valueConditionType, params Type[] moreValue
3131
/// <remarks>
3232
/// This method needs to be evolved as we replace ParseError with CliError
3333
/// </remarks>
34-
protected static List<ParseError> AddValidationError(ref List<ParseError>? parseErrors, string message, IEnumerable<object?> errorValues)
34+
protected static List<CliDiagnostic> AddValidationError(ref List<CliDiagnostic>? parseErrors, string message, IEnumerable<object?> errorValues)
3535
{
3636
// 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.
37-
parseErrors ??= new List<ParseError>();
38-
parseErrors.Add(new ParseError(message));
37+
parseErrors ??= new List<CliDiagnostic>();
38+
parseErrors.Add(new CliDiagnostic(new("", "", message, severity: CliDiagnosticSeverity.Error, null), []));
3939
return parseErrors;
4040
}
4141

src/System.CommandLine.Subsystems/ValidationSubsystem.cs

+5-4
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ private void ValidateValue(CliValueSymbol valueSymbol, ValidationContext validat
8181
var value = validationContext.GetValue(valueSymbol);
8282
var valueResult = validationContext.GetValueResult(valueSymbol);
8383

84-
do {
84+
do
85+
{
8586
ValidateValueCondition(value, valueSymbol, valueResult, enumerator.Current, validationContext);
8687
} while (enumerator.MoveNext());
8788
}
@@ -123,9 +124,9 @@ private void ValidateValueCondition(object? value, CliValueSymbol valueSymbol, C
123124
{
124125
if (condition.MustHaveValidator)
125126
{
126-
validationContext.AddError(new ParseError($"{valueSymbol.Name} must have {condition.Name} validator."));
127+
validationContext.AddError(new CliDiagnostic(new("", "", $"{valueSymbol.Name} must have {condition.Name} validator.", severity: CliDiagnosticSeverity.Error, null), [], cliSymbolResult: valueResult));
127128
}
128-
return;
129+
return;
129130
}
130131
validator.Validate(value, valueSymbol, valueResult, condition, validationContext);
131132

@@ -169,7 +170,7 @@ private void ValidateCommandCondition(CliCommandResult commandResult, CommandCon
169170
{
170171
if (condition.MustHaveValidator)
171172
{
172-
validationContext.AddError(new ParseError($"{commandResult.Command.Name} must have {condition.Name} validator."));
173+
validationContext.AddError(new CliDiagnostic(new("", "", $"{commandResult.Command.Name} must have {condition.Name} validator.", severity: CliDiagnosticSeverity.Error, null), []));
173174
}
174175
return;
175176
}

src/System.CommandLine.Subsystems/ValueConditions/Range.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ internal Range(ValueSource<T>? lowerBound, ValueSource<T>? upperBound, RangeBoun
4040
LowerBound = lowerBound;
4141
UpperBound = upperBound;
4242
RangeBound = rangeBound;
43-
}
44-
43+
}
44+
4545
/// <inheritdoc/>
4646
public void Validate(object? value,
4747
CliValueSymbol valueSymbol,
@@ -59,15 +59,15 @@ public void Validate(object? value,
5959
&& validationContext.TryGetTypedValue(LowerBound, out var lowerValue)
6060
&& comparableValue.CompareTo(lowerValue) < 0)
6161
{
62-
validationContext.AddError(new ParseError($"The value for '{valueSymbol.Name}' is below the lower bound of {LowerBound}"));
62+
validationContext.AddError(new CliDiagnostic(new("", "", $"The value for '{valueSymbol.Name}' is below the lower bound of {LowerBound}", severity: CliDiagnosticSeverity.Error, null), [], cliSymbolResult: valueResult));
6363
}
6464

6565

6666
if (UpperBound is not null
6767
&& validationContext.TryGetTypedValue(UpperBound, out var upperValue)
6868
&& comparableValue.CompareTo(upperValue) > 0)
6969
{
70-
validationContext.AddError(new ParseError($"The value for '{valueSymbol.Name}' is above the upper bound of {UpperBound}"));
70+
validationContext.AddError(new CliDiagnostic(new("", "", $"The value for '{valueSymbol.Name}' is above the upper bound of {UpperBound}", severity: CliDiagnosticSeverity.Error, null), [], cliSymbolResult: valueResult));
7171
}
7272
}
7373

src/System.CommandLine/ParseResult.cs

+2-6
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33

44
using System.Collections.Generic;
55
using System.CommandLine.Parsing;
6-
using System.Linq;
7-
using System.Threading.Tasks;
8-
using System.Threading;
96

107
namespace System.CommandLine
118
{
@@ -39,7 +36,7 @@ internal ParseResult(
3936
*/
4037
// TODO: unmatched tokens
4138
// List<CliToken>? unmatchedTokens,
42-
List<ParseError>? errors,
39+
List<CliDiagnostic>? errors,
4340
// TODO: commandLineText should be string array
4441
string? commandLineText = null //,
4542
// TODO: invocation
@@ -82,12 +79,11 @@ internal ParseResult(
8279
// TODO: unmatched tokens
8380
// _unmatchedTokens = unmatchedTokens is null ? Array.Empty<CliToken>() : unmatchedTokens;
8481

85-
Errors = errors is not null ? errors : Array.Empty<ParseError>();
82+
Errors = errors is not null ? errors : Array.Empty<CliDiagnostic>();
8683
}
8784

8885
public CliSymbol? GetSymbolByName(string name, bool valuesOnly = false)
8986
{
90-
9187
symbolLookupByName ??= new SymbolLookupByName(this);
9288
return symbolLookupByName.TryGetSymbol(name, out var symbol, valuesOnly: valuesOnly)
9389
? symbol

src/System.CommandLine/Parsing/CliArgumentResultInternal.cs

+27-23
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,9 @@ public void OnlyTake(int numberOfTokens)
138138
public override string ToString() => $"{nameof(CliArgumentResultInternal)} {Argument.Name}: {string.Join(" ", Tokens.Select(t => $"<{t.Value}>"))}";
139139

140140
/// <inheritdoc/>
141-
internal override void AddError(string errorMessage)
141+
internal override void AddError(string errorMessage, CliValueResult valueResult)
142142
{
143-
SymbolResultTree.AddError(new CliDiagnostic(new("", "", errorMessage, CliDiagnosticSeverity.Warning, null), [], symbolResult: AppliesToPublicSymbolResult));
143+
SymbolResultTree.AddError(new CliDiagnostic(new("", "", errorMessage, CliDiagnosticSeverity.Warning, null), [], cliSymbolResult: valueResult));
144144
_conversionResult = ArgumentConversionResult.Failure(this, errorMessage, ArgumentConversionResultType.Failed);
145145
}
146146

@@ -150,33 +150,37 @@ private ArgumentConversionResult ValidateAndConvert(bool useValidators)
150150
{
151151
return ReportErrorIfNeeded(arityFailure);
152152
}
153-
// TODO: validators
154-
/*
155-
// There is nothing that stops user-defined Validator from calling ArgumentResult.GetValueOrDefault.
156-
// In such cases, we can't call the validators again, as it would create infinite recursion.
157-
// GetArgumentConversionResult => ValidateAndConvert => Validator
158-
// => GetValueOrDefault => ValidateAndConvert (again)
159-
if (useValidators && Argument.HasValidators)
160-
{
161-
for (var i = 0; i < Argument.Validators.Count; i++)
162-
{
163-
Argument.Validators[i](this);
164-
}
165-
166-
// validator provided by the user might report an error, which sets _conversionResult
167-
if (_conversionResult is not null)
168-
{
169-
return _conversionResult;
170-
}
171-
}
172-
*/
153+
// TODO: validators
154+
/*
155+
// There is nothing that stops user-defined Validator from calling ArgumentResult.GetValueOrDefault.
156+
// In such cases, we can't call the validators again, as it would create infinite recursion.
157+
// GetArgumentConversionResult => ValidateAndConvert => Validator
158+
// => GetValueOrDefault => ValidateAndConvert (again)
159+
if (useValidators && Argument.HasValidators)
160+
{
161+
for (var i = 0; i < Argument.Validators.Count; i++)
162+
{
163+
Argument.Validators[i](this);
164+
}
165+
166+
// validator provided by the user might report an error, which sets _conversionResult
167+
if (_conversionResult is not null)
168+
{
169+
return _conversionResult;
170+
}
171+
}
172+
*/
173+
174+
// TODO: defaults
175+
/*
173176
if (Parent!.UseDefaultValueFor(this))
174177
{
175178
var defaultValue = Argument.GetDefaultValue(this);
176179
177180
// default value factory provided by the user might report an error, which sets _conversionResult
178181
return _conversionResult ?? ArgumentConversionResult.Success(this, defaultValue);
179182
}
183+
*/
180184

181185
if (Argument.ConvertArguments is null)
182186
{
@@ -218,7 +222,7 @@ ArgumentConversionResult ReportErrorIfNeeded(ArgumentConversionResult result)
218222
{
219223
if (result.Result >= ArgumentConversionResultType.Failed)
220224
{
221-
SymbolResultTree.AddError(new CliDiagnostic(new("ArgumentConversionResultTypeFailed", "Type Conversion Failed", result.ErrorMessage!, CliDiagnosticSeverity.Warning, null), [], symbolResult: AppliesToPublicSymbolResult));
225+
SymbolResultTree.AddError(new CliDiagnostic(new("ArgumentConversionResultTypeFailed", "Type Conversion Failed", result.ErrorMessage!, CliDiagnosticSeverity.Warning, null), [], cliSymbolResult: ValueResult));
222226
}
223227

224228
return result;

src/System.CommandLine/Parsing/CliCommandResultInternal.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ internal void Validate(bool completeValidation)
8484
if (Command.HasSubcommands)
8585
{
8686
SymbolResultTree.InsertFirstError(
87-
new CliDiagnostic(new("validateSubCommandError", "Validation Error", LocalizationResources.RequiredCommandWasNotProvided(), CliDiagnosticSeverity.Warning, null), [], symbolResult: this));
87+
new CliDiagnostic(new("validateSubCommandError", "Validation Error", LocalizationResources.RequiredCommandWasNotProvided(), CliDiagnosticSeverity.Warning, null), [], valueResult: ));
8888
}
8989
9090
// TODO: validators
@@ -171,10 +171,10 @@ private void ValidateOptions(bool completeValidation)
171171
{
172172
int errorsBefore = SymbolResultTree.ErrorCount;
173173
174-
for (var j = 0; j < optionResult.Option.Validators.Count; j++)
175-
{
176-
optionResult.Option.Validators[j](optionResult);
177-
}
174+
for (var j = 0; j < optionResult.Option.Validators.Count; j++)
175+
{
176+
optionResult.Option.Validators[j](optionResult);
177+
}
178178
179179
if (errorsBefore != SymbolResultTree.ErrorCount)
180180
{

0 commit comments

Comments
 (0)