0
# Rendering System
1
2
The Rendering System provides extensible infrastructure for formatting PMD analysis reports in various output formats. It includes a base renderer interface, built-in format implementations, and customizable properties for different output requirements.
3
4
## Capabilities
5
6
### Renderer Interface
7
8
Core interface for formatting PMD reports with support for multiple output formats and configurable properties.
9
10
```java { .api }
11
/**
12
* Interface for rendering PMD reports in various formats.
13
* Extends PropertySource to support configurable rendering options.
14
*/
15
public interface Renderer extends PropertySource {
16
17
/**
18
* Get renderer name/identifier
19
* @return Unique name for the renderer
20
*/
21
String getName();
22
23
/**
24
* Set renderer name
25
* @param name Unique identifier for renderer
26
*/
27
void setName(String name);
28
29
/**
30
* Get renderer description
31
* @return Human-readable description of renderer purpose
32
*/
33
String getDescription();
34
35
/**
36
* Set renderer description
37
* @param description Description of renderer functionality
38
*/
39
void setDescription(String description);
40
41
/**
42
* Get default file extension for output
43
* @return File extension without dot (e.g., "xml", "html")
44
*/
45
String defaultFileExtension();
46
47
/**
48
* Check if suppressed violations are shown
49
* @return true if renderer includes suppressed violations
50
*/
51
boolean isShowSuppressedViolations();
52
53
/**
54
* Set whether to show suppressed violations
55
* @param show true to include suppressed violations in output
56
*/
57
void setShowSuppressedViolations(boolean show);
58
59
/**
60
* Set output writer for rendering
61
* @param writer Writer for formatted output
62
*/
63
void setWriter(Writer writer);
64
65
/**
66
* Set report file path (alternative to setWriter)
67
* @param reportFile Path to output file
68
*/
69
void setReportFile(String reportFile);
70
71
/**
72
* Create analysis listener for receiving events
73
* @return GlobalAnalysisListener that forwards to this renderer
74
*/
75
GlobalAnalysisListener newListener();
76
77
/**
78
* Start rendering process (write headers, opening tags, etc.)
79
*/
80
void start();
81
82
/**
83
* End rendering process (write footers, closing tags, etc.)
84
*/
85
void end();
86
87
/**
88
* Flush any buffered output
89
*/
90
void flush();
91
}
92
```
93
94
**Usage Examples:**
95
96
```java
97
import net.sourceforge.pmd.renderers.*;
98
import net.sourceforge.pmd.*;
99
import java.io.*;
100
101
// Basic renderer usage
102
public class RendererExample {
103
104
public void useXMLRenderer() throws IOException {
105
// Create XML renderer
106
XMLRenderer xmlRenderer = new XMLRenderer();
107
xmlRenderer.setName("xml-report");
108
xmlRenderer.setDescription("XML format report");
109
110
// Configure output
111
FileWriter writer = new FileWriter("pmd-report.xml");
112
xmlRenderer.setWriter(writer);
113
xmlRenderer.setShowSuppressedViolations(true);
114
115
// Use with PMD analysis
116
PMDConfiguration config = new PMDConfiguration();
117
config.addInputPath(Paths.get("src/main/java"));
118
config.addRuleSet("rulesets/java/quickstart.xml");
119
120
try (PmdAnalysis analysis = PmdAnalysis.create(config)) {
121
analysis.addRenderer(xmlRenderer);
122
analysis.files().addDirectory(Paths.get("src/main/java"));
123
124
RuleSetLoader loader = analysis.newRuleSetLoader();
125
analysis.addRuleSet(loader.loadFromResource("rulesets/java/quickstart.xml"));
126
127
// Execute analysis - results go to XML renderer
128
analysis.performAnalysis();
129
} finally {
130
writer.close();
131
}
132
}
133
134
public void useMultipleRenderers() throws IOException {
135
PMDConfiguration config = new PMDConfiguration();
136
config.addInputPath(Paths.get("src"));
137
138
try (PmdAnalysis analysis = PmdAnalysis.create(config)) {
139
// Add multiple renderers for different formats
140
141
// XML renderer
142
XMLRenderer xmlRenderer = new XMLRenderer();
143
xmlRenderer.setWriter(new FileWriter("report.xml"));
144
analysis.addRenderer(xmlRenderer);
145
146
// HTML renderer
147
HTMLRenderer htmlRenderer = new HTMLRenderer();
148
htmlRenderer.setWriter(new FileWriter("report.html"));
149
analysis.addRenderer(htmlRenderer);
150
151
// Text renderer for console output
152
TextRenderer textRenderer = new TextRenderer();
153
textRenderer.setWriter(new OutputStreamWriter(System.out));
154
analysis.addRenderer(textRenderer);
155
156
// JSON renderer
157
JsonRenderer jsonRenderer = new JsonRenderer();
158
jsonRenderer.setWriter(new FileWriter("report.json"));
159
analysis.addRenderer(jsonRenderer);
160
161
// Configure analysis and run
162
analysis.files().addDirectory(Paths.get("src"));
163
RuleSetLoader loader = analysis.newRuleSetLoader();
164
analysis.addRuleSet(loader.loadFromResource("rulesets/java/quickstart.xml"));
165
166
analysis.performAnalysis();
167
}
168
}
169
170
public void configureRendererProperties() {
171
// Configure HTML renderer with custom properties
172
HTMLRenderer htmlRenderer = new HTMLRenderer();
173
174
// Set renderer properties (if supported)
175
Properties props = new Properties();
176
props.setProperty("linkPrefix", "https://github.com/myorg/myrepo/blob/main/");
177
props.setProperty("linePrefix", "#L");
178
props.setProperty("title", "PMD Analysis Report");
179
180
// Apply properties to renderer (method depends on specific renderer)
181
htmlRenderer.getPropertyDescriptors().forEach(desc -> {
182
String value = props.getProperty(desc.name());
183
if (value != null && desc.type() == String.class) {
184
@SuppressWarnings("unchecked")
185
PropertyDescriptor<String> stringDesc = (PropertyDescriptor<String>) desc;
186
htmlRenderer.setProperty(stringDesc, value);
187
}
188
});
189
190
System.out.printf("Configured %s with %d properties%n",
191
htmlRenderer.getName(),
192
htmlRenderer.getPropertyDescriptors().size());
193
}
194
}
195
```
196
197
### Built-in Renderers
198
199
PMD provides numerous built-in renderers for different output formats and integration scenarios.
200
201
```java { .api }
202
/**
203
* Built-in renderer implementations for various output formats
204
*/
205
206
/**
207
* XML renderer for structured XML output
208
*/
209
class XMLRenderer implements Renderer {
210
XMLRenderer();
211
XMLRenderer(String name);
212
}
213
214
/**
215
* HTML renderer with styling and hyperlinks
216
*/
217
class HTMLRenderer implements Renderer {
218
HTMLRenderer();
219
HTMLRenderer(String name);
220
}
221
222
/**
223
* Simple text renderer for plain text output
224
*/
225
class TextRenderer implements Renderer {
226
TextRenderer();
227
TextRenderer(String name);
228
}
229
230
/**
231
* Colored text renderer with ANSI color codes
232
*/
233
class TextColorRenderer implements Renderer {
234
TextColorRenderer();
235
TextColorRenderer(Properties colorSettings);
236
}
237
238
/**
239
* CSV renderer for comma-separated values
240
*/
241
class CSVRenderer implements Renderer {
242
CSVRenderer();
243
}
244
245
/**
246
* JSON renderer for structured JSON output
247
*/
248
class JsonRenderer implements Renderer {
249
JsonRenderer();
250
}
251
252
/**
253
* SARIF renderer for Static Analysis Results Interchange Format
254
*/
255
class SarifRenderer implements Renderer {
256
SarifRenderer();
257
}
258
259
/**
260
* GNU Emacs integration renderer
261
*/
262
class EmacsRenderer implements Renderer {
263
EmacsRenderer();
264
}
265
266
/**
267
* IntelliJ IDEA integration renderer
268
*/
269
class IDEAJRenderer implements Renderer {
270
IDEAJRenderer();
271
}
272
273
/**
274
* Empty renderer that produces no output (silent mode)
275
*/
276
class EmptyRenderer implements Renderer {
277
EmptyRenderer();
278
}
279
280
/**
281
* Code Climate renderer for CI/CD integration
282
*/
283
class CodeClimateRenderer implements Renderer {
284
CodeClimateRenderer();
285
}
286
```
287
288
**Usage Examples:**
289
290
```java
291
import net.sourceforge.pmd.renderers.*;
292
import java.io.*;
293
import java.util.Properties;
294
295
// Using different built-in renderers
296
public class BuiltInRenderersExample {
297
298
public void demonstrateTextRenderers() throws IOException {
299
PMDConfiguration config = new PMDConfiguration();
300
301
try (PmdAnalysis analysis = PmdAnalysis.create(config)) {
302
// Simple text renderer
303
TextRenderer textRenderer = new TextRenderer();
304
textRenderer.setWriter(new FileWriter("report.txt"));
305
analysis.addRenderer(textRenderer);
306
307
// Colored text renderer for console
308
Properties colorProps = new Properties();
309
colorProps.setProperty("color.high", "red");
310
colorProps.setProperty("color.medium", "yellow");
311
colorProps.setProperty("color.low", "blue");
312
313
TextColorRenderer colorRenderer = new TextColorRenderer(colorProps);
314
colorRenderer.setWriter(new OutputStreamWriter(System.out));
315
analysis.addRenderer(colorRenderer);
316
317
// Configure and run analysis...
318
setupAndRunAnalysis(analysis);
319
}
320
}
321
322
public void demonstrateStructuredRenderers() throws IOException {
323
PMDConfiguration config = new PMDConfiguration();
324
325
try (PmdAnalysis analysis = PmdAnalysis.create(config)) {
326
// XML renderer
327
XMLRenderer xmlRenderer = new XMLRenderer("detailed-xml");
328
xmlRenderer.setWriter(new FileWriter("detailed-report.xml"));
329
xmlRenderer.setShowSuppressedViolations(true);
330
analysis.addRenderer(xmlRenderer);
331
332
// JSON renderer
333
JsonRenderer jsonRenderer = new JsonRenderer();
334
jsonRenderer.setWriter(new FileWriter("report.json"));
335
analysis.addRenderer(jsonRenderer);
336
337
// SARIF renderer for security tools
338
SarifRenderer sarifRenderer = new SarifRenderer();
339
sarifRenderer.setWriter(new FileWriter("report.sarif"));
340
analysis.addRenderer(sarifRenderer);
341
342
// CSV renderer for spreadsheet analysis
343
CSVRenderer csvRenderer = new CSVRenderer();
344
csvRenderer.setWriter(new FileWriter("report.csv"));
345
analysis.addRenderer(csvRenderer);
346
347
setupAndRunAnalysis(analysis);
348
}
349
}
350
351
public void demonstrateIDERenderers() throws IOException {
352
PMDConfiguration config = new PMDConfiguration();
353
354
try (PmdAnalysis analysis = PmdAnalysis.create(config)) {
355
// Emacs integration
356
EmacsRenderer emacsRenderer = new EmacsRenderer();
357
emacsRenderer.setWriter(new FileWriter("emacs-report.txt"));
358
analysis.addRenderer(emacsRenderer);
359
360
// IntelliJ IDEA integration
361
IDEAJRenderer ideaRenderer = new IDEAJRenderer();
362
ideaRenderer.setWriter(new FileWriter("idea-report.txt"));
363
analysis.addRenderer(ideaRenderer);
364
365
setupAndRunAnalysis(analysis);
366
}
367
}
368
369
public void demonstrateSpecialRenderers() throws IOException {
370
PMDConfiguration config = new PMDConfiguration();
371
372
try (PmdAnalysis analysis = PmdAnalysis.create(config)) {
373
// Empty renderer for silent mode (no output)
374
EmptyRenderer silentRenderer = new EmptyRenderer();
375
analysis.addRenderer(silentRenderer);
376
377
// Code Climate renderer for CI/CD
378
CodeClimateRenderer ccRenderer = new CodeClimateRenderer();
379
ccRenderer.setWriter(new FileWriter("codeclimate.json"));
380
analysis.addRenderer(ccRenderer);
381
382
setupAndRunAnalysis(analysis);
383
}
384
}
385
386
private void setupAndRunAnalysis(PmdAnalysis analysis) throws IOException {
387
analysis.files().addDirectory(Paths.get("src/main/java"));
388
389
RuleSetLoader loader = analysis.newRuleSetLoader();
390
analysis.addRuleSet(loader.loadFromResource("rulesets/java/quickstart.xml"));
391
392
analysis.performAnalysis();
393
}
394
}
395
```
396
397
### Custom Renderer Implementation
398
399
Framework for implementing custom renderers with specific formatting requirements.
400
401
```java { .api }
402
/**
403
* Abstract base class for implementing custom renderers.
404
* Provides common functionality and lifecycle management.
405
*/
406
abstract class AbstractRenderer implements Renderer {
407
408
/**
409
* Constructor with renderer name
410
* @param name Unique name for the renderer
411
*/
412
protected AbstractRenderer(String name);
413
414
/**
415
* Constructor with name and description
416
* @param name Unique name for the renderer
417
* @param description Human-readable description
418
*/
419
protected AbstractRenderer(String name, String description);
420
421
/**
422
* Get output writer
423
* @return Writer for formatted output
424
*/
425
protected Writer getWriter();
426
427
/**
428
* Write string to output
429
* @param str String to write
430
*/
431
protected void write(String str) throws IOException;
432
433
/**
434
* Write formatted string to output
435
* @param format Format string
436
* @param args Format arguments
437
*/
438
protected void writef(String format, Object... args) throws IOException;
439
440
/**
441
* Write line to output
442
* @param line Line to write (newline added automatically)
443
*/
444
protected void writeln(String line) throws IOException;
445
446
/**
447
* Render single rule violation (template method)
448
* @param violation RuleViolation to render
449
*/
450
protected abstract void renderViolation(RuleViolation violation) throws IOException;
451
452
/**
453
* Render processing error (template method)
454
* @param error ProcessingError to render
455
*/
456
protected void renderError(Report.ProcessingError error) throws IOException;
457
458
/**
459
* Render configuration error (template method)
460
* @param error ConfigurationError to render
461
*/
462
protected void renderConfigError(Report.ConfigurationError error) throws IOException;
463
}
464
```
465
466
**Usage Examples:**
467
468
```java
469
import net.sourceforge.pmd.renderers.AbstractRenderer;
470
import net.sourceforge.pmd.reporting.*;
471
import java.io.IOException;
472
473
// Custom renderer implementation
474
public class CustomJSONRenderer extends AbstractRenderer {
475
476
private boolean firstViolation = true;
477
private int violationCount = 0;
478
479
public CustomJSONRenderer() {
480
super("custom-json", "Custom JSON renderer with extra metadata");
481
}
482
483
@Override
484
public String defaultFileExtension() {
485
return "json";
486
}
487
488
@Override
489
public void start() throws IOException {
490
writeln("{");
491
writeln(" \"tool\": \"PMD\",");
492
writef(" \"version\": \"%s\",%n", PMDVersion.VERSION);
493
writef(" \"timestamp\": \"%s\",%n", new Date());
494
writeln(" \"violations\": [");
495
firstViolation = true;
496
violationCount = 0;
497
}
498
499
@Override
500
protected void renderViolation(RuleViolation violation) throws IOException {
501
if (!firstViolation) {
502
writeln(",");
503
}
504
firstViolation = false;
505
violationCount++;
506
507
writeln(" {");
508
writef(" \"file\": \"%s\",%n", escapeJson(violation.getFilename()));
509
writef(" \"line\": %d,%n", violation.getBeginLine());
510
writef(" \"column\": %d,%n", violation.getBeginColumn());
511
writef(" \"endLine\": %d,%n", violation.getEndLine());
512
writef(" \"endColumn\": %d,%n", violation.getEndColumn());
513
writef(" \"rule\": \"%s\",%n", escapeJson(violation.getRule().getName()));
514
writef(" \"priority\": \"%s\",%n", violation.getRule().getPriority().getName());
515
writef(" \"message\": \"%s\",%n", escapeJson(violation.getDescription()));
516
517
// Add extra metadata
518
if (!violation.getPackageName().isEmpty()) {
519
writef(" \"package\": \"%s\",%n", escapeJson(violation.getPackageName()));
520
}
521
if (!violation.getClassName().isEmpty()) {
522
writef(" \"class\": \"%s\",%n", escapeJson(violation.getClassName()));
523
}
524
if (!violation.getMethodName().isEmpty()) {
525
writef(" \"method\": \"%s\",%n", escapeJson(violation.getMethodName()));
526
}
527
528
writef(" \"suppressed\": %b%n", violation.isSuppressed());
529
write(" }");
530
}
531
532
@Override
533
protected void renderError(Report.ProcessingError error) throws IOException {
534
// Add errors to separate section if needed
535
writef(" // Processing error in %s: %s%n",
536
error.getFile(), error.getMessage());
537
}
538
539
@Override
540
public void end() throws IOException {
541
writeln();
542
writeln(" ],");
543
writef(" \"summary\": {%n");
544
writef(" \"violationCount\": %d%n", violationCount);
545
writeln(" }");
546
writeln("}");
547
flush();
548
}
549
550
private String escapeJson(String str) {
551
if (str == null) return "null";
552
return str.replace("\\", "\\\\")
553
.replace("\"", "\\\"")
554
.replace("\n", "\\n")
555
.replace("\r", "\\r")
556
.replace("\t", "\\t");
557
}
558
}
559
560
// Custom renderer with properties
561
public class CustomHTMLRenderer extends AbstractRenderer {
562
563
private static final PropertyDescriptor<String> TITLE_PROPERTY =
564
PropertyFactory.stringProperty("title")
565
.desc("HTML report title")
566
.defaultValue("PMD Analysis Report")
567
.build();
568
569
private static final PropertyDescriptor<String> CSS_URL_PROPERTY =
570
PropertyFactory.stringProperty("cssUrl")
571
.desc("URL to external CSS file")
572
.defaultValue("")
573
.build();
574
575
public CustomHTMLRenderer() {
576
super("custom-html", "Custom HTML renderer with styling options");
577
definePropertyDescriptor(TITLE_PROPERTY);
578
definePropertyDescriptor(CSS_URL_PROPERTY);
579
}
580
581
@Override
582
public String defaultFileExtension() {
583
return "html";
584
}
585
586
@Override
587
public void start() throws IOException {
588
String title = getProperty(TITLE_PROPERTY);
589
String cssUrl = getProperty(CSS_URL_PROPERTY);
590
591
writeln("<!DOCTYPE html>");
592
writeln("<html>");
593
writeln("<head>");
594
writef(" <title>%s</title>%n", escapeHtml(title));
595
writeln(" <meta charset=\"UTF-8\">");
596
597
if (!cssUrl.isEmpty()) {
598
writef(" <link rel=\"stylesheet\" href=\"%s\">%n", escapeHtml(cssUrl));
599
} else {
600
writeDefaultCSS();
601
}
602
603
writeln("</head>");
604
writeln("<body>");
605
writef(" <h1>%s</h1>%n", escapeHtml(title));
606
writeln(" <table class=\"violations\">");
607
writeln(" <thead>");
608
writeln(" <tr>");
609
writeln(" <th>File</th>");
610
writeln(" <th>Line</th>");
611
writeln(" <th>Rule</th>");
612
writeln(" <th>Priority</th>");
613
writeln(" <th>Message</th>");
614
writeln(" </tr>");
615
writeln(" </thead>");
616
writeln(" <tbody>");
617
}
618
619
@Override
620
protected void renderViolation(RuleViolation violation) throws IOException {
621
writeln(" <tr class=\"violation\">");
622
writef(" <td>%s</td>%n", escapeHtml(violation.getFilename()));
623
writef(" <td>%d</td>%n", violation.getBeginLine());
624
writef(" <td>%s</td>%n", escapeHtml(violation.getRule().getName()));
625
writef(" <td class=\"priority-%s\">%s</td>%n",
626
violation.getRule().getPriority().name().toLowerCase(),
627
violation.getRule().getPriority().getName());
628
writef(" <td>%s</td>%n", escapeHtml(violation.getDescription()));
629
writeln(" </tr>");
630
}
631
632
@Override
633
public void end() throws IOException {
634
writeln(" </tbody>");
635
writeln(" </table>");
636
writeln("</body>");
637
writeln("</html>");
638
flush();
639
}
640
641
private void writeDefaultCSS() throws IOException {
642
writeln(" <style>");
643
writeln(" body { font-family: Arial, sans-serif; margin: 20px; }");
644
writeln(" table { border-collapse: collapse; width: 100%; }");
645
writeln(" th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }");
646
writeln(" th { background-color: #f2f2f2; }");
647
writeln(" .priority-high { color: #d32f2f; font-weight: bold; }");
648
writeln(" .priority-medium { color: #f57c00; }");
649
writeln(" .priority-low { color: #388e3c; }");
650
writeln(" </style>");
651
}
652
653
private String escapeHtml(String str) {
654
if (str == null) return "";
655
return str.replace("&", "&")
656
.replace("<", "<")
657
.replace(">", ">")
658
.replace("\"", """)
659
.replace("'", "'");
660
}
661
}
662
663
// Using custom renderers
664
public class CustomRendererUsage {
665
666
public void useCustomRenderers() throws IOException {
667
PMDConfiguration config = new PMDConfiguration();
668
669
try (PmdAnalysis analysis = PmdAnalysis.create(config)) {
670
// Use custom JSON renderer
671
CustomJSONRenderer jsonRenderer = new CustomJSONRenderer();
672
jsonRenderer.setWriter(new FileWriter("custom-report.json"));
673
analysis.addRenderer(jsonRenderer);
674
675
// Use custom HTML renderer with properties
676
CustomHTMLRenderer htmlRenderer = new CustomHTMLRenderer();
677
htmlRenderer.setProperty(htmlRenderer.TITLE_PROPERTY, "My Project Analysis");
678
htmlRenderer.setProperty(htmlRenderer.CSS_URL_PROPERTY, "styles/pmd-report.css");
679
htmlRenderer.setWriter(new FileWriter("custom-report.html"));
680
analysis.addRenderer(htmlRenderer);
681
682
// Configure analysis and run
683
analysis.files().addDirectory(Paths.get("src"));
684
RuleSetLoader loader = analysis.newRuleSetLoader();
685
analysis.addRuleSet(loader.loadFromResource("rulesets/java/quickstart.xml"));
686
687
analysis.performAnalysis();
688
}
689
}
690
}
691
```
692
693
## Types
694
695
```java { .api }
696
/**
697
* Factory for creating built-in renderers by name
698
*/
699
final class RendererFactory {
700
701
/**
702
* Create renderer by name
703
* @param name Renderer name (xml, html, text, json, etc.)
704
* @param properties Optional properties for configuration
705
* @return Renderer instance
706
*/
707
static Renderer createRenderer(String name, Properties properties);
708
709
/**
710
* Get all available renderer names
711
* @return Set of supported renderer names
712
*/
713
static Set<String> getAvailableRenderers();
714
715
/**
716
* Check if renderer name is supported
717
* @param name Renderer name to check
718
* @return true if renderer is available
719
*/
720
static boolean isRendererAvailable(String name);
721
}
722
723
/**
724
* Configuration for file name rendering in reports
725
*/
726
interface ConfigurableFileNameRenderer {
727
728
/**
729
* Get display name for file
730
* @param fileId File identifier
731
* @return Formatted display name
732
*/
733
String getDisplayName(FileId fileId);
734
735
/**
736
* Set root paths for relativizing file names
737
* @param roots List of root paths for making relative paths
738
*/
739
void setRelativizeRoots(List<Path> roots);
740
741
/**
742
* Add root path for relativizing
743
* @param root Root path to add
744
*/
745
void addRelativizeRoot(Path root);
746
}
747
748
/**
749
* Renderer properties for customization
750
*/
751
interface RendererProperties {
752
753
/**
754
* Set string property
755
* @param name Property name
756
* @param value Property value
757
*/
758
void setProperty(String name, String value);
759
760
/**
761
* Get string property with default
762
* @param name Property name
763
* @param defaultValue Default if not set
764
* @return Property value or default
765
*/
766
String getProperty(String name, String defaultValue);
767
768
/**
769
* Set boolean property
770
* @param name Property name
771
* @param value Property value
772
*/
773
void setBooleanProperty(String name, boolean value);
774
775
/**
776
* Get boolean property with default
777
* @param name Property name
778
* @param defaultValue Default if not set
779
* @return Property value or default
780
*/
781
boolean getBooleanProperty(String name, boolean defaultValue);
782
}
783
```
784
785
Now I'll complete the todo list:
786
787
<function_calls>
788
<invoke name="TodoWrite">
789
<parameter name="todos">[{"content": "Create tile.json manifest for PMD Core Knowledge Tile", "status": "completed", "activeForm": "Creating tile.json manifest"}, {"content": "Create entry-point documentation at docs/index.md with overview and capabilities", "status": "completed", "activeForm": "Creating entry-point documentation"}, {"content": "Create Core PMD Analysis sub-doc for PmdAnalysis and PMDConfiguration", "status": "completed", "activeForm": "Creating Core PMD Analysis sub-doc"}, {"content": "Create Rule System sub-doc for Rule, RuleSet, RulePriority APIs", "status": "completed", "activeForm": "Creating Rule System sub-doc"}, {"content": "Create Language Framework sub-doc for Language, LanguageRegistry APIs", "status": "completed", "activeForm": "Creating Language Framework sub-doc"}, {"content": "Create AST Processing sub-doc for Node and AST navigation APIs", "status": "completed", "activeForm": "Creating AST Processing sub-doc"}, {"content": "Create Reporting System sub-doc for Report, RuleViolation, listeners", "status": "completed", "activeForm": "Creating Reporting System sub-doc"}, {"content": "Create Properties System sub-doc for PropertySource, PropertyDescriptor APIs", "status": "completed", "activeForm": "Creating Properties System sub-doc"}, {"content": "Create Copy-Paste Detection sub-doc for CPD functionality", "status": "completed", "activeForm": "Creating Copy-Paste Detection sub-doc"}, {"content": "Create Utilities and Support Classes sub-doc for utility APIs", "status": "completed", "activeForm": "Creating Utilities sub-doc"}]