编写markdown-it的插件和规则

发布时间:2022-09-23 13:00

前言

最近看vuePress源码时发现在使用markdownLoader之余使用了大量的 markdown-it 插件,除了社区插件(如高亮代码、代码块包裹、emoji等),同时也自行编写了很多自定义插件(如内外链区分渲染等)。
文章结合源码和自己之前写过的插件来详细解读如何编写一个 markdown-it 插件规则。

简介

markdown-it 是一个辅助解析markdown的库,可以完成从 # test

test

的转换,渲染过程和babel类似为Parse -> Transform -> Generate。

Parse

source通过3个嵌套的规则链core、block、inline进行解析:

core
    core.rule1 (normalize)
    ...
    core.ruleX

    block
        block.rule1 (blockquote)
        ...
        block.ruleX

    inline (applied to each block token with "inline" type)
        inline.rule1 (text)
        ...
        inline.ruleX

解析的结果是一个token列表,将传递给renderer以生成html内容。
如果要实现新的markdown语法,可以从Parse过程入手:
可以在 md.core.rulermd.block.rulermd.inline.ruler 中自定义规则,规则的定义方法有 beforeafteratdisableenable 等。

// @vuepress/markdown代码片段
md.block.ruler.before('fence', 'snippet', function replace(state, startLine, endLine, silent) {
  //...
});

上述代码在 md.block.ruler.fence 之前加入snippet规则,用作解析 <<< @/filepath 这样的代码,它会把其中的文件路径拿出来和 root 路径拼起来,然后读取其中文件内容。
具体代码就不详细分析了,一般parse阶段用到的情况比较少,感兴趣的可以自行查看vuePress源码。

Transform

Token

通过官方在线示例# test 举例,会得到如下结果:

[
  {
    "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": "test",
        "markup": "",
        "info": "",
        "meta": null,
        "block": false,
        "hidden": false
      }
    ],
    "content": "test",
    "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,代替传统的AST。区别很简单:

  • 是一个简单的数组
  • 开始和结束标签是分开的
  • 会有一些特殊token (type: "inline") 嵌套token,根据标记顺序(bold, italic, text, ...)排序

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号