1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package com.lexicalscope.jewel.cli.validation;
16
17 import static com.lexicalscope.fluent.FluentDollar.$;
18 import static com.lexicalscope.jewel.cli.specification.OptionSpecificationMatchers.mandatory;
19
20 import java.util.ArrayList;
21 import java.util.List;
22 import java.util.Map;
23
24 import com.lexicalscope.fluent.map.FluentMap;
25 import com.lexicalscope.jewel.cli.ValidationErrorBuilder;
26 import com.lexicalscope.jewel.cli.specification.OptionSpecification;
27 import com.lexicalscope.jewel.cli.specification.OptionsSpecification;
28 import com.lexicalscope.jewel.cli.specification.ParsedOptionSpecification;
29
30 class ArgumentValidatorImpl<O> implements ArgumentValidator
31 {
32 private final ValidationErrorBuilder validationErrorBuilder;
33
34 private final Map<RawOption, List<String>> rawArguments;
35 private final FluentMap<ParsedOptionSpecification, List<String>> arguments = $.<ParsedOptionSpecification, List<String>>map();
36 private final FluentMap<ParsedOptionSpecification, List<String>> mandatoryArguments = $(arguments).$retainKeys(mandatory());
37
38 private final List<String> validatedUnparsedArguments = new ArrayList<String>();
39
40 private final OptionsSpecification<O> specification;
41
42 public ArgumentValidatorImpl(
43 final OptionsSpecification<O> specification,
44 final ValidationErrorBuilder validationErrorBuilder)
45 {
46 this.specification = specification;
47 this.validationErrorBuilder = validationErrorBuilder;
48
49 rawArguments = new ValidationPipeline(specification, validationErrorBuilder).buildValidationPipeline(validatedUnparsedArguments).outputTo(arguments);
50 }
51
52 @Override public void processOption(final String optionName, final List<String> values) {
53 rawArguments.put(new RawOption(optionName), values);
54 }
55
56 @Override public void processLastOption(final String optionName, final List<String> values) {
57 rawArguments.put(new RawOption(optionName, true), values);
58 }
59
60 @Override public void processUnparsed(final List<String> values) {
61 validatedUnparsedArguments.addAll(values);
62 }
63
64 @Override public OptionCollection finishedProcessing() {
65 validateUnparsedOptions();
66 validationErrorBuilder.validate();
67
68 specification.
69 getMandatoryOptions().
70 _withoutKeys(mandatoryArguments).
71 _forEach(ParsedOptionSpecification.class).
72 reportMissingTo(validationErrorBuilder);
73
74 validationErrorBuilder.validate();
75
76 return new OptionCollectionImpl(specification, arguments, validatedUnparsedArguments);
77 }
78
79 private void validateUnparsedOptions()
80 {
81 if (specification.hasUnparsedSpecification())
82 {
83 final OptionSpecification unparsedSpecification = specification.getUnparsedSpecification();
84
85 if (unparsedSpecification.isOptional() && validatedUnparsedArguments.isEmpty())
86 {
87
88 }
89 else if (!unparsedSpecification.allowedThisManyValues(validatedUnparsedArguments.size()))
90 {
91 validationErrorBuilder.wrongNumberOfValues(unparsedSpecification, validatedUnparsedArguments);
92 }
93 }
94 else if (!validatedUnparsedArguments.isEmpty())
95 {
96 validationErrorBuilder.unexpectedTrailingValue(validatedUnparsedArguments);
97 }
98 }
99 }