commitlint 规则配置完全指南:Level、Applicable 与 Value 的三种写法及内置规则全参考
2026/9/21 15:52:22 网站建设 项目流程

commitlint 规则配置完全指南:Level、Applicable 与 Value 的三种写法及内置规则全参考

【免费下载链接】commitlint📓 Lint commit messages项目地址: https://gitcode.com/gh_mirrors/co/commitlint

commitlint 通过「规则(Rules)」把提交信息规范化为可校验的约束体系,而每条规则的核心就是一段简单的配置数组。本文以 docs/reference/rules-configuration.md 为骨架,结合@commitlint/rules@commitlint/lint@commitlint/execute-rule等源码实现,系统讲解规则配置的三要素(Level / Applicable / Value)、三种等价写法(普通数组、函数、异步函数),并给出 rules.md 中全部内置规则的参数与默认值参考,帮助你读懂并编写任何一份 commitlint 配置。

规则的本质:名称 + 配置数组

在 commitlint 中,一条规则由「规则名称」和「配置数组」两部分构成,所有规则统一放在配置文件的rules对象下,键名即规则名。配置数组固定包含至多三个元素:

位置字段取值含义
第 1 个Level(级别)0120关闭规则;1视为警告(warning);2视为错误(error)
第 2 个Applicable(适用条件)alwaysnevernever表示反转规则的判定逻辑
第 3 个Value(取值)任意(数字、字符串、数组、对象等)规则校验时使用的参数

最小合法的配置只写前两个元素,例如"header-max-length": [2, "always"];而"header-max-length": [0, "always", 72]则同时给出了级别、条件和上限值 72。

这些语义在 lint 校验实现 中有严格的强制约束:配置必须是长度为 2 或 3 的数组;level必须是0~2之间的数字;when必须是字符串且只能是"always""never"。如果违反这些约束,lint 会直接抛出明确的错误信息(例如config for rule xxx must be arraycondition for rule xxx must be "always" or "never"),而不是静默忽略。

在 TypeScript 类型层面,级别常量在@commitlint/types中被定义为枚举RuleConfigSeverityDisabled = 0Warning = 1Error = 2。官方配置包 config-conventional 就大量使用这套常量,例如:

"body-leading-blank": [RuleConfigSeverity.Warning, "always"], "header-max-length": [RuleConfigSeverity.Error, "always", 100], "subject-empty": [RuleConfigSeverity.Error, "never"],

三种等价的配置写法

规则配置既可以是普通数组,也可以是「返回数组的函数」,甚至是「返回 Promise 的异步函数」。也就是说,rules对象上每个键的值,可以是以下任意一种:

type Config<T> = | T // 普通数组,例如 [2, "always", 72] | Promise<T> // 直接给一个 Promise(较少见) | (() => T) // 同步函数,返回数组 | (() => Promise<T>); // 异步函数,返回 Promise<array>

这种「函数式配置」的用途在于:规则值可以动态计算。例如根据环境变量、读取到的文件内容或异步查询结果来决定某个阈值,而不是在配置文件中写死。

1. 普通数组(Plain array)

最常见、最直观的写法,直接把配置数组写在规则名下:

