writing-comments

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Writing Comments

编写注释

Purpose

目的

Comments in this repository are read by contributors, months or years after they were written, with none of the context you have right now. This skill defines who that reader is, what each kind of comment is for, and which patterns are banned.
本仓库中的注释会在编写数月或数年后被贡献者阅读,他们不具备你当下拥有的任何上下文。本指南定义了目标读者、各类注释的用途,以及禁用的模式。

Scope Boundary

范围边界

This skill governs contributor-facing comments in the TypeScript/JavaScript source. It does not apply to end-user documentation:
  • JSDoc blocks tagged
    @docs
    in
    packages/astro/src/types/public/config.ts
    and
    packages/astro/src/core/errors/errors-data.ts
    are scraped by an external
    docgen
    tool and published to the Astro docs website. Follow
    packages/astro/src/core/errors/README.md
    for those, and get docs-team review — CI regenerates the reference when
    types/public/**
    changes.
  • Other JSDoc across
    types/public/**
    is surfaced to users through editor IntelliSense. Write it for Astro users building a site, not for contributors reading the source.
Everything below is about the source a contributor reads at HEAD.
本指南管控TypeScript/JavaScript源码中面向贡献者的注释,不适用于终端用户文档:
  • packages/astro/src/types/public/config.ts
    packages/astro/src/core/errors/errors-data.ts
    中标记了
    @docs
    的JSDoc块会被外部
    docgen
    工具抓取,并发布到Astro文档网站。这类注释请遵循
    packages/astro/src/core/errors/README.md
    的规范,并需获得文档团队的审核——当
    types/public/**
    目录内容变更时,CI会重新生成参考文档。
  • types/public/**
    目录下的其他JSDoc会通过编辑器的IntelliSense展示给用户。请面向构建站点的Astro用户编写,而非阅读源码的贡献者。
以下所有内容均针对贡献者在HEAD版本中阅读的源码。

The Reader

目标读者

Write for an Astro contributor who is competent in TypeScript but has no access to your current context: not this conversation, not the pull request, not the issue, not the diff. They see only the repository at HEAD.
Two consequences follow directly:
  1. Never narrate change history. Words like "now", "previously", "no longer", "the new approach" are meaningless at HEAD, where only one approach exists. State how the code works, not how it came to be. (A
    @deprecated
    notice is the exception — see Conventions — because it describes the contract's future, which the reader needs.)
  2. Never address the reviewer. A comment that argues your change is correct ("this properly handles X") belongs in the PR description, not in the source. The comment must justify the code as it stands, permanently.
请面向精通TypeScript但无法获取你当前上下文的Astro贡献者编写注释:他们看不到本次对话、PR、Issue或代码差异,只能看到HEAD版本的仓库内容。
由此直接得出两个结论:
  1. 切勿叙述变更历史。像“现在”“之前”“不再”“新方案”这类词汇在HEAD版本中毫无意义,因为此时只存在一种实现方式。请说明代码的工作方式,而非它的演变过程。(
    @deprecated
    注释是例外——详见本代码库约定——因为它描述了合约的未来状态,这是读者需要了解的信息。)
  2. 切勿针对评审者编写。诸如“这能正确处理X场景”这类为变更正确性辩护的注释应放在PR描述中,而非源码里。注释必须永久证明当前代码的合理性。

Three Kinds of Comments, Three Different Jobs

三类注释,三种不同用途

KindSyntaxJobContains
File / module overview
/** */
at the top of the file
ExplanationWhy the module exists, the concepts and terms it defines, how the pieces relate, design rationale
Item docs
/** */
directly above a declaration
ReferenceThe contract: behavior, parameters, return value, thrown errors, invariants. Neutral and factual
Inline comments
//
inside a body
RationaleOnly what the code cannot say: constraints, workarounds (with issue links), non-obvious coupling
Do not mix the jobs. Implementation details do not belong in the
/** */
contract — put them as
//
comments inside the body. The contract does not belong scattered across inline comments — put it on the declaration.
类型语法格式用途包含内容
文件/模块概述文件顶部的
/** */
解释说明模块存在的原因、定义的概念与术语、各部分的关联、设计思路
条目文档声明上方的
/** */
参考说明合约内容:行为、参数、返回值、抛出的错误、不变量。内容需中立且客观
行内注释代码块内部的
//
原理说明仅包含代码无法表达的信息:约束条件、临时解决方案(需附带Issue链接)、非直观的耦合关系
请勿混淆用途。实现细节不属于
/** */
合约注释的范畴——应放在代码块内部的
//
注释中。合约内容不应分散在行内注释中——应放在声明上方。

