mcpField
L
lint-and-style-config

lint-and-style-config

github.com/zakariaf開発63147 回インストール5 週間前に更新
リポジトリ

lint-and-style-config について

Dart と Flutter プロジェクトの lint・スタイル設定を保守するスキルです。ルールセットの固定、アナライザーの動作、抑制の扱い、解析だけでなくビルドも行う CI ゲートを説明します。

主な機能

  1. 01very_good_analysis のバージョン固定
  2. 02アナライザーと lint ルールの設定
  3. 03ルールの有効性確認
  4. 04生成ファイルとカバレッジ除外の同期
  5. 05抑制の制限と CI ビルドの必須化

活用シーン

  1. 01Dart lint ルールの追加や調整
  2. 02SDK またはルールセットの更新
  3. 03アナライザー設定が無効な原因の調査
  4. 04解析・フォーマット・ビルドゲートの設定

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/zakariaf/flutter-skills --skill lint-and-style-config

インストール後、Claude Code で/lint-and-style-configを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

examples/
analysis_options.yaml
callback_future_hole.dart
references/
config-mechanics.md
rule-catalog.md
scripts/
lint-gates.sh
verify-include-pin.sh

詳細

Lint とスタイル設定

スタイルは好みではなく、ツールチェーンによって適用されます。空白は dart format が管理し、正確性はアナライザーが管理します。また、見逃すと問題を引き起こす少数のバグクラスを、ビルド失敗となるエラーに昇格させます。このスキルは analysis_options.yaml 自体と、それが実際に機能するかどうかを決める仕組みを対象とします。このファイルの編集、lint の追加や抑制、SDK/ルールセットの更新時に適用してください。

作業内容に応じて、次のリファレンスを確認してください。

  • references/rule-catalog.md — 昇格対象のすべてのルールとそのバグクラス、意図的なレベル引き下げ、議論のある public_member_api_docs の判断、複雑度制限の表。
  • references/config-mechanics.md — include のピン留めで陥りやすい問題、errors: による再ランク付けと linter: による有効化、sealed switch の analyze と compile の違い、カバレッジのミラーリング、riverpod_lint プラグイン、抑制の規律。

examples/analysis_options.yaml をパッケージのルートにコピーし、初期設定として使用してください。PR の前に scripts/verify-include-pin.sh と scripts/lint-gates.sh を実行してください。

絶対に守るルール

  1. 空白を決めるのは dart format だけです。 手動でフォーマットしたり、結果に異議を唱えたりしてはいけません。正当な理由をコメントに記した手組みの表の周囲を除き、// dart format off は使用しないでください。CI では dart format --set-exit-if-changed . を実行します。
  2. バージョン番号付きの include をピン留めして、very_good_analysis をベースにしてください。 裸の analysis_options.yaml は使用しないでください。pub upgrade によって、何がエラーと見なされるかが予告なく変わってはいけません。VGA はすでに strict-casts、strict-inference、strict-raw-types を設定しています。language: ブロックに重複して記述しないでください(冗長な設定はずれが生じ、矛盾の原因になります)。
  3. info も失敗です。 CI では dart analyze --fatal-infos --fatal-warnings を実行します。未対応の info が蓄積するとノイズになり、実際の問題が見えにくくなります。
  4. エラーに昇格するのは、見逃すと問題を引き起こすバグクラスだけです。 Future の破棄、失敗の握りつぶし、await 後のデッドコンテキスト、リソースリーク、dynamic 境界の型の抜け穴、網羅性のない enum switch、print が該当します。スタイル上の好みは対象外です。
  5. errors: による昇格が機能するのは、ベースのルールセットですでにそのルールが有効な場合だけです。 errors: は既存の診断のランクを変更するもので、無効なルールを有効にはできません。VGA にないルールを有効にするには、まず linter: rules: に追加してください。
  6. linter: rules: でリスト形式とマップ形式を混在させてはいけません。 同じブロック内に - rule の項目と rule: true の項目があると、パースエラーになります。アナライザーが壊れていてもビルドは成功してしまいます。ベースルールを無効にするには、errors: <rule>: ignore を使用してください。
  7. CI では解析だけでなく、ビルドも実行してください。 sealed switch の網羅性チェックは lint ではなくコンパイルエラーです。errors: の上書きで抑制できるとは限らず、dart compile に到達するコードパスでは失敗します。解析だけのゲートでは、ビルドできないコードでも成功する可能性があります。
  8. 生成コードを除外し、カバレッジのフィルタリングにも同じ glob を正確に反映してください。 そうしないと生成ファイルがカバレッジの数値を薄め、意味のないものになります。
  9. 抑制は行単位に限り、同じ行または直前の行に理由を記載してください。 昇格対象のルールに // ignore_for_file: を使ってはいけません。また、アーキテクチャ/インポートのゲートに対する抑制も禁止です。コードを修正することを優先してください。
  10. custom_lint は追加しないでください。 riverpod_lint 3.x はファーストパーティのプラグインシステム上で動作し、通常の flutter analyze で診断が実行されます。

