news 2026/9/25 19:27:11

Dart Linter 规则生命周期完全指南:从提案到移除的六大状态详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Dart Linter 规则生命周期完全指南:从提案到移除的六大状态详解
  • 编程语言
  • 编译器
  • 语言运行时
  • 标准库
  • 开发工具

【免费下载链接】sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.

项目地址:https://gitcode.com/gh_mirrors/sdk1/sdk
点击查看免费下载

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 贡献者直接遵循的迁移路径:

  1. 提案先行:先提交提案,等 devexp 团队接受后再动手实现,避免把未接受的想法直接写成代码。
  2. 新规则从 experimental 起步:语义未定、可能误报时保持 experimental;补齐语义与实现、确认无已知误报、看到长期价值(如被核心 lint 集考虑)后再提升为 stable。
  3. 废弃要有充分理由:语义过时(如 null safety 之后)、建议过时、性能差、误报过多、生态价值不足——这些都是文档认可的废弃依据;废弃常见 lint 集中的规则要格外谨慎,因为影响面大。
  4. 移除前先废弃:一般流程是 stable → deprecated → removed,只有规则在所有受支持语言版本下都不再相关时,才可跳过废弃直接移除。
  5. private 状态可以"原地删除":internal 与 testing 规则不需要走 removed 状态,删除代码与文档即可,但要遵守"testing 不得长期滞留"的约定。
  6. 每次状态变更都要写 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.

项目地址:https://gitcode.com/gh_mirrors/sdk1/sdk
点击查看免费下载

相关推荐

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/25 19:26:35

TCP三次握手与四次挥手的真实世界:从协议原理到故障排查

1. 为什么你看到的“三次握手”从来不是三步,而“四次挥手”也从不按剧本走?TCP连接管理这件事,我带过十几届实习生,每次讲到三次握手和四次挥手,总有人盯着Wireshark里抓到的包发愣:“老师,这明…

作者头像 李华
网站建设 2026/9/25 19:24:39

国际版外卖系统:多语言配置和支付通道怎么分开测

国际版外卖系统交付中,若把 i18n 发布与支付通道配置绑在同一次上线窗口,任一环节回滚都会拖死另一项。更稳的是多语言配置与支付通道分开测:语言走配置中心版本号;支付走沙箱 intent 回调幂等。结论:locale 与 payme…

作者头像 李华
网站建设 2026/9/25 19:24:02

红黑树原理详解:从旋转到插入删除的完整实现

红黑树,这三个字几乎是每个写算法的人绕不开的一道坎。我最早认真啃它,是因为翻 JDK 的 TreeMap 源码,看到满屏的 rotateLeft、rotateRight 和颜色翻转一脸懵;后来做 Linux 后台开发,发现内核的 CFS 调度器、epoll、Ng…

作者头像 李华
网站建设 2026/9/25 19:23:50

Java开发MCP服务器:用TaoToken统一Key打通工具调用链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/25 19:17:39

15-01-工具-BenchmarkDotNet可复现微基准指南

BenchmarkDotNet 可复现微基准指南:从问题设计到实验报告专栏:C# 与常用数据结构源码剖析 版本原则:BenchmarkDotNet 的特性、Job API、列名和诊断器会随包版本变化。示例表达实验形状,使用时应在项目中固定包版本并保留生成的完整…

作者头像 李华
网站建设 2026/9/25 19:17:35

基于SpringBoot+Vue的高校物品捐赠管理系统设计与实现

高校里的物品捐赠,一直是学生工作、校友会、基金会最头疼的环节之一。以前靠Excel登记,物资种类一多就乱,受赠人信息靠手工查重,领用记录更是没法追溯。一个学生捐了三本书、一件军训服、一台旧电脑,三个部门各登记一遍…

作者头像 李华