Orcantus

Report

GitHub・Zenn・Qiitaのコールアウト記法11種を、4色に正規化して1つの見た目にする

GitHub・Zenn・note.com・Qiitaのどれで書いた記事もそのまま貼れることを、Orcantus Notesの記事は目標にしています。注意書きの囲み(コールアウト)だけを見ても、GitHubは> [!NOTE]、Zennは:::message、Qiitaは:::note infoと、書き方も記号も3者3様です。これを実際にどう1つの見た目へ揃えているかを、実装とビルド結果の両方で確認します。

結論。GitHub Alerts 5種・Zennの:::message系2種・Qiitaの:::note系4種、合計11種の入力パターンは、markdown-itのトークン変換(core ruleとコンテナプラグイン)によって、すべてOrcantusの4色コールアウト(note/tip/warning/strong)のいずれかへ正規化される。 実際にparseNoteへ通すと、どの記法で書いても出力されるHTMLの構造(<div class="callout callout--<tier>">)は共通になることを確認した。

パーサー自体は変えず、トークンを書き換える

実装は独自パーサーではなくmarkdown-it(CommonMark + GFM相当)が土台です(scripts/notes-markdown.mjs)。GitHub Alertsは独自ルールとしてではなく、CommonMark標準の引用(blockquote)として一度パースさせてから、先頭行がマーカーと一致する場合だけトークンの種類を書き換える実装になっています(scripts/notes-github-alerts.mjs)。

md.core.ruler.after('block', 'github_alerts', (state) => {
  const tokens = state.tokens
  for (let i = 0; i < tokens.length; i++) {
    if (tokens[i].type !== 'blockquote_open') continue
    // ...先頭のinlineトークンが `[!NOTE]` 等で始まるか調べる
    tokens[openIdx].type = 'callout_open'
    tokens[openIdx].tag = 'div'
    tokens[openIdx].meta = { tier }
    tokens[closeIdx].type = 'callout_close'
  }
})

マーカーに一致しなければblockquote_openのまま残るため、ただの引用文(マーカーなし)は普通の<blockquote>として表示されるという、GitHub自身の挙動(Alertsのマーカーが無ければ通常の引用)とも一致する副産物があります。

Zenn・Qiitaの:::message / :::note系は、どちらもmarkdown-it-containerが実装する「フェンス付きdiv」記法という、パーサーとしては同一のものです(scripts/notes-containers.mjs)。サービスごとに違うのは色分けの意味づけだけなので、firstArg(info)で2番目の単語(alert・info・warnなど)を読み取り、Orcantusの階層へマッピングする関数を記法ごとに1つずつ用意しています。

function zennMessageTier(info) {
  return firstArg(info) === 'alert' ? 'strong' : 'note'
}
function qiitaNoteTier(info) {
  const kind = firstArg(info)
  if (kind === 'warn') return 'warning'
  if (kind === 'alert') return 'strong'
  return 'note'
}

最終的な見た目はscripts/notes-callout.mjsの2関数(renderCalloutOpen / renderCalloutClose)にだけ集約されています。GitHub由来・Zenn由来・Qiita由来のどのレンダラーも、最後はこの共通関数を呼ぶ構造です。

実際に11種を通してみる

実装を読むだけでなく、parseNoteに実際のMarkdownを通して確認しました。入力は次の11パターンです。

> [!NOTE]
> GitHubのAlerts記法です。

> [!TIP]
> tip

> [!IMPORTANT]
> important

> [!WARNING]
> warning

> [!CAUTION]
> caution

:::message
通常メッセージ
:::

:::message alert
Zennの警告メッセージです。
:::

:::note
通常note
:::

:::note info
info
:::

:::note warn
Qiitaのwarnです。
:::

:::note alert
alert
:::

node -eでparseNoteを直接呼び出し、frontmatterを除いた本文の出力HTMLを確認すると、以下のようになりました(クラス名のみ抜粋)。

入力 由来 出力クラス
[!NOTE] GitHub callout--note
[!TIP] GitHub callout--tip
[!IMPORTANT] GitHub callout--strong
[!WARNING] GitHub callout--warning
[!CAUTION] GitHub callout--strong
:::message Zenn callout--note
:::message alert Zenn callout--strong
:::note Qiita callout--note
:::note info Qiita callout--note
:::note warn Qiita callout--warning
:::note alert Qiita callout--strong

実際に出力された[!NOTE]・:::message alert・:::note warnの3件のHTMLは次の通りです(parseNoteの戻り値bodyHtmlそのまま)。

<div class="callout callout--note"><p class="callout__title">Note</p>
<p>GitHubのAlerts記法です。</p>
</div>
<div class="callout callout--strong"><p class="callout__title">Important</p>
<p>Zennの警告メッセージです。</p>
</div>
<div class="callout callout--warning"><p class="callout__title">Warning</p>
<p>Qiitaのwarnです。</p>
</div>

マーカー文字列([!NOTE]やalert)自体は出力に残らず、タイトル(Note・Important・Warning)はOrcantus側の4段階(CALLOUT_TITLES)に置き換わっています。GitHubの5段階(note/tip/important/warning/caution)のうち、important と caution はどちらも「強い注意」としてstrong1段階へ合流する実装になっており、表の通り両方ともcallout--strongになることを確認しました。

マーカーが無ければ元の記法に戻る

正規化は「マーカーに一致した場合だけ」起こる設計です。マーカーの無い普通の引用を同じparseNoteに通すと、書き換えは起こらず通常のCommonMark出力になります。

> ただの引用で、マーカーなし。

出力:

<blockquote>
<p>ただの引用で、マーカーなし。</p>
</blockquote>

同様に:::details(Zenn由来の折りたたみ記法)はコールアウトではなく<details>要素に変換され、コールアウトの4色とは別経路で処理されています(:::details 展開して見る → <details class="note-details"><summary>展開して見る</summary>...)。「コンテナ記法だからすべてコールアウトになる」わけではなく、名前ごとに個別のレンダラーが登録されている、という実装の構造が出力からも確認できます。

この結果が言っていないこと

  • 確認したのは本リポジトリのscripts/notes-markdown.mjs・scripts/notes-github-alerts.mjs・scripts/notes-containers.mjs・scripts/notes-callout.mjs(2026-09時点のソース)と、そのコードへ実際にMarkdownを通したparseNoteの出力です。GitHub・Zenn・Qiita自身が将来マーカーの種類や意味づけを変更した場合、この記事の対応表は追従していません。
  • この記事が示しているのは「Orcantus Notesのビルドパイプラインが何を4色へ正規化するか」であり、GitHub・Zenn・Qiita自身の画面上での実際の見た目(アイコンの有無や配色)を調べたものではありません。各サービス自身の表示仕様については別記事の対象です。
  • 対応していない記法(数式・Mermaid・SNS埋め込み)はこの記事の対象外です。書いても壊れず、素のテキスト/コードブロックとして表示されます(docs/NOTES_PLAYBOOK.md参照)。

由来の違う記法が実装の中でどこまで合流し、どこで分岐したままなのかが、実際にコードを読んで入力を通すとはっきり見えました。