Template Toolkit と Maud の条件付きクラス抽出をサポート
この PR は、Template Toolkit の %]…[% デリミタと Rust の Maud テンプレートにおける条件付きクラス構文を、Tailwind CSS のクラススキャナが正しく認識できるように前処理を追加します。結果として、従来漏れが発生していたクラスが抽出対象に含まれるようになります。
背景
Template Toolkit のデリミタ [% … %] が単語境界として認識されなかった ため、[% IF $cond %]bg-white/40[% END %] のようにデリミタ直後に続くクラス名がスキャンされませんでした。Issue #20233 では、[ と ] が境界文字に含まれていないことが原因と指摘されており、テンプレートエンジン全般で類似の問題が報告されていました。
Maud の条件付きクラス p.text-black[condition] も同様に抽出できなかった ことが別途報告され、[ がそのままクラス名の一部として扱われるため、text-black が候補から外れていました。これらの問題は、HTML 以外のテンプレートファイルで Tailwind のユーティリティクラスを利用した際にビルド結果が期待通りにならない原因となっていました。
技術的な変更
Template Toolkit 用の前処理モジュール template_toolkit.rs を新規追加 し、[% と %] をそれぞれスペースに置換します。これによりデリミタが単語境界となり、クラス名が正しく分離されます。
use crate::cursor;
use crate::extractor::pre_processors::pre_processor::PreProcessor;
#[derive(Debug, Default)]
pub struct TemplateToolkit;
impl PreProcessor for TemplateToolkit {
fn process(&self, content: &[u8]) -> Vec<u8> {
let len = content.len();
let mut result = content.to_vec();
let mut cursor = cursor::Cursor::new(content);
while cursor.pos < len {
match (cursor.curr(), cursor.next()) {
(b'[', b'%') => result[cursor.pos] = b' ',
(b'%', b']') => result[cursor.pos + 1] = b' ',
_ => {}
}
cursor.advance();
}
result
}
}
pre_process_input の拡張 により、拡張子 .tt, .tt2, .tx のファイルに対して TemplateToolkit 前処理が適用されます。HTML ファイルではコストを回避するためにこのロジックは呼び出されません。
match extension {
"tt" | "tt2" | "tx" => TemplateToolkit.process(&content),
// 既存ケース省略
_ => content,
}
Rust 前処理 (rust.rs) に条件付きクラス対応を追加 し、[ が現れた際に前文字が - でなければスペースへ置換します。これにより p.text-black[condition] の [ が境界となり、text-black が抽出対象になります。
b'[' => {
bracket_stack.push(cursor.curr());
// `p.flex[condition]` の場合はスペースに置換。`-` 前の場合は任意値として除外。
if !matches!(cursor.prev(), b'-') {
result[cursor.pos] = b' ';
}
}
テストケースが複数追加 され、Template Toolkit と Maud の両シナリオで期待通りにクラスが抽出されることを自動検証しています。テストは mod tests 以下に配置され、assert_extract_candidates_contains ヘルパーで確認されています。
#[test]
fn test_template_toolkit_syntax() {
assert_extract_candidates_contains(
&pre_process_input(
r#"<div class=\"[% IF $is_open %]bg-white/40[% ELSE %]bg-white/10[% END %]\"></div>"#,
"tx",
),
vec!["bg-white/40", "bg-white/10"],
);
}
設計判断
前処理レイヤに機能を組み込む方針 が採用されました。スキャナ本体のトークナイザを変更せず、入力文字列を事前に加工するだけで既存ロジックを再利用できる点が評価されています。
ファイル拡張子ベースのディスパッチ によって、.html では余計な前処理コストが発生しません。PR の説明にもあるように、Template Toolkit の構文は特定拡張子でのみ使用されるため、対象を絞ることでパフォーマンスへの影響を最小化しています。
シンプルな置換ロジック(スペースへの置換)を選択したことで、正規表現や構文解析を導入するリスクを回避し、後方互換性を保持しつつ機能追加が実現できました。既存の true/false の判定ロジックには影響を与えていません。
まとめ
Template Toolkit の %]…[% デリミタと Maud の条件付きクラス構文を前処理で対応することで、Tailwind CSS のクラス抽出が正確になり、テンプレートエンジン固有の記法でもユーティリティクラスが利用可能になりました。実装は拡張子判定と文字置換という軽量手法にとどめ、既存コードへの侵入度を最小限に抑えた設計が特徴です。