1 module cogito;
2 
3 import dmd.frontend;
4 import dmd.astcodegen;
5 import dmd.errors;
6 import dmd.globals;
7 
8 public import cogito.list;
9 public import cogito.meter;
10 public import cogito.visitor;
11 
12 import std.algorithm;
13 import std.range;
14 
15 private Result runOnFile(string file)
16 {
17     initialize();
18     LocalHandler localHandler;
19     diagnosticHandler = &localHandler.handler;
20 
21     scope (exit)
22     {
23         diagnosticHandler = null;
24         deinitialize();
25     }
26     auto tree = parseModule!AST(file);
27 
28     if (tree.diagnostics.hasErrors())
29     {
30         return typeof(return)(localHandler.errors);
31     }
32     auto visitor = new CognitiveVisitor(file);
33 
34     tree.module_.accept(visitor);
35 
36     return typeof(return)(visitor.source);
37 }
38 
39 /**
40  * Map a filename to an array of files.
41  *
42  * Params:
43  *     filename = file or directory name.
44  *
45  * Returns: Array of filenames.
46  *   If the filename points to a folder all d-files are returned,
47  *   If the filename points to a file an array with only that file is returned.
48  */
49 string[] toFiles(string filename)
50 {
51     import std.file : isFile, isDir, dirEntries, SpanMode;
52     if (filename.isFile)
53     {
54         return [filename];
55     }
56     if (filename.isDir)
57     {
58         return filename
59             .dirEntries("*.d", SpanMode.breadth)
60             .filter!("a.isFile")
61             .map!("a.name")
62             .array;
63     }
64     import std.format : format;
65     throw new Exception(format!("%s is neither a file nor a directory")(filename));
66 }
67 
68 /**
69  * Measure the complexity in a list of modules.
70  *
71  * Params:
72  *     args = File paths.
73  *
74  * Returns: List of collected scores in each file.
75  */
76 auto runOnFiles(R)(R args)
77 if (isInputRange!R && is(ElementType!R == string))
78 {
79     return args
80         .map!toFiles
81         .joiner
82         .array
83         .sort
84         .map!runOnFile;
85 }
86 
87 /**
88  * Measure the complexity of the given code.
89  *
90  * Params:
91  *     code = Code as string.
92  *
93  * Returns: Collected score.
94  */
95 Result runOnCode(string code)
96 {
97     synchronized
98     {
99         initialize();
100         LocalHandler localHandler;
101         scope (exit)
102         {
103             diagnosticHandler = null;
104             deinitialize();
105         }
106         auto tree = parseModule!ASTCodegen("app.d", code);
107 
108         if (tree.diagnostics.hasErrors())
109         {
110             return typeof(return)(localHandler.errors);
111         }
112         auto visitor = new CognitiveVisitor();
113 
114         tree.module_.accept(visitor);
115 
116         return typeof(return)(visitor.source);
117     }
118 }