MDXファイル内のドット付きクラス名の抽出不具合を修正

tailwindlabs/tailwindcss

Tailwind CSS v4.2.1では、MDXファイル内で p-2.5 のようなドット付きユーティリティクラスが正しく抽出されない不具合が修正されました。これにより、MDXとMarkdownディレクティブ構文の両方で安定したクラス抽出が可能になります。

背景

v4.1.14でMarkdownディレクティブ構文(:span[Some Text]{.text-gray-500})のクラス抽出をサポートする修正が行われましたが、この修正がMDXファイルに副作用をもたらしていました。ディレクティブ構文内の . を空白に置換する前処理が、MDXのJSX構文内のクラス名にも適用されてしまったためです。

Tailwind CSSのドキュメントサイト自体が以下のような記法を使用しており、p-2.5 が正しく抽出されない状態になっていました:

<Example>
{
  <div class="p-2.5"></div>
}
</Example>

ディレクティブ構文のサポートとMDXの互換性を両立させる必要がありました。

技術的な変更

crates/oxide/src/extractor/pre_processors/markdown.rs に括弧のネストレベルを追跡する機構が追加されました。

変更前:

let mut in_directive = false;

while let Some(_) = cursor.next() {
    match (in_directive, cursor.curr()) {
        (false, b'{') => {
            result[cursor.pos] = b' ';
            in_directive = true;
        }
        (true, b'}') => {
            result[cursor.pos] = b' ';
            in_directive = false;
        }
        (true, b'.') => {
            result[cursor.pos] = b' ';
        }
        _ => {}
    }
}

変更後:

let mut in_directive = false;
let mut bracket_stack = vec![];

while let Some(_) = cursor.next() {
    match (in_directive, cursor.curr()) {
        (false, b'{') => {
            result[cursor.pos] = b' ';
            in_directive = true;
        }
        (true, b'(' | b'[' | b'{' | b'<') => {
            bracket_stack.push(cursor.curr());
        }
        (true, b')' | b']' | b'}' | b'>') if !bracket_stack.is_empty() => {
            bracket_stack.pop();
        }
        (true, b'}') => {
            result[cursor.pos] = b' ';
            in_directive = false;
        }
        (true, b'.') if bracket_stack.is_empty() => {
            result[cursor.pos] = b' ';
        }
        _ => {}
    }
}

bracket_stack がネストレベルを管理し、<{[( の出現時にスタックに追加、対応する閉じ括弧で削除します。. の置換処理は bracket_stack.is_empty() の場合のみ実行されるようになり、トップレベルのディレクティブ構文内でのみ動作します。

設計判断

実装は意図的にシンプルに保たれています。PR内で言及されている通り、括弧の順序検証、対応しない括弧、文字列内のエスケープ、コードブロックの除外といった複雑なケースには対応していません。

この判断の背景には、この不具合に関するバグレポートが確認されていないという事実があります。より堅牢な実装は複雑さとバグのリスクを増大させるため、実際に問題が報告された時点で対処する方針が採用されました。

現在の実装は、Markdownディレクティブ構文(トップレベルのクラス指定)とMDXのJSX構文(ネストしたクラス指定)という2つの主要なユースケースを満たしており、実用上十分な解決策となっています。

まとめ

本修正は、ネストレベルの追跡という最小限の変更で、Markdownディレクティブ構文とMDXの互換性問題を解決しました。意図的にシンプルな実装を選択することで、保守性を維持しながら実用上の問題を解消しています。Tailwind CSSのドキュメントサイト自体がこの構文に依存しているため、この修正は公式ドキュメントの品質向上にも直結します。

記事メタデータ

Generated by:
Claude Sonnet 4.5 for DiffDaily

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

「リード文(総論)→背景・技術詳細・設計判断(各論)→まとめ(結論)」という3部構成が明確です。特に、PRに記載された設計思想を「設計判断」として独立セクションで解説しており、読者の深い理解を促す優れた構成です。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きシンタックスハイライト(```rust:ファイルパス)とGitHubのPRリンク記法([#19711](URL))が正しく使用されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

Tailwind CSSの内部実装に関する内容であり、専門知識を持つエンジニアという対象読者に適した技術レベルと表現で書かれています。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが総論→各論の構成になっており、各段落はトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が守られています。これにより、非常に読みやすく、理解しやすい記事になっています。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事内で引用されているコードブロック(変更前・変更後)は、提供されたDiff情報と正確に一致しています。ファイルパスも正しく記載されています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「MDX」「Markdownディレクティブ構文」「プリプロセッサ」「スタック」などの技術用語が、PRの文脈に沿って正確かつ適切に使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

「bracket_stack」を用いたネストレベルの追跡機構に関する説明は、コードの変更内容と完全に一致しており、技術的に正確です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事内のすべての主張(v4.1.14での副作用、ドキュメントサイトでの利用例、意図的にシンプルな実装にした背景など)は、PRのDescriptionで完全に裏付けられており、ハルシネーションは一切見られません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号(#19711)、バージョン番号(v4.2.1, v4.1.14)、クラス名(p-2.5)などの数値・固有名詞はすべて正確です。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事のタイトル「MDXファイル内のドット付きクラス名の抽出不具合を修正」は、PRのタイトル「Fix missing extracted classes in mdx files」の内容をより具体的に、かつ正確に表現しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

記事内の情報はすべてPR情報(Description, Diff)に基づいており、バージョンサポート状況やリリース日程といったPRに記載のない外部知識の追加はありません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

記事内の時間表現はPRの文脈と一致しており、事実を歪めるような記述はありません。