Behavior Documentation

行为文档编写

When item documentation is warranted, write the contract for a human reader, not as a translation of the implementation. This does not require JSDoc for every function; names, types, and structure should carry straightforward behavior on their own.
  • Start with a plain-language description of what the function returns or accomplishes.
  • Use short or medium-length sentences with one main idea each.
  • Avoid internal Astro jargon when callers do not need it. If a technical term is necessary, explain it in the same paragraph.
  • Describe caller-visible caveats that can be surprising: fallback behavior, work limits, ambiguous results, overload ordering, side effects, and the conditions that return
    undefined
    ,
    null
    , an empty result, or another indeterminate value.
  • Document thrown errors when callers are expected to distinguish or recover from them.
  • Do not describe implementation details unless callers need them to understand the behavior or use the API safely.
Add an example when behavior depends on a relationship the signature cannot show clearly. Common Astro and TypeScript cases include:
  • which overload is selected;
  • how arguments map to optional or rest parameters;
  • which public Astro entrypoint exposes a symbol that is implemented or re-exported elsewhere;
  • fallback behavior for ambiguous routes, incomplete configuration, or missing content;
  • a result whose meaning is not obvious from its type.
Introduce the example in prose before the code block. State what it demonstrates and what result is expected. Keep snippets minimal, self-contained, and written from the perspective of an Astro user or the internal caller that owns the contract.
Module documentation should describe a durable concept, architectural boundary, or design reason. Do not list individual exports merely to summarize the file; such inventories become stale as symbols are added or renamed. If a module has no durable concept to explain, use a brief one-line description or no overview.
当需要编写条目文档时,请为人类读者编写合约,而非对实现逻辑的直译。并非每个函数都需要JSDoc;函数名、类型和结构应能直接体现简单明了的行为。
  • 以平实语言描述函数的返回结果或实现的功能开篇。
  • 使用短句或中等长度的句子,每句表达一个核心观点。
  • 当调用者无需了解Astro内部术语时,避免使用。若必须使用技术术语,请在同一段落中解释。
  • 描述调用者可能会感到意外的可见注意事项:回退行为、工作限制、模糊结果、重载顺序、副作用,以及返回
    undefined
    null
    、空结果或其他不确定值的条件。
  • 当期望调用者区分或从错误中恢复时,需记录抛出的错误。
  • 除非调用者需要了解实现细节才能理解行为或安全使用API,否则请勿描述实现细节。
当行为依赖于签名无法清晰展示的关系时,请添加示例。Astro和TypeScript中的常见场景包括:
  • 选择哪个重载;
  • 参数如何映射到可选参数或剩余参数;
  • 哪个公开的Astro入口点暴露了在其他地方实现或重新导出的符号;
  • 模糊路由、不完整配置或缺失内容的回退行为;
  • 类型无法体现其含义的结果。
在代码块前用 prose 介绍示例,说明示例展示的内容和预期结果。保持代码片段简洁、独立,并从Astro用户或拥有合约的内部调用者的角度编写。
模块文档应描述持久的概念、架构边界或设计原因。请勿仅为总结文件而列出单个导出项;此类清单会随着符号的添加或重命名而过时。如果模块没有需要解释的持久概念,请使用简短的单行描述或不添加概述。

The Deletion Test

删除测试

Before writing any comment, ask: does this state something the reader cannot recover from the code itself?
  • If the information is already carried by names, types, or structure, do not write the comment. If the name fails to carry it, improve the name.
  • Information that legitimately needs a comment: an invariant, a rationale, a coupling to code elsewhere, a workaround with a link, surprising behavior of a dependency, a term of art the module defines.
When editing later, the same test applies in reverse: a comment that no longer passes it should be deleted, not left to rot.
编写任何注释前,请自问:这条注释所陈述的信息是读者无法从代码本身中获取的吗?
  • 如果信息已通过命名、类型或结构体现,则无需编写注释。如果命名未能体现,请改进命名。
  • 确实需要注释的信息:不变量、设计思路、与其他代码的耦合关系、带链接的临时解决方案、依赖项的意外行为、模块定义的专业术语。
