1
+
/*
2
+
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3
+
*/
4
+
5
+
package net.sourceforge.pmd.docs;
6
+
7
+
import java.io.IOException;
8
+
import java.nio.charset.StandardCharsets;
9
+
import java.nio.file.FileVisitResult;
10
+
import java.nio.file.Files;
11
+
import java.nio.file.NoSuchFileException;
12
+
import java.nio.file.Path;
13
+
import java.nio.file.Paths;
14
+
import java.nio.file.SimpleFileVisitor;
15
+
import java.nio.file.attribute.BasicFileAttributes;
16
+
import java.util.ArrayList;
17
+
import java.util.HashMap;
18
+
import java.util.HashSet;
19
+
import java.util.List;
20
+
import java.util.Locale;
21
+
import java.util.Map;
22
+
import java.util.Set;
23
+
import java.util.logging.Level;
24
+
import java.util.logging.Logger;
25
+
import java.util.regex.Matcher;
26
+
import java.util.regex.Pattern;
27
+
28
+
public class RuleTagChecker {
29
+
private static final Logger LOG = Logger.getLogger(DeadLinksChecker.class.getName());
30
+
31
+
private static final Pattern RULE_TAG = Pattern.compile("\\{%\\s*rule\\s+\"(.*?)\"\\s*");
32
+
private static final Pattern RULE_REFERENCE = Pattern.compile("(\\w+)\\/(\\w+)\\/(\\w+)");
33
+
34
+
private final Path pagesDirectory;
35
+
private final List<String> issues = new ArrayList<>();
36
+
private final Map<Path, Set<String>> rulesCache = new HashMap<>();
37
+
38
+
public RuleTagChecker(Path rootDirectory) {
39
+
final Path pagesDirectory = rootDirectory.resolve("docs/pages");
40
+
41
+
if (!Files.isDirectory(pagesDirectory)) {
42
+
LOG.severe("can't check rule tags, didn't find \"docs/pages\" directory at: " + pagesDirectory);
43
+
System.exit(1);
44
+
}
45
+
46
+
this.pagesDirectory = pagesDirectory;
47
+
}
48
+
49
+
public List<String> check() throws IOException {
50
+
Files.walkFileTree(pagesDirectory, new SimpleFileVisitor<Path>() {
51
+
@Override
52
+
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
53
+
checkFile(file);
54
+
return super.visitFile(file, attrs);
55
+
}
56
+
});
57
+
return issues;
58
+
}
59
+
60
+
private void checkFile(Path file) throws IOException {
61
+
if (file == null || !file.getFileName().toString().toLowerCase(Locale.ROOT).endsWith(".md")) {
62
+
return;
63
+
}
64
+
65
+
LOG.finer("Checking " + file);
66
+
int lineNo = 0;
67
+
for (String line : Files.readAllLines(file, StandardCharsets.UTF_8)) {
68
+
lineNo++;
69
+
Matcher ruleTagMatcher = RULE_TAG.matcher(line);
70
+
while (ruleTagMatcher.find()) {
71
+
String ruleReference = ruleTagMatcher.group(1);
72
+
int pos = ruleTagMatcher.end();
73
+
if (line.charAt(pos) != '%' || line.charAt(pos + 1) != '}') {
74
+
addIssue(file, lineNo, "Rule tag for " + ruleReference + " is not closed properly");
75
+
} else if (!ruleReferenceTargetExists(ruleReference)) {
76
+
addIssue(file, lineNo, "Rule " + ruleReference + " is not found");
77
+
}
78
+
}
79
+
}
80
+
}
81
+
82
+
private boolean ruleReferenceTargetExists(String ruleReference) {
83
+
Matcher ruleRefMatcher = RULE_REFERENCE.matcher(ruleReference);
84
+
if (ruleRefMatcher.matches()) {
85
+
String language = ruleRefMatcher.group(1);
86
+
String category = ruleRefMatcher.group(2);
87
+
String rule = ruleRefMatcher.group(3);
88
+
89
+
Path ruleDocPage = pagesDirectory.resolve("pmd/rules/" + language + "/" + category.toLowerCase(Locale.ROOT) + ".md");
90
+
Set<String> rules = getRules(ruleDocPage);
91
+
return rules.contains(rule);
92
+
}
93
+
return false;
94
+
}
95
+
96
+
private Set<String> getRules(Path ruleDocPage) {
97
+
Set<String> result = rulesCache.get(ruleDocPage);
98
+
99
+
if (result == null) {
100
+
result = new HashSet<>();
101
+
try {
102
+
for (String line : Files.readAllLines(ruleDocPage, StandardCharsets.UTF_8)) {
103
+
if (line.startsWith("## ")) {
104
+
result.add(line.substring(3));
105
+
}
106
+
rulesCache.put(ruleDocPage, result);
107
+
}
108
+
} catch (NoSuchFileException e) {
109
+
LOG.warning("File " + ruleDocPage + " not found.");
110
+
} catch (IOException e) {
111
+
LOG.log(Level.SEVERE, "Unable to read rules from " + ruleDocPage, e);
112
+
}
113
+
}
114
+
115
+
return result;
116
+
}
117
+
118
+
private void addIssue(Path file, int lineNo, String message) {
119
+
issues.add(String.format("%s:%2d: %s", pagesDirectory.relativize(file).toString(), lineNo, message));
120
+
}
121
+
122
+
public static void main(String[] args) throws IOException {
123
+
if (args.length != 1) {
124
+
System.err.println("Wrong arguments!");
125
+
System.err.println();
126
+
System.err.println("java " + RuleTagChecker.class.getSimpleName() + " <project base directory>");
127
+
System.exit(1);
128
+
}
129
+
final Path rootDirectory = Paths.get(args[0]).resolve("..").toRealPath();
130
+
131
+
RuleTagChecker ruleTagChecker = new RuleTagChecker(rootDirectory);
132
+
List<String> issues = ruleTagChecker.check();
133
+
134
+
if (!issues.isEmpty()) {
135
+
issues.forEach(System.err::println);
136
+
throw new AssertionError("Wrong rule tags detected");
137
+
}
138
+
}
139
+
}
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4