All files / src validator.ts

96.61% Statements 57/59
88.23% Branches 15/17
100% Functions 1/1
96.61% Lines 57/59

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 601x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 43x 2x 2x 41x 41x 41x 41x 41x 43x 5x 5x 36x 36x 36x 36x 36x 36x 36x 43x 43x 43x 5x 1x 4x 5x 5x 5x 5x 5x 31x 31x 31x 31x 43x     31x 43x 43x 3x 3x 3x 3x 3x 28x 28x 28x  
import { ConfigManager } from './configManager';
 
export interface ValidationResult {
  valid: boolean;
  message?: string;
}
 
/**
 * Valida se uma mensagem de commit segue o padrão Conventional Commits.
 * Verifica apenas a primeira linha (header), respeitando as configurações.
 */
export function validateCommitMessage(message: string): ValidationResult {
  if (!message.trim()) {
    return { valid: false, message: 'Mensagem vazia' };
  }
 
  const config = ConfigManager.loadConfig();
  const firstLine = message.split('\n')[0];
 
  // Se não usar Conventional Commit, apenas verifica se não está vazio
  if (!config || !config.conventionalCommit) {
    return { valid: true };
  }
 
  // Regex para validar o padrão com ou sem escopo
  const withScopeRegex =
    /^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([^()\r\n]+\))?(!)?: .+/;
  const withoutScopeRegex =
    /^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(!)?: .+/;
 
  const regex = config.conventionalPattern === 'with-scope' ? withScopeRegex : withoutScopeRegex;
 
  if (!regex.test(firstLine)) {
    const expected = config.conventionalPattern === 'with-scope'
      ? 'type(scope): descrição'
      : 'type: descrição';
    return {
      valid: false,
      message: `Formato esperado: ${expected}`,
    };
  }
 
  const colonIndex = firstLine.indexOf(': ');
  const description = firstLine.slice(colonIndex + 2);
 
  if (description.length === 0) {
    return { valid: false, message: 'Descrição não pode ser vazia' };
  }
 
  const maxLength = config.maxLength || 100;
  if (firstLine.length > maxLength) {
    return {
      valid: false,
      message: `Primeira linha muito longa: ${firstLine.length}/${maxLength} caracteres`,
    };
  }
 
  return { valid: true };
}