codometer-configure
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseWriting a codometer configuration
编写 codometer 配置
codometer.config.{ts,mts,cts,js,mjs,cjs,json,jsonc}formatts
import { type CodometerConfiguration } from "@codometer/configuration";
const codometerConfiguration: CodometerConfiguration = {
format: "markdown",
exclude: ["notepads/**"],
excludeFrom: ["configuration/.codometerignore"],
defaultInput: "codebase",
limits: [{ metric: "typescript.interfaces", severity: "warn", value: 500 }],
inputs: [
{
analyses: ["size"],
include: ["dist/**/*.js", "!dist/**/*.map.js"],
name: "compiled",
},
],
outputs: [{ path: "README.md", type: "markdown" }],
};
export default codometerConfiguration;Output paths resolve relative to the process's own working directory, not to
the configuration file, so a configuration kept in a folder
still writes to wherever the run was invoked from. A configuration file is
always read as a plain object — there is no config-as-function escape hatch,
so one file cannot describe every project in a workspace on its own; a
repository with many projects gives each its own and
spreads a shared object across them, the way this repository's own
does.
configuration/codometer.config.tsconfiguration/codometer.config.tscodometer.config.{ts,mts,cts,js,mjs,cjs,json,jsonc}limitlimitformatts
import { type CodometerConfiguration } from "@codometer/configuration";
const codometerConfiguration: CodometerConfiguration = {
format: "markdown",
exclude: ["notepads/**"],
excludeFrom: ["configuration/.codometerignore"],
defaultInput: "codebase",
limits: [{ metric: "typescript.interfaces", severity: "warn", value: 500 }],
inputs: [
{
analyses: ["size"],
include: ["dist/**/*.js", "!dist/**/*.map.js"],
name: "compiled",
},
],
outputs: [{ path: "README.md", type: "markdown" }],
};
export default codometerConfiguration;输出路径相对于进程自身的工作目录解析,而不是相对于配置文件。因此,放在 文件夹中的配置仍会写入运行命令时所在的位置。配置文件始终作为普通对象读取——没有将配置写成函数的变通机制——所以单个文件无法独立描述 workspace 中的每个项目;包含多个项目的仓库应为每个项目提供各自的 ,并像本仓库自己的 那样,在这些项目中展开同一个共享对象。
configuration/codometer.config.tsconfiguration/codometer.config.tsExclusions
排除项
.gitignoreexcludeexcludeFrom| Option | Syntax | Use it for |
|---|---|---|
| Globs | A handful of paths named inline |
| Paths to gitignore-syntax files | A list a repository would rather keep in a file |
Reusing an existing ignore file is a trap worth knowing about: most are written
for one other tool's concerns. A that excludes all markdown
because a formatter doesn't touch it will erase every markdown metric if
codometer is pointed at the same file. A dedicated is
usually the right answer instead of reaching for a file another tool owns.
.prettierignore.codometerignore在文件发现过程中, 已经生效,因此 和 适用于那些会被保留、但并非人工编写的文件,例如 lockfile、vendored bundle 和生成的文档:
.gitignoreexcludeexcludeFrom| 选项 | 语法 | 用途 |
|---|---|---|
| Globs | 直接列出少量路径 |
| 采用 gitignore 语法的文件路径 | 存放仓库更希望保留在独立文件中的排除列表 |
复用现有 ignore 文件是一个值得注意的陷阱:大多数此类文件都是为另一个工具的特定需求编写的。某个 可能因为 formatter 不会处理 Markdown 而排除所有 Markdown;如果将 codometer 指向同一个文件,它会清除所有 Markdown 指标。通常,专用 才是正确选择,而不是使用另一个工具所拥有的文件。
.prettierignore.codometerignoreInputs
输入
An input is a named set of files matched by glob, with the analyses run
over it. The measured directory is always an input of its own, named
; declares the others — most often build output that every
excludes, and that therefore needs an input rather than an
exclusion to reach at all.
codebaseinputs.gitignore| Field | Required | Default | Meaning |
|---|---|---|---|
| yes | — | Unique name for this input |
| yes | — | Globs that add files; at least one must add rather than only remove |
| no | none | Globs that remove files |
| yes | — | |
| no | | |
| no | | Where this input's globs start, relative to the process's working directory |
A prefix in removes files; every negation across the array forms
one set applied to the whole input, so reordering the array can never change
what it matches. may not carry a — it already removes, so there
is nothing left to negate there. Ignore files are not consulted for a
declared input, which is exactly what lets one match compiled output at all.
!includeexclude!Naming an input replaces the built-in whole-tree scan rather
than adding beside it, and only its and are read —
its / are not consulted, because the whole-tree scan is
discovered by walking ignore files rather than by matching globs. To measure a
subset of the tree, declare an input under some other name instead.
codebasecompressionanalysesincludeexcludeinput 是由 glob 匹配的一组有名称的文件,并针对其运行各项分析。被测目录始终将自身作为一个 input,名称为 ; 用于声明其他 input——最常见的是构建输出,因为所有 都会排除这些文件,所以必须通过 input 而非排除项才能访问它们。
codebaseinputs.gitignore| 字段 | 必填 | 默认值 | 含义 |
|---|---|---|---|
| 是 | — | 此 input 的唯一名称 |
| 是 | — | 添加文件的 Globs;至少有一个必须用于添加文件,不能全部只用于移除文件 |
| 否 | 无 | 移除文件的 Globs |
| 是 | — | |
| 否 | | 用于 |
| 否 | | 此 input 的 globs 的起始目录,相对于进程工作目录 |
include!exclude!将某个 input 命名为 ,会替换内置的整树扫描,而不是在其旁边新增一个;此时只有它的 和 会被读取,/ 不会生效,因为整树扫描是通过遍历 ignore 文件发现的,而不是通过匹配 globs 实现的。若要测量树中的某个子集,请改用其他名称声明 input。
codebasecompressionanalysesincludeexcludeLimits
限制
A limit bounds how high one measured metric may go. Any metric can carry one —
a compressed size, a line count, a declared counter's count — and a metric
with no limit is measured and reported exactly as before, gated by nothing.
ts
defaultInput: "codebase",
limits: [
{ metric: "compiled.size", value: "8 KB" },
{ label: "Interfaces", metric: "typescript.interfaces", value: 500 },
{ metric: "linesOfCode", severity: "warn", value: 100_000 },
],| Field | Required | Default | Meaning |
|---|---|---|---|
| yes | — | Dotted path of the metric this bounds |
| yes | — | Ceiling, as a number or a string carrying a unit |
| no | | |
| no | the path | What the report calls this limit |
A metric is addressed as its input's name followed by its path within that
input. Setting lets an unprefixed path resolve to that input's
metric, but only where no input of a competing name exists — write the input
name in full wherever an input and a metric group could share one, because
an ambiguous path is refused outright, never guessed at. The same refusal
applies to a path naming no metric at all, or one from an analysis its input
never ran.
defaultInputA string value's unit is decimal and its trailing is required: is
8000 bytes, is 1000000, and is refused rather than read as
anything. An input that matches no files only fails the run if a limit is
written against it — declaring the limit is what asserts the files should be
there.
b"8 KB""1 MB""8 K"Never raise a limit's to make a breach pass. A configured limit is
a promise about the codebase's shape, and raising it on the change that broke
that promise erases the evidence the limit existed to keep. If a breach is a
real regression, reduce what is being measured instead — trim the metric down,
split the file, delete the dead code. If the limit itself was simply wrong for
what this metric should hold going forward, that is also a decision worth
making deliberately and explaining, not a number quietly bumped in the same
change that broke it. For everything else a breach could mean, reach for the
skill.
valuecodometer-triagelimit 用于限定某个已测指标的最高值。任何指标都可以设置 limit,例如压缩后的文件大小、行数或已声明计数器的计数;没有 limit 的指标仍会像以前一样被测量和报告,不受任何 gate 约束。
ts
defaultInput: "codebase",
limits: [
{ metric: "compiled.size", value: "8 KB" },
{ label: "Interfaces", metric: "typescript.interfaces", value: 500 },
{ metric: "linesOfCode", severity: "warn", value: 100_000 },
],| 字段 | 必填 | 默认值 | 含义 |
|---|---|---|---|
| 是 | — | 此 limit 所限定指标的点分路径 |
| 是 | — | 上限,可以是数字,也可以是带单位的字符串 |
| 否 | | |
| 否 | 指标路径 | 报告中用于称呼此 limit 的名称 |
指标的寻址方式是在前面加上 input 的名称,后接该指标在此 input 内的路径。设置 后,未加前缀的路径可以解析到该 input 的指标,但前提是不存在名称冲突的其他 input——如果 input 名称和指标组可能重名,应始终完整写出 input 名称,因为歧义路径会被直接拒绝,绝不会靠猜测处理。同样的拒绝规则也适用于未指向任何指标的路径,或指向该 input 从未运行过的分析类型的路径。
defaultInput字符串值的单位采用十进制,且末尾的 必填: 表示 8000 字节, 表示 1000000,而 会被拒绝,不会被解释为其他数值。只有当某个 input 上存在针对它的 limit 时,未匹配到任何文件的 input 才会导致运行失败——声明该 limit,就等于断言这些文件应当存在。
b"8 KB""1 MB""8 K"绝不要通过提高 limit 的 来让违规通过。 已配置的 limit 是对代码库形态作出的承诺;在破坏该承诺的变更中提高它,会抹掉 limit 原本要保留的证据。如果违规确实代表回归,应改为减少被测量的内容——缩小指标规模、拆分文件或删除死代码。如果 limit 本身确实不适合该指标今后应保持的范围,这也应是一项经过审慎决定并加以解释的变更,而不是在破坏承诺的同一次变更中悄悄调高数字。对于其他可能意味着违规的情况,请使用 skill。
valuecodometer-triageCustom statistics
自定义统计
The top-level array is what measures a counter — declaring it
there is what computes it, regardless of whether, or where, any output
renders it:
customts
custom: [
{ label: "Service Files", patterns: ["**/*.service.ts"] },
{ label: "Unit Tests", patterns: ["**/*.unit.test.ts"] },
{ color: "16a34a", label: "Migrations", patterns: ["**/migrations/*.sql"] },
],Each entry renders as one badge everywhere it is selected, in configured
order. is a shields.io hexadecimal triplet; an entry that omits it
takes the next color from a built-in palette per group, so a counter's color
stays stable between runs. A counter selects what it counts with exactly one
of three fields — , , or — and an entry naming
none of them is rejected rather than reported as a permanent zero.
colorpatternssymbolscommentAn entry's own array is a separate, later concern: it
selects, by label, which of the top-level counters that destination
renders — it never declares a counter of its own, so a JSON report and a
markdown report may still select entirely different labels:
outputscustomts
outputs: [
{ custom: ["Service Files"], path: "codometer-report.json", type: "json" },
{ custom: ["Unit Tests"], path: "README.md", type: "markdown" },
],A label an output selects that the top-level never declared is
refused when the configuration loads — selection cannot conjure a counter that
was never measured. A counter declares but no output selects is still
measured and still gates a limit; it simply renders nowhere.
customcustom顶层 数组负责测量计数器;在其中进行声明才会计算该计数器,无论任何 output 是否以及在哪里呈现它:
customts
custom: [
{ label: "Service Files", patterns: ["**/*.service.ts"] },
{ label: "Unit Tests", patterns: ["**/*.unit.test.ts"] },
{ color: "16a34a", label: "Migrations", patterns: ["**/migrations/*.sql"] },
],每个条目在所有选中它的位置呈现为一个徽章,并按配置顺序排列。 是 shields.io 十六进制三元组;如果条目省略该字段,它会从对应组的内置调色板中获取下一种颜色,因此计数器的颜色在不同运行之间保持稳定。计数器通过 、 或 这三个字段中的恰好一个来选择计数方式;如果一个条目三个字段都未指定,它会被拒绝,而不是永久显示为零。
colorpatternssymbolscommentoutputscustomts
outputs: [
{ custom: ["Service Files"], path: "codometer-report.json", type: "json" },
{ custom: ["Unit Tests"], path: "README.md", type: "markdown" },
],如果 output 选择的 label 未在顶层 中声明,配置加载时会被拒绝——选择操作无法凭空创建一个从未被测量的计数器。如果某个计数器已由 声明,但没有任何 output 选择它,它仍会被测量,也仍可对 limit 产生 gate 作用,只是不会呈现在任何地方。
customcustomCounting declarations
统计声明
symbolsts
custom: [
{ group: "typescript", label: "Static Methods", symbols: { kinds: ["method"], modifiers: ["static"] } },
],kindsclassenumfunctiongetterinterfacemethodpropertysettermodifiersabstractasyncexportoverrideprivateprotectedpublicreadonlystaticmethodfunctionpropertypatternsgroupconventionssymbolsts
custom: [
{ group: "typescript", label: "Static Methods", symbols: { kinds: ["method"], modifiers: ["static"] } },
],kindsclassenumfunctiongetterinterfacemethodpropertysettermodifiersabstractasyncexportoverrideprivateprotectedpublicreadonlystaticmethodfunctionproperty符号计数器上的 用于限定搜索哪些文件,而不是被计数的对象。 用于将徽章放在指定组的内置项之后;默认组为 ,也可以是内置语言组之一。如果使用该范围之外的组名,配置会失败,而不是将徽章呈现在无处可见的位置。
patternsgroupconventionsSelecting a comment budget
选择注释预算
commentcommentsdocumentationlimits[]custom.<label>ts
custom: [
{ comment: { language: "yaml", maximumWords: 128 }, label: "YAML Comment Budget" },
{ comment: { kind: "class", maximumLines: 24 }, label: "Class Comment Budget" },
],
limits: [{ metric: "custom.YAML Comment Budget", value: 0 }],| Field | Required | Default | Meaning |
|---|---|---|---|
| no | every language with comments | Narrows to one of |
| no | a plain comment block | Narrows to a documented declaration's JSDoc-style comment for this declaration kind |
| no | — | Characters a block may hold, markers and newlines and all |
| no | — | Lines a block may span |
| no | — | Words of prose a block may hold, once markers are stripped |
| no | | |
Its count is how many blocks broke the selector's own maxima, and its
names each breaching block's and 1-indexed , plus how
much it measured. A block that stayed within budget contributes to neither.
instancesfilelineA selector carries no inheritance. There is no top-level default
a per-language entry merges over, so "every language at 128 words except shell
at 256" is written as one selector per language, not as a shared budget with
an override — this repository's own
derives that enumeration from and types it so a
language added to the schema is a compile error there until this repository's
list covers it. A language codometer starts measuring comments in is not
gated until that enumeration is updated to name it — nothing about adding a
language to the schema gates it automatically.
commentconfiguration/codometer.config.tsCODOMETER_COMMENT_LANGUAGESThe three maxima are separate fields rather than one steered by a
, because they are not alternatives. A block can sit inside a line
budget and outside a word one. A field left out is not measured, and
nothing is defaulted to a number — a budget nobody wrote is one nobody
chose.
maximumunitThe budget is per block, never file-wide. A block is the run of comment
lines a reader takes as one thought: a blank line ends one, a comment trailing
a value is never part of the block above it, and a shebang is never a
comment at all. There is no file-wide counterpart to a selector — a
file holding forty well-sized comments is not the same problem as one holding
a single essay, but codometer has no way to measure the second kind today.
#!commentPrefer a word budget over a character one where a linter already holds
lines to a column limit: the character count would only restate what
formatting already enforces, while words budget what the comment actually
says. JSDoc is ungated by default — a selector with a reaches
it, but declaring one is a deliberate choice, not something that happens by
naming a language.
commentkindcommentcommentsdocumentationcustom.<label>limits[]ts
custom: [
{ comment: { language: "yaml", maximumWords: 128 }, label: "YAML Comment Budget" },
{ comment: { kind: "class", maximumLines: 24 }, label: "Class Comment Budget" },
],
limits: [{ metric: "custom.YAML Comment Budget", value: 0 }],| 字段 | 必填 | 默认值 | 含义 |
|---|---|---|---|
| 否 | 所有带注释的语言 | 将范围限定为 |
| 否 | 普通注释块 | 将范围限定为指定声明种类的 JSDoc 风格注释 |
| 否 | — | 注释块可容纳的字符数,包括标记和换行符 |
| 否 | — | 注释块可跨越的行数 |
| 否 | — | 移除标记后,注释块可容纳的正文词数 |
| 否 | | |
其计数表示有多少注释块违反了选择器自身的最大值; 会列出每个违规注释块的 和从 1 开始计数的 ,以及测得的超出量。未超出预算的注释块不会贡献计数,也不会出现在 中。
instancesfilelineinstancescommentconfiguration/codometer.config.tsCODOMETER_COMMENT_LANGUAGES三个最大值是彼此独立的字段,而不是由 控制的单一 ,因为它们并不是互斥选项。 一个注释块可能符合行数预算,却超出词数预算。未填写的字段不会被测量,而且任何字段都不会默认成一个数字——没有人写下的预算,就代表没有人选择过的预算。
unitmaximum预算始终按注释块计算,绝不按文件整体计算。 注释块是读者视为一个完整想法的一段连续注释行:空行会结束一个注释块,值后面的尾随注释绝不属于上方注释块,而 shebang 始终不属于注释。 选择器没有文件级对应项——包含四十个大小合适的注释的文件,与包含一篇长篇大论的文件并非同一类问题,但 codometer 目前无法测量后一种情况。
#!comment如果 linter 已经将行长度限制在某一列宽,应优先使用词数预算,而不是字符数预算:字符数只会重复格式化工具已经强制执行的内容,而词数预算才能限制注释实际表达的信息量。JSDoc 默认不受 gate 约束——带 的 选择器可以覆盖它,但声明这种限制是一项有意选择,而不是仅指定语言就会自动发生的行为。
kindcommentWhat a breach means, and what it does not
违规意味着什么,以及不意味着什么
A breach names its file and line. Condense the block, or move the detail into
documentation that has room for it — never raise the budget to make the run
pass, for the same reason a limit's is never raised.
valueTwo accuracy caveats worth knowing before trusting a count:
- Some languages read a real parser, and some a line scanner. CSS
(postcss), Python (), YAML (its CST), and TypeScript/JavaScript (the compiler's scanner) all know a comment marker inside a string literal from a real comment. Shell, TOML, SQL, and HCL use a line scanner and cannot — a
tokenizeor#inside a string is read as a comment, exactly as those languages' existing comment counters already read it. HCL is the one language measured with three syntaxes:--,#, and//./* */ - Python's comments need a reachable interpreter, the same way every other Python metric does. An interpreter codometer cannot run leaves them unmeasured rather than miscounted.
For what to do about a breach, reach for the skill.
codometer-triage违规会指出对应的文件和行。应当压缩注释块,或将细节迁移到有足够空间的文档中——绝不要提高预算来让运行通过,原因与绝不提高 limit 的 相同。
value在信任计数之前,需要了解两项准确性限制:
- 有些语言使用真正的解析器,有些则使用行扫描器。 CSS(postcss)、Python()、YAML(其 CST)以及 TypeScript/JavaScript(编译器的 scanner)都能识别字符串字面量中的注释标记与真正的注释之间的区别。Shell、TOML、SQL 和 HCL 使用行扫描器,无法做到这一点——字符串中的
tokenize或#会被当作注释读取,与这些语言现有的注释计数器所采用的读取方式完全一致。HCL 是唯一一个按三种语法进行测量的语言:--、#和//。/* */ - Python 注释需要可访问的 interpreter,这一点与所有其他 Python 指标相同。如果 codometer 无法运行 interpreter,它会留下未测量的结果,而不是给出错误计数。
对于如何处理违规,请使用 skill。
codometer-triageOutput destinations
输出目标
outputsjsonmarkdownts
outputs: [
{ indentation: 2, path: "output/codometer.json", type: "json" },
{
description: "Measured on every push.",
path: "README.md",
type: "markdown",
},
],A JSON entry needs ; defaults to . A markdown entry
needs a , a function, or both — a destination naming neither is
rejected when the configuration loads.
pathindentation2pathwriteoutputsjsonmarkdownts
outputs: [
{ indentation: 2, path: "output/codometer.json", type: "json" },
{
description: "Measured on every push.",
path: "README.md",
type: "markdown",
},
],JSON 条目必须设置 ; 默认为 。Markdown 条目必须设置 、 函数,或两者同时设置;如果目标两者均未设置,配置加载时会被拒绝。
pathindentation2pathwriteWriting markdown
编写 Markdown
writerenderwritets
{
path: "README.md",
type: "markdown",
write: ({ anchors, renderBadges, statistics }) =>
anchors.syncAnchoredBlock({
content: `Lines of code: ${statistics.linesOfCode}\n\n${renderBadges()}`,
}),
}| Argument | Meaning |
|---|---|
| The configured description, for a writer that wants to place it itself |
| The built-in badge rendering of these same statistics — call it to build the default content, or to add to it |
| The measured statistics |
| True when nothing may be written and the file is only being inspected |
| The configured path, resolved against the process's working directory |
| The marker mechanics — |
Leaving unset keeps the built-in rendering and writing. A
function returns to report its destination as stale, which is what
fails a run; anything else counts as up to date.
writewritefalse--check reportswriterenderwritets
{
path: "README.md",
type: "markdown",
write: ({ anchors, renderBadges, statistics }) =>
anchors.syncAnchoredBlock({
content: `Lines of code: ${statistics.linesOfCode}\n\n${renderBadges()}`,
}),
}| 参数 | 含义 |
|---|---|
| 已配置的描述,供需要自行放置它的 writer 使用 |
| 针对同一组统计信息提供的内置徽章渲染;可调用它来构建默认内容,或将其添加到其他内容中 |
| 已测得的统计数据 |
| 为 true 时,不允许写入任何内容,仅检查文件 |
| 已配置的路径,相对于进程工作目录解析 |
| 标记机制—— |
不设置 会保留内置的渲染和写入行为。 函数返回 时,会将目标报告为过期,这正是 运行失败的方式;返回其他任何值都视为目标为最新状态。
writewritefalse--check reportsAuthoring says inputs, the report says targets
配置端称 inputs,报告端称 targets
inputstargetsinputsdefaultTargetdefaultInputCodometerReport.targetscodebase.typescript.interfacesCompiled JavaScript.sizeCodometerReport.targetsMeasured Targetsinputstargetsconfiguration --limitsinputstargetsinputsdefaultTargetdefaultInputCodometerReport.targetscodebase.typescript.interfacesCompiled JavaScript.sizeCodometerReport.targetsMeasured Targetsinputsconfiguration --limitstargets