CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-commitlint--types

Shared TypeScript type definitions for the commitlint ecosystem.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

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);
}

docs

case-validation.md

configuration.md

formatting.md

index.md

linting.md

parsing.md

plugins.md

prompts.md

rules-config.md

tile.json