2
1

More than 1 year has passed since last update.

unified.jsでMarkdownをHTMLに変換する

Posted at

unified.jsはAST(抽象構文木)を使いテキストフォーマットを変換できるライブラリです。
remark(Markdown)、rehype(HTML)、retext(自然言語)といったフォーマットの実装があります。

今回はremarkとrehypeを使い、MarkdownをHTMLに変換してみます。

インストール

必要なパッケージをあらかじめインストールします。

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

unifiedはES Modulesとして提供されているので、Node.jsで使うにはpackage.jsonに次の記載を追加する必要があるようです。

package.json
"type" : "module"

Markdownをパースする

unifiedではある形式のテキストをASTに変換する処理をParserが担います。
今回はMarkdownをパースするのにremark-parseを使います。

import unified from 'unified';
import remarkParse from 'remark-parse';

const parser = unified().use(remarkParse);
const mdast = parser.parse('# test');

// できたASTを出力
console.log(JSON.stringify(mdast, null, 2));

実際のmdastの内容はこのようになっていました。headingの下にtextがぶら下がっていますね。

{
  "type": "root",
  "children": [
    {
      "type": "heading",
      "depth": 1,
      "children": [
        {
          "type": "text",
          "value": "test",
          "position": {
            "start": {
              "line": 1,
              "column": 3,
              "offset": 2
            },
            "end": {
              "line": 1,
              "column": 7,
              "offset": 6
            }
          }
        }
      ],
      "position": {
        "start": {
          "line": 1,
          "column": 1,
          "offset": 0
        },
        "end": {
          "line": 1,
          "column": 7,
          "offset": 6
        }
      }
    }
  ],
  "position": {
    "start": {
      "line": 1,
      "column": 1,
      "offset": 0
    },
    "end": {
      "line": 1,
      "column": 7,
      "offset": 6
    }
  }
}

Markdown ASTからHTML ASTに変換

Markdown形式のASTからHTML形式のASTに変換をかけます。
unifiedではこれを行うのはTransformerです。今回はremark2rehypeを使います。

...
import remark2rehype from 'remark-rehype';
...
const transformer = unified().use(remark2rehype);
const hast = transformer.runSync(mdast);

console.log(JSON.stringify(hast, null, 2));

次のようにh1タグのelementの子供にtextがぶら下がりました。

{
  "type": "root",
  "children": [
    {
      "type": "element",
      "tagName": "h1",
      "properties": {},
      "children": [
        {
          "type": "text",
          "value": "test",
          "position": {
            "start": {
              "line": 1,
              "column": 3,
              "offset": 2
            },
            "end": {
              "line": 1,
              "column": 7,
              "offset": 6
            }
          }
        }
      ],
      "position": {
        "start": {
          "line": 1,
          "column": 1,
          "offset": 0
        },
        "end": {
          "line": 1,
          "column": 7,
          "offset": 6
        }
      }
    }
  ],
  "position": {
    "start": {
      "line": 1,
      "column": 1,
      "offset": 0
    },
    "end": {
      "line": 1,
      "column": 7,
      "offset": 6
    }
  }
}

HTMLに変換

最後にHTMLのASTからテキストに変換します。
unifiedではCompilerとよばれ、今回はrehype-stringifyを使います。

...
import rehypeStringify from 'rehype-stringify';
...
const compiler = unified().use(rehypeStringify);
const html = compiler.stringify(hast);

console.log(html);

次のようにHTMLに変換されました。

<h1>test</h1>

まとめて実行

parse,run,stringifyはまとめてprocessで実行できます。
3段階の処理をまとめたコードは次のようになります。

import { unified } from 'unified';
import remarkParse from 'remark-parse'
import remark2rehype from 'remark-rehype'
import rehypeStringify from 'rehype-stringify';

const processor = unified()
  .use(remarkParse) // Parser
  .use(remark2rehype) // Transformer
  .use(rehypeStringify); // Compiler
const html = processor.processSync('# test');

console.log(html.value);
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1