后续编辑时,同样适用反向测试:不再通过测试的注释应删除,而非保留至过时。

Link to the Issue for Workarounds

临时解决方案需链接Issue

This codebase consistently anchors workarounds to a source. Any comment that explains a workaround, a
HACK
, a regression guard, or surprising behavior of a dependency must link the GitHub issue or PR that motivates it. The link is what lets a future reader tell whether the workaround is still needed.
ts
// Handle recommended nanostores. Only @nanostores/preact is required from our testing!
// Full explanation and related bug report: https://github.com/withastro/astro/pull/3667
'@nanostores/preact',
A workaround with no link is indistinguishable from a mistake.
本代码库始终为临时解决方案锚定来源。任何解释临时解决方案、
HACK
、回归防护或依赖项意外行为的注释必须链接相关的GitHub Issue或PR。链接能让未来的读者判断该临时解决方案是否仍有必要。
ts
// 处理推荐的nanostores。根据我们的测试,仅需@nanostores/preact!
// 完整说明及相关Bug报告:https://github.com/withastro/astro/pull/3667
'@nanostores/preact',
没有链接的临时解决方案与错误代码无法区分。

Banned Patterns

禁用模式

Narrating the next line. Delete these on sight:
ts
// Increment the generation counter
generation += 1;
Change-history narration. Rewrite as present-tense rationale:
ts
// BAD: We now resolve lightningcss from the user's root instead of ours.
// GOOD: lightningcss is an optional peer dep, so it resolves from the user's project root.
Reviewer-addressed justification. Move the argument to the PR:
ts
// BAD: This correctly handles the multi-encoded path from the bug report.
// GOOD: A path still encoded after MAX_DECODE_ITERATIONS is rejected, so
//       middleware and routing can never disagree on the decoded path.
Restated JSDoc. A
/** */
block that rewords the declaration name says nothing:
ts
// BAD:
/** Compiles the styles. */
function compileStyles(...)

// GOOD:
/** Rewrites relative `url()` references in `css` against `base`, leaving
 *  absolute and data URLs untouched. */
function compileStyles(...)
Vague hedging. "Some cases", "various reasons", "handles edge cases", "etc." — either name them or drop the sentence.
Emojis. Banned in source, comments included (repo-wide policy).
Ad-hoc section banners (
// ----- helpers -----
,
// ==== TYPES ====
). This codebase has no
// #region
folding convention; do not add banners. If a file is long enough that you reach for one, that is a signal to split the file, not to decorate it.
叙述下一行代码。看到此类注释请直接删除:
ts
// 递增生成计数器
generation += 1;
叙述变更历史。改写为现在时态的原理说明:
ts
// 错误示例:我们现在从用户根目录而非我们的目录解析lightningcss。
// 正确示例:lightningcss是可选的peer依赖,因此从用户项目根目录解析。
针对评审者的辩护内容。将论点移至PR描述中:
ts
// 错误示例:这能正确处理Bug报告中的多重编码路径。
// 正确示例:经过MAX_DECODE_ITERATIONS后仍编码的路径会被拒绝,因此中间件和路由永远不会对解码路径产生分歧。
重复JSDoc内容。仅重述声明名称的
/** */
块毫无意义:
ts
// 错误示例:
/** 编译样式。 */
function compileStyles(...)

// 正确示例:
/** 将css中相对的`url()`引用根据`base`重写,绝对URL和data URL保持不变。 */
function compileStyles(...)
模糊的措辞。“某些情况”“各种原因”“处理边缘情况”“等等”——要么明确说明,要么删除句子。
表情符号。源码(包括注释)中禁用(仓库全局政策)。
临时章节横幅
// ----- helpers -----
// ==== TYPES ====
)。本代码库没有
// #region
折叠约定;请勿添加横幅。如果文件长到需要使用横幅,这是拆分文件的信号,而非装饰文件。

Conventions in This Codebase

本代码库约定

