PMD’s documentation usesJekyll withtheI’d rather be writing Jekyll Theme.
Here are some quick tips.
The pages are in general inGithub Flavored Markdown.
The documentation sources can be found in two places based on how they are generated:
All handwritten documentation is stored in the subfolders underdocs/pages
. The folder structure resembles the sidebar structure.Since all pages use a simplepermalink, in the rendered html pages, all pages are flattened in one directory.This makes it easy to view the documentation also offline.
The categories for a language%lang%
are located inpmd-%lang%/src/main/resources/category/%lang%
. So for Java the categoriescan be found underpmd-java/src/main/resources/category/java.The XML category files in this directory are transformed during build into markdown pagesdescribing the rules they contain. These pages are placed underdocs/
like the handwrittendocumentation, and are then rendered with Jekyll like the rest of them. The rule documentationgenerator is the separate submodulepmd-doc
.
Modifying the documentation of a rule should thus not be done on the markdown page,but directly on the XMLrule
tag corresponding to the rule, in the relevantcategory file.
The XML documentation of rules can contain GitHub flavoured markdown.Just wrap the markdown inside CDATA section in the xml. CDATA sections preserveall formatting inside the delimiters, and allow to write code samples without escaping special xml characters. For example:
<rule ...> <description> <![CDATA[ Full description, can contain markup And paragraphs ]]> </description> ...</rule>
We have some additional custom liquid tags that help in writing the documentation.
Here’s a short overview:
Liquid | Rendered as |
---|---|
{% rule "java/codestyle/LinguisticNaming" %} | LinguisticNaming |
{% jdoc core::lang.rule.Rule %} | Rule |
{% jdoc !q!core::lang.rule.Rule %} | net.sourceforge.pmd.lang.rule.Rule |
{% jdoc core::lang.rule.Rule#setName(java.lang.String) %} | setName |
{% jdoc !c!core::lang.rule.Rule#setName(java.lang.String) %} | Rule#setName |
{% jdoc !a!core::lang.rule.Rule#setName(java.lang.String) %} | setName(String) |
{% jdoc !ac!core::lang.rule.Rule#setName(java.lang.String) %} | Rule#setName(String) |
{% jdoc core::properties.PropertyDescriptor %} | PropertyDescriptor |
{% jdoc_nspace :jast java::lang.java.ast %}{% jdoc jast::ASTTypeDeclaration %} | ASTTypeDeclaration |
{% jdoc_nspace :jast java::lang.java.ast %}{% jdoc_package :jast %} | net.sourceforge.pmd.lang.java.ast |
{% jdoc_nspace :PrD core::properties.PropertyDescriptor %}{% jdoc !ac!:PrD#uiOrder() %} | PropertyDescriptor#uiOrder() |
{% jdoc_old core::Rule %} | Rule |
For the javadoc tags, the standard PMD maven modules are already defined as namespaces, e.g.core
,java
,apex
, ….
For the implementation of these tags, see the_plugins folder.
There are two ways, to execute jekyll:
Usingbundler. This will install all the needed ruby packages locally and execute jekyll:
# this is required only once, to download and install the dependenciesbundle install# this builds the documentation under _sitebundle exec jekyll build# this runs a local webserver as http://localhost:4005bundle exec jekyll serve
Usingdocker. This will create a local docker image, into which all needed rubypackages and jekyll is installed.
# this is required only once to create a local docker image named "pmd-doc"docker build --no-cache -t pmd-doc .# this builds the documentation under _sitedocker run --rm=true -v "$PWD:/src" pmd-doc build -H 0.0.0.0# this runs a local webserver as http://localhost:4005docker run --rm=true -v "$PWD:/src" -p 4005:4005 pmd-doc serve -H 0.0.0.0
The built site is stored locally in the (git ignored) directory_site
. You canpoint your browser to_site/index.html
to see the pmd documentation.
Alternatively, you can start the local webserver, that will serve the documentation.Just go to http://localhost:4005.If a page is modified, the documentation will automatically be rendered again andall you need to do, is refreshing the page in your browser.
See also the scriptpmd-jekyll.sh.It starts the jekyll server in the background and doesn’t block the current shell.
The sidebar is stored as a YAML document under_data/sidebars/pmd_sidebar.yml
.
Make sure to add an entry there, whenever you create a new page.
Each page in jekyll begins with a YAML section at the beginning. This sectionis separated by 3 dashes (---
). Example:
---title: Writing Documentationlast_updated: January 2025 (7.10.0)permalink: pmd_devdocs_writing_documentation.html---Some Text# Some header
There are a couple of possible fields. Most important and alwaysrequired aretitle andpermalink.
By default, a pagetoc (table of contents) is automatically generated.You can prevent this with “toc: false”.
You can addkeywords, that will be used for the on-site search: “keywords: documentation, jekyll, markdown”
It’s useful to maintain alast_update field. This will be added at the bottom of thepage.
Asummary can also be provided. It will be added in a box before the content.
For a more exhaustive list, seePages - Frontmatter.
SeeAlerts.
For example, a info-box can be created like this:
{% include note.html content="This is a note." %}
It renders as:
Note:This is a note.
Other available types are:
A callout is created like this:
{% include callout.html content="This is a callout of type default.<br/><br/>There are the following types available: danger, default, primary, success, info, and warning." type="default" %}
It renders as:
This is as easy as:
``` javapublic class Foo { public void bar() { System.out.println("x"); }}```
This looks as follows:
publicclassFoo{publicvoidbar(){System.out.println("x");}}
mvn verify -pl pmd-doc
. This only checks links within the site. HTTP links can be checkedby specifying-Dpmd.doc.checkExternalLinks=true
on the command line.