YAMLの構文チェックをVSCodeで自動化する方法（JSON Schema）

こんにちは、サーバエンジニアの池脇です。
今回は独自定義したYAMLをVSCode上でチェックする方法についてご紹介します。

## なぜYAMLのチェックが必要なのか
設定ファイルであるため、補完等が効きづらく、また手動チェックになりがちだからです。
補完についてはCopilotがあればどうにかなるかもしれませんが、その分チェックには力を入れる必要があります。

## なぜJSON Schemaを使うのか
YAMLの専用バリデーションにメジャーどころは存在せず、検索するとまずJSON Schemaが出てきます。そのためJSON Schemaを使用します。
「なぜJSONではなくYAMLのバリデーションをJSON Schemaでできるのか」
それはYAMLがJSONのスーパーセットであり、JSONの全ての機能が含まれているからです。

## VSCodeでの設定方法
まずVSCodeのYAML拡張を導入してください。

https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml

導入が終わったらJSON Schemaの設定ファイルを作成しましょう。
設定ファイルの作り方は検索して調べてみてください。
例えば[こちら](https://transform.tools/json-to-json-schema)でJSONからJSON Schemaを生成し編集してもいいかもしれません。

設定ファイルが作成できたらVSCodeの設定をいじりましょう。
次のように記述すると設定完了です。
```json
    "yaml.schemas": {
        "【作成したJSON Schemaファイルが配置してある場所のパス】": [
            "【対象にしたいYAMLファイル群の配置してある場所のパス】"
        ],
    }
```
また次のように書くことで複数のJSON Schemaファイルを扱うこともできます。
```json
    "yaml.schemas": {
        "./config/hoge_config.json": [
            "yaml/hoge/*.yml"
        ],
        "./config/fuga_config.json": [
            "yaml/fuga/*.yml"
        ],
    }
```

## 実際に使っている設定の例
実際に使用しているJSON Schemaファイルを簡略化したものを例に解説します。
<details open><summary>tableConfig.json</summary>

```json
{
    "$schema": "http://json-schema.org/draft-07/schema",
    "type": "object",
    "patternProperties": {
        "^(?!(ignore_pattern)).*$": {
            "type": "object",
            "required": [
                "category",
                "keys",
                "fields"
            ],
            "additionalProperties": false,
            "properties": {
                "category": {
                    "type": "string",
                    "description": "master or transaction",
                    "enum": [
                        "master",
                        "transaction"
                    ]
                },
                "keys": {
                    "type": "array",
                    "description": "keys",
                    "additionalItems": false,
                    "items": {
                        "type": "string"
                    }
                },
                "fields": {
                    "type": "array",
                    "description": "fields",
                    "additionalItems": false,
                    "items": {
                        "type": "object",
                        "additionalProperties": false,
                        "required": [
                            "name",
                            "type"
                        ],
                        "properties": {
                            "name": {
                                "type": "string",
                                "description": "field name",
                                "pattern": "^[a-z]{1}[a-z0-9_]*$"
                            },
                            "type": {
                                "type": "string",
                                "description": "field type",
                                "examples": [
                                    "long",
                                    "string",
                                    "bool",
                                    "DateTime"
                                ]
                            },
                            "description": {
                                "type": "string",
                                "description": "field description"
                            },
                            "default": {
                                "type": "string",
                                "description": "field default value"
                            }
                        }
                    }
                }
            }
        }
    }
}
```
</details>

---

### `type`
```
"type": "object",
```
型のバリデートです。
定義できるものについては下記のリンクを参照してください。

https://json-schema.org/understanding-json-schema/reference/type

---

### `patternProperties`
```
"patternProperties": {
    "^(?!(ignore_pattern)).*$": {
```
正規表現を利用してオブジェクト名のバリデートが可能です。
この場合は`ignore_pattern`という名前以外のオブジェクト名に以下のJSON Schemaを適用します。

---

### `required`
```
"required": [
    "category",
    "keys",
    "fields"
],
```
必須プロパティのバリデートです。
プロパティの定義漏れを防ぐことができます。

---

### `additionalProperties`
```
"additionalProperties": false,
```
定義されていないプロパティを許可するか指定できます。
`false`の場合は未定義のプロパティがあるとエラーになります。

---

### `enum`
```
"enum": [
    "master",
    "transaction"
]
```
定義した項目のみを許可します。
未定義の値が設定されるとエラーになります。

---

### `additionalItems`、`items`
```
"additionalItems": false,
"items": {
    "type": "string"
}
```
`type: array`の場合に設定できます。
通常先頭の値のみをバリデートするため、全ての値にバリデートをかけたい場合は`additionalItems: false`を記述します。

---

### `pattern`
```
"pattern": "^[a-z]{1}[a-z0-9_]*$"
```
正規表現で値のバリデートをします。
詳しい記述方法については下記のリンクを参照してください。

https://json-schema.org/understanding-json-schema/reference/regular_expressions

---

### `examples`
```
"examples": [
    "long",
    "string",
    "bool",
    "DateTime"
]
```
こちらは記述例のため、バリデートには使用しません。
この設定を行なっているとVSCodeでの補完時に提案を行なってくれます。

## まとめ
最近はCopilot等でYAMLを書く際の労力が減っていますが、その分チェックに時間をかけてしまってはもったいないです。
JSON Schema + VSCodeを利用して、手動になりがちなYAMLのチェックを自動化してみてはいかがでしょうか？

## 参考
- [VSCodeで快適に設定ファイルを書く](https://qiita.com/uzuna/items/3f8ae7775b2136fffc7f)
- [YAMLファイルはJSON Schemaでバリデーションしよう](https://qiita.com/ssc-ksaitou/items/c5f580c70bd9c7e76b6c)