CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-net-sourceforge-pmd--pmd-vm

PMD language module for static analysis of Apache Velocity Template Language (VTL) files

Pending
Overview
Eval results
Files

builtin-rules.mddocs/

Built-in Static Analysis Rules

Production-ready rules for detecting common issues in Velocity templates including best practices violations, design problems, and error-prone patterns. These rules are organized by category and ready for use in PMD rulesets.

Capabilities

Best Practices Rules

Rules that enforce Velocity template best practices and coding standards.

Avoid Reassigning Parameters

Detects reassignment of macro parameters, which can lead to confusion and unexpected behavior.

/**
 * Rule that detects reassignment of macro parameters.
 * Parameter reassignment can make templates harder to understand and debug.
 * Location: net.sourceforge.pmd.lang.vm.rule.bestpractices.AvoidReassigningParametersRule
 */
public class AvoidReassigningParametersRule extends AbstractVmRule {
    // Implementation analyzes #set directives and macro parameter usage
    // Reports violations when macro parameters are reassigned
}

What it detects:

  • Reassignment of macro parameters using #set directive
  • Modification of parameter values within macro body
  • Potential confusion between parameter names and local variables

Example violations:

#macro(processUser $userName $userAge)
    #set($userName = "Modified")  ## Violation: reassigning parameter
    #set($userAge = $userAge + 1) ## Violation: reassigning parameter
    <p>User: $userName, Age: $userAge</p>
#end

Recommended fix:

#macro(processUser $userName $userAge)
    #set($displayName = "Modified")    ## Use different variable name
    #set($calculatedAge = $userAge + 1) ## Use different variable name
    <p>User: $displayName, Age: $calculatedAge</p>  
#end

Unused Macro Parameter

Identifies macro parameters that are declared but never used, indicating potential dead code or missing implementation.

/**
 * Rule that detects unused macro parameters.
 * Unused parameters suggest incomplete implementation or unnecessary complexity.
 * Location: net.sourceforge.pmd.lang.vm.rule.bestpractices.UnusedMacroParameterRule
 */
public class UnusedMacroParameterRule extends AbstractVmRule {
    // Implementation tracks macro parameter declarations and usage
    // Reports violations for parameters that are never referenced
}

What it detects:

  • Macro parameters that are declared but never referenced
  • Parameters that may have been used in earlier template versions
  • Potential API cleanup opportunities

Example violations:

#macro(displayUser $userName $userAge $userEmail)
    <p>Welcome $userName!</p>
    <p>Age: $userAge</p>
    ## $userEmail is never used - violation
#end

Recommended fix:

#macro(displayUser $userName $userAge)  ## Remove unused parameter
    <p>Welcome $userName!</p>
    <p>Age: $userAge</p>
#end

Design Rules

Rules that identify design issues and structural problems in Velocity templates.

Avoid Deeply Nested If Statements

Detects excessive nesting of if statements, which reduces readability and maintainability.

/**
 * Statistical rule that detects deeply nested if statements.
 * Deep nesting makes templates difficult to read and maintain.
 * Location: net.sourceforge.pmd.lang.vm.rule.design.AvoidDeeplyNestedIfStmtsRule
 */
public class AvoidDeeplyNestedIfStmtsRule extends AbstractStatisticalVmRule {
    // Implementation tracks nesting depth of if statements
    // Default threshold typically set to 3-4 levels
}

What it detects:

  • If statements nested beyond configurable threshold (default: 3 levels)
  • Complex conditional logic that may benefit from refactoring
  • Templates that are difficult to test and maintain

Example violations:

#if($user)
    #if($user.isActive)
        #if($user.hasPermission)
            #if($user.inGroup)  ## Violation: 4th level nesting
                <p>User has access</p>
            #end
        #end
    #end
#end

Recommended fix:

#if($user && $user.isActive && $user.hasPermission && $user.inGroup)
    <p>User has access</p>
#end

## Or use a macro to encapsulate complex logic
#macro(hasFullAccess $user)
    #if($user && $user.isActive && $user.hasPermission && $user.inGroup)
        true
    #else
        false
    #end
#end

Collapsible If Statements

Identifies adjacent if statements that can be combined into a single conditional.

/**
 * Rule that detects if statements that can be collapsed into a single condition.
 * Collapsible if statements indicate opportunities for simplification.
 * Location: net.sourceforge.pmd.lang.vm.rule.design.CollapsibleIfStatementsRule
 */
