CJK フレンドリーな強調
CJK の表意文字やかなに隣接する太字・斜体マーカーが正しく解釈されるようにする。
CjkFriendlyPlugin はデフォルトで有効です。パース済みの Markdown AST を後処理し、CJK コンテンツに対して強調のフランキング規則を再トークン化します。同じ cjkFriendly ゲートは、GFM の bare URL autolink が隣接する CJK テキストを飲み込むことを防ぐ CjkAutolinkBoundaryPlugin も制御します。
なぜこれが必要か
CommonMark の強調フランキング規則は、CJK の表意文字やかなを 「非空白かつ非句読点」として扱います。これにより、CJK テキストに隣接する ** — たとえば **テスト。**テスト — は基本パーサーでは右フランキングとみなされず、 <strong> ではなくそのままのアスタリスクとして描画されてしまいます。
CjkFriendlyPlugin はパース済みの Markdown AST を後処理し、これらのケースを 再トークン化します。その結果は、日本語・中国語・韓国語のコンテンツサイトにおける 直感的な期待と一致します。
GFM autolink literal には関連する境界問題があります。詳細はhttps: のように CJK テキストに密着して URL を書くと、末尾の CJK の並びがリンクの一部として扱われることがあります。cjkFriendly が有効で、gfm.autolinkLiteral が on のとき、CjkAutolinkBoundaryPlugin は最初に隣接する CJK 文字の位置で autolink を分割します。
挙動
デフォルト: 常に有効。設定キーは不要です。
オプトアウト(まれ): 厳密な CommonMark / GFM 出力が必要で、かつコンテンツに CJK の強調や bare URL の境界ケースが含まれない場合に限り、zfb.config.ts で cjkFriendly: false を 設定します:
import { defineConfig } from "zfb/config";
export default defineConfig({
markdown: {
cjkFriendly: false,
},
});スコープ
このオプションは次を処理します:
CJK 文字に隣接する
**bold**と*italic*。gfm.autolinkLiteralが有効なときの、CJK 文字に隣接する GFM bare URL autolink 境界。セカンダリパースサイトを経由するコンテンツ —
:::includeで取り込まれたファイルや、 ディレクティブレジストリによって再パースされるディレクティブ本体 — も、この設定に 従うようになりました(#2398)。
リテラルの * と ** の修復は、対応するパース済みインライン兄弟ノードをまたぐことができ、それらのノードはそのまま保持されます。たとえば:
知られる**[LA-2A](https://example.com)光学式コンプレッサー**と、**Neve 1073 EQ**という最初の strong 範囲には保持された LA-2A リンクと 光学式コンプレッサー が含まれ、既存の続く strong 範囲には Neve 1073 EQ が含まれます。未対応または不透明なインラインコンテンツは境界のままです。
GFM の打ち消し線(~~foo~~)にはこのトグルは不要です — markdown-rs の GFM トークナイザーが ~~ のデリミタ連続を独立して処理するため、両方のモードで CJK の境界においても打ち消し線は正しく機能します。
HTML レンダリングパスにおけるディレクティブ本体の強調
cjkFriendly はマーカーを正しく再トークン化しますが、HTML レンダリングパス — @takazudo/zfb-md-wasm の renderHtml — を通るコンテナ ディレクティブの本体は、インラインの書式を意図的に落とす lossy な文字列化処理で JSX 本体が再構築されます。つまり次のソースは:
:::note
これは**重要。**テスト
:::このように描画されます:
<Note>これは重要。テスト</Note>コンテンツは失われません — 本体テキストの文字はすべて残り、落ちるのは <strong> のラッパーだけです。同じマーカーを通常の本文に書いた場合は <p>これは<strong>重要。</strong>テスト</p> になります。
これは cjkFriendly に固有の挙動ではなく、collapsed(空行なし)のディレクティブ 本体に固有の挙動でもありません。cjkFriendly が off の ASCII でも同じで、 plain **bold** text を :::note で囲むと <Note>plain bold text</Note> に なりますし、本体の前後に空行を入れても変わりません。cjkFriendly が決めるのは ** が強調としてトークン化されるかどうかだけで、その後それを平坦化するのは HTML パスの文字列化処理です。cjkFriendly: false ではそもそもトークン化されない ため、** はリテラルのまま残ります。
ページのビルドには影響しません。 zfb build はコンテンツを MDX/JSX の出力 パスでコンパイルし、そちらは本体を再帰的に描画するため、同じソースから <_ がネストして出力されます。
書式だけが失われるのは意図的な挙動です。一方このパスでのコンテンツの削除は バグとして扱われます。hardBreaks が有効なとき、ディレクティブ 本体内のハードブレークが完全に消えて前後の語が繋がってしまう問題がありました。 これは修正済みで(zfb#2401)、現在は <br /> として描画されます。
関連項目
Markdown のカスタマイズ — パイプライン全体の概要。