TOMLを自動フォーマットしてみないか【Taplo】

# 背景
最近、pyproject.tomlを編集しているときに、ふと自動整形してくれるようなフォーマッターがないかと思い、探してみました。結果として[Taplo](https://taplo.tamasfe.dev/)というフォーマッターが簡単に使えましたので、この記事で紹介したいと思います。使用環境としてはLinuxのターミナルを想定していますが、Windowsでも使えるようです。

# ダウンロード
以下からご自身の環境に合ったファイルをダウンロードしてください。なお、バージョン0.9.0がリリースされていますが、添付忘れなのかAssetsがないため、ここでは0.8.1のリンクを貼っています（2024年3月10日現在）。

https://github.com/tamasfe/taplo/releases/tag/0.8.1

# 前準備
ダウンロードしたファイルは圧縮されたバイナリですので、これを解凍して、実行権限を付与します。
```sh
$ gunzip taplo-linux-x86_64.gz  # or gzip -d taplo-linux-x86_64.gz
$ mv taplo-linux-x86_64 taplo   # rename as you like
$ chmod +x taplo
```
あとは必要に応じてパスを通してください。

ここでヘルプを見てみましょう。
```sh
$ ./taplo -h
taplo 0.8.1

USAGE:
    taplo [OPTIONS] <SUBCOMMAND>

OPTIONS:
        --colors <COLORS>    [default: auto] [possible values: auto, always, never]
    -h, --help               Print help information
        --log-spans          Enable logging spans
    -V, --version            Print version information
        --verbose            Enable a verbose logging format

SUBCOMMANDS:
    config    Operations with the Taplo config file [aliases: cfg]
    format    Format TOML documents [aliases: fmt]
    get       Extract a value from the given TOML document
    help      Print this message or the help of the given subcommand(s)
    lint      Lint TOML documents [aliases: check, validate]
    lsp       Language server operations
```
基本的に、サブコマンドとしては`format`を用いることが多いと思います。以下で詳細なヘルプを確認できます。
```sh
$ ./taplo format -h
```

# 使い方
フォーマットする場合は
```sh
$ ./taplo format hoge.toml
```
リンターとして利用する場合（ファイルを書き換えない場合）は
```sh
$ ./taplo format --check hoge.toml
```
となります。ヘルプにもあるように、`format`は`fmt`と書いてもOKです。サブコマンド`lint`は、単にTOMLの構文チェックをするだけのもののようです。

# コンフィグ設定
`.taplo.toml`か`taplo.toml`という名前のファイルがあれば、それを自動で読みにいくようになっています。明示的に指定したい場合は、`taplo format`の`-c`オプションで設定できます。コンフィグファイルには`formatting`テーブルを用意し、そこに設定を列挙する形になります。以下は例です。
```toml
[formatting]
align_entries = false
```
また、`rule`テーブルを用いることで、特定のファイルのみフォーマットするようなこともできます。詳細は[ドキュメント](https://taplo.tamasfe.dev/configuration/file.html)を参照してください。

`formatting`テーブルで設定するオプションの挙動が[ドキュメント](https://taplo.tamasfe.dev/configuration/formatter-options.html)からは分かりにくかったので、以下にまとめました。

## align_entries
`false`
```toml
[tool.black]
target-version = ["py37", "py38"]
line-length = 120
```
`true`
```toml
[tool.black]
target-version = ["py37", "py38"]
line-length    = 120
```
イコールでそろえる（デフォルトは`false`）

## align_comments
`false`
```toml
[tool.black]
target-version = ["py37", "py38"] # ABC
line-length = 120 # abc
```
`true`
```toml
[tool.black]
target-version = ["py37", "py38"] # ABC
line-length = 120                 # abc
```
コメントをそろえる（デフォルトは`true`）

## array_trailing_comma
`false`
```toml
classifiers = [
  "Programming Language :: Python :: 3.6",
  "Programming Language :: Python :: 3.7"
]
```
`true`
```toml
classifiers = [
  "Programming Language :: Python :: 3.6",
  "Programming Language :: Python :: 3.7",
]
```
末尾要素にカンマを付ける（デフォルトは`true`）

## array_auto_expand
`false`
```toml
classifiers = ["Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7"]
```
`true`
```toml
classifiers = [
  "Programming Language :: Python :: 3.6",
  "Programming Language :: Python :: 3.7",
]
```
`column_width`の値を越えるなら、要素ごとに改行する（デフォルトは80文字で`true`）

## inline_table_expand
`false`
```toml
a = { classifiers = ["Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7"] }
```
`true`
```toml
a = { classifiers = [
  "Programming Language :: Python :: 3.6",
  "Programming Language :: Python :: 3.7",
] }
```
`column_width`の値を越えるなら、インラインテーブル内で改行する（デフォルトは`true`）

## array_auto_collapse
`false`
```toml
classifiers = [
  "Programming Language :: Python :: 3.6",
]
```
`true`
```toml
classifiers = ["Programming Language :: Python :: 3.6"]
```
一行で書けるなら一行にまとめる（デフォルトは`true`）

## compact_arrays
`false`
```toml
package = [ "a", "b" ]
```
`true`
```toml
package = ["a", "b"]
```
括弧`[]`の内側にスペースを追加しない（デフォルトは`true`）

## compact_inline_tables
`false`
```toml
mypackage = { version = "^1.0", optional = true }
```
`true`
```toml
mypackage = {version = "^1.0", optional = true}
```
括弧`{}`の内側にスペースを追加しない（デフォルトは`false`）

## compact_entries
`false`
```toml
mypackage = { version = "^1.0", optional = true }
```
`true`
```toml
mypackage={ version="^1.0", optional=true }
```
イコールの両側にスペースを追加しない（デフォルトは`false`）

## indent_tables
`false`
```toml
[tool.poetry]
version = "0.1.0"

[tool.poetry.dependencies]
python = "*"
```
`true`
```toml
[tool.poetry]
version = "0.1.0"

  [tool.poetry.dependencies]
  python = "*"
```
サブテーブルをインデントする（デフォルトは`false`）
インデントの文字は`indent_string`で設定する

## indent_entries
`false`
```toml
[tool.poetry]
version = "0.1.0"

[tool.poetry.dependencies]
python = "*"
```
`true`
```toml
[tool.poetry]
  version = "0.1.0"

[tool.poetry.dependencies]
  python = "*"
```
エントリーをインデントする（デフォルトは`false`）
インデントの文字は`indent_string`で設定する

## reorder_keys
`false`
```toml
[tool.black]
target-version = ["py37", "py38"]
line-length = 120
```
`true`
```toml
[tool.black]
line-length = 120
target-version = ["py37", "py38"]
```
キーをアルファベット順に並べる（デフォルトは`false`）

## reorder_arrays
`false`
```toml
[tool.black]
target-version = ["py39", "py310"]
line-length = 120
```
`true`
```toml
[tool.black]
target-version = ["py310", "py39"]
line-length = 120
```
配列要素をアルファベット順に並べる（デフォルトは`false`）

## allowed_blank_lines
`0`
```toml
[tool.poetry]
version = "0.1.0"
[tool.poetry.dependencies]
python = "*"
```
`1`
```toml
[tool.poetry]
version = "0.1.0"

[tool.poetry.dependencies]
python = "*"
```
最大の空行数を設定する（デフォルトは`2`）

## trailing_newline
ファイルの最後に改行コードを入れる（デフォルトは`true`）

## crlf
改行コードをCRLFにする（デフォルトは`false`)

## 設定できない事項
シングルクォートとダブルクォートの統一は今のところできないみたいです。

https://github.com/tamasfe/taplo/issues/392

# その他
サブコマンド`get`を使うことで、TOMLの内容を取ってくることができます。便利ですね！
```sh
$ ./taplo get formatting.compact_inline_tables -f .taplo.toml
false
$ echo "data = ['a', 'b', 'c']" | ./taplo get data
a
b
c
```

# 終わりに
今回はCLIの使い方のみを説明しましたが、VSCodeでも使えるようです。
こちらの記事が開発の一助となれば幸いです。

# 参考

https://users.rust-lang.org/t/any-auto-formatter-for-toml/97292

https://github.com/toml-lang/toml/issues/532