Dartでコードを書く際、末尾カンマ(trailing commas)を適切に使うことで、フォーマッタが複数行に整形してくれるため可読性が向上し、git diffも見やすくなります。しかし、標準のrequire_trailing_commasルールは厳しすぎて実用的でないケースがあるため、より良い代替ルールが以前より欲しかったのです。そこで、better_require_trailing_commas というpubパッケージを作成しました。
Table of Contents
- 既存のrequire_trailing_commasルールの問題点
- 無限カンマサンドイッチ地獄
- useEffectで最後にカンマが付いてダサい
- Enum、Switch式、Recordに対応していない
- better_require_trailing_commasとは
- インストール方法
- Dart 3.10以降をお使いの場合
- Dart 3.9以前をお使いの場合
既存のrequire_trailing_commasルールの問題点
現在linterに同梱されているrequire_trailing_commasのソースを見てみると、カッコの開きと閉じが同じ行にない場合には末尾カンマが必要とされています。また、末尾カンマを入れないことを許可する場合の例外が複数のケースについて設定されています(参考)。このルールに基づいてコーディングしていくと、以下のような問題にぶち当たることがあります。
無限カンマサンドイッチ地獄
クラスのイニシャライザや関数の引数などで、その個数が1つであることがわかりきっている場合には、そのためだけにカッコの中身を改行したくない場合があります。そのようなときに公式のルールを適用すると、末尾にカンマとカッコ閉じが連なって、サンドイッチが出来上がってしまう場合があります。
Foo(Bar(Baz(
// ...
),),);
フォーマットするとたぶんこうなります。
```Dart
Foo(
Bar(
Baz(
// ...
),
),
);
どちらが好ましいかは場合によるかもしれませんが、カッコの中身のクラスが分かりきっていて、認知的に意味を持たない場合には同じ行に書きたい場合もありますので、かなり不便です。
useEffectで最後にカンマが付いてダサい
ダサくなります。
useEffect(() {
// ...
}, [],);
Enum、Switch式、Recordに対応していない
例えば以下のように書いても、なんと指摘してくれません。
var foo = switch (x) {
0 => false,
1 => true // <--
}
better_require_trailing_commasとは
そこで、こちらを作成しました。動作は、JavaScriptのLinterであるESLint(現在はStylisticに同梱)のcomma-dangleルールで、オプションにalways-multilineを設定したときのものとほぼ同じ、といえば分かりやすいかと思います。公式ルールでは細々とした例外を設定していましたが、本ルールの指摘対象は非常にシンプルで、カッコ、カッコの中身、閉じカッコがすべて異なる行にある時 に指摘が働きます。
Foo(
a: 1,
b: 2 // <-
);
Foo(Bar(
a: 1,
b: 2 // <-
));
useEffect(
() {
// ...
},
[] // <-
);
詳細はREADMEに記載しました。とりあえず半年ほど色々とコードを書いて、これで困ったことは1回もないです。
インストール方法
Dart 3.10以降をお使いの場合
こちらのパッケージは、プロジェクトで直接依存する必要はありません。
以下のようにanalysis_options.yamlに書き加えます。
# ...
plugins:
better_require_trailing_commas: ^2.0.5
# ...
Dart 3.9以前をお使いの場合
better_require_trailing_commasはDart 3.10で新規導入された機能を使用して作られていますが、それ以前でも使えるcustom_lint版もあります。詳細はREADMEをご確認ください。