-
Notifications
You must be signed in to change notification settings - Fork 481
/
Copy pathSpecification.cs
154 lines (131 loc) · 4.58 KB
/
Specification.cs
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
// Copyright 2005-2015 Giacomo Stelluti Scala & Contributors. All rights reserved. See License.md in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using CommandLine.Infrastructure;
using CSharpx;
namespace CommandLine.Core
{
enum SpecificationType
{
Option,
Value
}
enum TargetType
{
Switch,
Scalar,
Sequence
}
abstract class Specification
{
private readonly SpecificationType tag;
private readonly bool required;
private readonly bool hidden;
private readonly Maybe<int> min;
private readonly Maybe<int> max;
private readonly Maybe<object> defaultValue;
private readonly string helpText;
private readonly string metaValue;
private readonly IEnumerable<string> enumValues;
/// This information is denormalized to decouple Specification from PropertyInfo.
private readonly Type conversionType;
private readonly TargetType targetType;
protected Specification(SpecificationType tag, bool required, Maybe<int> min, Maybe<int> max,
Maybe<object> defaultValue, string helpText, string metaValue, IEnumerable<string> enumValues,
Type conversionType, TargetType targetType, bool hidden = false)
{
this.tag = tag;
this.required = required;
this.min = min;
this.max = max;
this.defaultValue = defaultValue;
this.conversionType = conversionType;
this.targetType = targetType;
this.helpText = helpText;
this.metaValue = metaValue;
this.enumValues = enumValues;
this.hidden = hidden;
}
public SpecificationType Tag
{
get { return tag; }
}
public bool Required
{
get { return required; }
}
public Maybe<int> Min
{
get { return min; }
}
public Maybe<int> Max
{
get { return max; }
}
public Maybe<object> DefaultValue
{
get { return defaultValue; }
}
public string HelpText
{
get { return helpText; }
}
public string MetaValue
{
get { return metaValue; }
}
public IEnumerable<string> EnumValues
{
get { return enumValues; }
}
public Type ConversionType
{
get { return conversionType; }
}
public TargetType TargetType
{
get { return targetType; }
}
public bool Hidden
{
get { return hidden; }
}
public static Specification FromProperty(PropertyInfo property)
{
var attrs = property.GetCustomAttributes(true);
#if NET7_0_OR_GREATER
var isRequired = attrs.OfType<RequiredMemberAttribute>().Any();
#else
var isRequired = false;
#endif
var oa = attrs.OfType<OptionAttribute>();
if (oa.Count() == 1)
{
var optionAttribute = oa.Single();
optionAttribute.Required |= isRequired;
var spec = OptionSpecification.FromAttribute(optionAttribute, property.PropertyType,
ReflectionHelper.GetNamesOfEnum(property.PropertyType));
if (spec.ShortName.Length == 0 && spec.LongName.Length == 0)
{
return spec.WithLongName(property.Name.ToLowerInvariant());
}
return spec;
}
var va = attrs.OfType<ValueAttribute>();
if (va.Count() == 1)
{
var valueAttribute = va.Single();
valueAttribute.Required |= isRequired;
return ValueSpecification.FromAttribute(valueAttribute, property.PropertyType,
property.PropertyType.GetTypeInfo().IsEnum
? Enum.GetNames(property.PropertyType)
: Enumerable.Empty<string>());
}
throw new InvalidOperationException();
}
}
}