Skip to content

Commit bd98d30

Browse files
Cleanup, notes, and a small fix
1 parent 7aff35a commit bd98d30

File tree

7 files changed

+74
-8
lines changed

7 files changed

+74
-8
lines changed

OpenQuestions.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Open questions
2+
3+
Please also include TODO in appropriate locations. This is intended as a wrap up.
4+
5+
Also, include whether the question is to add or remove something, and add date/initials
6+
7+
## NotNulWhen on TryGetValue in ValueSource and ValueProvider
8+
9+
Things to consider:
10+
11+
* Within System.CommandLine all TryGetValue should probably be the same
12+
* TryGetValue on dictionary can return null
13+
* For nullable values, the actual value can be null
14+
* For nullable or non-nullable ref types, the default for the type is null
15+
* Allowing null out values keeps a single meaning to "not found" and allows "found but null". Conflating these blocks expressing which happened
16+
17+
The recovery is the same as with Dictionary.TryGetValue. The first line of the block that handles the return Boolean is a guard.
18+
19+
## The extensibility story for ValueSource
20+
21+
The proposal and current code seal our value sources and expect people to make additional ones based on ValueSource. The classes are public and sealed, the constructors are internal.
22+
23+
Reasons to reconsider: Aggregate value source has a logical precedence or an as entered one. If someone adds a new value source, it is always last in the logic precedence.There are likely to be other similar cases.
24+
25+
Possible resolution: Have this be case by case and allow aggregate values to be unsealed and have a mechanism for overriding. Providing a non-inheritance based solution could make this look like a normal operation when it is a rare one.
26+
27+
## Contexts [RESOLVED]
28+
29+
We had two different philosophies at different spots in subsystems. "Give folks everything they might need" and "Give folks only what we know they need".
30+
31+
The first probably means we pass around `PipelineResult`. The second means that each purpose needs a special context. Sharing contexts is likely to mean that something will be added to one context that is unneeded by the other. Known expected contexts are:
32+
33+
- `AnnotationProviderContext`
34+
- `ValueSourceContext`
35+
- `ValidationContext` (includes ability to report diagnostics)
36+
- `CompletionContext`
37+
- `HelpContext`
38+
39+
## Which contexts should allow diagnostic reporting?
40+
41+
## Should we have both Validators and IValidator on Conditions? [RESOLVED]
42+
43+
We started with `Validators` and then added the IValidator interface to allow conditions to do validation because they have the strong type. Checking for this first also avoids a dictionary lookup.
44+
45+
Our default validations will be on the Condition for the shortcut. Users can offer alternatives by creaing custom validators. The dictionary for custom validators will be lazy, and lookups will be pay for play when the user has custom validators. (This is not yet implemented.)
46+
47+
When present, custom validators have precedence. There is no cost when they are not present.
48+
49+
## Should conditions be public
50+
51+
Since there are factory methods and validators could still access them, current behavior could be supported with internal conditions.
52+
53+
However, the point of conditions is that they are a statement about the symbol and not an implementation. They are known to be used by completions and completions are expected to be extended. Thus, to get the values held in the condition (such as environment variable name) need to be available outside the external scope.
54+
55+
Suggestion: Use internal constructors and leave conditions public
56+

System.CommandLine.sln

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
1616
Directory.Packages.props = Directory.Packages.props
1717
global.json = global.json
1818
LICENSE.md = LICENSE.md
19+
OpenQuestions.md = OpenQuestions.md
1920
README.md = README.md
2021
restore.cmd = restore.cmd
2122
restore.sh = restore.sh

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ internal class VersionWithInitializeAndTeardown : VersionSubsystem
4343
internal bool ExecutionWasRun;
4444
internal bool TeardownWasRun;
4545

46-
protected override void Initialize(InitializationContext context)
46+
protected internal override void Initialize(InitializationContext context)
4747
{
4848
base.Initialize(context);
4949
// marker hack needed because ConsoleHack not available in initialization
@@ -56,7 +56,7 @@ public override void Execute(PipelineResult pipelineResult)
5656
base.Execute(pipelineResult);
5757
}
5858

