1 module served.linters.dub;
2 
3 import core.thread;
4 
5 import painlessjson;
6 
7 import served.extension;
8 import served.linters.diagnosticmanager;
9 import served.types;
10 
11 import std.algorithm;
12 import std.array;
13 import std.file;
14 import std.json;
15 import std.path;
16 import std.process;
17 import std.stdio;
18 import std.string;
19 
20 import workspaced.api;
21 import workspaced.coms;
22 
23 import workspaced.com.dub : ErrorType;
24 
25 enum DiagnosticSlot = 1;
26 
27 enum DubDiagnosticSource = "DUB";
28 
29 string fixPath(string workspaceRoot, string path, string[] stringImportPaths)
30 {
31 	auto mixinIndex = path.indexOf("-mixin-");
32 	if (mixinIndex != -1)
33 		path = path[0 .. mixinIndex];
34 	auto absPath = isAbsolute(path) ? path : buildNormalizedPath(workspaceRoot, path);
35 	if (path.endsWith(".d"))
36 		path = absPath;
37 	else if (!isAbsolute(path))
38 	{
39 		bool found;
40 		foreach (imp; stringImportPaths)
41 		{
42 			if (!isAbsolute(imp))
43 				imp = buildNormalizedPath(workspaceRoot, imp);
44 			auto modPath = buildNormalizedPath(imp, path);
45 			if (exists(modPath))
46 			{
47 				path = modPath;
48 				found = true;
49 				break;
50 			}
51 		}
52 		if (!found)
53 			path = absPath;
54 	}
55 	else
56 		path = absPath;
57 	return path;
58 }
59 
60 DiagnosticSeverity mapDubLintType(ErrorType type)
61 {
62 	final switch (type)
63 	{
64 	case ErrorType.Deprecation:
65 		return DiagnosticSeverity.information;
66 	case ErrorType.Warning:
67 		return DiagnosticSeverity.warning;
68 	case ErrorType.Error:
69 		return DiagnosticSeverity.error;
70 	}
71 }
72 
73 void lint(Document document)
74 {
75 	auto workspaceRoot = workspaceRootFor(document.uri);
76 
77 	stderr.writeln("Running dub build");
78 	auto imports = backend.get!DubComponent(workspaceRoot).stringImports;
79 	auto issues = backend.get!DubComponent(workspaceRoot).build.getYield;
80 	PublishDiagnosticsParams[] result;
81 	foreach (issue; issues)
82 	{
83 		auto uri = uriFromFile(fixPath(workspaceRoot, issue.file, imports));
84 		Diagnostic error;
85 		error.range = TextRange(Position(issue.line - 1, issue.column - 1));
86 		error.severity = mapDubLintType(issue.type);
87 		error.source = DubDiagnosticSource;
88 		error.message = issue.text;
89 		bool found;
90 		foreach (ref elem; result)
91 			if (elem.uri == uri)
92 			{
93 				found = true;
94 				elem.diagnostics ~= error;
95 			}
96 		if (!found)
97 			result ~= PublishDiagnosticsParams(uri, [error]);
98 	}
99 
100 	diagnostics[DiagnosticSlot] = result;
101 	updateDiagnostics(document.uri);
102 }