-
Notifications
You must be signed in to change notification settings - Fork 481
/
Copy pathSpecificationPropertyRules.cs
216 lines (200 loc) · 9.63 KB
/
SpecificationPropertyRules.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
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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
// Copyright 2005-2015 Giacomo Stelluti Scala & Contributors. All rights reserved. See License.md in the project root for license information.
using CSharpx;
using System;
using System.Collections.Generic;
using System.Linq;
namespace CommandLine.Core
{
static class SpecificationPropertyRules
{
public static IEnumerable<Func<IEnumerable<SpecificationProperty>, IEnumerable<Error>>>
Lookup(
IEnumerable<Token> tokens)
{
return new List<Func<IEnumerable<SpecificationProperty>, IEnumerable<Error>>>
{
EnforceMutuallyExclusiveSet(),
EnforceGroup(),
EnforceMutuallyExclusiveSetAndGroupAreNotUsedTogether(),
EnforceRequired(),
EnforceRange(),
EnforceSingle(tokens)
};
}
private static Func<IEnumerable<SpecificationProperty>, IEnumerable<Error>> EnforceMutuallyExclusiveSetAndGroupAreNotUsedTogether()
{
return specProps =>
{
var options =
from sp in specProps
where sp.Specification.IsOption()
let o = (OptionSpecification)sp.Specification
where o.SetName.Length > 0
where o.Group.Length > 0
select o;
if (options.Any())
{
return from o in options
select new GroupOptionAmbiguityError(new NameInfo(o.ShortName, o.LongName));
}
return Enumerable.Empty<Error>();
};
}
private static Func<IEnumerable<SpecificationProperty>, IEnumerable<Error>> EnforceGroup()
{
return specProps =>
{
var optionsValues =
from sp in specProps
where sp.Specification.IsOption()
let o = (OptionSpecification)sp.Specification
where o.Group.Length > 0
select new
{
Option = o,
Value = sp.Value,
DefaultValue = sp.Specification.DefaultValue
};
var groups = from o in optionsValues
group o by o.Option.Group into g
select g;
var errorGroups = groups.Where(gr => gr.All(g => g.Value.IsNothing() && g.DefaultValue.IsNothing()));
if (errorGroups.Any())
{
return errorGroups.Select(gr => new MissingGroupOptionError(gr.Key, gr.Select(g => new NameInfo(g.Option.ShortName, g.Option.LongName))));
}
return Enumerable.Empty<Error>();
};
}
private static Func<IEnumerable<SpecificationProperty>, IEnumerable<Error>> EnforceMutuallyExclusiveSet()
{
return specProps =>
{
var options =
from sp in specProps
where sp.Specification.IsOption()
where sp.Value.IsJust()
let o = (OptionSpecification)sp.Specification
where o.SetName.Length > 0
select o;
var groups = from o in options
group o by o.SetName into g
select g;
if (groups.Count() > 1)
{
return
from o in options
select new MutuallyExclusiveSetError(o.FromOptionSpecification(), o.SetName);
}
return Enumerable.Empty<Error>();
};
}
private static Func<IEnumerable<SpecificationProperty>, IEnumerable<Error>> EnforceRequired()
{
return specProps =>
{
var requiredWithValue = from sp in specProps
where sp.Specification.IsOption()
where sp.Specification.Required
where sp.Value.IsJust()
let o = (OptionSpecification)sp.Specification
where o.SetName.Length > 0
select sp.Specification;
var setWithRequiredValue = (
from s in requiredWithValue
let o = (OptionSpecification)s
where o.SetName.Length > 0
select o.SetName)
.Distinct();
var requiredWithoutValue = from sp in specProps
where sp.Specification.IsOption()
where sp.Specification.Required
where sp.Value.IsNothing()
let o = (OptionSpecification)sp.Specification
where o.SetName.Length > 0
where o.Group.Length == 0
where setWithRequiredValue.ContainsIfNotEmpty(o.SetName)
select sp.Specification;
var missing =
requiredWithoutValue
.Except(requiredWithValue)
.Concat(
from sp in specProps
where sp.Specification.IsOption()
where sp.Specification.Required
where sp.Value.IsNothing()
let o = (OptionSpecification)sp.Specification
where o.SetName.Length == 0
where o.Group.Length == 0
select sp.Specification)
.Concat(
from sp in specProps
where sp.Specification.IsValue()
where sp.Specification.Required
where sp.Value.IsNothing()
select sp.Specification);
return
from sp in missing
select new MissingRequiredOptionError(sp.FromSpecification());
};
}
private static Func<IEnumerable<SpecificationProperty>, IEnumerable<Error>> EnforceRange()
{
return specProps =>
{
var options = specProps
.Where(sp => sp.Specification.TargetType == TargetType.Sequence)
.Where(sp => sp.Value.IsJust())
.Where(sp =>
(sp.Specification.Min.IsJust() && ((Array)sp.Value.FromJustOrFail()).Length < sp.Specification.Min.FromJustOrFail())
|| (sp.Specification.Max.IsJust() && ((Array)sp.Value.FromJustOrFail()).Length > sp.Specification.Max.FromJustOrFail())
);
if (options.Any())
{
return
from s in options
select new SequenceOutOfRangeError(s.Specification.FromSpecification());
}
return Enumerable.Empty<Error>();
};
}
private static Func<IEnumerable<SpecificationProperty>, IEnumerable<Error>> EnforceSingle(IEnumerable<Token> tokens)
{
return specProps =>
{
var specs = from sp in specProps
where sp.Specification.IsOption()
where sp.Value.IsJust()
select (OptionSpecification)sp.Specification;
var shortOptions = from t in tokens
where t.IsName()
join o in specs on t.Text equals o.ShortName into to
from o in to.DefaultIfEmpty()
where o != null
select new { o.ShortName, o.LongName };
var longOptions = from t in tokens
where t.IsName()
join o in specs on t.Text equals o.LongName into to
from o in to.DefaultIfEmpty()
where o != null
select new { o.ShortName, o.LongName };
var groups = from x in shortOptions.Concat(longOptions)
group x by x into g
let count = g.Count()
select new { Value = g.Key, Count = count };
var errors = from y in groups
where y.Count > 1
select new RepeatedOptionError(new NameInfo(y.Value.ShortName, y.Value.LongName));
return errors;
};
}
private static bool ContainsIfNotEmpty<T>(this IEnumerable<T> sequence, T value)
{
if (sequence.Any())
{
return sequence.Contains(value);
}
return true;
}
}
}