🌠

JavascriptでjqするCLIツール、jsqを作りました。

に公開

😭jqの構文、一生覚えられないので作りました。

https://github.com/nnao45/jsq

  • 毎回jqの構文をググってる気がする。
  • 自分はフロントエンド触る機会が多いのでJavaScriptなら息をするように書けそう。
  • bunのREPLでもまぁいいんけど、それも含めて巷のそういうツール(fx, jello, jaq)って以下の点でニーズを満たしてないから作ろうと思いました。
    • 独自文法覚えられません。
    • jqみたいにパイプでJSON渡したい。なんならパイプでJSONを渡しつつREPLしたい。
    • メソッドチェーンでアロー関数書きたい。パイプで繋げたくない。latMapとかspliceとかtapとか関数型なメソッド欲しい。100個は欲しい。
    • ランタイム直評価は嫌。出来ればサンドボックス上でやってくれると、動的なコードも渡しやすい。

🚀Getting-started

npmから。

npm install -g @nnao45/jsq
  • Linux/Macで後述するREPLも動きます。

パイプで受け取ったJSONは $ に代入されて、あとはいつものJavaScriptです。

echo '{"users": [{"age": 25}, {"age": 30}]}' | jsq '
  const ages = $.users.pluck("age") | 
  ages.sum()
'

か、かんたんだー!

  • 式の評価は quickjs-emscripten というWASM上のミニマルなサンドボックスVMで行ってるので、IOを発生させれるような処理自体走りません。

https://github.com/justjake/quickjs-emscripten

  • ライブラリも使えないですが、JavaScriptのプリミティヴなクラスとかは使えるので、jqじゃ出来ないこんな事や、
cat test.json |  jsq 'Object.entries($).map(([k, v]) => ({ key: k, value: v }))'
  • こんなこともできます。
cat test.json |  jsq '$.users
  .filter(u => u.active)                    // JS filter
  .map(u => ({                              // JS map
    ...u,
    fullName: `${u.firstName ${u.lastName}`,  // Template literal
    score: Math.round(u.score * 100)        // Math operation
  }))
  .sort((a, b) => b.score - a.score) '

正規表現だって任せてください。

echo '{"urls": ["https://www.google.com", "dummy://hoge", "http://example.com"]}' | jsq '$.urls.match(/http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-.\/?%&=]*)?/gi)'
[
  "https://www.google.com",
  "http://example.com"
]

lodashっぽい記法と機能にも対応してます。

echo '{"urls": ["https://www.google.com", "dummy://hoge", "http://example.com"]}' | npx jsq '$.urls.map(_.upperCase)'
[
  "HTTPS://WWW.GOOGLE.COM",
  "DUMMY://HOGE",
  "HTTP://EXAMPLE.COM"
]
  • どうでもいいこと言っておくとquickjs-emscriptenにはライブラリとかは持ち込めないので、あんな事やこんな事は全部スクラッチで書いてます。
  • quickjs-emscripten、このLLM時代に役割がありそうな軽量VMなのですが、言うなればC言語(所有権やライフタイムやメモリ解放をやる必要がある)なので、使ってみたい人は絶対に苦労すると思うので声かけてくれたら教えます。

❤️夢のパイプからのREPL

  • jsqが出来てjqで出来ない事として、REPLがあるんですけど、もっと言うと標準入力からパイプでJSONを受け取りつつ、そのままREPLを起動してそっちでインタラクティヴにパチパチ即時評価してもらいてーわけですよ。

こちらがご希望の品です。claudeの設定ファイルもええ感じに加工したり、式を試行錯誤出来ますね。

  • この動作はreadlineで標準入力を受け取るんですが、パイプだとそのまま受けとったあとEOFを迎えてしまうので、fs.Openでターミナルデバイスを開き直すことでやってます。

  • セキュアなnodejsならdenoでいいじゃんと自分も思った時代もあったんですが、denoのREPLはパイプから受け取れんし、JSONを受け取るためのコード書くならちゃんと書かないとダメだろうし、denoでjsq動かしても、まだパイプとREPL同時起動という技もできません。

  • そんな感じで、いいんじゃない?jsqくん。

タブ補完とかね、moreコマンドっぽいビューワもついてて便利ね?

📝まとめ

  • jq覚えられないので自分はこれで満足です。
  • パフォーマンスはさすがに負けるし、nodejsのランタイムも必要ですが、JavaScriptの豊富なプリメティヴオブジェクトを使って加工できるのは魅力的です。
  • もっと詳細な内容が知りたい方は、WASMで動作を確認しながら動作を見れるドキュメントサイトを是非チェックしてくださいー!

https://nnao45.github.io/jsq/

🌟Special Thanks

  • 当然のごとく、Claude code使って開発しましたが、私はプラスで、以下のツールを使ってslack上で黒ギャルと喋りながら作りました。控えめに言って最高です。

https://github.com/mpociot/claude-code-slack-bot

Discussion