remark-gfmの脚注内リンクを処理するremarkプラグインの作り方
はじめに
Astroではremark-gfm(GitHub風マークダウンを実現するremark)がデフォルトで有効です。そのため、astro.config.ts
のremarkPlugins
で渡されるmdastは、すでにremark-gfm
で処理されています。
AstroはGitHub風のマークダウンをデフォルトで使用します。
設定方法
docs.astro.build
remark-gfmで生成される脚注ノード
remark-gfmでは下記のようなMarkdownで脚注を記述できます。
sample[^1]なんだよ
[^1]: https://example.com/
得られるmdastは下記です。ちなみに、こんな感じでunified系のASTをツリー表示したい場合はunist-util-inspectライブラリが非常に便利です。
root[2] (1:1-5:1, 0-44)├─0 paragraph[3] (2:1-2:15, 1-15)│ ├─0 text "sample" (2:1-2:7, 1-7)│ ├─1 footnoteReference (2:7-2:11, 7-11)│ │ identifier: "1"│ │ label: "1"│ └─2 text "なんだよ" (2:11-2:15, 11-15)└─1 footnoteDefinition[1] (4:1-4:27, 17-43) │ identifier: "1" │ label: "1" └─0 paragraph[1] (4:7-4:27, 23-43) └─0 link[1] (4:7-4:27, 23-43) │ title: null │ url: "https://example.com/" └─0 text "https://example.com/" (4:7-4:27, 23-43)
ここから最終的に脚注セクションとしてHTMLに現れるわけですが、footnoteDefinition
以下のlink
ノードのみ処理するremarkプラグインをどう作るかというのが表題の意です。
脚注内リンクノードの検知
tree走査用のライブラリとしてunist-util-visit-parentsを使います。
unist-util-visit
とは違い、第三引数のvisitor
メソッドで親ノードではなく祖先ノードリストを受け取ることができます。
unist-util-visit
やunist-util-visit-parents
のvisit
メソッドの第二引数はNodeタイプのマッチング条件です。link
を指定したことでLinkノードのみを処理することを意味します。
さらにvisitor
側で祖先ノードにfootnoteDefinition
が存在しない場合にreturn
するようにすれば、脚注内以外のLinkノードを除外できます。
import { type Plugin } from 'unified';import { visitParents } from 'unist-util-visit-parents';
import type { Root } from 'mdast';
export const remarkLinkCard: Plugin<[], Root> = () => { return (tree) => { visitParents(tree, 'link', (node, ancestors) => { if (!ancestors.some((ancestor) => ancestor.type === 'footnoteDefinition')) return;
// 脚注内のリンクノードに対する処理 }); };};
おわりに
unist-util-visit
でfootnoteDefinition
をtest
に指定して、そのノードのchildren
に含まれるLinkノードという順でも実装可能ですね。
でも、コードがちょっと煩雑になりそうな気がする🤔
以上、忘れないようにメモでした。
関連記事
