Quartz v4アップデート したところ、preactとremarkの知識が必要になったので調べた。 いくつかの用語や概念を知っている必要があって、初学者には厳しかったので調べたことをまとめておく。
unified
テキストからASTを作成したり、そのAST木を解析して別のテキストに変換したりするためのJavaScript製フレームワークのこと。
構文木は自然言語を名詞や動詞など、構文にそって解析して木構造としたもので、 Abstract Syntax Tree(AST, 抽象構文木)はその構文木から、文法のための記号や助詞など、意味のない部分を除いた木構造。
parser, compiler, transformerといった各コンポーネントに分かれて、ファイルを仮想化したvfile(virtualized file)を用いてデータを受け渡しする
remark
unifiedの中でMarkdownの処理を担当する。 Markdownをparseする remark-parse、compileするremark-stringify、ASTやHTMLへの変換を担当する各transformerがある。
MarkdownのASTをmdastという。
rehype
unifiedの中でHTMLの処理を担当する。 HTMLのASTをhastという。
unifiedの処理の流れ
https://github.com/unifiedjs/unified#overview に図が書かれている通りで、 Input → parser -(ASTに変換)→ transformer → compiler → Output として
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import remarkStringify from 'remark-stringify';
const processer = unified()
.use(remarkParse) // MarkdownをparseしてASTを作成
.use(remarkRehype) // MarkdownからHTMLのASTに変換
.use(rehypeStringify); // HTMLのASTをテキストに変換
const markdownText = fs.readFileSync('./content/hello.md');
const markdownTree = processer.parse(markdownText);
const htmlTree = await processer.run(markdownTree);
const htmlText = processer.stringify((htmlTree as any));
transformerの作成
ASTに対して独自の編集を行うためtransformerを作成する。
トラバース
unist-util-visit を使う。
import { Literal, Node, Parent } from "unist"
import { Paragraph, Text, Link } from "mdast"
import { VFile } from "vfile"
import { visit } from "unist-util-visit"
const transformer = () => {
return (tree: Node, file: VFile) => {
// Paragraph型のノードを探して処理する
visit(tree, "paragraph", (paragraghNode: Paragraph, index: number, parent: Parent) => {
const child0 = paragraghNode.children[0]
if (isText(child0)) {
console.log(child0.value)
}
})
}
}
function isText(node: Node): node is Text {
return (
node.type === "text" && typeof node.value === "string"
);
}
現在のASTを表示する
プラグイン開発にあたって、現在のASTがどうなっているかを確認するために便利なヘルパーが用意されている。
unist-util-inspect の inspect
にtreeを渡すと、木構造をprintできる。
import unified from "unified";
import { Node } from "unist";
import { VFile } from "vfile";
import { inspect } from "unist-util-inspect";
const print: unified.Plugin = () => {
return (tree: Node, file: VFile) => {
console.log(inspect(tree));
};
};
/* 以下のようなツリーが出力される
├─0 yaml "title: hoge" (1:1-4:4, 0-53)
├─1 paragraph[2] (6:1-6:116, 55-170)
│ ├─0 link[1] (6:1-6:46, 55-100)
│ │ │ title: null
│ │ │ url: "https://github.com/"
│ │ └─0 text "GitHub" (6:2-6:8, 56-62)
│ └─1 text " を参照する " (6:46-6:53, 100-107)
├─2 paragraph[1] (8:1-8:73, 172-244)
│ └─0 link[1] (8:1-8:73, 172-244)
│ │ title: null
│ │ url: "note/sample2.md"
│ └─0 text "this is sample" (8:2-8:34, 173-205)
└─3 list[4] (10:1-13:32, 246-362)
│ ordered: false
│ start: null
│ spread: false
├─0 listItem[1] (10:1-10:22, 246-267)
│ │ spread: false
....
*/