Writing custom linting rules

So you’ve decided to write a custom linting rule for whatever the reason is.

The bad news is that you won’t be able to embed it within the plugin and share it with the community as is, but the good news is that it requires less effort than writing a built-in one!

What you will learn by reading that page:

Getting started

A custom linting rule is basically a rule that is not integrated to the plugin itself, but is present in your classpath.

Before you start, you should at least read the following: Understanding how the parsing is done

So the first step to create such a rule would be to create a simple Maven project, and to include the following dependency to you pom.xml:

<dependency>
    <groupId>org.thewonderlemming.c4plantuml</groupId>
    <artifactId>c4plantuml-maven-plugin</artifactId>
    <version>1.0.0-RC1</version>
    <type>maven-plugin</type>
</dependency>
<dependency>
    <groupId>org.thewonderlemming.c4plantuml</groupId>
    <artifactId>c4plantuml-linter-lib</artifactId>
    <version>1.0.0-RC1</version>
</dependency>

You can also include the following if you intent to test your rule using the plugin testbed libraries:

<dependency>
    <groupId>org.thewonderlemming.c4plantuml</groupId>
    <artifactId>c4plantuml-linter-lib</artifactId>
    <version>1.0.0-RC1</version>        
    <scope>test</scope>
    <classifier>testbed</classifier>
</dependency>
<dependency>
    <groupId>org.thewonderlemming.c4plantuml</groupId>
    <artifactId>c4plantuml-testingutils-lib</artifactId>
    <version>1.0.0-RC1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.thewonderlemming.c4plantuml</groupId>
    <artifactId>c4plantuml-commons-lib</artifactId>
    <version>1.0.0-RC1</version>
    <scope>test</scope>
    <classifier>testbed</classifier>
</dependency>
<dependency>
    <groupId>org.thewonderlemming.c4plantuml</groupId>
    <artifactId>c4plantuml-grammars-lib</artifactId>
    <version>1.0.0-RC1</version>
    <scope>test</scope>
    <classifier>testbed</classifier>
</dependency>

Shared steps between custom and built-in rules

Let’s have a look at the following diagram from the Architecture page:

UML class diagram

You can see that the AbstractLintingRule from the linting library has a specialized version called AbstractCustomLintingRule, which your custom rule will need to extend: this is your first step.

You can then read the following built-in linting rule sections as they remain almost the same for custom rules - the main difference being that your rule won’t extend AbstractC4Rule:

Custom linting rules specific steps

By now, you should have a working linting rule class, that you want to use within the plugin: well, you’re almost done.

Extending the custom rule factory

You need to extend the AbstractCustomLintingRuleFactory class, in order to instruct the plugin about how to instantiate your rule, given a set of parameters (java.util.Properties).

That abstract class contains a single method, createCustomRule, which returns a Java java.util.Optional if the rule cannot be instantiated.

Adding your project JAR as a dependency to the plugin

Add the following to your C4 project pom.xmlfile, where propertyName1 would be the name of a required property to configure your custom rule:

<build>
    <plugins>
        <plugin>
            <groupId>org.thewonderlemming.c4plantuml</groupId>
            <artifactId>c4plantuml-maven-plugin</artifactId>
            <version>1.0.0-RC1</version>
            <executions>
                <execution>
                    <id>linting-c4-files</id>
                    <goals>
                        <goal>lint</goal>
                    </goals>
                    <configuration>
                        <!-- OPTIONAL: if your custom rule does not require any property, then leave this field empty -->
                        <customRules>
                            <property>
                                <name>propertyName1</name>
                                <value>propertyValue1</value>
                            <property>
                            ...
                        </customRules>
                    </configuration>
                </execution>
            </executions>
            <!-- Do not forget to add your custom rule JAR as a dependency if it is not in the same project -->
            <dependencies>
                <dependency>
                    <groupId>${your.custom.rule.groupId}</groupId>
                    <artifactId>${your.custom.rule.artifactId}</artifactId>
                    <version>${your.custom.rule.version}</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</build>

Remember, in order to be detected, your custom rule classes have to be in the plugin classpath.