ImageGalleryNodeの単一子要素アンラップ時に`$makeSafeForRoot`を適用
Trixギャラリーが やメンションなど予期しない単一子要素を持つ場合に発生していたクラッシュを、$makeSafeForRoot を適用することで修正しました。
背景
ImageGalleryNode は、ギャラリー内の画像が1枚だけになった場合に replaceWithSingularChild() を呼び出し、ノードを単一の子要素で置換します。しかし、Trixが生成するギャラリーのHTMLには やメンション要素など、Lexxyのルートノードに直接追加できない要素が子として混入するケースがありました。
この状況では、 のようなテキストノードやメンションがルートに直接 replace されようとしてエラーが発生していました。バグを再現するには「2つのメンションの後に を含むギャラリー」という特定の条件が必要であり、テストコードのコメントにもその旨が明記されています。
技術的な変更
変更は src/nodes/image_gallery_node.js の replaceWithSingularChild() 内の1行のみです。$makeSafeForRoot をラップすることで、ルートに追加不可能な子要素を安全な形に変換してから置換するようになりました。
変更前:
replaceWithSingularChild() {
if (this.#hasSingularChild) {
const child = this.getFirstChild()
return this.replace(child)
}
}
変更後:
replaceWithSingularChild() {
if (this.#hasSingularChild) {
const child = this.getFirstChild()
return this.replace($makeSafeForRoot(child))
}
}
あわせて test/browser/tests/attachments/gallery.test.js にリグレッションテストが追加されました。startMonitoringConsole でコンソールエラーを監視し、2つのメンションと を含むギャラリーをセットした後にエディタをクリックしても page.toHaveNoErrors() を満たすことを確認しています。
設計判断
$makeSafeForRoot はLexxyがルート直下に配置できない要素を安全なノードへ変換するユーティリティです。この修正では child を直接渡すのではなく、一度このユーティリティを通すことで、ImageGalleryNode 側がルートの制約を意識せずに済む設計が維持されています。
ギャラリーの子要素を正規化するアプローチではなく、アンラップ時点でルート安全性を保証する方針が採られました。これにより、Trix側からどのような予期しない要素が混入しても replaceWithSingularChild() が堅牢に動作します。変更箇所が最小限(1行)であり、既存の正常系フローへの影響もありません。
まとめ
本PRは、$makeSafeForRoot を一箇所挿入するだけで、Trix由来の不正な子要素によるクラッシュを防ぐ堅実な修正です。ルートへの挿入可否をアンラップ処理の責務として明確に位置づけた判断により、外部入力の多様性に対する耐性が高まりました。