export default { // ... rules: { "header-max-length": [0, "always", 72], // 关闭该规则(演示用),正常应设为 1 或 2 }, // ... };

[0, "always", 72]表示:级别为0(禁用)、条件为always、上限值为72。这是原文档给出的标准示例格式。

2. 函数返回数组(Function returning array)

把配置数组包裹在箭头函数中,lint 执行时调用该函数拿到数组:

export default { // ... rules: { "header-max-length": () => [0, "always", 72], // 函数式写法,效果同上 }, // ... };

3. 异步函数返回数组(Async function returning array)

当取值需要异步获取时(例如从远端拉取团队约定、读取数据库中的历史数据),可以使用async函数:

export default { // ... rules: { "header-max-length": async () => [0, "always", 72], // 异步函数,返回 Promise<array> }, // ... };

从源码结构看,execute-rule 包 正是这三种写法的统一执行器:它先判断配置是否为函数(typeof config === "function"),是函数就调用它,否则包一层async () => config,最终await拿到真正的数组,因此无论你写哪种形式,结果完全等价。而在 lint.ts 中,最终都会以const [level, when, value] = config解构出三要素,再调用allRules.get(name)找到规则实现函数执行。level 为0的规则会被直接过滤跳过(config[0] > 0才参与校验),这正对应「0表示关闭规则」的行为。

规则校验的整体流程

理解了配置写法后,把整条链路串起来看会更清晰。以commitlint命令校验一条提交信息为例,核心调用链如下:

  1. @commitlint/lint 接收提交信息与rules配置;
  2. 如果配置了某个规则名但没有对应实现,会抛出RangeError,列出「缺少实现的规则」与「支持的规则全集」;
  3. 逐条校验配置数组的合法性(长度、级别、条件),不合法直接抛错;
  4. 过滤掉 level 为0的规则后,对每条规则调用其实现函数(parsed, when, value)
  5. 汇总所有结果,level 为2且不通过的产生errors,level 为1且不通过的产生warnings;只要存在 error,整体valid即为false

内置规则实现的注册表在 rules/index.ts,例如"header-max-length": headerMaxLength"scope-enum": scopeEnum"breaking-change-exclamation-mark": breakingChangeExclamationMark等,共 33 个内置规则。

规则实现中的细节:when 如何反转判定

「Applicable」字段always/never的实现方式值得留意。以内置规则源码为例,never并不是简单取反整个表达式,而是在规则内部对语义做了精细化处理:

  • type-enum(type-enum.ts):always要求 type 必须在枚举列表中,never则要求 type 不能出现在列表中,错误信息也会相应插入not
  • subject-empty(subject-empty.ts):always要求 subject 为空,never要求 subject 非空——[2, "never"]即「subject 不能为空」。
  • subject-case(subject-case.ts):当never模式下某个 case 匹配导致失败时,错误信息只报告实际命中的 case;always模式下失败则报告所有配置的 case。同时该规则要求 subject 首字符必须是 Unicode 字母(\p{Ll}\p{Lu}\p{Lt}),非字母开头直接放行。

内置规则完整参考(含默认值)

下面汇总 rules.md 中全部内置规则,按提交信息的组成部分(body / header / footer / scope / subject / type / 整体)分组,并给出「判定条件」与「默认值/取值范围」。规则配置中的 value 会覆盖默认值。

body 相关

规则判定条件默认规则默认 value
body-casebody属于 value 指定的大小写格式always'lower-case',可选lower-case / upper-case / camel-case / kebab-case / pascal-case / sentence-case / snake-case / start-case
body-emptybody是否为空never
body-full-stopbody是否以 value 结尾never'.'
body-leading-blankbody是否以空行开头always
body-max-lengthbody字符数不超过 valuealwaysInfinity
body-max-line-lengthbody每行不超过 value(含 URL 的行豁免)alwaysInfinity
body-min-lengthbody字符数不少于 valuealways0

footer 相关

规则判定条件默认规则默认 value
footer-emptyfooter是否为空never
footer-leading-blankfooter是否以空行开头always
footer-max-lengthfooter字符数不超过 valuealwaysInfinity
footer-max-line-lengthfooter每行不超过 valuealwaysInfinity
footer-min-lengthfooter字符数不少于 valuealways0

header 相关

规则判定条件默认规则默认 value
header-caseheader属于 value 指定的大小写格式always'lower-case'(可选值同body-case
header-full-stopheader是否以 value 结尾never'.'
header-max-lengthheader字符数不超过 valuealways72
header-min-lengthheader字符数不少于 valuealways0
header-trimheader首尾不能有空白字符always

scope 相关

规则判定条件默认规则默认 value
scope-casescope属于 value 指定的大小写格式always'lower-case';也支持对象写法{ cases: ["kebab-case"], delimiters: ["/"] }
scope-delimiter-stylescope中出现的所有分隔符必须属于 valuealways["/", "\\", ","]
scope-emptyscope是否为空never
scope-enumscope必须(always)/ 不得(never)出现在 value 中always[];支持对象写法{ scopes: ["foo", "bar"], delimiters: ["/"] }
scope-max-lengthscope字符数不超过 valuealwaysInfinity
scope-min-lengthscope字符数不少于 valuealways0

关于多段 scope(multi-segment scope)的几个要点(来自 rules.md 与源码 scope-enum.ts、scope-case.ts):

  • delimiters默认为["/", "\\", ","],用于把scope按分隔符拆成多段分别校验;逗号会按, ?(允许空格)处理,其余分隔符会被正则转义。
  • scope-enum在「提交信息没有 scope」或「value 为空数组」时始终通过;always要求所有 scope 段都在枚举中,never要求所有 scope 段都不在枚举中。
  • 使用scope-delimiter-style时,若同时使用scope-enum/scope-case,务必在这些规则里配置相同的delimiters,否则 scope 的解析可能不一致。

subject 相关

规则判定条件默认规则默认 value
subject-casesubject不得(never)/ 必须(always)属于 value 指定格式never["sentence-case", "start-case", "pascal-case", "upper-case"](可选值同body-case
subject-emptysubject是否为空never
subject-exclamation-marksubject:前是否带!never
subject-full-stopsubject是否以 value 结尾never'.'
subject-max-lengthsubject字符数不超过 valuealwaysInfinity
subject-min-lengthsubject字符数不少于 valuealways0

type 相关

规则判定条件默认规则默认 value
type-casetype属于 value 指定格式always'lower-case'(可选值同body-case
type-emptytype是否为空never
type-enumtype必须(always)/ 不得(never)出现在 value 中always["build", "chore", "ci", "docs", "feat", "fix", "perf", "refactor", "revert", "style", "test"]
type-max-lengthtype字符数不超过 valuealwaysInfinity
type-min-lengthtype字符数不少于 valuealways0

整条 message 相关

规则判定条件默认规则默认 value
breaking-change-exclamation-markheader 的:前带!与 footer 中的^BREAKING[ -]CHANGE:要么同时存在、要么同时不存在(XNOR 行为)always
references-emptyreferences是否有条目never
signed-off-bymessage中是否包含 valuealways'Signed-off-by:'
trailer-existsmessage中是否存在 value 指定的 traileralways'Signed-off-by:'

其中几个规则的实现细节值得说明:

  • breaking-change-exclamation-mark(breaking-change-exclamation-mark.ts):header 与 footer 均为空时直接通过;否则用正则^(\w*)(?:\((.*)\))?!: (.*)$检查 header 是否带!,用/^BREAKING[ -]CHANGE:/m检查 footer。hasExclamationMark === hasBreakingChange即 XNOR:两者同时存在或同时不存在才通过。
  • trailer-exists(trailer-exists.ts):实现上会调用git interpret-trailers --parse子进程解析 trailer,因此依赖本机 Git 环境。
  • signed-off-bytrailer-exists的默认 value 都是'Signed-off-by:',但前者检查的是整条 message 文本,后者检查的是解析出的 trailer 行,语义略有差异。

一份可落地的完整配置示例

把三种写法组合进同一份配置中(基于 config-conventional 的默认风格扩展):

export default { extends: ["@commitlint/config-conventional"], rules: { // 普通数组写法:header 最长 72 字符,超长报 error "header-max-length": [2, "always", 72], // 函数写法:值可以动态计算 "subject-case": () => [2, "never", ["sentence-case", "start-case", "pascal-case", "upper-case"]], // 异步函数写法:适合从外部动态获取枚举 "scope-enum": async () => [2, "always", ["core", "cli", "docs"]], // 利用 never 反转语义 "subject-empty": [2, "never"], // subject 不能为空 "subject-full-stop": [2, "never", "."], // subject 不能以句点结尾 // 多段 scope 场景 "scope-case": [2, "always", { cases: ["kebab-case"], delimiters: ["/"] }], "scope-enum": [2, "always", { scopes: ["core/utils", "cli/parser"], delimiters: ["/"] }], }, };

需要注意:同一规则名在对象中只能出现一次,因此「异步动态获取 scope-enum」与「对象式 scope-enum」需要按实际场景二选一。另外,extends与自定义rules合并时,自定义规则会覆盖被继承配置中同名规则。

小结

规则配置是 commitlint 中最基础也最灵活的机制:Level控制规则的开关与严重程度,Applicable控制判定的正反方向,Value提供校验参数;而「数组 / 函数 / 异步函数」三种写法由 execute-rule 统一归一化,让配置既可以静态声明,也可以动态计算。配合 rules.md 中的完整规则清单与 lint 源码 的严格校验,你可以精确掌控团队提交信息的每一个细节。

【免费下载链接】commitlint📓 Lint commit messages项目地址: https://gitcode.com/gh_mirrors/co/commitlint

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询