or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

cli-interface.mdconfiguration.mdcore-api.mdindex.mdvalidation-rules.md
tile.json

validation-rules.mddocs/

Validation Rules

Comprehensive rule system with 35 built-in rules covering all aspects of conventional commit messages. Rules are configurable with severity levels and conditions.

Capabilities

Rule Configuration Format

All rules follow a consistent configuration tuple format with severity levels and conditions.

// Rule configuration tuple format
type RuleConfigTuple<T> = 
  | Readonly<[RuleConfigSeverity.Disabled]>                    // [0] - Disable rule
  | Readonly<[RuleConfigSeverity, RuleConfigCondition]>        // [level, when] 
  | Readonly<[RuleConfigSeverity, RuleConfigCondition, T]>     // [level, when, value]

enum RuleConfigSeverity {
  Disabled = 0,   // Rule is disabled
  Warning = 1,    // Rule produces warnings
  Error = 2,      // Rule produces errors
}

type RuleConfigCondition = 'always' | 'never';

// Configuration examples
{
  'type-empty': [2, 'never'],              // Error if type is empty
  'subject-max-length': [2, 'always', 72], // Error if subject > 72 chars
  'scope-case': [1, 'always', 'kebab-case'], // Warning if scope not kebab-case
  'body-leading-blank': [0]                 // Disable rule
}

Type Rules

Rules for validating the commit type (feat, fix, docs, etc.).

// Type case validation
'type-case': [RuleConfigSeverity, RuleConfigCondition, TargetCaseType];

// Type presence validation
'type-empty': [RuleConfigSeverity, RuleConfigCondition];

// Type enumeration validation
'type-enum': [RuleConfigSeverity, RuleConfigCondition, string[]];

// Type length validation
'type-max-length': [RuleConfigSeverity, RuleConfigCondition, number];
'type-min-length': [RuleConfigSeverity, RuleConfigCondition, number];

type TargetCaseType = 
  | 'camel-case' | 'kebab-case' | 'snake-case' | 'pascal-case'
  | 'upper-case' | 'lower-case' | 'sentence-case' | 'start-case';

Usage Examples:

module.exports = {
  rules: {
    'type-case': [2, 'always', 'lower-case'],           // Type must be lowercase
    'type-empty': [2, 'never'],                         // Type cannot be empty
    'type-enum': [2, 'always', ['feat', 'fix', 'docs', 'style', 'refactor', 'test', 'chore']],
    'type-max-length': [2, 'always', 10],               // Type max 10 characters
    'type-min-length': [2, 'always', 3]                 // Type min 3 characters
  }
};

Scope Rules

Rules for validating the commit scope (api, ui, core, etc.).

// Scope case validation
'scope-case': [RuleConfigSeverity, RuleConfigCondition, TargetCaseType];

// Scope presence validation
'scope-empty': [RuleConfigSeverity, RuleConfigCondition];

// Scope enumeration validation
'scope-enum': [RuleConfigSeverity, RuleConfigCondition, string[]];  

// Scope length validation
'scope-max-length': [RuleConfigSeverity, RuleConfigCondition, number];
'scope-min-length': [RuleConfigSeverity, RuleConfigCondition, number];

Usage Examples:

module.exports = {
  rules: {
    'scope-case': [2, 'always', 'kebab-case'],          // Scope must be kebab-case
    'scope-empty': [1, 'never'],                        // Warn if scope is empty
    'scope-enum': [2, 'always', ['api', 'ui', 'core', 'docs', 'ci']], // Allowed scopes
    'scope-max-length': [2, 'always', 20],              // Scope max 20 characters
    'scope-min-length': [2, 'always', 2]                // Scope min 2 characters
  }
};

Subject Rules

Rules for validating the commit subject/description.

// Subject case validation
'subject-case': [RuleConfigSeverity, RuleConfigCondition, TargetCaseType];

// Subject presence validation
'subject-empty': [RuleConfigSeverity, RuleConfigCondition];

// Subject punctuation validation
'subject-full-stop': [RuleConfigSeverity, RuleConfigCondition, string];

