Open
Description
If I omit parameter value for one parameter name, next parametername is treated as value of the parameter.
Occurred at v2.9.1 from Nuget.
What I observed
Code:
using System;
using CommandLine;
class Options
{
[Option('a', "option1", Required = true)]
public string Option1 { get; set; }
[Option('b', "option2", Required = false)]
public int option2 { get; set; }
}
class Program
{
static int Main(string[] args)
{
return Parser.Default.ParseArguments<Options>(args)
.MapResult(
options => RunAndReturnExitCode(options),
_ => -1);
}
static int RunAndReturnExitCode(Options options)
{
Console.WriteLine($"option1={options.Option1}, option2={options.option2}");
return 0;
}
}
Command line,
$command --option1 --option2 5
gives the result output,
option1=option2, option2=0
But expected result is to report error with lacking of required "option1".
Suggested fix
In the method "CommandLine.Core.TokenPartitioner.PartitionTokensByType", scalarTokens.add(Scalar nem token) shall be occurred only when the following value is confirmed.
public static Tuple<IEnumerable<Token>, IEnumerable<Token>, IEnumerable<Token>, IEnumerable<Token>> PartitionTokensByType(
IEnumerable<Token> tokens,
Func<string, Maybe<TypeDescriptor>> typeLookup)
{
var switchTokens = new List<Token>();
var scalarTokens = new List<Token>();
var sequenceTokens = new List<Token>();
var nonOptionTokens = new List<Token>();
var sequences = new Dictionary<Token, IList<Token>>();
var count = new Dictionary<Token, int>();
var max = new Dictionary<Token, Maybe<int>>();
var state = SequenceState.TokenSearch;
var separatorSeen = false;
Token nameToken = null;
foreach (var token in tokens)
{
if (token.IsValueForced())
{
separatorSeen = false;
nonOptionTokens.Add(token);
}
else if (token.IsName())
{
separatorSeen = false;
if (typeLookup(token.Text).MatchJust(out var info))
{
switch (info.TargetType)
{
case TargetType.Switch:
nameToken = null;
switchTokens.Add(token);
state = SequenceState.TokenSearch;
break;
case TargetType.Scalar:
nameToken = token;
// scalarTokens.Add(nameToken); <- don't add here
state = SequenceState.ScalarTokenFound;
break;
case TargetType.Sequence:
nameToken = token;
if (! sequences.ContainsKey(nameToken))
{
sequences[nameToken] = new List<Token>();
count[nameToken] = 0;
max[nameToken] = info.MaxItems;
}
state = SequenceState.SequenceTokenFound;
break;
}
}
else
{
nameToken = null;
nonOptionTokens.Add(token);
state = SequenceState.TokenSearch;
}
}
else
{
switch (state)
{
case SequenceState.TokenSearch:
case SequenceState.ScalarTokenFound when nameToken == null:
case SequenceState.SequenceTokenFound when nameToken == null:
separatorSeen = false;
nameToken = null;
nonOptionTokens.Add(token);
state = SequenceState.TokenSearch;
break;
case SequenceState.ScalarTokenFound:
separatorSeen = false;
scalarTokens.Add(nameToken); // add here instead so that scalar name token is valid only when a value is given
nameToken = null;
scalarTokens.Add(token);
state = SequenceState.TokenSearch;
break;
......