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

parsing.mddocs/

Commit Parsing

The commit parsing system provides types for integrating with conventional-commits-parser to parse and analyze commit message structure. This enables extracting structured data from commit messages for validation and processing.

Parser Function

Parser Type

type Parser = (message: string, options: Options) => Omit<Commit, "raw">;

Parser function that converts a raw commit message string into a structured commit object:

  • message: Raw commit message string to parse
  • options: Parser configuration options from conventional-commits-parser
  • Returns: Parsed commit object without the "raw" property

Integration with conventional-commits-parser

The parsing types integrate directly with the conventional-commits-parser library:

import type { Commit, Options } from "conventional-commits-parser";
  • Commit: Complete commit object structure from conventional-commits-parser
  • Options: Parser configuration options for customizing parsing behavior

Usage Examples

Basic Commit Parsing

import { Parser } from "@commitlint/types";
import { sync as parser } from "conventional-commits-parser";

// Using the parser type
const parseCommit: Parser = (message, options) => {
  const parsed = parser(message, options);
  
  // Remove raw property to match return type
  const { raw, ...commit } = parsed;
  return commit;
};

// Parse a commit message
const commitMessage = "feat(auth): add OAuth2 integration\n\nThis enables users to login with Google and GitHub.";

const parsedCommit = parseCommit(commitMessage, {
  headerPattern: /^(\w*)(?:\(([\w$.\-* ]*)\))?: (.*)$/,
  headerCorrespondence: ["type", "scope", "subject"]
});

console.log(parsedCommit);
// {
//   type: "feat",
//   scope: "auth", 
//   subject: "add OAuth2 integration",
//   header: "feat(auth): add OAuth2 integration",
//   body: "This enables users to login with Google and GitHub.",
//   footer: null,
//   notes: [],
//   references: [],
//   mentions: [],
//   revert: null
// }

Custom Parser Configuration

import { Parser } from "@commitlint/types";
import type { Options } from "conventional-commits-parser";

// Custom parser options for different commit formats
const angularOptions: Options = {
  headerPattern: /^(\w*)(?:\(([\w$.\-* ]*)\))?: (.*)$/,
  headerCorrespondence: ["type", "scope", "subject"],
  noteKeywords: ["BREAKING CHANGE"],
  revertPattern: /^(?:Revert|revert:)\s"?([\s\S]+?)"?\s*This reverts commit (\w*)\./i,
  revertCorrespondence: ["header", "hash"]
};

const conventionalCommitsOptions: Options = {
  headerPattern: /^(\w*)(?:\((.*)\))?!?: (.*)$/,
  headerCorrespondence: ["type", "scope", "subject"],
  noteKeywords: ["BREAKING CHANGE", "BREAKING-CHANGE"],
  issuePrefixes: ["#", "gh-"],
  referenceActions: [
    "close", "closes", "closed",
    "fix", "fixes", "fixed", 
    "resolve", "resolves", "resolved"
  ]
};

// Parser factory
function createParser(options: Options): Parser {
  return (message, parserOptions) => {
    const mergedOptions = { ...options, ...parserOptions };
    const parsed = parser(message, mergedOptions);
    const { raw, ...commit } = parsed;
    return commit;
  };
}

const angularParser = createParser(angularOptions);
const conventionalParser = createParser(conventionalCommitsOptions);

Parser Integration in Linting

import { Parser, LintOptions } from "@commitlint/types";
import type { Options } from "conventional-commits-parser";

// Using parser in lint context
function createLintOptions(
  customParser?: Parser,
  parserOpts?: Options
): LintOptions {
  return {
    parserOpts: parserOpts || {
      headerPattern: /^(\w*)(?:\(([\w$.\-* ]*)\))?: (.*)$/,
      headerCorrespondence: ["type", "scope", "subject"],
      noteKeywords: ["BREAKING CHANGE"]
    },
    defaultIgnores: true,
    ignores: [
      (commit) => commit.startsWith("Merge"),
      (commit) => commit.startsWith("Revert")
    ]
  };
}

// Example usage with custom parsing options
const lintOptions = createLintOptions(undefined, {
  headerPattern: /^(\w+)(\(.+\))?: (.+)$/,
  headerCorrespondence: ["type", "scope", "subject"],
  fieldPattern: /^-(.*?)-$/,
  noteKeywords: ["BREAKING CHANGE", "DEPRECATED"],
  referenceActions: ["closes", "fixes", "resolves"]
});

Commit Structure Analysis