include と、すべてを知らぬ間に無効化する落とし穴

include: package:very_good_analysis/analysis_options.10.3.0.yaml

解決済みのパッケージ内にそのファイル名が存在しない場合、warning • include_file_not_found が 1 件表示され、ルールが一切ない状態で解析が実行されます。何もチェックしないビルドでも成功します。

SDK/VGA を更新するコミットと同じコミット内で include のファイル名も更新し、ファイルが存在することを確認してください(ls ~/.pub-cache/hosted/pub.dev/very_good_analysis-*/lib/)。更新のたびに、既知の違反が引き続きエラーになることを確認してください。成功表示を鵜呑みにしてはいけません。scripts/verify-include-pin.sh が存在確認を自動化します。

無視されるバグをエラーに昇格する

analyzer:
  errors:
    unawaited_futures: error
    discarded_futures: error
    empty_catches: error
    avoid_catches_without_on_clauses: error
    only_throw_errors: error
    throw_in_finally: error
    use_build_context_synchronously: error
    cancel_subscriptions: error
    close_sinks: error            # VGA ships this at `ignore`; re-promoted
    avoid_dynamic_calls: error
    always_declare_return_types: error
    cast_nullable_to_non_nullable: error
    exhaustive_cases: error
    avoid_print: error
    avoid_slow_async_io: error

それぞれ、個人開発者が読み飛ばす情報レベルの波線を、ビルド失敗に変えます。各ルールのバグの種類と、意図的に warning/ignore のままにしているルール(deprecated_member_use、invalid_annotation_target、lines_longer_than_80_chars)については、references/rule-catalog.md を参照してください。

errors: は優先度を変更し、linter: rules: は有効化する

# Promoting works ONLY because VGA already enables these rules (close_sinks even
# at severity `ignore` counts as enabled — the override resurrects it).
analyzer:
  errors:
    close_sinks: error

# To enable a rule VGA does NOT ship, add it here FIRST, then optionally promote.
linter:
  rules:
    some_rule_vga_omits: true

実際に違反を起こして検証してください。昇格が適用されたと決めつけてはいけません。出荷時の設定では、昇格するすべてのルールが VGA で有効になっているため、linter: rules: ブロックは不要です。

sealed の網羅性チェックはコンパイルエラーであり、Lint ではない

sealed class SaveResult {}
class Saved extends SaveResult {}
class SaveFailed extends SaveResult {}

// Missing a case is `non_exhaustive_switch_statement` — a COMPILE error.
// (A switch *expression* raises `non_exhaustive_switch_expression` instead.)
String describe(SaveResult r) {
  switch (r) {
    case Saved():
      return 'saved';
    case SaveFailed():
      return 'failed';
  }
}

exhaustive_cases が対象とするのは、enum/static const の集合だけです。失敗とモードの型は sealed としてモデル化し、新しいケースが追加されたとき、default に落ちて見過ごされるのではなく、すべての呼び出し箇所でビルドが失敗するようにしてください。errors: による上書きで網羅性診断を抑制できるとは限りません。また、dart analyze をどうにか通せた場合でも dart compile は失敗します。そのため、CI では必ずビルドし、解析だけで済ませてはいけません。dart3-idioms-and-coding-standards を参照してください。

除外設定をカバレッジにも反映する

analyzer:
  exclude:
    - "**/*.g.dart"
    - "**/*.freezed.dart"
    - "**/*.drift.dart"
    - "**/generated_plugin_registrant.dart"
    - "test/drift/generated/**"   # drift schema snapshots — never reformat/fix

