昨日行き詰まっていたところでどうしようか考えて、結局はjkr2255/sorted-json-stringifyなんてものを作ってしまいました。
オブジェクトの管理に依存せず並べ替える
突然ですが、JSON.stringify({'30': 'a', '5': 'b'})
はどうなると思いますか?多くのブラウザでは、'{"5":"b","30":"a"}'
という結果となります。実際、他の値を入れてみた感触でも、数値キーに関しては別枠でハンドリングしているような、妙な挙動を示しました。
実際にこのようなブラックボックスに遭遇してしまった以上、デフォルトのJSON.stringify
では、順番がどうなるかなんてわかりません。とはいえ、JSON.stringify
全部を再実装するのも面倒だし、出来上がったJSONのパースも色々考えると複雑そうだし…みたいなことを考えていました。
JSON.stringify
の仕様を見ていて
そんな中でMDNを見ていると、JSON.stringify
には3つの引数があると書いてありました。
-
replacer
…ルールに従ってオブジェクトを置き換える -
space
…見栄えをよくするために、JSONにスペースを挿入する
つまり、space
でインデントをかけた上で、そのインデントを数える、という手法を取れば、改めて大掛かりにパースしなくてもJSONの入れ子構造を抽出できるということがわかりました。
実際に作ってみた
ということで、
-
space = 1
で、デフォルトのJSON.stringify
を使って、改行&インデントありのJSONを生成する - 行ごとに区切って、インデントのスペースの数を数えておく
- インデント位置で構造を把握しつつ、JSONを並べ替えていく
- 最後にインデントなどを調整して、最終型のJSONを作る
このような流れで実装することができました。なお、ハマった箇所としては、space=0
のときは"foo":"bar"
のようにキーと値が密着するのに対して、space
が入る場合には"foo": "bar"
とスペースが1つ入る、となっていて、そこの差で一度コケました。
なお、今回これを作るのにあたって、Mocha、Chai、Rollupと言ったライブラリをはじめて使ってみました。