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ノードという順でも実装可能ですね。
でも、コードがちょっと煩雑になりそうな気がする🤔
以上、忘れないようにメモでした。
関連記事