天才クールスレンダー美少女になりたい

チラシの表(なぜなら私はチラシの表にも印刷の上からメモを書くため)

DenoでScrapbox→Re:VIEW変換ツールを実装した話

これはTSG Advent Calendar 2021の17日目の記事です。前日(16日目)の記事はしとお先生の「なもり当てクイズの解き方とかコツとか?」でした。楽しみだな〜〜〜〜

adventar.org

また、東京大学きらら同好会 Advent Calendar 2021の17日目の記事でもあります。
前日(16日目)の記事は、ちさとしさんの「きららファンタジアについて、色々」でした。

adventar.org

cst-oshino.hatenablog.com


え、投稿時間が18日の0時26分? 知らんな!!!!!!!!!!





本日のお題は、私が実装したScrapbox記法→Re:VIEW記法の変換ツール「sb2re」です。

github.com



同人誌執筆とScrapboxRe:VIEW

東京大学きらら同好会では、同人誌の執筆にRe:VIEWAdobe InDesignを利用しています。前者は自由ソフトウェア、後者は不自由なプロプライエタリ・ソフトウェアです。

note.com

awomomiji.fanbox.cc



さらに、サークル内のさまざまな情報をScrapboxで管理しています。Discordだけで管理するのに向いていない、いわゆるストック情報というやつですね。



さて、前回の#FindOurStars vol.2とMicare vol.1では、一部の部員がScrapboxで記事を執筆しました。確かに、端末を変えても常に最新版を更新・閲覧できますし、進捗度合いを他の人が把握することも容易ですし、意外と理に適っている気がします。

同じような利点を持つサービスとしてGoogleドキュメントが挙げられますが、Googleドキュメントはあまりに装飾などの自由度が高く、Re:VIEWなどのテキスト形式とはさほど親和性が高くありません。docx形式でダウンロードして手作業で修正してpandoc、みたいなことになります。

一方、Scrapboxは結局テキスト形式なので、理論上は別の形式に容易に変換できることになります。これは大変便利です。

ScrapboxからMarkdown経由でRe:VIEWに変換、したはずが……

というわけで、前回の編集作業ではScrapbox形式をMarkdown形式に変換するソフトウェアを使い、そこからRe:VIEW形式のテキストを出力しました。


が、どうも利用したScrapboxMarkdown変換器の出来がイマイチだったようで、結局手で修正する羽目になりました。当時はかなりの修羅場で本当にギリギリだったので、別のツールを試す時間もなかったのです。





入稿後、いろいろ調べたのですが、「なんか結局既存の変換ツールでMarkdown経由というのはかったるいな、しかもMarkdownってシンプルな形式だから途中で書式データ失われたりしたら嫌だなあ」みたいな気持ちがあり、そのまま直接Re:VIEWにするツールを作ればいいのでは……? という気持ちになってきました。

ふぁぼん「sb2review、作りますか……」

高品質最強Scrapboxパーサ

そこで、出来のいいScrapboxのパーサが存在しないか調べてみました。そもそも本家ではテキストデータをクライアント側でパース・整形・表示しているので、だったらそのコードをライブラリとして切り出してくれていれば万々歳なんですけど。


本家のものではありませんが、めちゃくちゃ丁寧に実装・テストされているJavaScript製パーサを発見しました。

github.com


これを使わない手はありません。というわけで、実装言語はJavaScriptで決まりです。


Deno事始

ちょうどその当時の私は「Denoとかいうの、楽しそう。機会があれば使ってみたい」という気分になっていました。せっかくだし、Denoでやってみようかな〜〜、と。

そこで気になるのが、このScrapbox記法のパーサはnpmのパッケージであるという点です。そしてDenoのパッケージシステムはES Module準拠で、Node.jsのCommonJSとは互換性がありません。読み込めるんでしょうか……?


そこで、Denoからこのライブラリを利用できるか試してみることにしました。



esm.shから無事インポートできました。神。

実装実装実装実装実装実装実装実装実装実装実装実装

最高のライブラリのおかげで、無事パーサを書く必要がなくなりました。ここまでくれば、あとはやるだけです。

さまざまな記法について、パーサを通した後のASTの構造を眺め、適切なコードジェネレータを実装して適切なRe:VIEW形式のテキストを出力できるようにするだけの簡単なお仕事。


この日はかなりノリノリだったようで、本体(約210 SLOC)とテスト(130 SLOC)を勢いだけで24時間+αで実装してしまったらしいです。「それのどこがすごいの?」って言われそうですが、私はめちゃくちゃ実装が遅いんですよ。本当に。たぶん人生で一番集中してコード書いた気がします。

書くべきプログラムの構造が脳内でしっかりイメージできていたので、本当に書くだけでした。私は雑魚なので、普段はここまで明瞭にイメージできません。



ハマった点を強いて述べるとするなら、Re:VIEW形式のエスケープでしょうか。どの文字がエスケープされるべきなのかをちゃんと把握するために、手元にあったRe:VIEWプロジェクトでいろいろ試して「○○記法の中のこの文字はエスケープするべき、この文字はエスケープ不要」みたいなのを調べました。ドキュメントを参照するだけだと少々不安だったので。

CLI対応

今回は要件が単純だったので、Deno標準ライブラリ(deno_std)に含まれるflagsというオプションパーサを利用しました。Node.jsのminimistというライブラリのインスパイアらしいです。

https://deno.land/std@0.118.0/flags

標準出力に色をつけるライブラリとかも標準ライブラリに揃ってて、大変助かりました。

Denoかなり最高じゃないですか?

特に小さいプロジェクトだと、Denoは最高だと思います。いろいろごちゃごちゃインストールするまでもなくTypeScriptが使えて、しかもlinterとかテストランナーとかが揃っているので。しかも標準ライブラリが充実していて便利です。


パッケージ管理に関しては、「package.jsonがいらないから最高」というのはちょっと詭弁な気がしています。真面目にやろうと思ったら結局deps.tsとかで依存性管理しないといけないんで……npmみたいに公式でそこらへんケアしてくれてた方が楽じゃない……? 真面目にやらない書き捨てコードならともかく。
ライブラリでなければimport maps使えばいいんですけどね。


逆に言えば、書き捨てコードでTypeScriptが使えてパッケージのインストールも必要ないわけで、これは本当にありがたい話です。


あと、地味にtop-level awaitが便利です。

今後の展望

概してScrapbox記法の方がRe:VIEW記法より自由度が高いので、どうしても変換できない部分はあります。そこらへんは諦め。


あと、ユーザのことを考えると、Webで変換できるツールも欲しいですね。どうしようかなあ。


追記: 同じサークルのkn1chtさんが作ってくれました。

kn1cht.github.io







TSG Advent Calendar 2021、明日はAzaika先生の「なんかかく」です。
東京大学きらら同好会 Advent Calendar 2021、明日の記事はみゃーこ先輩先生による「アルファブロガー折部やすな ※予定はフィクションです」です。どんな記事か全く想像できなくて楽しみ〜〜〜〜


この記事は約1時間で生成されました 技術系記事じゃなければこの分量だと2時間半以上はかかってましたね