💪

え!? JSONファイルにコメントとケツカンマを書けるようにしろ!?

2024/12/14に公開

出来らあっ!

そんなときは YAMLファイルとして読み込んでしまいましょう。
それで「JSON + コメント + ケツカンマ」なファイルを読み込めるようになります。

jsonc (json with comment) は?

読み書きするのに有名なパッケージも無さそうですし、あまり見かけないフォーマットなので採用しませんでした。

経緯

私は自作ツールの設定ファイルによく JSON を使うのですが、他の人(特に非エンジニアの人)にツールを使ってもらっていると「この設定ファイルコメント書けないの?」って聞かれることがあり、その度に「あー、コメントは書けないですね……😔」って答えなければなりませんでした。つらい。

こんな風に書きたいことありますもんね。

{
    # data1〜3のうち必要なものだけ書く
    "data1": 10,
    #"data2": 20,
    "data2": 21,  # テストのため一時的に変更
    "data3": 30
}

あと、「設定ファイルいじったら動かなくなっちゃったんだけど?」と言われて見に行くと、

{
    "data1": 10,
    "data2": 20,
                 # ← どうやら末尾の "data3": 30 の行が消された模様
}

ってな感じにされていて、「何もしてないのに動かなくなった」って顔を横目に、そっと末尾のカンマを消してあげたりすることもあります。つらい。

そこで考えたのが

YAML のフロースタイルは JSON のスーパーセットになっているらしい、ということは YAML として読み込めばコメントを書けるのでは、と考えました。

Go や Python ならコードの変更も少なくて済みます。Go なら、encoding/json の代わりに gopkg.in/yaml.v3 をインポートして、コード中の "json" って書いてあるところを "yaml" に変えたらほぼ完成です。

例えばこんな感じ。

import (
    "io"
    "os"

-   "encofing/json"
+   "gopkg.in/yaml.v3"
)

...

    // データを格納する構造体
    type Person struct {
-       Name    string  `json:"name"`
-       Age     int     `json:"age"`
+       Name    string  `yaml:"name"`
+       Age     int     `yaml:"age"`
    }

    // ファイル読み込み
    f, err := os.Open("foo.json")
    if err != nil {
        panic(err)
    }
    defer f.Close()
    d, err := io.ReadAll(f)
    if err != nil {
        panic(err)
    }
    var p Person
-   if err := json.Unmarshal(d, &p); err != nil {
+   if err := yaml.Unmarshal(d, &p); err != nil {
        panic(err)
    }

注意点

YAMLとして読み込んでいることは伏せて、JSONファイルですよって顔をしておくのが大事です。拡張子も ".json" のままにしておきましょう。そして、「これってコメントは書けないの?」って聞かれたら「# で書けますよ👌」って答えればOKです。ケツカンマに関しては、それを書くような人はそもそもJSONに詳しくないので気にもしないです。

……というのは冗談ですが、とりあえず自作ツールの設定ファイルに JSON 使う派だけどコメントも書きたい人にはこれで十分だったりします。

ただし、このようなやり方は、あくまで自分とその周りの一部の人だけで使うようなプログラムに留めておくのが無難です。正式に利用されるようなプログラムの場合は、利用するファイルフォーマットをきちんと規定しましょう。

Discussion