同一の glob をカバレッジのフィルタリングにも適用する必要があります(lcov --remove またはレポーターの除外設定)。除外設定とカバレッジフィルターの不一致は、数値を実態より高く見せます。testing-strategy と codegen-and-toolchain を参照してください。

Lint では検出できない穴

// WRONG — flagged by NOTHING. The arrow returns the Future (so discarded_futures
// is satisfied), but the target is VoidCallback, so Dart drops it silently.
onPressed: () => repository.save(note),

// RIGHT — a void-returning intent method the callback holds safely.
class NoteController {
  void saveNow(Note note) => unawaited(_repo.save(note).catchError(_report));
}
// onPressed: () => controller.saveNow(note),

対策は構造によって行い、規律に頼ってはいけません。アナライザーが問題なしと判定しても、処理が実行された証拠にはなりません。重大度が最も高い障害はどのルールでも検出できず、手動での確認が必要です。examples/callback_future_hole.dart と async-safety を参照してください。

アンチパターン

  • include: package:very_good_analysis/analysis_options.yaml をそのまま使う — pub のアップグレードでルールセットが予告なく変わり、固定したファイルがないとルールが予告なく無効になります。バージョンを固定して検証してください。
  • language: ブロックで strict-casts/strict-raw-types を再宣言する — VGA が設定しているため、複製した設定はずれて、いずれ矛盾します。
  • VGA で有効になっていないルールを昇格する — errors: では無効なルールを復活させられないため、昇格しても何も起きません。
  • 1 つの linter: rules: ブロックで - rule と rule: false を混在させる — 解析エラーが発生し、アナライザーが壊れてもビルドは成功します。
  • 解析だけを行う CI — sealed switch の網羅性が不十分で、dart compile に失敗するコードも通過します。
  • 除外設定をカバレッジに反映しない — 生成ファイルによって数値が実態より高くなります。
  • 昇格したルールに // ignore_for_file: を付ける、またはインポートのゲートに抑制を付ける — 次の編集で保護が失われます。正しさを守るゲートの抑制はブロッカーです。
  • custom_lint を追加する — レガシーのプラグインシステムです。riverpod_lint 3.x では不要です。
  • ドリフトスキーマのスナップショットを再フォーマットする — マイグレーションテストのベースラインが壊れます。

完了の定義

  • dart format --set-exit-if-changed . がクリーンであり、dart analyze --fatal-infos --fatal-warnings が成功し、CI で解析だけでなくビルドも行われる。
  • include はバージョン固定された VGA ファイルで、pub キャッシュ内に解決される(scripts/verify-include-pin.sh が成功する)。
  • 冗長な language: ブロックがなく、厳格モードは VGA から設定される。
  • 無視されるバグの種類が error に昇格され、昇格したルールはすべて VGA で実際に有効になっている。
  • linter: rules: にリスト形式とマップ形式が混在していない。
  • 生成ファイルの除外設定があり、カバレッジのフィルタリングにも反映されている。
  • 抑制は理由を添えて行単位で指定され、アーキテクチャのゲートには抑制がなく、昇格したルールに // ignore_for_file: が付いていない。
  • riverpod_lint が version: キーを指定して設定されており、custom_lint がない。

関連スキル

  • dartdoc-conventions — public_member_api_docs: error と、文書化すべき境界を支えます。
  • async-safety — この設定では検出できない、コールバック内で Future が破棄される問題です。
  • error-handling-typed-results — 網羅性をコンパイル時の保証にする、sealed な Failure/Result の骨格です。
  • dart3-idioms-and-coding-standards — ルール 7 を支える sealed 型と網羅的な switch の規律です。
  • naming-conventions — アナライザーでは強制されない、役割を示す接尾辞と Effective Dart の命名規則です。
  • state-management-riverpod — riverpod_lint がチェックする Riverpod のパターンです。
  • codegen-and-toolchain/run-codegen — これらの除外設定が対象とする生成ファイルです。
  • ci-pipeline-and-gates — これらのゲートと、ビルド時には解析を実行しないルールを適用する場所です。
  • testing-strategy — カバレッジのミラーリングと、アナライザーが成功しても証明できないことです。
  • dependency-hygiene — バージョンを固定した lint の include を依存関係の観点から扱います。

参考資料

コメント