lazy developers blog

unified(remark,rehype)を利用してMarkdownをHTMLに変換する

unifiedを使用してMarkdown形式の文章をHTMLに変換するための備忘録です。

unifiedとは

unifiedは、テキストを構文木(syntax tree)として扱うためのインターフェース。unifiedで使用する構文木はunistとして仕様が決められています。
このunistを拡張し、さまざまな形式を取り扱うようにしたパッケージの一部が以下になります。

  • remark : Markdownを扱うためのプロセッサで、unistを拡張したmdastと呼ばれる構文木を使用する
  • rehype : HTMLを扱うためのプロセッサで、unistを拡張したhastと呼ばれる構文木を使用する

この2つのパッケージのプラグインを使用することで、MarkdownからHTMLへの変換を行います。

remarkについて

remarkは、Markdownを取り扱うためのプロセッサです。remarkには以下のようなプラグインがあります。

  • remark-parse : Markdownをmdastに変換するためのプラグイン
  • remark-stringify : mdastをMarkdownに変換するためのプラグイン

rehypeについて

rehypeは、HTMLを取り扱うためのプロセッサです。rehypeには以下のようなプラグインがあります。

  • rehype-parse : HTMLをhastに変換するためのプラグイン
  • rehype-stringify : hastをMarkdownに変換するためのプラグイン

MarkdownからHTMLへ変換する

実際にMarkdownからHTMLへ変換してみます。
処理の流れは以下のようになります。

  1. Markdownをmdastに変換する
  2. mdasthastに変換する
  3. hastをHTMLに変換する

必要なプラグインをインストールします。remark-rehypeはmdastをhastに変換するためのプラグインです。

1npm i -D unified remark-parse remark-rehype rehype-stringify

プログラムは以下のようになります。
useで使用するプラグインを順番に設定し、processSyncでMarkdownを受け取り処理を実行します。

1import unified from 'unified';
2import remarkParse from 'remark-parse';
3import remarkRehype from 'remark-rehype';
4import rehypeStringify from 'rehype-stringify';
5
6const test = () => {
7  console.log(
8    unified()
9      .use(remarkParse)
10      .use(remarkRehype)
11      .use(rehypeStringify)
12      .processSync('# Hello World')
13      .toString(),
14  );
15};

実行した結果は以下のようになります。

1<h1>Hello World</h1>

プラグインの自作

プラグインを自作するにはunifiedのプラグインの作り方を参考にしていきます。

remarkプラグインの自作

ここでは、入力されたMarkdownの後ろにhogehogeという文字を追加するだけのプラグインを作成します。
まずは、トランスフォーマーを宣言します。

1import { Transformer } from 'unified';
2import { Node } from 'unist';
3
4const remarkTest: () => Transformer = () => {
5  const transformer: Transformer = (tree: Node) => {
6  };
7  return transformer;
8};
9
10export default remarkTest;

次に、トランスフォーマーの中身を追加します。
treeノードをRoot型に変換し、childrenに新しいパラグラフを追加します。値は返さなくても変更されていますが、ここでは分かりやすく変更した値を返しています。

1import { Transformer } from 'unified';
2import { Node } from 'unist';
3import { Root } from 'mdast';
4
5const remarkTest: () => Transformer = () => {
6  const transformer: Transformer = (tree: Node) => {
7     const root = tree as Root;
8     root.children.push({
9       type: 'paragraph',
10       children: [
11         {
12           type: 'text',
13           value: 'hogehoge',
14         },
15       ],
16     });
17     return root;
18  };
19
20  return transformer;
21};
22
23export default remarkTest;

作成したremarkTestプラグインはmdastを変更するため、remarkParsemdastに変換された後に追加します。

1const test = () => {
2  console.log(
3    unified()
4      .use(remarkParse)
5      .use(remarkTest)
6      .use(remarkRehype)
7      .use(rehypeStringify)
8      .processSync('# Hello world')
9      .toString(),
10  );
11};

実行結果は以下のようになります。

1<h1>Hello world</h1>
2<p>hogehoge</p>

rehypeプラグインの自作

remarkと同様に作成します。違いはremarkがmdastを操作するのに対し、rehypeはhastを操作する点だけです。

おわりに

unifiedを利用し、MarkdownをHTMLに変換する方法を書きました。
unifiedのエコシステムには数多くのプラグインが存在するため、それらをうまく活用することでMarkdownやHTMLはもちろん、それ以外の文章もすばやく編集することができるようになると思います。