1 module cogito.arguments;
2 
3 import argparse;
4 import std.algorithm;
5 import std.conv;
6 import std.format;
7 import std.range;
8 import std.traits;
9 
10 // Help message.
11 private enum string returnCodes = q"HELP
12   Return codes:
13     0  Success
14     1  Command line arguments are invalid
15     2  Some source files contain errors
16     3  Function threshold violation
17     4  Aggregate threshold violation
18     5  Module threshold violation
19 HELP";
20 
21 /**
22  * Possible output formats.
23  */
24 enum OutputFormat
25 {
26     silent,
27     flat,
28     verbose,
29     debug_,
30 }
31 
32 private enum string allowedOutputFormat(OutputFormat Member) =
33     Member.to!string.strip('_');
34 private enum string[] allowedOutputFormats = [
35     staticMap!(allowedOutputFormat, EnumMembers!OutputFormat)
36 ];
37 
38 private OutputFormat parseOutputFormat(string input)
39 {
40     switch (input)
41     {
42         case "debug":
43             return OutputFormat.debug_;
44         case "silent":
45             return OutputFormat.silent;
46         case "flat":
47             return OutputFormat.flat;
48         case "verbose":
49             return OutputFormat.verbose;
50         default:
51             enum string validValues = allowedOutputFormats.join(',');
52             enum string errorFormat =
53                 "Invalid value '%s' for argument '--format'.\nValid argument values are: %s";
54             throw new Exception(format!errorFormat(input, validValues));
55     }
56 }
57 
58 /**
59  * Arguments supported by the CLI.
60  */
61 @(Command("cogito").Epilog(returnCodes))
62 struct Arguments
63 {
64     /// Input files.
65     @(PositionalArgument(0).Description("Source files").Required())
66     string[] files = [];
67 
68     /// Module threshold.
69     @(NamedArgument(["module-threshold"])
70             .Optional()
71             .Description("Fail if the source score exceeds this threshold")
72             .Placeholder("NUMBER"))
73     uint moduleThreshold = 0;
74 
75     /// Function threshold.
76     @(NamedArgument(["threshold"])
77             .Optional()
78             .Description("Fail if a function score exceeds this threshold")
79             .Placeholder("NUMBER"))
80     uint threshold = 0;
81 
82     /// Aggregate threshold.
83     @(NamedArgument(["aggregate-threshold"])
84             .Optional()
85             .Description("Fail if an aggregate exceeds this threshold")
86             .Placeholder("NUMBER"))
87     uint aggregateThreshold = 0;
88 
89     /// Output format.
90     @(NamedArgument
91             .AllowedValues!allowedOutputFormats
92             .PreValidation!((string x) => true)
93             .Parse!parseOutputFormat
94             .Validation!((OutputFormat x) => true)
95     )
96     OutputFormat format = OutputFormat.flat;
97 }