or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

case-validation.mdconfiguration.mdformatting.mdindex.mdlinting.mdparsing.mdplugins.mdprompts.mdrules-config.md
tile.json

formatting.mddocs/

Output Formatting

The formatting system provides types for customizing the display and formatting of lint results. This includes support for colors, symbols, verbose output, and custom formatters.

Formatter Function

Formatter Type

type Formatter = (
  report: FormattableReport,
  options: FormatOptions,
) => string;

A formatter is a function that takes a lint report and formatting options, then returns a formatted string representation of the results.

Format Options

Format Options Interface

interface FormatOptions {
  color?: boolean;
  signs?: readonly [string, string, string];
  colors?: readonly [ChalkColor, ChalkColor, ChalkColor];
  verbose?: boolean;
  helpUrl?: string;
}

Configuration options for formatting output:

  • color: Whether to include ANSI color codes in output
  • signs: Array of symbols for [input, warning, error] indicators
  • colors: Array of chalk colors for [input, warning, error] text
  • verbose: Whether to include detailed information in output
  • helpUrl: URL to include in formatted output for additional help

Chalk Color Types

type ChalkColor = ColorName | ModifierName;

Union type representing all available chalk colors and modifiers from the chalk library.

Report Structure

Formattable Report

interface FormattableReport {
  results?: (FormattableResult & WithInput)[];
}

Top-level report structure containing an array of results, each combining result data with input information.

Formattable Result

interface FormattableResult {
  errors?: FormattableProblem[];
  warnings?: FormattableProblem[];
}

Result structure containing arrays of problems categorized by severity:

  • errors: Problems with severity level 2 (RuleConfigSeverity.Error)
  • warnings: Problems with severity level 1 (RuleConfigSeverity.Warning)

Formattable Problem

interface FormattableProblem {
  level: RuleConfigSeverity;
  name: keyof QualifiedRules;
  message: string;
}

Individual problem representation:

  • level: Severity level (1 for warning, 2 for error)
  • name: Rule name that generated the problem
  • message: Human-readable problem description

WithInput Mixin

interface WithInput {
  input?: string;
}

Mixin interface that adds optional input property to associate results with their original commit message.

Usage Examples

Basic Formatter Implementation

import { 
  Formatter, 
  FormattableReport, 
  FormatOptions,
  RuleConfigSeverity 
} from "@commitlint/types";

const simpleFormatter: Formatter = (report, options) => {
  if (!report.results || report.results.length === 0) {
    return "No results to format";
  }
  
  const lines: string[] = [];
  
  report.results.forEach(result => {
    if (result.input) {
      lines.push(`Input: ${result.input}`);
    }
    
    // Format errors
    if (result.errors && result.errors.length > 0) {
      lines.push("Errors:");
      result.errors.forEach(error => {
        const sign = options.signs?.[2] || "✖";
        lines.push(`  ${sign} ${error.name}: ${error.message}`);
      });
    }
    
    // Format warnings  
    if (result.warnings && result.warnings.length > 0) {
      lines.push("Warnings:");
      result.warnings.forEach(warning => {
        const sign = options.signs?.[1] || "⚠";
        lines.push(`  ${sign} ${warning.name}: ${warning.message}`);
      });
    }
  });
  
  return lines.join("\n");
};

Colorized Formatter

import { Formatter, ChalkColor } from "@commitlint/types";
import chalk from "chalk";

const colorFormatter: Formatter = (report, options) => {
  if (!report.results || report.results.length === 0) {
    return chalk.green("✓ All commit messages are valid");
  }
  
  const lines: string[] = [];
  const errorColor: ChalkColor = options.colors?.[2] || "red";
  const warningColor: ChalkColor = options.colors?.[1] || "yellow";
  const inputColor: ChalkColor = options.colors?.[0] || "dim";
  
  report.results.forEach(result => {
    if (result.input) {
      lines.push(chalk[inputColor](`Commit: ${result.input}`));
    }
    
    // Colorized errors
    if (result.errors && result.errors.length > 0) {
      result.errors.forEach(error => {
        const sign = options.signs?.[2] || "✖";
        lines.push(chalk[errorColor](`  ${sign} ${error.name}: ${error.message}`));
      });
    }
    
    // Colorized warnings
    if (result.warnings && result.warnings.length > 0) {
      result.warnings.forEach(warning => {
        const sign = options.signs?.[1] || "⚠";
        lines.push(chalk[warningColor](`  ${sign} ${warning.name}: ${warning.message}`));
      });
    }
  });
  
  if (options.helpUrl) {
    lines.push("");
    lines.push(`For more information, visit: ${options.helpUrl}`);
  }
  
  return lines.join("\n");
};

