shwldshwld6 days ago

コードブロック内の@メンションは変換しない

コメント本文中の @userId@displayName に変換するとき、コードブロック内のトークンまで置換してしまうと表示が崩れる。マークダウンをコードブロック境界で分割してから、非コード部分だけ変換するとうまくいった。

具体的には、コードブロックのパターンで本文を split し、セグメントがコードかどうかで処理を切り替える。

const CODE_SEGMENT_PATTERN = /(```[\s\S]*?```|`[^`\n]*`)/g;

function renderWithDisplayMentions(body: string, members: Member[]): string {
  const idToName = new Map(members.map(m => [m.id, m.displayName]));

  return body
    .split(CODE_SEGMENT_PATTERN)
    .map(segment =>
      isCodeSegment(segment)
        ? segment                          // コードはそのまま
        : replaceMentions(segment, idToName) // テキストだけ変換
    )
    .join("");
}

function isCodeSegment(s: string) {
  return (s.startsWith("```") && s.endsWith("```")) ||
         (s.startsWith("`") && s.endsWith("`"));
}

split に capture group を使うことで、コードブロック自体も配列の要素として残るのがポイント。capture group がないと区切り文字が消えてしまう。

メンションの置換時は displayName にマークダウン特殊文字が含まれうるのでエスケープも忘れずに。