• 作成:

tidy-html5が5.9バージョンあたりからpreタグの改行を消してしまうので加工した内容を使わないようにする

背景

このサイト、 ncaq/www.ncaq.net: ncaq website はHakyllで構築しています。

そして最終的に出力するHTMLが正しいかどうかを、 htacg/tidy-html5: The granddaddy of HTML tools, with support for modern standards を通すことでチェックして、ついでにHTMLとXML(feed)をインデントしています。

問題

tidy-html5の5.9あたりからは以下のバグが発生しています。

tidy removes line breaks inside a pre element containing another element · Issue #1006 · htacg/tidy-html5

短く解説すると、バージョン5.7あたりのtidy-html5はpreタグなどの内容は改行やスペースを維持していましたが、 5.9からは改行やスペースを雑に消去してしまうというものです。

これにより何が起きるのかと言うと、ソースコードを埋め込み表示した場合に2つスペースを入れたつもりが1つだけになってしまったりして、特にインデントセンシティブなHaskellなどの言語では意味不明なソースコード埋め込みが発生します。このサイトでも一時的にそうなっていました。

issueにも書きましたがbisectで発生コミットは特定しましたが、コミットの内容が再帰スタックからヒープにデータを格納するというパーサコアに7482行の修正を加える大工事で、原因を特定するのが難しいです。

試しにスペース関係の判定をちょっと書き換えてみましたが、改善しなかったので諦めています。

ワークアラウンド

仕方がないので、チェックだけしてインデントは行わないようにします。

これまではunixFilterでtidyの出力する内容にHTMLデータを書き換えていましたが、以下のように--errorsで構文のチェックだけして、出力内容を捨てて現状のデータを使います。

-indentHtml :: Item String -> Compiler (Item String)
-indentHtml = withItemBody $ unixFilter "tidy"
-  [ "--mute-id", "y"
-  , "--drop-empty-elements", "n"
-  , "--tidy-mark", "n"
-  , "--wrap", "0"
-  ]
+-- | HTMLとして正しいかをチェックだけして、
+-- 内容は変更せずに返します。
+tidyHtml :: Item String -> Compiler (Item String)
+tidyHtml item = check item >> pure item
+  where check =
+          withItemBody $ unixFilter "tidy"
+          [ "--errors"
+          , "--mute-id", "y"
+          , "--drop-empty-elements", "n"
+          , "--tidy-mark", "n"
+          , "--wrap", "0"

このようにしてもunixFilterはコマンドが正常終了したかはチェックするので、インデントは出来なくなりますが、不正なHTML閉じなどの検出は可能です。