Format Options Configuration

import { FormatOptions } from "@commitlint/types";

// Minimal format options
const minimalOptions: FormatOptions = {
  color: false,
  verbose: false
};

// Detailed format options
const detailedOptions: FormatOptions = {
  color: true,
  signs: ["→", "⚠", "✖"] as const,
  colors: ["dim", "yellow", "red"] as const,
  verbose: true,
  helpUrl: "https://commitlint.js.org/"
};

// Custom symbols
const customOptions: FormatOptions = {
  color: true,
  signs: ["📝", "⚠️", "❌"] as const,
  colors: ["blue", "yellow", "red"] as const,
  verbose: false
};

JSON Formatter

import { Formatter } from "@commitlint/types";

const jsonFormatter: Formatter = (report, options) => {
  const output = {
    valid: !report.results?.some(r => r.errors && r.errors.length > 0),
    results: report.results?.map(result => ({
      input: result.input,
      valid: !result.errors || result.errors.length === 0,
      errorCount: result.errors?.length || 0,
      warningCount: result.warnings?.length || 0,
      errors: result.errors?.map(e => ({
        rule: e.name,
        severity: e.level,
        message: e.message
      })) || [],
      warnings: result.warnings?.map(w => ({
        rule: w.name,
        severity: w.level,
        message: w.message
      })) || []
    })) || []
  };
  
  return JSON.stringify(output, null, options.verbose ? 2 : 0);
};

Verbose Formatter

import { Formatter, RuleConfigSeverity } from "@commitlint/types";

const verboseFormatter: Formatter = (report, options) => {
  if (!options.verbose) {
    return "Use --verbose for detailed output";
  }
  
  const lines: string[] = [];
  let totalErrors = 0;
  let totalWarnings = 0;
  
  lines.push("=".repeat(50));
  lines.push("COMMITLINT DETAILED REPORT");
  lines.push("=".repeat(50));
  
  report.results?.forEach((result, index) => {
    lines.push(`\nResult #${index + 1}:`);
    
    if (result.input) {
      lines.push(`Input: "${result.input}"`);
      lines.push(`Length: ${result.input.length} characters`);
    }
    
    const errors = result.errors || [];
    const warnings = result.warnings || [];
    
    totalErrors += errors.length;
    totalWarnings += warnings.length;
    
    lines.push(`Errors: ${errors.length}`);
    lines.push(`Warnings: ${warnings.length}`);
    
    if (errors.length > 0) {
      lines.push("\nError Details:");
      errors.forEach((error, i) => {
        lines.push(`  ${i + 1}. Rule: ${error.name}`);
        lines.push(`     Level: ${error.level} (${RuleConfigSeverity[error.level]})`);
        lines.push(`     Message: ${error.message}`);
      });
    }
    
    if (warnings.length > 0) {
      lines.push("\nWarning Details:");
      warnings.forEach((warning, i) => {
        lines.push(`  ${i + 1}. Rule: ${warning.name}`);
        lines.push(`     Level: ${warning.level} (${RuleConfigSeverity[warning.level]})`);
        lines.push(`     Message: ${warning.message}`);
      });
    }
    
    lines.push("-".repeat(30));
  });
  
  lines.push("\nSUMMARY:");
  lines.push(`Total Results: ${report.results?.length || 0}`);
  lines.push(`Total Errors: ${totalErrors}`);
  lines.push(`Total Warnings: ${totalWarnings}`);
  lines.push(`Overall Status: ${totalErrors > 0 ? "FAILED" : "PASSED"}`);
  
  if (options.helpUrl) {
    lines.push(`\nHelp: ${options.helpUrl}`);
  }
  
  return lines.join("\n");
};

Report Building

import { 
  FormattableReport, 
  FormattableResult, 
  FormattableProblem,
  WithInput,
  RuleConfigSeverity 
} from "@commitlint/types";

function buildReport(
  input: string,
  errors: FormattableProblem[],
  warnings: FormattableProblem[]
): FormattableReport {
  const result: FormattableResult & WithInput = {
    input,
    errors,
    warnings
  };
  
  return {
    results: [result]
  };
}

// Example usage
const sampleErrors: FormattableProblem[] = [
  {
    level: RuleConfigSeverity.Error,
    name: "type-enum",
    message: "type must be one of [feat, fix, docs]"
  }
];

const sampleWarnings: FormattableProblem[] = [
  {
    level: RuleConfigSeverity.Warning,
    name: "subject-max-length",
    message: "subject may not be longer than 50 characters"
  }
];

const report = buildReport(
  "invalid: this is a test commit message that is too long",
  sampleErrors,
  sampleWarnings
);