public class CollapsibleIfStatementsRule extends AbstractVmRule {
    // Implementation analyzes nested if statements with same conditional logic
    // Reports violations when inner if can be combined with outer if
}

What it detects:

  • Nested if statements that can be combined with logical operators
  • Sequential if statements with related conditions
  • Opportunities to simplify conditional logic

Example violations:

#if($user)
    #if($user.isActive)  ## Violation: can be collapsed
        <p>Active user: $user.name</p>
    #end
#end

Recommended fix:

#if($user && $user.isActive)
    <p>Active user: $user.name</p>
#end

Excessive Template Length

Measures template length and flags templates that exceed reasonable size limits.

/**
 * Statistical rule that detects excessively long templates.
 * Long templates are difficult to maintain and may indicate design issues.
 * Location: net.sourceforge.pmd.lang.vm.rule.design.ExcessiveTemplateLengthRule
 */
public class ExcessiveTemplateLengthRule extends AbstractStatisticalVmRule {
    // Implementation counts lines or AST nodes in template
    // Default threshold typically set to 500-1000 lines
}

What it detects:

  • Templates exceeding configurable line count threshold
  • Templates that may benefit from decomposition
  • Potential maintenance and testing challenges

Configuration:

  • maxLines: Maximum allowed lines (default: 500)
  • countBlankLines: Whether to include blank lines in count

Recommended fixes:

  • Break large templates into smaller, focused templates
  • Extract reusable sections into macros
  • Use template inheritance or composition patterns

No Inline JavaScript

Detects inline JavaScript code within Velocity templates, promoting separation of concerns.

/**
 * Rule that detects inline JavaScript in Velocity templates.
 * Inline JavaScript violates separation of concerns and complicates maintenance.
 * Location: net.sourceforge.pmd.lang.vm.rule.design.NoInlineJavaScriptRule
 */
public class NoInlineJavaScriptRule extends AbstractVmRule {
    // Implementation analyzes text content for JavaScript patterns
    // Reports violations when <script> tags or JavaScript code detected
}

What it detects:

  • <script> tags with JavaScript content
  • Inline event handlers (onclick, onload, etc.)
  • JavaScript code mixed with template markup

Example violations:

<div onclick="alert('Hello')">Click me</div>  ## Violation: inline JS
<script>
    function doSomething() {  ## Violation: inline script block
        alert('Action performed');
    }
</script>

Recommended fix:

<div class="clickable-element">Click me</div>
## Move JavaScript to separate .js files
## Use CSS classes and external event handlers

No Inline Styles

Detects inline CSS styles within Velocity templates, promoting separation of concerns and maintainable styling.

/**
 * XPath-based rule that detects inline CSS styles in Velocity templates.
 * Inline styles violate separation of concerns and complicate maintenance.
 * Location: Implemented as XPath rule in category/vm/design.xml
 */
// XPath Rule: //Text[matches(@literal, "<[^>]+\s[sS][tT][yY][lL][eE]\s*=")]
// Rule Class: net.sourceforge.pmd.lang.rule.XPathRule

What it detects:

  • style attributes on HTML elements
  • Inline CSS declarations mixed with template markup
  • CSS code that should be externalized to CSS files

Example violations:

<div style="color: red; font-size: 14px;">Styled text</div>  ## Violation: inline style
<p style="margin: 10px;">Content</p>  ## Violation: inline style
<span style="background-color: #fff;">Text</span>  ## Violation: inline style

Recommended fix:

<div class="error-text">Styled text</div>
<p class="content-paragraph">Content</p>
<span class="highlighted-text">Text</span>
## Move styles to separate .css files
## Use CSS classes and external stylesheets

Error-Prone Rules

Rules that detect patterns likely to cause runtime errors or unexpected behavior.

Empty Foreach Statement

Detects foreach loops with empty bodies, which may indicate incomplete implementation.

/**
 * Rule that detects empty foreach statements.
 * Empty foreach loops suggest incomplete implementation or missing content.
 * Location: net.sourceforge.pmd.lang.vm.rule.errorprone.EmptyForeachStmtRule
 */
public class EmptyForeachStmtRule extends AbstractVmRule {
    // Implementation analyzes foreach statement bodies
    // Reports violations when body contains no meaningful content
}

What it detects:

  • Foreach loops with completely empty bodies
  • Foreach loops containing only whitespace or comments
  • Potentially incomplete loop implementations

Example violations:

#foreach($item in $items)
    ## Empty loop body - violation
#end

