SwiftFormat（0.45.0以降）で想定外の整形結果になったので解決方法をまとめました

# はじめに
私のチームではソースコードを綺麗な状態で保つために、OSSの[SwiftFormat](https://github.com/nicklockwood/SwiftFormat)を利用してソースコードの自動整形（フォーマット）を行なっています。
今回、[SwiftFormat](https://github.com/nicklockwood/SwiftFormat)を**0.45.0以降**にアップデートしたところ、今までは自動整形されていなかった箇所まで変更されてしまう事象が2つ発生したため、解決方法についてまとめました :thumbsup: 

# 実行環境

| 環境 | バージョン |
|:--|:--|
| macOS Catalina | 10.15.6 |
| Xcode | 11.6.0 |
| SwiftFormat | 0.45.0以降 |

# 発生した事象その1

次のように、修飾子の順番が変更されてしまう事象が発生しました。

```diff
- convenience required init?(hoge: Hoge) {
+ required convenience init?(hoge: Hoge) {
```

```diff
- static public func hoge() {
+ public static func hoge() {
```

## 原因
[CHANGELOG.md](https://github.com/nicklockwood/SwiftFormat/blob/master/CHANGELOG.md#0450-2020-07-29)を確認したところ、バージョン**0.45.0**にて以下のオプション、ルール、構成オプションの名前が変更されていました。[^1]

[^1]: ちゃんと[CHANGELOG.md](https://github.com/nicklockwood/SwiftFormat/blob/master/CHANGELOG.md#0450-2020-07-29)を読んでいなかった自分も悪いと思いつつ、[セマンティック バージョニング](https://semver.org/lang/ja/)の考え方からするとマイナーバージョンのアップで互換性が失われるのはどうなんだろう？:thinking: という気もしています。 


```CHANGELOG.md
Renamed --empty option to --voidtype, which better describes its function
Renamed specifiers rule to modifierOrder for consistency with SwiftLint
Renamed --specifierorder configuration option to --modifierorder
```

このことが原因で、**.swiftformat**に設定していた**specifiers**の無効指定が**0.45.0以降**では意味を成しておらず、**現象その1**が発生していました。

```.swiftformat
# disable
--disable specifiers
```

## 対応方法

[CHANGELOG.md](https://github.com/nicklockwood/SwiftFormat/blob/master/CHANGELOG.md#0450-2020-07-29)の内容に従って、名前を変更することで無事解決できました :thumbsup: 

```diff
  # disable
- --disable specifiers
+ --disable modifierOrder
```

# 発生した事象その2

次のように、guard-else文で改行を含む複数条件の場合、`else {` が改行されてしまう事象が発生しました。

```diff
  guard let foo = foo,
-     let bar = bar else {
+     let bar = bar
+ else {
      fatalError()
  }
```

## 原因

[CHANGELOG.md](https://github.com/nicklockwood/SwiftFormat/blob/master/CHANGELOG.md#0450-2020-07-29)を確認したところ、バージョン**0.45.0**にて以下のオプションが追加されていました。

```CHANGELOG.md
Added --guardelse option to control wrapping of else clauses in guard statements
```

[**--guardelse**オプションの説明](https://github.com/nicklockwood/SwiftFormat/blob/master/Rules.md#elseonsameline)を確認すると、defaultは**auto**となっており、このことが原因で**現象その2**が発生していました。


>**elseOnSameLine**
>Place else, catch or while keyword in accordance with current style (same or next line).
>
>| Option | Description |
|:--|:--|
| --elseposition | Placement of else/catch: "same-line" (default) or "next-line" |
| --guardelse | Guard else: "same-line", "next-line" or "auto" (default) |

## 対応方法

**--guardelse**オプションに指定できる値は、**same-line** or **next-line** or **auto**となっているため、今までのように何もしないという動作を選択することはできないようです。[^2]
このため、今回は**--guardelse**オプションに現状のソースコードにより近い値を指定することで、（ほぼ）解決ということにしました。
（もっといい解決方法を知っている方いましたら、ぜひ教えてください :raised_hand: ）

[^2]: **--disable**で無効化できないか試してみたのですが、上手くいきませんでした。ソースコードを自動整形（フォーマット）して綺麗に保つという趣旨からすると、何もしないという動作は許容したくないのかも？けど、無効化できるオプションもあるしなー:thinking: 

## 補足

類似問題として、**--guardelse**を**next-line** or **auto(default)** にした場合に `else {`のインデントがずれる事象も観測されましたが、こちらの事象は障害のようでした。
すでに以下のIssueとして管理され、`fixed in develop` ラベルが付与されている状態のため、次のリリース（たぶん、0.45.4だと思われる）で修正される予定のようです。

* ['else' in multi-line 'guard' statement loses indentation #690](https://github.com/nicklockwood/SwiftFormat/issues/690)

# 最後に

今回取り上げた内容以外にも新しい機能が複数追加されているため、上記とは異なる問題が起きている方もいるかもしれません。
そのような場合は、まず[CHANGELOG.md](https://github.com/nicklockwood/SwiftFormat/blob/master/CHANGELOG.md)の内容確認をオススメします。

# 参考情報
* [SwiftFormat](https://github.com/nicklockwood/SwiftFormat)
* [SwiftFormat 0.45.0 の CHANGELOG.md](https://github.com/nicklockwood/SwiftFormat/blob/master/CHANGELOG.md#0450-2020-07-29)
* [セマンティック バージョニング](https://semver.org/lang/ja/)