JSDoc tags.
@param name - description
,
@returns
, and
@throws
state the contract. Brace-wrap a type (
@returns {Promise<string>}
) only when the signature alone is ambiguous. Use
@example
with a fenced
```js
block for non-obvious usage.
Cross-references. Use
{@link Symbol}
/
{@linkcode Symbol}
rather than a bare name, so a rename updates the reference and editors can jump to the target.
@internal
.
Marks API that is not part of the public surface. It is a convention only — there is no typedoc or api-extractor here to strip it — so it documents intent but does not replace access modifiers.
@deprecated
.
State the migration, then the removal horizon:
ts
/** @deprecated Use the instance method `cookies.consume()` instead. This will be removed in Astro 7 */
Say what to use instead, not merely that the symbol is deprecated. This future-tense note is contract information the reader needs, not banned change-history narration.
TODO. Use
// TODO:
for deferred work; link an issue when one tracks it. For work gated on a breaking-change window, use the established idiom
// TODO: remove in Astro <N>
. There is no
FIXME
in this codebase — do not introduce it.
JSDoc标签
@param name - description
@returns
@throws
用于声明合约。仅当签名本身不明确时,才用大括号包裹类型(
@returns {Promise<string>}
)。对于非直观用法,使用
@example
并搭配 fenced
```js
块。
交叉引用。使用
{@link Symbol}
/
{@linkcode Symbol}
而非裸名,这样重命名时引用会自动更新,编辑器也能跳转到目标位置。
@internal
。标记不属于公共接口的API。这只是一个约定——此处没有typedoc或api-extractor来剥离它——因此它仅用于记录意图,不能替代访问修饰符。
@deprecated
。说明迁移方案,然后标记移除版本:
ts
/** @deprecated 改用实例方法`cookies.consume()`。此API将在Astro 7中移除 */
请说明替代方案,而非仅标记符号已废弃。这个未来时态的说明是读者需要的合约信息,不属于禁用的变更历史叙述。
TODO。使用
// TODO:
标记待完成工作;如有相关Issue,请附带链接。对于需在重大变更窗口处理的工作,请使用既定写法
// TODO: remove in Astro <N>
。本代码库中没有
FIXME
——请勿引入。

Editing Existing Code

编辑现有代码

  • Preserve existing comments. If your change alters behavior, extend or correct the specific prose — never replace it with generic text. Deleting hard-won context is worse than leaving a comment slightly stale.
  • When your change makes a comment false, fix it in the same diff. A stale comment is worse than none.
  • Match the surrounding density. A heavily documented module deserves the same level on new items; do not blanket a sparse module with comments.
  • 保留现有注释。如果你的变更改变了行为,请扩展或修正特定内容——切勿替换为通用文本。删除来之不易的上下文比保留略有过时的注释更糟糕。
  • 当你的变更使注释失效时,请在同一个diff中修复它。过时的注释比没有注释更糟糕。
  • 匹配周围的注释密度。注释丰富的模块在新增条目时应保持相同的注释水平;请勿在注释稀疏的模块中批量添加注释。

Self-Check Before Finishing

完成前的自我检查

After completing any task that touched comments, re-read only the comments in your diff, in isolation from the code changes:
  1. Does each one pass the deletion test?
  2. Does any reference the conversation, the change itself, or the reviewer?
  3. Does every workaround link its issue or PR?
  4. Would a reader without access to the diff understand each one?
Fix or delete what fails. Deletion is the default; a missing comment is cheaper than a misleading one.
完成任何涉及注释的任务后,请单独重新阅读你diff中的所有注释,脱离代码变更本身:
  1. 每条注释都通过删除测试了吗?
  2. 是否有注释提及对话、变更本身或评审者?
  3. 每个临时解决方案都链接了相关Issue或PR吗?
  4. 没有diff上下文的读者能理解每条注释吗?
修复或删除未通过检查的内容。默认选择删除;缺少注释比误导性注释的代价更低。

References

参考资料

  • Diátaxis — the framework behind the explanation / reference / rationale split above.
  • packages/astro/src/core/errors/README.md
    — for
    @docs
    -tagged error entries, which are end-user documentation.
  • TSDoc — the tag reference for TypeScript doc comments.
  • Diátaxis——上述“解释/参考/原理”划分背后的框架。
  • packages/astro/src/core/errors/README.md
    ——针对标记了
    @docs
    的错误条目,属于终端用户文档。
  • TSDoc——TypeScript文档注释的标签参考。