dartdoc-conventions
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDartdoc Conventions — the public surface is a contract
Dartdoc 规范——公开 API 就是契约
Public code is read far more than it is written. A symbol with no leading is a contract callers depend on, so it carries a doc a reader understands without opening the body. Doc comments use and follow Effective Dart: Documentation. Applies whenever you add or change a public declaration, or write an in-body comment.
_////////公共代码被阅读的次数远多于被编写。一个不以 开头的符号就是调用方所依赖的契约,因此必须带有 文档,让读者无需查看实现即可理解。文档注释使用 ,并遵循 Effective Dart: Documentation。每当新增或修改公开声明,或编写函数体内的 注释时,都应遵循此规范。
_////////Non-negotiable rules
不可妥协的规则
- Every public declaration gets a doc — public classes, constructors, methods, getters, top-level functions, typedefs, and fields.
///is an error with no "obvious member" exemption: it flags every undocumented public member, so a missing doc fails the build. Making a symbol public "just in case" is a review reject — make itpublic_member_api_docs-private instead so it needs no doc and no contract._ - , never
///. Dartdoc only recognizes/** */. A JavaDoc block is silently ignored and the symbol reads as undocumented.///flags it.slash_for_doc_comments - First line is one standalone sentence ending in a period, in its own paragraph. Tools show only this sentence in API lists, so it must stand alone; a blank line separates it from the body.
/// - Method/function docs start with a verb phrase (third person): "Returns…", "Schedules…", "Loads…", "Marks…". A boolean getter or -returning method starts with "Whether…".
bool - Never restate the name. on
/// The name.,String nameon/// Returns the total.— banned. If a public member has nothing to add beyond its name, that is the signal to make ittotal()-private (a private member needs no doc, so the tension disappears). A member that must stay public still needs a real_— never leave it public-and-undocumented; add meaning: units, ranges, nullability, throws, side effects, and the invariant the symbol enforces./// - Cross-link identifiers in so dartdoc resolves them:
[brackets]/// Throws [StateError] if [id] is unknown; see [copyWith].warns on a broken link.comment_references - In-body explains why, never what. The code already says what. Narrating comments (
//) rot out of sync and become misinformation. Comment the reason, the gotcha, or the invariant.// loop over items - Restate an enforced invariant at its enforcement point. Where one line upholds a guarantee — an ordering, a clamp, a persist-before-publish, a canonical-unit conversion — a terse states it so a diff that weakens it gets an unmissable flag. Same for a magic constant: cite where the number comes from.
// - Docs change in the same diff as the code. A wrong doc is worse than none. Every comment your change touches must still be true — put it on the PR checklist.
- One library doc per exported barrel. The public entry point (e.g. ) gets a
my_package.dartlibrary doc above the///directive.library;is an error — a leadingdangling_library_doc_commentswith no attached declaration must be a real library doc, not an orphan above a blank line or an///.export
- 每个公开声明都要有 文档——包括公开的 class、构造函数、方法、getter、顶层函数、typedef 和 field。
///是 error,不存在所谓“显而易见的成员”豁免:它会标记每一个未写文档的公开成员,因此缺少文档就会导致构建失败。以“万一以后需要”为由将符号设为 public 会在审查中被拒绝——应改为使用public_member_api_docs设为私有,这样既不需要文档,也不构成契约。_ - 始终使用 ,绝不使用
///。 Dartdoc 只识别/** */。JavaDoc 风格的代码块会被静默忽略,导致该符号看起来没有文档。///会标记此类问题。slash_for_doc_comments - 首行是单独成句、以句号结尾的一句话,并独占一个段落。 工具在 API 列表中只显示这句话,因此它必须能够独立成立;用一行空白的 将其与正文分隔开。
/// - 方法/函数文档以动词短语(第三人称)开头,例如“返回…”、“调度…”、“加载…”、“标记…”。布尔 getter 或返回 的方法以“Whether…”开头。
bool - 绝不复述名称。 上的
String name、/// The name.上的total()都被禁止。如果某个公开成员除了名称之外没有可补充的信息,就应将其设为/// Returns the total.私有(私有成员无需文档,于是这一矛盾自然消失)。必须保持公开的成员仍需提供真实的_文档——绝不能让它处于“公开但无文档”的状态;应补充实际含义:单位、范围、可空性、抛出的异常、副作用,以及该符号所强制的不变量。/// - 使用 交叉链接标识符,以便 dartdoc 能够解析:
[方括号]/// Throws [StateError] if [id] is unknown; see [copyWith].会对断链发出警告。comment_references - 函数体内的 注释解释为什么,绝不解释做什么。 代码本身已经说明了做什么。叙述性注释(
//)会逐渐与代码不同步,最终变成错误信息。应该注释原因、陷阱或不变量。// loop over items - 在执行点重申所强制的不变量。 当某一行代码维持某项保证——例如顺序、clamp、先持久化后发布、规范单位转换——应使用简洁的 说明这一点,使削弱该保证的 diff 一眼就能被发现。魔法常量也应如此:注明数字来源。
// - 文档与代码在同一个 diff 中一起修改。 错误的文档比没有文档更糟。你改动到的每条注释都必须仍然属实——将其加入 PR 检查清单。
- 每个导出的 barrel 只有一个库文档。 公开入口(例如 )应在
my_package.dart指令上方添加library;库文档。///是 error——位于空行或dangling_library_doc_comments上方、没有附着到任何声明的前导export,必须是真正的库文档,而不能是悬空注释。///
Documenting a value type
为 value type 编写文档
dart
/// A note the user has authored and can later edit or archive.
///
/// Immutable; derive changes with [copyWith]. [updatedAt] is UTC and never
/// precedes [createdAt].
class Note {
/// Creates a note; [updatedAt] must not precede [createdAt].
const Note({
required this.id,
required this.title,
required this.createdAt,
required this.updatedAt,
});
/// Stable unique identifier, assigned once at creation.
final String id;
/// Human-readable heading shown in lists; may be empty, never null.
final String title;
/// Creation instant, in **UTC**.
final DateTime createdAt;
/// Last-edit instant, in **UTC**; equals [createdAt] until first edited.
final DateTime updatedAt;
/// Returns a copy with the given fields replaced.
Note copyWith({String? title, DateTime? updatedAt}) => Note(
id: id,
title: title ?? this.title,
createdAt: createdAt,
updatedAt: updatedAt ?? this.updatedAt,
);
}Every public field carries a , including — under the enforced a field that "restates the name" is not a licence to drop the doc but a prompt to say something real (or make the field -private). Document units and constraints explicitly where the type does not carry them: minor currency units, a – hour, an inclusive/exclusive range, what means, "must be ".
///titlepublic_member_api_docs_023null> 0dart
/// A note the user has authored and can later edit or archive.
///
/// Immutable; derive changes with [copyWith]. [updatedAt] is UTC and never
/// precedes [createdAt].
class Note {
/// Creates a note; [updatedAt] must not precede [createdAt].
const Note({
required this.id,
required this.title,
required this.createdAt,
required this.updatedAt,
});
/// Stable unique identifier, assigned once at creation.
final String id;
/// Human-readable heading shown in lists; may be empty, never null.
final String title;
/// Creation instant, in **UTC**.
final DateTime createdAt;
/// Last-edit instant, in **UTC**; equals [createdAt] until first edited.
final DateTime updatedAt;
/// Returns a copy with the given fields replaced.
Note copyWith({String? title, DateTime? updatedAt}) => Note(
id: id,
title: title ?? this.title,
createdAt: createdAt,
updatedAt: updatedAt ?? this.updatedAt,
);
}每个公开 field 都必须带有 文档,包括 ——在启用的 下,field“复述名称”并不是省略文档的许可,而是提示你应当说明真实信息(或将 field 设为 私有)。当类型本身无法表达这些约束时,应明确记录单位和约束:辅币单位、– 小时、包含/不包含的边界范围、 的含义、“必须 ”等。
///titlepublic_member_api_docs_023null> 0Documenting behavior — throws, async, side effects
记录行为——异常、异步与副作用
dart
/// Schedules a reminder for [task] at [when].
///
/// [when] must be in the future; a past instant is clamped to now. Persists the
/// scheduled row before arming the OS notification, so a crash mid-call cannot
/// leave a notification the store never recorded.
///
/// Throws [PermissionDeniedException] if the OS denied notification permission.
Future<void> scheduleReminder(Task task, DateTime when) async {
// persist-before-arm: the store is the source of truth, the OS mirrors it
await _store.saveScheduled(task.id, when);
await _plugin.schedule(task.id, when);
}State async behavior, what a method writes or mutates, and every exception it can throw. If a function is total (returns for every input, never throws), say so — it is a real guarantee callers rely on.
dart
/// Schedules a reminder for [task] at [when].
///
/// [when] must be in the future; a past instant is clamped to now. Persists the
/// scheduled row before arming the OS notification, so a crash mid-call cannot
/// leave a notification the store never recorded.
///
/// Throws [PermissionDeniedException] if the OS denied notification permission.
Future<void> scheduleReminder(Task task, DateTime when) async {
// persist-before-arm: the store is the source of truth, the OS mirrors it
await _store.saveScheduled(task.id, when);
await _plugin.schedule(task.id, when);
}应说明异步行为、方法会写入或改变什么,以及所有可能抛出的异常。如果函数是 total(对任何输入都有返回且从不抛出异常),也应明确说明——这是调用方依赖的真实保证。
Library docs and the exported barrel
库文档与导出的 barrel
dart
/// Pure-Dart domain core: value types, typed failures, and total functions.
///
/// No Flutter, Riverpod, or `dart:io` import — this purity is what lets the
/// core be unit-tested without a widget harness and reused across platforms.
library;
export 'src/note.dart';
export 'src/task.dart';The attaches to the directive. Never leave a dangling above an or a blank line.
///library;///exportdart
/// Pure-Dart domain core: value types, typed failures, and total functions.
///
/// No Flutter, Riverpod, or `dart:io` import — this purity is what lets the
/// core be unit-tested without a widget harness and reused across platforms.
library;
export 'src/note.dart';
export 'src/task.dart';///library;///exportRestating the invariant at the enforcement point
在执行点重申不变量
Where a symbol enforces a rule, document the rule as part of its contract and pin it in-body at the one line that upholds it:
dart
/// Failure modes of a checkout. Switched exhaustively by the caller, so a new
/// case is a compile error at every call site.
sealed class CheckoutFailure {
/// Const base constructor, so subclasses can be `const`.
const CheckoutFailure();
}
/// The account balance was below the order total; no charge was made.
final class InsufficientFunds extends CheckoutFailure {
/// Creates an [InsufficientFunds] failure.
const InsufficientFunds();
}
/// Read-only view of the current order; mutated only through this notifier.
class OrderNotifier extends Notifier<Order> {
Order build() => Order.empty();
/// Adds [item] and recomputes the total.
///
/// Persists via the repository before emitting, so a mid-write crash cannot
/// surface a line the store never saw.
Future<void> addItem(Item item) async {
// persist-before-emit: emitted state is always a state the store holds
await _repository.append(item);
state = state.withItem(item);
}
}当符号强制执行某项规则时,应将该规则作为契约的一部分记录下来,并在维持该规则的那一行代码中用函数体注释加以固定:
dart
/// Failure modes of a checkout. Switched exhaustively by the caller, so a new
/// case is a compile error at every call site.
sealed class CheckoutFailure {
/// Const base constructor, so subclasses can be `const`.
const CheckoutFailure();
}
/// The account balance was below the order total; no charge was made.
final class InsufficientFunds extends CheckoutFailure {
/// Creates an [InsufficientFunds] failure.
const InsufficientFunds();
}
/// Read-only view of the current order; mutated only through this notifier.
class OrderNotifier extends Notifier<Order> {
Order build() => Order.empty();
/// Adds [item] and recomputes the total.
///
/// Persists via the repository before emitting, so a mid-write crash cannot
/// surface a line the store never saw.
Future<void> addItem(Item item) async {
// persist-before-emit: emitted state is always a state the store holds
await _repository.append(item);
state = state.withItem(item);
}
}Anti-patterns
反模式
- — dartdoc ignores it; the symbol reads as undocumented and fails
/** JavaDoc-style */.public_member_api_docs - Restating the name — on
/// Gets the id.. Delete it or add units/ranges/invariants.String get id - A paragraph before the one-sentence summary — the first sentence must stand alone in list views.
- Narrating mechanics in-body — ,
// loop over items. Explain why, or delete.i++ // increment - A magic constant with no source — a bare for a cap with no comment saying where the number is defined.
3 - Stale docs describing pre-refactor parameters, or an invariant comment left on code that no longer honors it.
- Commented-out code "just in case" — git remembers. with no owner or issue link — write
// TODOor nothing.// TODO(name): reason - Documenting private trivia while a public method sits undocumented.
- A dangling above a blank line or an
///— failsexport.dangling_library_doc_comments - Banner / ASCII-art comment dividers that bloat files; rely on structure and naming.
- ——dartdoc 会忽略它;该符号会显示为未写文档,并触发
/** JavaDoc 风格 */。public_member_api_docs - 复述名称——上的
String get id。应删除它,或补充单位/范围/不变量。/// Gets the id. - 在单句摘要之前添加段落——首句在列表视图中必须能够独立成立。
- 在函数体内叙述实现过程——、
// loop over items。应解释为什么,否则直接删除。i++ // increment - 没有来源的魔法常量——例如用裸写的 表示上限,却没有注释说明这个数字定义在哪里。
3 - 过时的文档——描述重构前的参数,或不变量注释所对应的代码已不再满足该不变量。
- 注释掉的代码——“以防万一”——会一直保留它。没有负责人或 issue 链接的
git——应写成// TODO,否则不要写。// TODO(name): reason - 记录无关紧要的私有细节,同时却让某个公开方法没有文档。
- 悬空的 ——位于空行或
///上方,会触发export。dangling_library_doc_comments - Banner / ASCII-art 注释分隔符——只会让文件膨胀;应依靠结构和命名。
Definition of done
完成标准
- Every public declaration in the touched code has a doc; first line is a standalone sentence ending in a period.
/// - Method/function docs start with a verb; boolean getters start with "Whether".
- Units, ranges, nullability, throws/, and side effects documented where they exist.
Result - Identifiers cross-linked with ; no broken
[brackets].comment_references - Enforced invariants restated at their enforcement points; magic constants cite their source.
- No restated-name docs, no narrating , no commented-out code, no ownerless TODO, no JavaDoc blocks.
// - Each exported barrel has a doc; no dangling doc comments.
library; - Every comment the diff touched is still true.
- clean;
dart analyze --fatal-infos --fatal-warningsgenerates without warnings for packages.dart doc
- 所有被改动代码中的每个公开声明都有 文档;首行是单独成句并以句号结尾的一句话。
/// - 方法/函数文档以动词开头;布尔 getter 以“Whether”开头。
- 在存在相关约束时,记录单位、范围、可空性、抛出的异常/和副作用。
Result - 标识符使用 交叉链接;不存在失效的
[方括号]。comment_references - 在执行点重申所强制的不变量;魔法常量注明来源。
- 不存在复述名称的文档、叙述实现的 、被注释掉的代码、没有负责人的 TODO 或 JavaDoc 代码块。
// - 每个导出的 barrel 都有 文档;不存在悬空文档注释。
library; - diff 改动到的每条注释都仍然属实。
- 检查通过;对于 package,
dart analyze --fatal-infos --fatal-warnings生成文档时无警告。dart doc
Related skills
相关 skill
- See for wiring
lint-and-style-config,public_member_api_docs, anddangling_library_doc_commentsas analyzer errors.comment_references - See for the role-suffix names (
naming-conventions/Notifier/Repository/Service) these docs describe.Failure - See for the sealed-type and total-function guarantees the docs promise.
dart3-idioms-and-coding-standards - See for the
error-handling-typed-results/Resultcontract a method doc must state.Failure
- 参阅 ,了解如何将
lint-and-style-config、public_member_api_docs和dangling_library_doc_comments配置为 analyzer error。comment_references - 参阅 ,了解这些文档所描述的角色后缀命名(
naming-conventions/Notifier/Repository/Service)。Failure - 参阅 ,了解文档所承诺的 sealed type 和 total function 保证。
dart3-idioms-and-coding-standards - 参阅 ,了解方法文档必须说明的
error-handling-typed-results/Result契约。Failure
References
参考资料
- Effective Dart: Documentation
- tool
dart doc - Linter rules — ,
public_member_api_docs,dangling_library_doc_comments,comment_referencesslash_for_doc_comments - Developing packages & plugins
- Effective Dart: Documentation
- 工具
dart doc - Linter 规则——、
public_member_api_docs、dangling_library_doc_comments、comment_referencesslash_for_doc_comments - 开发 package 与 plugin