remark
插件驱动的体系架构。以AST为默认输出标准。可以进行lint等操作。
命令行为remark。
不同的措辞树可搭配不同的转换器
- mdast搭配remark给markdown用
- nlcst搭配retext给prose用
- hast搭配rehype给HTML用
以上属于unified.js范畴
remark github
仓库包含四个料包:
- remark-parse,解析用
- remark-stringify,将mdast措辞树转为markdown输出
- remark,包含unified, remark-parse和remark-stringify,适用于输入和输出都是markdown的情况
- remark-cli,围绕着remark的命令行
也就是说,如果输入himarkdown,那么搭配unified使用remark-parse; 如果输出是markdown,那么搭配unified使用remark-stringify; 如果输入和输出都是markdown,那么使用remark本身。
插件概览
- remark-gfm
- remark-lint
- remark-toc
- remark-html
https://github.com/remarkjs/awesome-remark
看了一下 https://github.com/remarkjs/remark/tree/main/packages/remark-parse, 基本就是包装
https://github.com/remarkjs/remark-gfm
https://github.com/syntax-tree/mdast
micromark github
最小化的遵循CommonMark的解析器,带有位置信息和具体的符号。
- 100% CommonMark
- 通过扩展可以支持GFM、directives、frontmatter、math、MDX.js等
- 默认安全
- 最小的CM解析器
- 100% 测试覆盖
使用状态机来将整个markdown解析成具体的号牌。用作remark-parse内部。
API包括两部分,一部分是micromark
另一部分是micromark/stream
。
可以通过node --conditions development module.js
来获得https://nodejs.org/api/packages.html#packages_resolving_user_conditions
micromark(value[, encoding][, options])
将markdown转为HTML。
stream(options?)
也将markdown转为HTML,不够采用的是流式处理。
接收两种扩展,一种是SyntaxExtension,另一种是HtmlExtension。
gfm作为扩展提供micromark-extension-gfm github。
可以扩展markdown语法,但是通常有现成的解决方案。
Architecture
micromark仓库有以下料包
- micromark-build,从开发代码构建生产代码
- micromark-core-commonmar,CommonMark 相关的构造
- micromark-factory-*,可以重用的子过程
- micromark-util-*,可以重用的实用工具
- micromark,核心部件
整个处理过程:
micromark
+-----------------------------------------------------------------------------------------------+
| +------------+ +-------+ +-------------+ +---------+ |
| -markdown->+ preprocess +-chunks->+ parse +-events->+ postprocess +-events->+ compile +-html- |
| +------------+ +-------+ +-------------+ +---------+ |
+-----------------------------------------------------------------------------------------------+
预处理器micromark/dev/lib/preprocess.js
将markdown撕成分块(chunk),由单个字符码或者字符串构成。
micromark/dev/lib/parse.js
将分块转化为事件。事件是号牌的开始或者结束。号牌可以嵌套。号牌跨一到多个字符码。号牌可以互相链接。
micromark/dev/lib/postprocess.js
接收所有的事件,保证所有的内容都被解析。
micromark/dev/lib/compile.js
将事件转为HTML。
Examples
Syntax tree
micromark-extension-math可以用katex渲染数学公式。
mdast-util-from-markdown可以给出AST。
Markdown
一开始markdown只是用一个perl文件markdown.pl
实现。
随后有了CommonMark标准。然后不同的平台又自定义了一些语法,比如Github就有了Github Flavored Markdown,俗称GFM。
Project
Comparison
micromark是底层引擎
remark聚焦在AST
marked是经典的markdown解析器,但是对CommonMark和GFM的支持不够好,默认允许不安全的内容。
markdown-it是经典的CommonMark解析器,措辞上有很多扩展,可以自定义语法,支持不同风格的markdown。
Security
安全性是指https://en.wikipedia.org/wiki/Cross-site_scripting,可能来自于内嵌的HTML或者links/images中的可疑协议。
通过allowDangerousHtml
和allowDangerousProtocol
选项可以关闭默认的安全性。
unifiedjs
Github网址是https://github.com/unifiedjs/unified。
用于remark、rehype等等,提供通用的处理接口。
https://github.com/vfile/vfile是其对文件的抽象。
其他markdown parser
markdown-it
支持 CommonMark
marked
底层级的markdown编译器。
prosemirror-markdown
处理CommonMark和Markdown之间的转化。
md4c
prosemirorr base markdown
- https://github.com/benrbray/noteworthy
- https://github.com/benrbray/noteworthy/discussions/16讨论了noteworthy为啥使用remark
其他对比
- https://www.libtrends.info/npm-compare/commonmark-vs-markdown-vs-markdown-it-vs-marked-vs-remark-vs-remarkable
- https://www.npmtrends.com/commonmark-vs-markdown-it-vs-marked-vs-remark-vs-remark-parse
- https://stackoverflow.com/questions/889434/markdown-implementations-for-c-c
- https://github.com/micromark/common-markup-state-machine
mentioned unistd/mdast syntax tree
- https://github.com/syntax-tree/mdast
- https://github.com/syntax-tree/unist
- https://github.com/syntax-tree/mdast-util-from-markdown
Markdown Editor
相关工具
- https://astexplorer.net/可以用来查看remark的ast
(草草了事)
2022-06-19更新:markdown-it
markdown-it是一款老牌的基于JS的Markdown解析器,特点如下:
- 解析方式基于规则,则不是基于状态机
- 可以方便自定义新的解析规则
- 中间产物是一个号牌流,而不是AST
- 具有很多扩展
一些限制:
- 似乎一次必须解析整块markdown文本
一些参考:
- https://github.com/yhatt/markdown-it-incremental-dom
- markdown-it 源码分析及插件编写:parse 和 token(1/3)
- markdown-it源代码分析
- Markdown-it 原理解析
- markdown-it 原理浅析
- Markdown Performance Comparison (version: 0)
- Remark vs MarkdownIt #16
- https://wiki.nikiv.dev/writing/markdown
一些思考:
- 其实并不需要每次都过一堆规则,根据当前的状态,适合的规则其实有限
- 但是需要预先的编译,才能减少不必要的规则匹配
- https://github.com/markdown-it/markdown-ast-spec/issues/5对增量处理做了一些讨论
- 如果要增量处理,一方面要能够设置解析器状态,以适配增量解析的开始位置
- 架构上或许需要改变一下,比如像remark那样按输入的字符进行状态变迁,然后通过事件的方式来产生token
(更新完)