yigarashiのブログ

学んだことや考えていることを書きます

webextension-polyfill-tsの型定義の自動生成がバグっていたので直した

Fix type generation for WebExtensionManifest.commands by yigarashi-9 · Pull Request #66 · Lusito/webextension-polyfill-ts

珍しくOSS活動をしたので簡単に報告記事を書く。

問題

最近ブラウザ拡張をよく触っている。同僚がmanifest.jsonをTypeScriptから生成できる良い仕組みを整えてくれており、自分も元気に開発を進めたのだが、どうにも型が合わない。最初は型がついたおかげでミスが静的に検出されていいな〜と眺めていたのだけど、よくよく調べるとどうも型定義が間違っている。具体的にはmanifest.d.tsの以下の箇所。

        commands?: WebExtensionManifestCommandsType;
    interface WebExtensionManifestCommandsType {
        /**
         * Optional.
         */
        suggested_key?: WebExtensionManifestCommandsSuggestedKeyType;

        /**
         * Optional.
         */
        description?: string;
    }

MDNのドキュメントにあるように、commandsは任意のkeyでcommand名を指定しつつ、ショートカットキーの設定を与えることになっている。しかし型定義のほうは、commandsに直接ショートカットキーの設定を与える形になっていて誤っている。commandsはRecord<string, WebExtensionManifestCommandsType>といった型になっていると良さそうに見える。

解決

型定義を1行直したら解決と思いきやそうではない。MozillaはWebExtensions APIJSON SchemaライクなAPI Schemaで定義している。今回使っているwebextension-polyfill-tsは、そのAPI Schemaから型定義を自動生成している。今回の問題はその自動生成プロセスのバグによるものであった。

具体的には、API Schemaに対する前処理として、別ファイルでextendしているものをひとつにまとめ(上の例ではmanifest.d.tsの単位でまとめている)、その上で入れ子になっている定義を分割する(上の例だとWebExtensionManifestCommandsTypeのような分割)のだが、その過程でobjectが入れ子構造になっている情報が潰れてしまっていた。

再帰処理の感じから一般のケースとして直すのが難しそうに見えたので、コーナーケースとしてobjectの入れ子を補う処理を加えて修正とした。半信半疑で修正を加えて型定義を再生成したところ、見事に問題の箇所だけdiffができて直ったので自己肯定感がだいぶ高まった。