markdown-it 提供了三种模式:commonmark、default、zero。分别对应最严格、GFM、最宽松的解析模式。
markdown-it 的解析规则可分为块(block)和内联(inline)两种。具体可体现为 MarkdownIt.block
对应的是解析块规则的 ParserBlock, MarkdownIt.inline
对应的是解析内联规则的 ParserInline。解析时,先创建一个 Core Parser,该 Core Parser 包含一系列的缺省 rules。这些 rules 按顺序执行,每个 rules 都在前面的 Tokens 的基础上,修改或添加新的 Token。这个 rules 的执行链称为 Core Chain。
经过解析后我们得到一个数组,markdown-it 称之为 token 流。
- Tokens 是一个简单的数组。
- 打开的标签和关闭的标签可以隔离。
- 将“内联容器(inline container)”作为一种特殊的 block token 对象。它有嵌套的 tokens,如粗体,斜体,文本等等。
这样做的好处是可以并行处理 block 和 inline 类型的 token 。比如通过markdown-it我们可以把# change!
转化为以下内容:
[
{
"type": "heading_open",
"tag": "h1",
"attrs": null,
"map": [
0,
1
],
"nesting": 1,
"level": 0,
"children": null,
"content": "",
"markup": "#",
"info": "",
"meta": null,
"block": true,
"hidden": false
},
{
"type": "inline",
"tag": "",
"attrs": null,
"map": [
0,
1
],
"nesting": 0,
"level": 1,
"children": [
{
"type": "text",
"tag": "",
"attrs": null,
"map": null,
"nesting": 0,
"level": 0,
"children": null,
"content": "change!",
"markup": "",
"info": "",
"meta": null,
"block": false,
"hidden": false
}
],
"content": "change!",
"markup": "",
"info": "",
"meta": null,
"block": true,
"hidden": false
},
{
"type": "heading_close",
"tag": "h1",
"attrs": null,
"map": null,
"nesting": -1,
"level": 0,
"children": null,
"content": "",
"markup": "#",
"info": "",
"meta": null,
"block": true,
"hidden": false
}
]
渲染器
渲染器会遍历所有 token,将每个 token 传递给与 token 的 type 属性同名的 rule。markdown-it 内置了九种规则:
- 围栏
- 行内代码
- 代码块
- HTML 块
- 行内 HTML
- 图片
- 硬换行
- 软换行
- 文本。
type 属性不在内置规则时,token 将会被被传入 renderToken 中当做普通的 token 处理。
MarkdownIt.renderer.render
和 MarkdownIt.renderer.renderInline
分别对应按照块规则和内联规则生成 HTML 代码。而在 MarkdownIt.renderer 中有一个特殊的属性:rules,它代表着对于 token 们的渲染规则,可以被使用者更新或扩展:
var md = require('markdown-it')();
md.renderer.rules.strong_open = function () { return '<b>'; };
md.renderer.rules.strong_close = function () { return '</b>'; };
var result = md.renderInline(...);
比如这段代码就更新了渲染 strong_open 和 strong_close 这两种 token 的渲染规则。
插件系统
markdown-it 只做纯粹的 Markdown 解析,我们可以通过插件来实现扩展其功能。MarkdownIt.use
可以将指定的插件加载到当前的解析器实例中:
var md = require('markdown-it')()
.use(require('markdown-it-container'), name [, options]);
下一节:markdown-it的文档和语法确实有点难理解, 我也只琢磨出了我想要的插件的写法, 所以 这篇文章目前应该叫: 为markdown-it编写一个渲染自定义块语法的插件.