// Subject exclamation mark validation
'subject-exclamation-mark': [RuleConfigSeverity, RuleConfigCondition];

// Subject length validation
'subject-max-length': [RuleConfigSeverity, RuleConfigCondition, number];
'subject-min-length': [RuleConfigSeverity, RuleConfigCondition, number];

Usage Examples:

module.exports = {
  rules: {
    'subject-case': [2, 'always', 'sentence-case'],     // Subject must be sentence case
    'subject-empty': [2, 'never'],                      // Subject cannot be empty
    'subject-full-stop': [2, 'never', '.'],             // Subject should not end with period
    'subject-exclamation-mark': [1, 'never'],           // Warn on exclamation marks
    'subject-max-length': [2, 'always', 72],            // Subject max 72 characters
    'subject-min-length': [2, 'always', 10]             // Subject min 10 characters
  }
};

Header Rules

Rules for validating the entire commit message header.

// Header case validation
'header-case': [RuleConfigSeverity, RuleConfigCondition, TargetCaseType];

// Header punctuation validation
'header-full-stop': [RuleConfigSeverity, RuleConfigCondition, string];

// Header length validation
'header-max-length': [RuleConfigSeverity, RuleConfigCondition, number];
'header-min-length': [RuleConfigSeverity, RuleConfigCondition, number];

// Header whitespace validation
'header-trim': [RuleConfigSeverity, RuleConfigCondition];

Usage Examples:

module.exports = {
  rules: {
    'header-case': [2, 'always', 'lower-case'],         // Header must be lowercase
    'header-full-stop': [2, 'never', '.'],              // Header should not end with period
    'header-max-length': [2, 'always', 100],            // Header max 100 characters
    'header-min-length': [2, 'always', 15],             // Header min 15 characters
    'header-trim': [2, 'always']                        // Header should be trimmed
  }
};

Body Rules

Rules for validating the commit message body.

// Body case validation
'body-case': [RuleConfigSeverity, RuleConfigCondition, TargetCaseType];

// Body presence validation
'body-empty': [RuleConfigSeverity, RuleConfigCondition];

// Body punctuation validation
'body-full-stop': [RuleConfigSeverity, RuleConfigCondition, string];

// Body formatting validation
'body-leading-blank': [RuleConfigSeverity, RuleConfigCondition];

// Body length validation
'body-max-length': [RuleConfigSeverity, RuleConfigCondition, number];
'body-max-line-length': [RuleConfigSeverity, RuleConfigCondition, number];
'body-min-length': [RuleConfigSeverity, RuleConfigCondition, number];

Usage Examples:

module.exports = {
  rules: {
    'body-case': [1, 'always', 'sentence-case'],        // Warn if body not sentence case
    'body-empty': [1, 'never'],                         // Warn if body is empty
    'body-full-stop': [2, 'always', '.'],               // Body should end with period
    'body-leading-blank': [2, 'always'],                // Body should have leading blank line
    'body-max-length': [2, 'always', 500],              // Body max 500 characters
    'body-max-line-length': [2, 'always', 80],          // Body line max 80 characters
    'body-min-length': [2, 'always', 20]                // Body min 20 characters
  }
};

Footer Rules

Rules for validating the commit message footer.

// Footer presence validation
'footer-empty': [RuleConfigSeverity, RuleConfigCondition];

// Footer formatting validation
'footer-leading-blank': [RuleConfigSeverity, RuleConfigCondition];

// Footer length validation
'footer-max-length': [RuleConfigSeverity, RuleConfigCondition, number];
'footer-max-line-length': [RuleConfigSeverity, RuleConfigCondition, number];
'footer-min-length': [RuleConfigSeverity, RuleConfigCondition, number];

Usage Examples:

module.exports = {
  rules: {
    'footer-empty': [1, 'never'],                       // Warn if footer is empty
    'footer-leading-blank': [2, 'always'],              // Footer should have leading blank line
    'footer-max-length': [2, 'always', 300],            // Footer max 300 characters
    'footer-max-line-length': [2, 'always', 80],        // Footer line max 80 characters
    'footer-min-length': [2, 'always', 10]              // Footer min 10 characters
  }
};

