forked from microsoft/mcp
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCommandResultExtensions.cs
More file actions
202 lines (172 loc) · 7.83 KB
/
CommandResultExtensions.cs
File metadata and controls
202 lines (172 loc) · 7.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System.CommandLine.Parsing;
namespace Microsoft.Mcp.Core.Extensions;
public static class CommandResultExtensions
{
public static bool HasOptionResult(this CommandResult commandResult, Option option)
=> HasOptionResult(commandResult, option.Name);
public static bool HasOptionResult<T>(this CommandResult commandResult, Option<T> option)
=> HasOptionResult(commandResult, option.Name);
/// <summary>
/// Checks if an option with the specified name or alias has a result in the command result.
/// </summary>
/// <param name="commandResult">The command result to check.</param>
/// <param name="optionName">The option name or any configured alias to check for.</param>
/// <returns>True if the option has a result, false otherwise.</returns>
public static bool HasOptionResult(this CommandResult commandResult, string optionName)
{
// Find the option by name in the command
var option = commandResult.Command.Options
.FirstOrDefault(o => o.Name == optionName || o.Aliases.Contains(optionName));
if (option is null)
return false;
var result = commandResult.GetResult(option);
if (result is null)
return false;
// Bool options (nullable or non-nullable) can work as switches or with explicit values
// Check if this is a bool option by looking at the value type
var isBoolOption = option.ValueType == typeof(bool) || option.ValueType == typeof(bool?);
if (isBoolOption)
{
// For bool options, consider present if:
// 1. Identifier was provided (switch usage: --verbose)
// 2. OR explicit value tokens exist (explicit usage: --verbose true)
return result.IdentifierTokenCount > 0;
}
// For other zero-arity options, identifier presence indicates explicit usage
var expectsValue = option.Arity.MaximumNumberOfValues > 0;
if (!expectsValue)
{
return result.IdentifierTokenCount > 0;
}
// For value-taking options, consider present only if there is at least one non-empty value token
var hasNonEmptyValue = result.Tokens is { Count: > 0 } && result.Tokens.Any(t => !string.IsNullOrWhiteSpace(t.Value));
return hasNonEmptyValue;
}
public static bool TryGetValue<T>(this CommandResult commandResult, Option<T> option, out T? value)
=> TryGetValue(commandResult, option.Name, out value);
public static bool TryGetValue<T>(this CommandResult commandResult, string optionName, out T? value)
{
// Find the option by name in the command
var option = FindOptionTByName<T>(commandResult, optionName);
if (option is null)
{
value = default;
return false;
}
// If the option has any result (explicit or implicit), attempt to read its value.
var result = commandResult.GetResult(option);
if (result is not null)
{
try
{
value = commandResult.GetValue(option);
return true;
}
catch
{
// Fall through to check default value below
}
}
// If no result (or GetValue failed), return the option's default when available.
if (option.HasDefaultValue)
{
var def = option.GetDefaultValue();
// Handle nullable types explicitly - null is a valid value for nullable types
if (def is null && typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>))
{
value = default; // This will be null for nullable types
return true;
}
if (def is T typed)
{
value = typed;
return true;
}
}
value = default;
return false;
}
public static T? GetValueOrDefault<T>(this CommandResult commandResult, Option<T> option)
{
ArgumentNullException.ThrowIfNull(commandResult);
ArgumentNullException.ThrowIfNull(option);
return GetValueOrDefault<T>(commandResult, option.Name);
}
public static T? GetValueOrDefault<T>(this CommandResult commandResult, string optionName)
{
// Find the option by name in the command
var option = FindOptionTByName<T>(commandResult, optionName);
if (option is null)
{
return default;
}
return GetValueOrDefaultImpl(commandResult, option);
}
private static T? GetValueOrDefaultImpl<T>(CommandResult commandResult, Option<T> option)
{
ArgumentNullException.ThrowIfNull(commandResult);
ArgumentNullException.ThrowIfNull(option);
// Find the OptionResult in the parse tree
var optionResult = commandResult.GetResult(option);
// If the option was not provided (null) OR it was implicitly assigned (no token supplied),
// check if there's a default value before returning null
if (optionResult is null || optionResult.Implicit)
{
// If the option has a default value, return it
if (option.HasDefaultValue)
{
var def = option.GetDefaultValue();
// Handle nullable types explicitly - null is a valid value for nullable types
if (def is null && typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>))
{
return default; // This will be null for nullable types
}
if (def is T typed)
{
return typed;
}
}
return default; // For value types, this is default(T?) => null; for refs => null
}
// At this point it was explicitly supplied by the user; get its value.
// Using the System.CommandLine API directly to avoid accidental recursion.
return optionResult.GetValueOrDefault<T>();
}
public static T? GetValueWithoutDefault<T>(this CommandResult commandResult, Option<T> option)
{
ArgumentNullException.ThrowIfNull(commandResult);
ArgumentNullException.ThrowIfNull(option);
return GetValueWithoutDefault<T>(commandResult, option.Name);
}
public static T? GetValueWithoutDefault<T>(this CommandResult commandResult, string optionName)
{
// Find the option by name in the command
var option = FindOptionTByName<T>(commandResult, optionName);
if (option is null)
{
return default;
}
return GetValueWithoutDefaultImpl(commandResult, option);
}
private static T? GetValueWithoutDefaultImpl<T>(CommandResult commandResult, Option<T> option)
{
ArgumentNullException.ThrowIfNull(commandResult);
ArgumentNullException.ThrowIfNull(option);
// Find the OptionResult in the parse tree
var optionResult = commandResult.GetResult(option);
// If the option was not provided (null) OR it was implicitly assigned (no token supplied),
// return without considering option default values
if (optionResult is null || optionResult.Implicit)
{
return default; // For value types, this is default(T?) => null; for refs => null
}
// At this point it was explicitly supplied by the user; get its value.
// Using the System.CommandLine API directly to avoid accidental recursion.
return optionResult.GetValueOrDefault<T>();
}
private static Option<T>? FindOptionTByName<T>(CommandResult commandResult, string optionName)
=> commandResult.Command.Options.OfType<Option<T>>()
.FirstOrDefault(o => o.Name == optionName || o.Aliases.Contains(optionName));
}