aboutsummaryrefslogtreecommitdiffhomepage
path: root/services/nuldoc/content/posts/2024-07-19/reparojson-fix-only-json-formatter.md
blob: b9590c5303f54c4da638551f647d78f705726c65 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
---
[article]
uuid = "222488dd-cf07-4961-83aa-a014b05369ff"
title = "reparojson: 文法エラーを直すだけの JSON フォーマッタを作った"
description = "文法エラーだけを直し、空白の削除や挿入といった整形処理を一切おこなわない JSON フォーマッタを作成した。Neovim と連携させる設定例も紹介する。"
tags = [
  "neovim",
  "vim",
]

[[article.revisions]]
date = "2024-07-19"
remark = "公開"
---
:::note
この記事は [Vim 駅伝](https://vim-jp.org/ekiden/) #218 の記事です。
:::

# 欲しかったもの {#intro}

Vim で JSON を編集しているときに、文法エラー (末尾カンマやカンマの不足) のみを修正して一切の整形をおこなわないプラグインが欲しかった。
整形も同時におこなうプラグインは見つかっただけでも多数あったのだが、整形しないものは見つけられなかったので自作することにした。

なお、作成したツール自体は単体の CLI として動作し、Vim とは無関係に使うことができる。
この記事では Neovim と組み合わせる場合の設定を紹介するが、およそ任意のエディタで使えるだろう。

# 作ったもの {#reparojson}

作成したものがこちら: [ReparoJSON](https://github.com/nsfisis/reparojson)

次のように動作する。

```
$ echo '[ 1 2 ]' | reparojson
[ 1, 2 ]

$ echo '[ 1, 2, ]' | reparojson
[ 1, 2 ]

$ echo '{ "foo": 1 "bar": 2 }' | reparojson
{ "foo": 1, "bar": 2 }

$ echo '{ "foo": 1, "bar": 2, }' | reparojson
{ "foo": 1, "bar": 2 }
```

バージョン 0.1.1 時点で修正対象の文法エラーは次のとおり:

* 配列末尾の余計なカンマ (削除する)
* 配列内のカンマ不足 (挿入する)
* オブジェクト末尾の余計なカンマ (削除する)
* オブジェクト内のカンマ不足 (挿入する)

他にも自動で直せそうなエラーはいくつか思いつくが (オブジェクトのキーがクォートされていない等)、私自身があまり困っていないので優先度は低い。

# Neovim との連携 {#itegration-with-neovim}

Neovim で JSON ファイルを保存したときに、上記のツールを自動で走らせるように設定する。

ここでは、 [nvim-lspconfig](https://github.com/neovim/nvim-lspconfig) と [efm-langserver](https://github.com/mattn/efm-langserver) を用いた設定例を紹介する。

```lua
   local lspconfig = require('lspconfig')

   lspconfig.efm.setup({
      init_options = { documentFormatting = true },
      settings = {
         rootMarkers = {".git/"},
         languages = {
            json = {
               {
                  formatCommand = "reparojson -q",
                  formatStdin = true,
               },
            },
         },
      }
   })

   vim.api.nvim_create_autocmd('LspAttach', {
      callback = function(e)
         vim.api.nvim_create_autocmd('BufWritePre', {
            buffer = e.buf,
            callback = function()
               vim.lsp.buf.format({ async = false })
            end
         })
      end,
   })
```

ほとんどは nvim-lspconfig と efm-langserver を使う際のボイラープレートだが、`formatCommand` で `-q` フラグを指定していることに注意してほしい。
このツールは、デフォルトでは JSON が修正された場合 exit code 1 で終了する。
これは、入力が最初から正しかった場合と修正して正しくなった場合を区別するためだが、異常終了してしまうと置き換えが発生しない。
そのため、`-q` フラグを指定して、修正されたときも exit code 0 で終了するようにしている。

# おわりに {#outro}

このツールが威力を発揮するのは、行の入れ換え時である。次のような JSON があり、

```json
   {
      "a": true,
      "b": false
   }
```

2行目と3行目を入れ換えて以下のように編集した。

```json
   {
      "b": false
      "a": true,
   }
```

これは不正な JSON だが、このツールを通せば次のようになる。

```json
   {
      "b": false,
      "a": true
   }
```

もちろん、このような操作を文法を壊さずにおこなう Vim プラグインは存在する。
しかし、単なる行の入れ換えであれば `ddp` の3ストロークでおこなうことができ、専用のキーバインドを覚える必要もない。
このツールを用いることで、より Vimmer-friendly な JSON 編集が可能となる。