Skip to content

Commit 05bd9eb

Browse files
WIP on CliError
Get rid of compile error and clean up some docs File scoped namespace Reverting whitespace changes Adding link Removing out-dated TODO Additional review feedback Adding additional reference link
1 parent d25d2da commit 05bd9eb

10 files changed

+198
-82
lines changed

Diff for: Directory.Packages.props

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
<Project>
2-
32
<PropertyGroup>
43
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
54
<CentralPackageTransitivePinningEnabled>false</CentralPackageTransitivePinningEnabled>
65
<!-- Using multiple feeds isn't supported by Maestro: https://github.com/dotnet/arcade/issues/14155. -->
76
<NoWarn>$(NoWarn);NU1507</NoWarn>
87
</PropertyGroup>
9-
108
<ItemGroup>
119
<!-- Roslyn dependencies -->
1210
<PackageVersion Include="Microsoft.CodeAnalysis" Version="4.0.1" />
@@ -24,14 +22,13 @@
2422
<PackageVersion Include="Microsoft.CSharp" Version="4.7.0" />
2523
<PackageVersion Include="Microsoft.DotNet.PlatformAbstractions" Version="3.1.6" />
2624
<PackageVersion Include="Newtonsoft.Json" Version="13.0.2" />
27-
<PackageVersion Include="System.Memory" Version="4.5.4" />
25+
<PackageVersion Include="System.Collections.Immutable" Version="8.0.0" />
26+
<PackageVersion Include="System.Memory" Version="4.5.5" />
2827
<PackageVersion Include="system.reactive.core" Version="5.0.0" />
2928
</ItemGroup>
30-
3129
<ItemGroup Condition="'$(DisableArcade)' == '1'">
3230
<!-- The xunit version should be kept in sync with the one that Arcade promotes -->
3331
<PackageVersion Include="xunit" Version="2.4.2" />
3432
<PackageVersion Include="xunit.runner.visualstudio" Version="2.4.3" />
3533
</ItemGroup>
36-
37-
</Project>
34+
</Project>

Diff for: src/System.CommandLine/ParseResult.cs

