こんにちは。 今回は、最近話題のGemini CLIに搭載されているCLI型エージェントを使って、RustとWebAssembly (Wasm) によるJSFuckエンコーダーを作成してみました。
この記事では、「なぜ作ったのか」という動機から、エージェントと一緒に作り上げた実装のポイントまでを紹介します。
JSFuckとは?
そもそもJSFuckをご存知でしょうか?
JSFuckは、JavaScriptの非常に奇妙なサブセットで、わずか6種類の文字 ([, ], (, ), !, +) だけを使って、任意のJavaScriptコードを記述・実行する手法(およびその仕様)です。
例えば、false という値は、JSFuckでは以下のように表現されます。
![]
// -> false これを文字列の "false" にするには、空の配列を足し合わせます。
![] + []
// -> "false" さらに、この文字列から文字を取り出すことができます。例えば "a" は "false" の2文字目(インデックス1)なので:
(![]+[])[+!![]]
// -> "a" ※ +!![] は 1 になります(true を数値変換)。
このように、JavaScriptの型変換や標準オブジェクトの挙動をパズルのように組み合わせることで、最終的に eval や Function コンストラクタを作り出し、任意のコードを実行させてしまうのがJSFuckの正体です。
作った動機
今回の開発の主なモチベーションは以下の3点でした。
- Gemini CLIで「CLI型エージェント」を使ってみたかった: チャット画面ではなく、自分のターミナル上で直接コマンドを実行したりファイルを編集してくれるエージェントの実力を試してみたかったのが最大の理由です。
- RustのWasmビルドを試してみたかった: 私自身、Rustは基本構文や概念を理解している程度で、バリバリ書けるわけではありません。Wasm周りのエコシステム(wasm-bindgenなど)のセットアップも含めて、エージェントがどこまでサポートしてくれるのか興味がありました。
- 何らかのエンコーダーを実装してみたかった: テキスト処理はRustの得意分野です。複雑すぎず、かつ実装しがいのある題材としてJSFuckを選びました。
アーキテクチャ
エージェントと相談しながら決めた構成は以下の通りです。
- Core (Rust): エンコードロジックとSWCを使った簡易Minifier。
- Wasm Interface:
wasm-bindgenを使用してRust関数をJSに公開。 - Frontend: Vite + Monaco Editor。
実装のポイント
1. エンコードの仕組み(基本はマッピング)
JSFuckのエンコード処理は、極論すると文字ごとの単純なマッピングです。
入力された文字列を一文字ずつ走査し、それに対応するJSFuckの表現("a" なら (![]+[])[1] など)に置き換えて + で結合していくだけです。
ただし、単純に一文字ずつ変換するとコードが膨大になりすぎるため、一部の予約語や頻出単語については専用の生成パターン(ショートカット)を用意しています。
Rust側では、この戦略を GenStrategy というEnumで管理しています。
enum GenStrategy {
Simple(&'static str), // 固定文字列 (例: "false", "undefined")
Func(fn() -> String), // 動的に生成する関数 (例: "constructor")
Chars(&'static str), // 一文字ずつ分解して結合 (通常パターン)
} 例えば constructor という単語は、一文字ずつ作るよりも、既存のオブジェクトからプロパティ名として引っ張ってくる方が短くなる場合があるため、専用のロジック(Func)を適用します。それ以外の一般的な単語は、単純に文字の変換ルールに従って Chars で処理されます。
このあたりの設計も、エージェントに「効率的にやりたい」と伝えて提案してもらいました。
2. SWCによる簡易Minifier
JSFuckは元のコードの数千倍〜数万倍のサイズに膨れ上がります。そのため、エンコード前のソースコードは1文字でも短い方が有利です。
そこで、Rust製の高速なJSトランスパイラである SWC (swc_core) を組み込んでみました。 src/minifier.rs にて、入力コードをパースし、変数名の短縮や空白削除を行っています。
正直なところ、今回実装したMinifierはそこまで実用的なレベルではありません。 市販のMinifier(Terserなど)ほどの圧縮率は出ませんが、それでもコメント削除や不要な空白の除去といった基本的な処理だけでも、最終的なJSFuckコードのサイズ削減には大きく貢献しています。 また、Rust初心者の私一人ではSWCのAST(抽象構文木)を扱うのはハードルが高かったため、ここもエージェントの力を借りられたのが大きかったです。
3. ブラウザでの実行
生成されたJSFuckコードは、最終的に Function(code)() という形式でラップして返します。
これにより、ブラウザのコンソールや eval でそのまま実行可能な文字列となります。
まとめ
Rustの基本構文しかわからない状態でも、Gemini CLIのエージェントを活用することで、Wasm連携やSWCを使った構文解析といった少し高度なトピックを含むツールを短時間で作成できました。
特に、ボイラープレートの作成や、クレート(ライブラリ)の選定・実装例の提示といった部分でエージェントは非常に強力なパートナーになります。 「難解言語」の実装は言語仕様の隅をつつくような面白さがあるので、Rustやエージェント操作の練習課題としておすすめです。
ぜひ、リポジトリをチェックして遊んでみてください!

