Markdown Parser
我们主要介绍两款 Markdown 解析器,分别是 UnifiedJs 和 Markdown-it
UnifiedJs
用于通过语法树解析、检查、转换和序列化内容。其核心功能很轻,
主要的工作都是通过第三方插件来完成的,这给了我们针对目标主观选择插件的灵活性,它的相关生态也非常丰富。不仅如此,已有的差距不满足要求的时候,我们可以自己写一些插件,这也非常简单
下面是官方给出的工作示意:
| ........................ process ........................... |
| .......... parse ... | ... run ... | ... stringify ..........|
+--------+ +----------+
Input ->- | Parser | ->- Syntax Tree ->- | Compiler | ->- Output
+--------+ | +----------+
X
|
+--------------+
| Transformers |
+--------------+主要包含了三个流程:解析、加工、和还原。结合官方的示例代码来看,也能看出这个工作流程:
import rehypeDocument from 'rehype-document'
import rehypeFormat from 'rehype-format'
import rehypeStringify from 'rehype-stringify'
import remarkParse from 'remark-parse'
import remarkRehype from 'remark-rehype'
import {unified} from 'unified'
import {reporter} from 'vfile-reporter'
const file = await unified()
.use(remarkParse) // 选择一款解析器
.use(remarkRehype)
.use(rehypeDocument, {title: '👋🌍'})
.use(rehypeFormat)
.use(rehypeStringify) // 选择一款字符串转换器
.process('# Hello world!') // 目标解析的文本
console.error(reporter(file))
console.log(String(file))Unified 下面诞生了多个 ecosystem,其中就有用于解析 markdown 的 remark 和用于解析 HTML 的 rehype
插件功能
介绍一些常用的插件
| 插件 | 功能 |
|---|---|
| remark-parse | 添加对 markdown 的解析支持 |
| remark-gfm | 添加对自动链接、脚注、删除线、表格、任务列表的支持 |
| remark-frontmatter | 添加对 formatter 的支持 |
| remark-math | 添加对数学公式的支持 |
| remark-toc | 添加 toc 的支持 |
| remark-rehype | 将 markdown 转为 HTML 以便支持 rehype |
| rehype-rewrite | 遍历 HTML 元素并重写 |
| rehype-document | 将片段包在 Document 中 |
| rehype-minify | 压缩 HTML |
| rehype-format | 格式化 HTML |
| rehype-stringify | 添加对 HTML 的序列化支持 |
把上面的常用插件看一下,基本就能够理解两者的使用场景,值得一提的关键插件是 remark-rehype,将二者的生态系统打通了
当不需要同时使用 remark 和 rehype 的插件时候,我们也可以不安装 unified 等过多的插件,使用的使用方式更为简洁。
例如只使用 remark 相关插件,用于处理 Markdown
import { remark } from 'remark'
import remarkGfm from 'remark-gfm'
const file = await remark()
.use(remarkGfm)
.process(`### Hello World`)
console.log(String(file))同理,也可以只使用 rehype,来处理 HTML
import { rehype } from 'rehype';
import rehypeRewrite from 'rehype-rewrite';
import rehypeStringify from 'rehype-stringify';
const file = rehype()
.data('settings', { fragment: true })
.use(rehypeRewrite, {
rewrite: (node, index, parent) => {
if(node.type == 'text' && node.value == 'header') {
node.value = ''
}
}
})
.use(stringify)
.processSync(`<h1>header</h1>`)
console.log(String(file))Syntax Tree
上面提到了 unified 之后,不得不介绍一下 Syntax Tree
Syntax-tree 是一个包含 100 多个处理基于 unist 的语法树的项目的组织,上面的 remark 和 rehype 的多个插件,其实都是基于这个组织的包简单地封装了一层
这些树通常处理内容
- unist: Universal Syntax Tree
- mdast: Markdown AST
- hast: HTML AST
- east: ECMAScript AST
- xast: XML AST
- nlast: Natural Language AST
每一个 AST 标准中都提供了丰富的工具包,而上面的这些包的本身,由于只是定义了一个标准,所以其包内只有 TS 类型,安装的也都是 @types 下的包,例如:
$ npm i -D @types/mdast @typs/hast @types/east