#foreach($user in $users)
    <!-- TODO: implement user display -->
    ## Only comments - violation
#end

Recommended fix:

#foreach($item in $items)
    <p>Item: $item</p>
#end

## Or remove the loop if not needed

Empty If Statement

Identifies if statements with empty bodies, indicating incomplete conditional logic.

/**
 * Rule that detects empty if statements.
 * Empty if statements suggest incomplete implementation or unnecessary conditions.
 * Location: net.sourceforge.pmd.lang.vm.rule.errorprone.EmptyIfStmtRule
 */
public class EmptyIfStmtRule extends AbstractVmRule {
    // Implementation analyzes if statement bodies
    // Reports violations when body contains no meaningful content
}

What it detects:

  • If statements with completely empty bodies
  • If statements containing only whitespace or comments
  • Conditional logic that may be incomplete

Example violations:

#if($user.isAdmin)
    ## Empty if body - violation
#end

#if($showSpecialContent)
    <!-- Content will be added later -->
    ## Only comments - violation  
#end

Recommended fix:

#if($user.isAdmin)
    <p>Admin panel access granted</p>
#end

## Or remove the condition if not needed

Rule Configuration Examples

PMD Ruleset Configuration

<?xml version="1.0"?>
<ruleset name="velocity-rules"
         xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 
                             http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
    
    <description>Custom Velocity template rules</description>
    
    <!-- Best Practices Rules -->
    <rule ref="category/vm/bestpractices.xml/AvoidReassigningParameters"/>
    <rule ref="category/vm/bestpractices.xml/UnusedMacroParameter"/>
    
    <!-- Design Rules with Custom Configuration -->
    <rule ref="category/vm/design.xml/ExcessiveTemplateLength">
        <properties>
            <property name="maxLines" value="300"/>
        </properties>
    </rule>
    
    <rule ref="category/vm/design.xml/AvoidDeeplyNestedIfStmts">
        <properties>
            <property name="maxNesting" value="3"/>
        </properties>
    </rule>
    
    <rule ref="category/vm/design.xml/CollapsibleIfStatements"/>
    <rule ref="category/vm/design.xml/NoInlineJavaScript"/>
    
    <!-- Error-Prone Rules -->
    <rule ref="category/vm/errorprone.xml/EmptyIfStmt"/>
    <rule ref="category/vm/errorprone.xml/EmptyForeachStmt"/>
</ruleset>

Programmatic Rule Usage

import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.PMDConfiguration;
import net.sourceforge.pmd.RuleSet;
import net.sourceforge.pmd.RuleSetFactory;

// Configure PMD for Velocity analysis
PMDConfiguration config = new PMDConfiguration();
config.setInputPaths("src/main/resources/templates");
config.setReportFormat("text");

// Load built-in Velocity rules
RuleSetFactory factory = new RuleSetFactory();
RuleSet ruleSet = factory.createRuleSet("category/vm/bestpractices.xml");

// Run analysis
PMD.runPMD(config);

Custom Rule Integration

import net.sourceforge.pmd.lang.vm.rule.AbstractVmRule;

// Custom rule extending built-in functionality
public class EnhancedUnusedParameterRule extends UnusedMacroParameterRule {
    
    @Override
    public Object visit(ASTReference node, Object data) {
        // Call parent implementation
        Object result = super.visit(node, data);
        
        // Add custom analysis
        analyzeReferencePattern(node, data);
        
        return result;
    }
    
    private void analyzeReferencePattern(ASTReference node, Object data) {
        // Custom pattern analysis
        String refName = node.getRootString();
        if (refName != null && refName.matches("^unused.*")) {
            addViolation(data, node, "Reference suggests unused parameter: " + refName);
        }
    }
}

Rule Suppression

In-Template Suppression

## Suppress specific rule for next directive
## NOPMD: AvoidReassigningParameters
#set($userName = "Modified")

## Suppress multiple rules
## NOPMD: EmptyIfStmt, UnusedMacroParameter  
#if($condition)
#end

External Suppression

<!-- PMD suppression file -->
<suppressions>
    <suppress files="legacy-template.vm" 
              checks="ExcessiveTemplateLength"/>
    <suppress files="generated-.*\.vm"
              checks=".*"/>
</suppressions>

Install with Tessl CLI

npx tessl i tessl/maven-net-sourceforge-pmd--pmd-vm

docs

ast-nodes.md

builtin-rules.md

index.md

language-integration.md

parsing.md

rule-development.md

tile.json