#!/usr/bin/env node /** * normalize-commit-msg.js * * Git commit-msg hook: reads the commit message file, applies normalization * rules to the subject line, rewrites the file in place. * * Rules: * 1. Trim leading/trailing whitespace from the subject line * 2. Capitalize the first letter of the subject * 3. Strip a trailing period from the subject * 4. Warn (but do not block) if the subject exceeds 72 characters */ 'use strict'; const fs = require('fs'); const MAX_SUBJECT_LEN = 72; /** * Normalize the subject line of a commit message. * Returns { subject, warned } where warned is true if a length warning was emitted. * * @param {string} subject * @returns {{ subject: string, warned: boolean }} */ function normalizeSubject(subject) { let s = subject.trimEnd(); // Trim leading whitespace s = s.trimStart(); // Capitalize first letter if (s.length > 0) { s = s[0].toUpperCase() + s.slice(1); } // Strip trailing period if (s.endsWith('.')) { s = s.slice(0, -1); } const warned = s.length > MAX_SUBJECT_LEN; return { subject: s, warned }; } /** * Normalize a full commit message string. * Only the subject line (first non-empty, non-comment line) is modified. * * @param {string} message * @returns {{ message: string, warned: boolean }} */ function normalizeMessage(message) { const lines = message.split('\n'); let warned = false; // Find the subject line (first non-comment line) for (let i = 0; i < lines.length; i++) { const line = lines[i]; if (!line.startsWith('#')) { const result = normalizeSubject(line); lines[i] = result.subject; warned = result.warned; break; } } return { message: lines.join('\n'), warned }; } // Only run as a hook when invoked directly (not when required in tests) if (require.main === module) { const msgFile = process.argv[2]; if (!msgFile) { process.stderr.write('commit-msg hook: no message file argument\n'); process.exit(1); } const original = fs.readFileSync(msgFile, 'utf8'); const { message, warned } = normalizeMessage(original); if (warned) { process.stderr.write( `commit-msg warning: subject line exceeds ${MAX_SUBJECT_LEN} characters — consider shortening it.\n` ); } fs.writeFileSync(msgFile, message, 'utf8'); process.exit(0); } module.exports = { normalizeSubject, normalizeMessage };