-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathNameConventionBinder.cs
More file actions
90 lines (74 loc) · 3.36 KB
/
NameConventionBinder.cs
File metadata and controls
90 lines (74 loc) · 3.36 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
using System.Collections.Generic;
using System.CommandLine.Invocation;
using System.Linq;
using System.Reflection;
using CaseExtensions;
namespace System.CommandLine.PropertyMapBinder.NameConventionBinder
{
public delegate bool NameConventionComparer(IReadOnlyCollection<string> cliAliases, string memberName);
public static class NameConventions {
public static NameConventionComparer PascalCaseComparer = (aliases, memberName) =>
{
return aliases.Any(a => a.ToPascalCase() == memberName);
};
public static NameConventionComparer CamelCaseComparer = (aliases, memberName) =>
{
return aliases.Any(a => a.ToCamelCase() == memberName);
};
public static NameConventionComparer SnakeCaseComparer = (aliases, memberName) =>
{
return aliases.Any(a => a.ToSnakeCase() == memberName);
};
}
public class NameConventionBinder<TInputModel> : IPropertyBinder<TInputModel>
{
private NameConventionComparer NullComparer = (aliases, memberName) => false;
NameConventionComparer _conventionComparer;
public NameConventionBinder(NameConventionComparer nameComparer)
{
_conventionComparer = nameComparer;
}
private object GetSymbolValue(InvocationContext context, Symbol symbol)
{
object value;
if(symbol is Argument arg) value = context.ParseResult.GetValueForArgument(arg);
else if(symbol is Option opt) value = context.ParseResult.GetValueForOption(opt);
else value = null;
return value;
}
private IReadOnlyCollection<string> GetSymbolAliases(Symbol symbol)
{
if (symbol is Argument arg) return new[] { arg.Name }.ToReadOnlyCollection();
else if (symbol is Option opt) return opt.Aliases.ToReadOnlyCollection();
else return new string[0].ToReadOnlyCollection();
}
public TInputModel Bind(TInputModel inputModel, InvocationContext context)
{
var currentCommand = context.ParseResult.CommandResult.Symbol;
var symbols = currentCommand.Children;
Type inputModelType = typeof(TInputModel);
var inputModelMembers = new List<MemberInfo>()
//TODO: probably want to limit to public if this goes beyond proof of concept
.Concat(inputModelType.GetProperties() ?? Enumerable.Empty<MemberInfo>())
.Concat(inputModelType.GetFields() ?? Enumerable.Empty<MemberInfo>());
foreach(Symbol symbol in symbols)
{
var symbolAliases = GetSymbolAliases(symbol);
MemberInfo matchedMember = inputModelMembers.FirstOrDefault(member => _conventionComparer(symbolAliases, member.Name));
if(matchedMember != null)
{
object parsedValue = GetSymbolValue(context, symbol);
if(parsedValue != null) ReflectionHelper.SetMemberValue(matchedMember, inputModel, parsedValue);
}
}
return inputModel;
}
}
public static class ReadOnlyExtensions
{
public static IReadOnlyCollection<T> ToReadOnlyCollection<T>(this IEnumerable<T> seq)
{
return new System.Collections.ObjectModel.ReadOnlyCollection<T>(seq.ToList());
}
}
}