import { Parser } from "@commitlint/types";
import type { Commit } from "conventional-commits-parser";

// Analyzer using parsed commit structure
function analyzeCommit(parser: Parser, message: string, options: Options) {
  const commit = parser(message, options);
  
  return {
    hasType: Boolean(commit.type),
    hasScope: Boolean(commit.scope),
    hasSubject: Boolean(commit.subject),
    hasBody: Boolean(commit.body),
    hasFooter: Boolean(commit.footer),
    hasBreakingChanges: commit.notes?.some(note => 
      note.title === "BREAKING CHANGE"
    ) || false,
    references: commit.references?.length || 0,
    mentions: commit.mentions?.length || 0,
    isRevert: Boolean(commit.revert),
    
    // Validation helpers
    isValid: Boolean(commit.type && commit.subject),
    isEmpty: !commit.type && !commit.subject && !commit.body,
    
    // Structure summary
    structure: {
      header: commit.header,
      components: {
        type: commit.type,
        scope: commit.scope,
        subject: commit.subject
      },
      body: commit.body,
      footer: commit.footer
    }
  };
}

// Usage
const analysis = analyzeCommit(
  parseCommit,
  "feat(api)!: add user authentication\n\nBREAKING CHANGE: API now requires auth tokens\n\nCloses #123",
  angularOptions
);

console.log(analysis);
// {
//   hasType: true,
//   hasScope: true, 
//   hasSubject: true,
//   hasBody: false,
//   hasFooter: false,
//   hasBreakingChanges: true,
//   references: 1,
//   mentions: 0,
//   isRevert: false,
//   isValid: true,
//   isEmpty: false,
//   structure: { ... }
// }

Multi-Format Parser

import { Parser } from "@commitlint/types";
import type { Options } from "conventional-commits-parser";

// Parser that detects and handles multiple commit formats
class MultiFormatParser {
  private parsers: Map<string, { parser: Parser; options: Options }> = new Map();
  
  addFormat(name: string, parser: Parser, options: Options) {
    this.parsers.set(name, { parser, options });
  }
  
  parse(message: string): { format: string; commit: ReturnType<Parser> } | null {
    for (const [format, { parser, options }] of this.parsers) {
      try {
        const commit = parser(message, options);
        
        // Check if parse was successful (has required components)
        if (commit.type && commit.subject) {
          return { format, commit };
        }
      } catch (error) {
        // Continue to next parser
        continue;
      }
    }
    
    return null; // No parser succeeded
  }
}

// Setup multi-format parser
const multiParser = new MultiFormatParser();

multiParser.addFormat("angular", parseCommit, angularOptions);
multiParser.addFormat("conventional", parseCommit, conventionalCommitsOptions);
multiParser.addFormat("custom", parseCommit, {
  headerPattern: /^(\w+): (.+)$/,
  headerCorrespondence: ["type", "subject"]
});

// Usage
const result = multiParser.parse("feat: add new feature");
if (result) {
  console.log(`Detected format: ${result.format}`);
  console.log("Parsed commit:", result.commit);
}

Parser Validation

import { Parser } from "@commitlint/types";
import type { Options, Commit } from "conventional-commits-parser";

// Validation wrapper for parser
function createValidatingParser(
  baseParser: Parser,
  validator: (commit: Omit<Commit, "raw">) => string[]
): Parser {
  return (message, options) => {
    const commit = baseParser(message, options);
    const errors = validator(commit);
    
    if (errors.length > 0) {
      throw new Error(`Parse validation failed: ${errors.join(", ")}`);
    }
    
    return commit;
  };
}

// Validation rules
function validateParsedCommit(commit: Omit<Commit, "raw">): string[] {
  const errors: string[] = [];
  
  if (!commit.type) {
    errors.push("Missing commit type");
  }
  
  if (!commit.subject) {
    errors.push("Missing commit subject");
  }
  
  if (commit.subject && commit.subject.length > 50) {
    errors.push("Subject too long (max 50 characters)");
  }
  
  if (commit.type && !["feat", "fix", "docs", "style", "refactor", "test", "chore"].includes(commit.type)) {
    errors.push(`Invalid commit type: ${commit.type}`);
  }
  
  return errors;
}

// Create validating parser
const validatingParser = createValidatingParser(parseCommit, validateParsedCommit);

// Usage
try {
  const commit = validatingParser("invalid: this is a very long subject that exceeds the maximum allowed length", angularOptions);
  console.log("Valid commit:", commit);
} catch (error) {
  console.error("Parse error:", error.message);
}