- 编程语言
- 编译器
- 语言运行时
- 标准库
- 开发工具
【免费下载链接】sdk
The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
lint 生命周期(lint lifecycle)是 Dart SDK 中pkg/linter包用来管理每一条 lint 规则成熟度与可见性的核心机制:每一条规则都有且仅有一个当前状态,同时它的全部状态变迁历史都会被记录在pkg/linter/messages.yaml中。本文以 lint-lifecycle.md 为骨架,结合pkg/analyzer中的RuleState实现、pkg/linter的规则源码与生成工具,系统讲解 lint 从提案、实验、稳定、废弃到移除的完整生命周期,帮助 SDK 贡献者理解状态语义,也帮助使用 lint 的开发者判断某条规则的可靠性等级。
生命周期总览:状态即契约
每一条在pkg/linter中实现的 lint 规则都有一个状态(state),它同时描述两件事:
- 成熟度(maturity):规则的语义、实现与测试完备到什么程度;
- 是否公开可见(publicly visible):规则是否面向所有 Dart/Flutter 用户暴露、是否会出现在 IDE 的补全建议与官方文档中。
一个 lint 的当前状态写在其实现文件里(通过LintRule/AnalysisRule的super构造调用指定),而它的完整状态历史则记录在 pkg/linter/messages.yaml 中——这保证了后人可以追溯"这条规则是什么时候变的 stable、什么时候被 deprecated"。
需要注意的是,lint 在被实现之前还要走一段提案(proposal)流程,而提案阶段并不以状态形式记录,也就是说:提案 → 接受这一过程发生在代码之外,只有进入实现后的状态才落在messages.yaml与源码里。
实现之前:Proposed 与 Accepted
Proposed(提案中)
一条 lint 的生命始于一份提案(proposal)。提案的状态是pending,即等待 Dart developer experience 团队(devexp 团队)的裁决。这一阶段不写入任何状态字段,对应仓库中也看不到对应的规则文件。
Accepted(已接受)
经过团队讨论并取得充分共识后,提案被接受(accepted),规则随即进入"待实现"状态。从这一步开始,规则才会以源码、测试与messages.yaml条目的形式进入仓库。
一个重要的工程约定:任何落地一条新的、公开可用lint 的变更(change),都应当附带对应的CHANGELOG条目——这一点在 pkg/linter/CHANGELOG.md 中持续累积,也是 reviewer 检查新规则提交的硬性关注点。
公开状态(Public states):Experimental / Stable / Deprecated / Removed
处在这四种状态的 lint 都是公开可用且有文档的。它们之间的区别在于稳定程度、变更风险与维护承诺。
Experimental(实验性)
实验性 lint 允许公开使用,但随时可能被移除或变更,且不会提前通知。文档 lint-lifecycle.md 明确列举了规则处于 experimental 的典型原因:
- 试探性地引入(tentatively introduced);
- 价值尚不确定(unknown value);
- 语义不完整(incomplete semantics);
- 存在已知但可修复的误报(outstanding but fixable false positives);
- 已知只是临时存在(known to be temporary)。
实验性状态不是终点,规则应当"以成为 stable 为目标"。一条 experimental lint 在满足以下条件时可以视为 stable 的候选:
- 语义完整(complete semantics);
- 实现完整且没有已知误报(no known false positives);
- 已被证明有长期价值——例如某个核心 lint 集(core lint set)正在考虑将其纳入。
从源码可以看到当前仍处于 experimental 的规则,例如 annotate_redeclares.dart 与 implicit_reopen.dart 都以const RuleState.experimental()声明状态。
Stable(稳定)
稳定 lint 公开可用,通常测试与文档都比较完善,并且"未经通知就移除或变更"的可能性大大降低。稳定状态意味着:
- 规则的语义与实现被视为完整(complete);
- 误报属于 bug,除非是已知且被文档记录的局限(known and documented limitations),修复误报应被优先处理;
- 漏报(false negatives)可能是 bug 也可能是增强,具体取决于该 lint 的语义定义。
稳定 lint 有可能被纳入核心规则集(core rule sets,例如官方package:lints推荐集)。同时,一条稳定 lint在移除前通常应先经历 deprecated 阶段——除非它在任何受支持的语言版本下都不再相关或不再有效。
仓库中通过RuleState.stable(since: Version(...))指定稳定状态及其起始 SDK 版本,例如 omit_obvious_local_variable_types.dart 与 specify_nonobvious_local_variable_types.dart 都以Version(3, 11, 0)为稳定起始版本。
Deprecated(已废弃)
Deprecated 意味着规则已计划在 SDK 的某个未来版本中被移除。文档列出的废弃原因包括:
- 语义与当前语言语义不再契合,例如null safety 之后变得没有意义的规则;
- 建议已过时(stale advice);
- 性能不佳(poor performance);
- 开发者体验差,例如误报过多;
- 生态中使用不足或价值不足(insufficient usage or value)。
文档特别提醒:废弃一条常见 lint 集(如package:lints)中的规则影响面很大,必须谨慎行事。废弃后的 lint仍然公开可见、仍然有文档——这正是为了让用户能够了解"为什么废弃、改用哪个替代规则"。
废弃变更同样要求CHANGELOG条目。
仓库中的典型示例是 prefer_final_parameters.dart,它以RuleState.deprecated(since: Version(3, 11, 0))声明从 3.11.0 起废弃;同批的 avoid_null_checks_in_equality_operators.dart 也是如此。
Removed(已移除)
Removed 意味着规则不再被实现、也不再受支持。这个状态专门用于曾经公开可用的规则;而那些从未公开、仅用于内部或测试的规则不需要经历 removed 状态(详见下文私有状态)。
一般情况下,移除之前会先经历一段废弃期(deprecation)。移除一条公开可用 lint 的变更同样需要CHANGELOG条目。
在代码层面,removed 状态由RuleState.removed(since: Version(...))表示。需要注意的是,源码 rule_state.dart 中该构造函数已被标记为@Deprecated('Use RemovedAnalysisRule instead')——从代码结构可以看出,新的实现方式是通过RemovedAnalysisRule来声明已移除规则,但状态历史仍完整保留在messages.yaml中。writing-lints.md中给出了一个典型的状态历史示例(writing-lints.md):
package_api_docs: # ... state: stable: "2.0" deprecated: "3.6" removed: "3.7"这正体现了"实现文件只写当前状态、messages.yaml记录完整历史"的约定:从 2.0 稳定,3.6 废弃,3.7 移除,一目了然。
私有状态(Private states):Internal / Testing
处于这两种状态的 lint不应出现在面向用户的工具补全建议中,也不应被公开文档化。它们服务于 SDK 自身或测试流程,普通用户不会也不应依赖它们。
Internal(内部)
Internal lint仅供 Dart SDK 内部使用。它们被移除时不需要迁移到 removed 状态——代码与配套文档直接删除即可,因为它们从未对公众承诺过任何稳定性。
仓库中的实例包括 analyzer_public_api.dart、analyzer_element_model_tracking.dart 以及 erase_dart_type_extension_types.dart,均以const RuleState.internal()声明。在messages.yaml中它们则记录为internal: "3.10"之类的历史版本信息。
Testing(测试)
Testing lint 是仅供内部测试使用的临时规则。它的使用范围不限于 Dart SDK(其他测试环境也可以引用),但没有任何稳定性保证,也不面向公开使用。
文档给出了两条硬性约定:
- lint不应无限期停留在 testing 状态;
- 测试完成后,规则必须被移除,或升格到其他状态(graduated)。
同样地,testing 规则被移除时不需要经过 removed 状态,代码与文档可直接删除。在RuleState的实现中(rule_state.dart),testing 状态被描述为 "experimental, temporary, and have no stability guarantees",与文档语义完全吻合。
状态在代码中的落地:三处记录、一份生成产物
理解生命周期后,可以沿着仓库源码看清状态机制的真实实现。规则状态在pkg/linter中一共有三个落点:
1. 类型定义:RuleState(rule_state.dart)
RuleState是pkg/analyzer中定义的final class,提供了与六种状态一一对应的命名构造函数:
| 构造函数 | 语义 | 额外字段 |
|---|---|---|
RuleState.deprecated | 已废弃 | since(起始版本)、replacedBy(替代规则名) |
RuleState.experimental | 实验性 | since |
RuleState.internal | 仅 SDK 内部 | since |
RuleState.removed | 已移除(已弃用,改用RemovedAnalysisRule) | since、replacedBy |
RuleState.stable | 稳定 | since |
RuleState.testing | 内部测试 | since |
每个构造函数还对应一个只读判断属性(isDeprecated、isExperimental、isInternal、isRemoved、isStable、isTesting)以及用于文档展示的label。注意since是可选的Version类型——它记录的是该状态起始的 Dart 版本,这正是"当前状态 + 历史版本"信息模型的基础。
2. 实现文件:当前状态(pkg/linter/lib/src/rules)
每条规则的实现文件中,super构造调用只指定最新的状态。例如:
PackageApiDocs() : super( name: LintNames.package_api_docs, description: _desc, state: State.removed(since: Version(3, 7, 0)), );3. 元数据文件:完整历史(pkg/linter/messages.yaml)
messages.yaml中的state字段按从旧到新的顺序列出全部历史状态,并附带每个状态的起始版本号。该文件头部注释也给出了编辑后的必做步骤(messages.yaml):
dart run pkg/linter/tool/generate_lints.dart dart run pkg/analyzer/tool/messages/generate.dart其中generate_lints.dart负责重新生成LintNames与LinterLintCode静态访问器,machine.dart(dart run pkg/linter/tool/machine.dart -w)负责更新旧的rules.json机器可读清单(位于 pkg/linter/tool/machine/rules.json)。writing-lints.md中还有专门的 Generating docs 章节强调:修改messages.yaml或 super 构造信息后,必须重新生成相关文件,保证产物与元数据一致。
状态迁移的实战建议与测试保障
综合文档与源码,可以总结出几条可供 SDK 贡献者直接遵循的迁移路径:
- 提案先行:先提交提案,等 devexp 团队接受后再动手实现,避免把未接受的想法直接写成代码。
- 新规则从 experimental 起步:语义未定、可能误报时保持 experimental;补齐语义与实现、确认无已知误报、看到长期价值(如被核心 lint 集考虑)后再提升为 stable。
- 废弃要有充分理由:语义过时(如 null safety 之后)、建议过时、性能差、误报过多、生态价值不足——这些都是文档认可的废弃依据;废弃常见 lint 集中的规则要格外谨慎,因为影响面大。
- 移除前先废弃:一般流程是 stable → deprecated → removed,只有规则在所有受支持语言版本下都不再相关时,才可跳过废弃直接移除。
- private 状态可以"原地删除":internal 与 testing 规则不需要走 removed 状态,删除代码与文档即可,但要遵守"testing 不得长期滞留"的约定。
- 每次状态变更都要写 CHANGELOG:新增、废弃、移除公开 lint 的变更都必须附带 pkg/linter/CHANGELOG.md 条目。
仓库为这些状态语义还提供了配套的校验测试:例如 test/rules/analyzer_public_api_test.dart 等针对 internal 规则的测试、以及 verify_generated_files_test.dart 这类验证生成产物与元数据一致性的测试。运行 linter 全部测试的方式在 writing-lints.md 中有说明:
dart run pkg/linter/test/all.dart由于 linter 与pkg/analyzer、pkg/analysis_server紧密耦合,涉及这两处的改动还应运行:
dart run pkg/analyzer/test/test_all.dart dart run pkg/analysis_server/test/test_all.dart小结
lint 生命周期本质上是 Dart 团队对"一条规则从想法到退休"的全过程治理:提案(Proposed)→ 接受(Accepted)→ 实验(Experimental)→ 稳定(Stable)→ 废弃(Deprecated)→ 移除(Removed)构成公开规则的主干演进路径,而Internal与Testing则划定了 SDK 内部与测试用规则的私有边界。对贡献者而言,理解这套状态机意味着知道"何时该把规则定为 experimental、何时可以升 stable、废弃与移除各有什么前提、CHANGELOG 何时必须更新";对使用者而言,官方文档与messages.yaml中的状态历史就是判断一条 lint 可靠性最直接的依据——stable可以放心纳入核心规则集,experimental则要接受"可能随时变更或移除"的风险。
- 编程语言
- 编译器
- 语言运行时
- 标准库
- 开发工具
【免费下载链接】sdk
The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
相关推荐
OpenSandbox OSEP 提案流程完全指南:从 init-osep.sh 到状态生命周期
OpenSandbox OSEP 提案流程完全指南:从 init osep.sh 到状态生命周期 OpenSandbox 采用 OSEP(OpenSandbox
人工智能AI 应用Agent 沙箱云原生后端代码智能体编写 Dart Linter 规则(Writing Lints):Dart SDK 内置 Linter 规则开发的完整指南
编写 Dart Linter 规则(Writing Lints):Dart SDK 内置 Linter 规则开发的完整指南 引言 pkg/linter/doc/
编程语言编译器语言运行时标准库开发工具JupyterLab 版本生命周期(Version Lifecycle)完全指南:维护期规则、支持状态与升级规划
JupyterLab 版本生命周期(Version Lifecycle)完全指南:维护期规则、支持状态与升级规划 JupyterLab 以主版本(major v
前端后端数据科学开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考