59-
protected override void TearDown(PipelineResult pipelineResult)
59+
protected internal override void TearDown(PipelineResult pipelineResult)
6060
{
6161
TeardownWasRun = true;
6262
base.TearDown(pipelineResult);

src/System.CommandLine.Subsystems/System.CommandLine.Subsystems.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,18 @@
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
77
<RootNamespace>System.CommandLine</RootNamespace>
8+
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
89
</PropertyGroup>
910

1011
<ItemGroup>
1112
<ProjectReference Include="..\System.CommandLine\System.CommandLine.csproj" />
1213
</ItemGroup>
1314

15+
<ItemGroup>
16+
<!-- This was added to allow testing of ValueSource -->
17+
<InternalsVisibleTo Include="System.CommandLine.Subsystems.Tests" />
18+
</ItemGroup>
19+
1420
<ItemGroup>
1521
<Compile Include="..\Common\Compat\**\*.cs" Link="Compat\%(RecursiveDir)%(Filename).%(Extension)" />
1622
</ItemGroup>

src/System.CommandLine.Subsystems/ValueSources/RelativeToEnvironmentVariableValueSource.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ internal RelativeToEnvironmentVariableValueSource(
3030
/// <summary>
3131
/// The description of this value, used to clarify the intent of the values that appear in error messages.
3232
/// </summary>
33-
public override string? Description { get; }
33+
public override string? Description { get; }
3434

3535
public override bool TryGetTypedValue(PipelineResult pipelineResult, out T? value)
3636
{

src/System.CommandLine.Subsystems/ValueSources/ValueSource.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ internal ValueSource()
2222

2323
// TODO: Should we use ToString() here?
2424
public abstract string? Description { get; }
25+
2526
public static ValueSource<T> Create<T>(T value, string? description = null)
2627
=> new SimpleValueSource<T>(value, description);
2728

@@ -47,7 +48,7 @@ public static ValueSource<T> CreateFromEnvironmentVariable<T>(string environment
4748
=> new RelativeToEnvironmentVariableValueSource<T>(environmentVariableName, calculation, description);
4849
}
4950

50-
// TODO: Determine philosophy for custom value sources and whether tehy can buld on existing sources.
51+
// TODO: Determine philosophy for custom value sources and whether they can build on existing sources.
5152
public abstract class ValueSource<T> : ValueSource
5253
{
5354
/// <summary>
@@ -56,12 +57,13 @@ public abstract class ValueSource<T> : ValueSource
5657
/// <param name="pipelineResult">The current pipeline result.</param>
5758
/// <param name="value">An out parameter which contains the converted value, with the calculation applied, if it is found.</param>
5859
/// <returns>True if a value was found, otherwise false.</returns>
59-
public abstract bool TryGetTypedValue(PipelineResult pipelineResult,
60-
[NotNullWhen(true)] out T? value);
60+
// TODO: Determine whether this and `TryGetValue` should have NotNullWhen(true) attribute. Discussion in <reporoot>/OpenQuestions.md
61+
public abstract bool TryGetTypedValue(PipelineResult pipelineResult,
62+
out T? value);
6163

6264
/// <inheritdoc/>
63-
public override bool TryGetValue(PipelineResult pipelineResult,
64-
[NotNullWhen(true)] out object? value)
65+
public override bool TryGetValue(PipelineResult pipelineResult,
66+
out object? value)
6567
{
6668

6769
if (TryGetTypedValue(pipelineResult, out T? newValue))

src/System.CommandLine/System.CommandLine.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
</ItemGroup>
7070

7171
<ItemGroup>
72+
<!-- This was added to allow tests of tokenization -->
7273
<InternalsVisibleTo Include="System.CommandLine.Tests" />
7374
</ItemGroup>
7475

0 commit comments

Comments
 (0)