Reference and Trailer Rules

Rules for validating issue references and Git trailers.

// Issue reference validation
'references-empty': [RuleConfigSeverity, RuleConfigCondition];

// Git trailer validation
'signed-off-by': [RuleConfigSeverity, RuleConfigCondition, string];
'trailer-exists': [RuleConfigSeverity, RuleConfigCondition, string];

Usage Examples:

module.exports = {
  rules: {
    'references-empty': [1, 'never'],                   // Warn if no issue references
    'signed-off-by': [2, 'always', 'Signed-off-by'],   // Require signed-off-by trailer
    'trailer-exists': [2, 'always', 'Reviewed-by']     // Require reviewed-by trailer
  }
};

Rule Validation Behavior

Understanding how rules are applied and validated.

// Condition behavior
'always' // Rule applies when the condition is met
'never'  // Rule applies when the condition is NOT met

// Examples:
'type-empty': [2, 'never']    // Error when type IS empty
'type-empty': [2, 'always']   // Error when type IS NOT empty

'body-leading-blank': [2, 'always']  // Error when there IS NOT a leading blank
'body-leading-blank': [2, 'never']   // Error when there IS a leading blank

Complete Rule Configuration Example

// Comprehensive rule configuration
module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    // Type rules
    'type-case': [2, 'always', 'lower-case'],
    'type-empty': [2, 'never'],
    'type-enum': [2, 'always', [
      'build', 'chore', 'ci', 'docs', 'feat', 
      'fix', 'perf', 'refactor', 'revert', 'style', 'test'
    ]],
    'type-max-length': [2, 'always', 10],
    'type-min-length': [2, 'always', 3],
    
    // Scope rules
    'scope-case': [2, 'always', 'kebab-case'],
    'scope-empty': [1, 'never'],
    'scope-enum': [2, 'always', [
      'api', 'ui', 'core', 'docs', 'ci', 'build', 'test'
    ]],
    'scope-max-length': [2, 'always', 15],
    
    // Subject rules
    'subject-case': [2, 'always', 'sentence-case'],
    'subject-empty': [2, 'never'],
    'subject-full-stop': [2, 'never', '.'],
    'subject-max-length': [2, 'always', 72],
    'subject-min-length': [2, 'always', 10],
    
    // Header rules
    'header-max-length': [2, 'always', 100],
    'header-trim': [2, 'always'],
    
    // Body rules
    'body-leading-blank': [2, 'always'],
    'body-max-line-length': [2, 'always', 80],
    'body-case': [1, 'always', 'sentence-case'],
    
    // Footer rules
    'footer-leading-blank': [2, 'always'],
    'footer-max-line-length': [2, 'always', 80],
    
    // Other rules
    'references-empty': [1, 'never'],
    'signed-off-by': [2, 'always', 'Signed-off-by']
  }
};

Custom Rule Development

Creating custom validation rules.

// Custom rule function signature
function customRule(parsed, when, value) {
  // parsed: Parsed commit object
  // when: 'always' | 'never'
  // value: Rule configuration value
  
  // Return [isValid, message]
  const isValid = /* validation logic */;
  const message = isValid ? '' : 'Custom validation error message';
  
  return [isValid, message];
}

// Plugin with custom rules
const customPlugin = {
  rules: {
    'custom-type-prefix': (parsed, when, prefix) => {
      const hasPrefix = parsed.type && parsed.type.startsWith(prefix);
      const valid = when === 'always' ? hasPrefix : !hasPrefix;
      const message = valid ? '' : `Type should ${when === 'always' ? 'start' : 'not start'} with "${prefix}"`;
      return [valid, message];
    }
  }
};

module.exports = {
  plugins: [customPlugin],
  rules: {
    'custom-type-prefix': [2, 'always', 'feat-']
  }
};

Rule Testing

Testing rule configurations and validation.

# Test specific commit message
echo "feat(api): add user authentication" | commitlint

# Test with specific rules
echo "invalid commit" | commitlint --config test-rules.js

# Verbose output for rule debugging
echo "fix: bug fix" | commitlint --verbose

# Print applied rules
commitlint --print-config json | jq '.rules'