@commitlint/lint is a TypeScript library that provides core linting functionality for commitlint, a tool that validates commit messages against conventional commit format rules. It analyzes commit messages by parsing their structure and checking compliance with configurable rules, supporting both built-in and custom validation rules through a flexible plugin system.
npm install @commitlint/lintimport lint from "@commitlint/lint";For CommonJS:
const lint = require("@commitlint/lint").default;Type imports from @commitlint/types:
import type {
LintOptions,
LintOutcome,
QualifiedRules,
RuleConfigSeverity
} from "@commitlint/types";import lint from "@commitlint/lint";
// Basic linting with no rules (always passes)
const result = await lint("feat: add new feature");
console.log(result.valid); // true
// Linting with specific rules
const result = await lint(
"feat: add new feature",
{
"type-enum": [2, "always", ["feat", "fix", "docs"]], // Error level
"subject-empty": [2, "never"], // Subject must not be empty
}
);
if (!result.valid) {
console.log("Errors:", result.errors);
console.log("Warnings:", result.warnings);
}@commitlint/lint is built around several key components:
Core linting functionality that validates commit messages against a configurable set of rules.
/**
* Lint a commit message against commitlint rules
* @param message - The commit message string to validate
* @param rawRulesConfig - Optional rules configuration object
* @param rawOpts - Optional linting options
* @returns Promise resolving to validation results
*/
export default function lint(
message: string,
rawRulesConfig?: QualifiedRules,
rawOpts?: LintOptions
): Promise<LintOutcome>;
interface LintOptions {
/** If it should ignore the default commit messages (defaults to true) */
defaultIgnores?: boolean;
/** Additional commits to ignore, defined by ignore matchers */
ignores?: Matcher[];
/** The parser configuration to use when linting the commit */
parserOpts?: Options;
/** Plugin system for custom rules */
plugins?: PluginRecords;
/** Help URL for documentation */
helpUrl?: string;
}
interface LintOutcome {
/** The processed commit message as string */
input: string;
/** If the linted commit is considered valid */
valid: boolean;
/** All errors, per rule, for the commit */
errors: LintRuleOutcome[];
/** All warnings, per rule, for the commit */
warnings: LintRuleOutcome[];
}
interface LintRuleOutcome {
/** If the commit is considered valid for the rule */
valid: boolean;
/** The severity of the rule (1 = warning, 2 = error) */
level: RuleConfigSeverity;
/** The name of the rule */
name: string;
/** The message returned from the rule, if invalid */
message: string;
}Usage Examples:
import lint from "@commitlint/lint";
// Simple validation
const result = await lint("fix: resolve memory leak");
// With custom rules
const result = await lint(
"feat(auth): add JWT support",
{
"type-enum": [2, "always", ["feat", "fix", "docs", "style"]],
"scope-empty": [1, "never"], // Warning level
"subject-min-length": [2, "always", 10],
}
);
// With parser options
const result = await lint(
"JIRA-123: implement feature",
{
"references-empty": [2, "never"],
},
{
parserOpts: {
issuePrefixes: ["JIRA-"],
},
}
);
// With custom ignore patterns
const result = await lint(
"WIP: work in progress",
{
"type-empty": [2, "never"],
},
{
ignores: [(commit) => commit.startsWith("WIP:")],
}
);Rules are configured using arrays with severity level, condition, and optional value:
// QualifiedRules is imported from @commitlint/types
type QualifiedRules = Partial<RulesConfig<RuleConfigQuality.Qualified>>;
type RuleConfigTuple<T = unknown> =
| Readonly<[RuleConfigSeverity.Disabled]> // [0]
| Readonly<[RuleConfigSeverity, RuleConfigCondition]> // [1, "always"]
| Readonly<[RuleConfigSeverity, RuleConfigCondition, T]>; // [2, "always", ["feat", "fix"]]
enum RuleConfigSeverity {
Disabled = 0,
Warning = 1,
Error = 2,
}
type RuleConfigCondition = "always" | "never";
enum RuleConfigQuality {
User,
Qualified,
}
// RulesConfig interface defines all available built-in rules
interface RulesConfig<V = RuleConfigQuality.User> {
"body-case": RuleConfig<V>;
"body-empty": RuleConfig<V>;
"body-full-stop": RuleConfig<V, string>;
"body-leading-blank": RuleConfig<V>;
"body-max-length": RuleConfig<V, number>;
"body-max-line-length": RuleConfig<V, number>;
"body-min-length": RuleConfig<V, number>;
"footer-empty": RuleConfig<V>;
"footer-leading-blank": RuleConfig<V>;
"footer-max-length": RuleConfig<V, number>;
"footer-max-line-length": RuleConfig<V, number>;
"footer-min-length": RuleConfig<V, number>;
"header-case": RuleConfig<V>;
"header-full-stop": RuleConfig<V, string>;
"header-max-length": RuleConfig<V, number>;
"header-min-length": RuleConfig<V, number>;
"header-trim": RuleConfig<V>;
"references-empty": RuleConfig<V>;
"scope-case": RuleConfig<V>;
"scope-empty": RuleConfig<V>;
"scope-enum": RuleConfig<V, string[]>;
"scope-max-length": RuleConfig<V, number>;
"scope-min-length": RuleConfig<V, number>;
"signed-off-by": RuleConfig<V, string>;
"subject-case": RuleConfig<V>;
"subject-empty": RuleConfig<V>;
"subject-full-stop": RuleConfig<V, string>;
"subject-max-length": RuleConfig<V, number>;
"subject-min-length": RuleConfig<V, number>;
"trailer-exists": RuleConfig<V, string>;
"type-case": RuleConfig<V>;
"type-empty": RuleConfig<V>;
"type-enum": RuleConfig<V, string[]>;
"type-max-length": RuleConfig<V, number>;
"type-min-length": RuleConfig<V, number>;
// Plugins may add their custom rules
[key: string]: RuleConfig<V, unknown> | RuleConfig<V, void>;
}
type RuleConfig<V = RuleConfigQuality.Qualified, T = void> =
V extends RuleConfigQuality.Qualified ? RuleConfigTuple<T> : RuleConfigTuple<T>;Rule Configuration Examples:
const rules: QualifiedRules = {
// Disable rule
"type-empty": [0],
// Warning when condition is not met
"subject-min-length": [1, "always", 10],
// Error when condition is not met
"type-enum": [2, "always", ["feat", "fix", "docs", "style", "refactor", "test", "chore"]],
// Error when condition IS met (never allow empty subjects)
"subject-empty": [2, "never"],
};Custom rules can be added through the plugin system:
type PluginRecords = Record<string, Plugin>;
interface Plugin {
rules: {
[ruleName: string]: Rule<unknown>;
};
}
type Rule<Value = unknown> = (
parsed: Commit,
when?: RuleConfigCondition,
value?: Value
) => RuleOutcome | Promise<RuleOutcome>;
type RuleOutcome = Readonly<[boolean, string?]>;Plugin Usage Example:
import lint from "@commitlint/lint";
const result = await lint(
"custom: my commit",
{
"custom-rule": [2, "always", "required-value"],
},
{
plugins: {
"my-plugin": {
rules: {
"custom-rule": (parsed, when, value) => {
const isValid = parsed.header?.includes(value) ?? false;
return [isValid, isValid ? "" : `Header must contain "${value}"`];
},
},
},
},
}
);Configure how commit messages are parsed (using Options from conventional-commits-parser):
interface Options {
/** Custom header pattern regex */
headerPattern?: RegExp;
/** Issue reference prefixes (e.g., ["JIRA-", "TICKET-"]) */
issuePrefixes?: string[];
/** Comment character to ignore in commit messages */
commentChar?: string;
/** Custom merge pattern regex */
mergePattern?: RegExp;
/** Custom revert pattern regex */
revertPattern?: RegExp;
/** Merge correlation pattern */
mergeCorrespondence?: string[];
/** Revert correspondence pattern */
revertCorrespondence?: string[];
/** Field patterns for parsing */
fieldPattern?: RegExp;
/** Header correspondence */
headerCorrespondence?: string[];
/** Note keywords for parsing commit notes */
noteKeywords?: string[];
/** Reference actions for parsing references */
referenceActions?: string[];
}The lint function throws errors for invalid configurations:
Error Examples:
// Throws RangeError for unknown rule
await lint("test", { "unknown-rule": [2, "always"] });
// RangeError: Found rules without implementation: unknown-rule
// Throws Error for invalid config format
await lint("test", { "type-enum": "invalid" } as any);
// Error: config for rule type-enum must be array
// Throws Error for invalid severity level
await lint("test", { "type-enum": [5, "always"] } as any);
// Error: level for rule type-enum must be between 0 and 2Control which commit messages are ignored during linting:
type Matcher = (commit: string) => boolean;
interface IsIgnoredOptions {
/** Custom ignore pattern functions */
ignores?: Matcher[];
/** Whether to use built-in default ignore patterns */
defaults?: boolean;
}Default ignore patterns include:
Merge branch ...Revert "..."fixup! ...squash! ...Custom Ignore Example:
const result = await lint(
"WIP: work in progress",
{ "type-empty": [2, "never"] },
{
defaultIgnores: true, // Keep default ignores
ignores: [
(commit) => commit.startsWith("WIP:"),
(commit) => commit.includes("[skip-lint]"),
],
}
);
// This commit will be ignored and return { valid: true }interface Commit {
raw: string;
header: string | null;
type: string | null;
scope: string | null;
subject: string | null;
body: string | null;
footer: string | null;
notes: CommitNote[];
references: CommitReference[];
mentions: string[];
merge: string | null;
revert: Revert | null;
}
interface CommitNote {
title: string;
text: string;
}
interface CommitReference {
action: string;
owner: string | null;
repository: string | null;
issue: string;
raw: string;
prefix: string;
}
interface Revert {
header: string | null;
hash: string | null;
}