+2-2
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.Collections.Generic;
@@ -121,7 +121,7 @@ internal ParseResult(
121121
/// <summary>
122122
/// Gets the parse errors found while parsing command line input.
123123
/// </summary>
124-
public IReadOnlyList<ParseError> Errors { get; }
124+
public IReadOnlyList<CliDiagnostic> Errors { get; }
125125

126126
/*
127127
// TODO: don't expose tokens

Diff for: src/System.CommandLine/Parsing/CliArgumentResultInternal.cs

+2-6
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ public void OnlyTake(int numberOfTokens)
140140
/// <inheritdoc/>
141141
internal override void AddError(string errorMessage)
142142
{
143-
SymbolResultTree.AddError(new ParseError(errorMessage, AppliesToPublicSymbolResult));
143+
SymbolResultTree.AddError(new CliDiagnostic(new("", "", errorMessage, CliDiagnosticSeverity.Warning, null), [], symbolResult: AppliesToPublicSymbolResult));
144144
_conversionResult = ArgumentConversionResult.Failure(this, errorMessage, ArgumentConversionResultType.Failed);
145145
}
146146

@@ -170,17 +170,13 @@ private ArgumentConversionResult ValidateAndConvert(bool useValidators)
170170
}
171171
}
172172
*/
173-
174-
// TODO: defaults
175-
/*
176173
if (Parent!.UseDefaultValueFor(this))
177174
{
178175
var defaultValue = Argument.GetDefaultValue(this);
179176

180177
// default value factory provided by the user might report an error, which sets _conversionResult
181178
return _conversionResult ?? ArgumentConversionResult.Success(this, defaultValue);
182179
}
183-
*/
184180

185181
if (Argument.ConvertArguments is null)
186182
{
@@ -222,7 +218,7 @@ ArgumentConversionResult ReportErrorIfNeeded(ArgumentConversionResult result)
222218
{
223219
if (result.Result >= ArgumentConversionResultType.Failed)
224220
{
225-
SymbolResultTree.AddError(new ParseError(result.ErrorMessage!, AppliesToPublicSymbolResult));
221+
SymbolResultTree.AddError(new CliDiagnostic(new("ArgumentConversionResultTypeFailed", "Type Conversion Failed", result.ErrorMessage!, CliDiagnosticSeverity.Warning, null), [], symbolResult: AppliesToPublicSymbolResult));
226222
}
227223

228224
return result;

Diff for: src/System.CommandLine/Parsing/CliCommandResultInternal.cs

+2-2
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.Collections.Generic;
@@ -84,7 +84,7 @@ internal void Validate(bool completeValidation)
8484
if (Command.HasSubcommands)
8585
{
8686
SymbolResultTree.InsertFirstError(
87-
new ParseError(LocalizationResources.RequiredCommandWasNotProvided(), this));
87+
new CliDiagnostic(new("validateSubCommandError", "Validation Error", LocalizationResources.RequiredCommandWasNotProvided(), CliDiagnosticSeverity.Warning, null), [], symbolResult: this));
8888
}
8989
9090
// TODO: validators

Diff for: src/System.CommandLine/Parsing/CliDiagnostic.cs

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System.Collections.Immutable;
5+
6+
namespace System.CommandLine.Parsing;
7+
8+
/*
9+
* Pattern based on:
10+
* https://github.com/mhutch/MonoDevelop.MSBuildEditor/blob/main/MonoDevelop.MSBuild/Analysis/MSBuildDiagnostic.cs
11+
* https://github.com/mhutch/MonoDevelop.MSBuildEditor/blob/main/MonoDevelop.MSBuild/Analysis/MSBuildDiagnosticDescriptor.cs
12+
* https://github.com/dotnet/roslyn/blob/main/src/Compilers/Core/Portable/Diagnostic/DiagnosticDescriptor.cs
13+
* https://github.com/dotnet/roslyn/blob/main/src/Compilers/Core/Portable/Diagnostic/Diagnostic.cs
14+
*/
15+
internal static class ParseDiagnostics
16+
{
17+
public const string DirectiveIsNotDefinedId = "CMD0001";
18+
public static readonly CliDiagnosticDescriptor DirectiveIsNotDefined =
19+
new(
20+
DirectiveIsNotDefinedId,
21+
//TODO: use localized strings
22+
"Directive is not defined",
23+
"The directive '{0}' is not defined.",
24+
CliDiagnosticSeverity.Error,
25+
null);
26+
}
27+
28+
public sealed class CliDiagnosticDescriptor
29+
{
30+
public CliDiagnosticDescriptor(string id, string title, string messageFormat, CliDiagnosticSeverity severity, string? helpUri)
31+
{
32+
Id = id;
33+
Title = title;
34+
MessageFormat = messageFormat;
35+
Severity = severity;
36+
HelpUri = helpUri;
37+
}
38+
39+
public string Id { get; }
40+
public string Title { get; }
41+
public string MessageFormat { get; }
42+
public CliDiagnosticSeverity Severity { get; }
43+
public string? HelpUri { get; }
44+
}
45+
46+
public enum CliDiagnosticSeverity
47+
{
48+
Hidden = 0,
49+
Info,
50+
Warning,
51+
Error
52+
}
53+
54+
/// <summary>
55+
/// Describes an error that occurs while parsing command line input.
56+
/// </summary>
57+
public sealed class CliDiagnostic
58+
{
59+
// TODO: reevaluate whether we should be exposing a SymbolResult here
60+
// TODO: Rename to CliError
61+
62+
/// <summary>
63+
/// Initializes a new instance of the <see cref="CliDiagnostic"/> class.
64+
/// </summary>
65+
/// <param name="descriptor">Contains information about the error.</param>
66+
/// <param name="messageArgs">The arguments to be passed to the <see cref="CliDiagnosticDescriptor.MessageFormat"/> in the <paramref name="descriptor"/>.</param>
67+
/// <param name="properties">Properties to be associated with the diagnostic.</param>
68+
/// <param name="symbolResult">The symbol result detailing the symbol that failed to parse and the tokens involved.</param>
69+
/// <param name="location">The location of the error.</param>
70+
public CliDiagnostic(
71+
CliDiagnosticDescriptor descriptor,
72+
object?[]? messageArgs,
73+
ImmutableDictionary<string, object>? properties = null,
74+
SymbolResult? symbolResult = null,
75+
Location? location = null)
76+
{
77+
Descriptor = descriptor;
78+
MessageArgs = messageArgs;
79+
Properties = properties;
80+
SymbolResult = symbolResult;
81+
}
82+
83+
/// <summary>
84+
/// Gets a message to explain the error to a user.
85+
/// </summary>
86+
public string Message
87+
{
88+
get
89+
{
90+
if (MessageArgs is not null)
91+
{
92+
return string.Format(Descriptor.MessageFormat, MessageArgs);
93+
}
94+
return Descriptor.MessageFormat;
95+
}
96+
}
97+
98+
public ImmutableDictionary<string, object>? Properties { get; }
99+
100+
public CliDiagnosticDescriptor Descriptor { get; }
101+
102+
public object?[]? MessageArgs { get; }
103+
104+
/// <summary>
105+
/// Gets the symbol result detailing the symbol that failed to parse and the tokens involved.
106+
/// </summary>
107+
public SymbolResult? SymbolResult { get; }
108+
109+
/// <inheritdoc />
110+
public override string ToString() => Message;
111+
}

Diff for: src/System.CommandLine/Parsing/CliSymbolResultInternal.cs

+3-3
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.Collections.Generic;
@@ -24,7 +24,7 @@ private protected CliSymbolResultInternal(SymbolResultTree symbolResultTree, Cli
2424
/// <summary>
2525
/// The parse errors associated with this symbol result.
2626
/// </summary>
27-
public IEnumerable<ParseError> Errors
27+
public IEnumerable<CliDiagnostic> Errors
2828
{
2929
get
3030
{
@@ -64,7 +64,7 @@ public IEnumerable<ParseError> Errors
6464
/// Adds an error message for this symbol result to it's parse tree.
6565
/// </summary>
6666
/// <remarks>Setting an error will cause the parser to indicate an error for the user and prevent invocation of the command line.</remarks>
67-
internal virtual void AddError(string errorMessage) => SymbolResultTree.AddError(new ParseError(errorMessage, this));
67+
internal virtual void AddError(string errorMessage) => SymbolResultTree.AddError(new CliDiagnostic(new("", "", errorMessage, severity: CliDiagnosticSeverity.Error, null), [], symbolResult: this));
6868
/// <summary>
6969
/// Finds a result for the specific argument anywhere in the parse tree, including parent and child symbol results.
7070
/// </summary>

Diff for: src/System.CommandLine/Parsing/Location.cs

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public Location(string text, string source, int index, Location? outerLocation,
4949
public bool IsImplicit
5050
=> Source == Implicit;
5151

52+
/// <inheritdoc/>
5253
public override string ToString()
5354
=> $"{(OuterLocation is null ? "" : OuterLocation.ToString() + "; ")}{Text} from {Source}[{Index}, {Length}, {Offset}]";
5455

Diff for: src/System.CommandLine/Parsing/ParseError.cs

-54
This file was deleted.

0 commit comments

Comments
 (0)