0.3.0 • Published 3 years ago

zmdjs v0.3.0

Weekly downloads
2
License
MIT
Repository
github
Last release
3 years ago

zmd

怎么的,假装自己是 markdown 解析工具不行吗?

Overview

尝试进行 markdown 编译,直接对标 GitHub Flavored Markdown

Spec

Demo

提供一个在线演练的页面:zmd Playground,可以在上面随意调试该工具。

  • 左边部分为输入,右边部分为展示。
  • 点击 clear 按钮可清空输入的文本。
  • 点击 clear 右侧的选择框可以切换到选项设置。
  • Permalink 为当前访问链接,可以进行分享操作。
  • 点击右边部分的下拉选择框可以在预览界面、HTML 文本、和块状语法分析结果的查看。

Install

npm i zmdjs --save

Usage

const zmd = require('zmdjs')
const out = zmd('## Hello `zmd`!')
...
<script src="/path/to/zmd.js"></script>
...
<script>
  document.getElementById('content').innerHTML = zmd('## Hello `zmd`!')
</script>
...

通常来说,输出的文本会有拖尾换行,在使用时可根据实际情况进行移除。

Options

zmd(text, options)
选项类型默认值说明
langPrefixStringlanguage-代码块给定语言时的 CSS 类名前缀
headerIdsBooleantrue是否给标题一个唯一标识
headerPrefixString''标题唯一标识的前缀
footnoteBooleantrue是否开启脚注功能
highlightFunctionnullfence 代码块高亮方法
xhtmlBooleanfalse使用 XHTML 语法
autourlBooleanfalse是否开启链接自动识别
divClassString''自定义 div 的类名
ignoreBlankLineBooleanfalse忽略空行
encodeURIBooleanfalse是否对链接的 href 开启 encodeURI 转义
rfc3986Booleanfalse是否对链接的 href 开启 encodeURI 转义并遵循 RFC3986

options.renderer 的说明见下面的 Renderer 说明。

Markdown Extend Syntax

raw 文本

原始文本,将不做任何处理,原样进来,原样出去。

语法标识为以 {% raw %} 开头,以 {% endraw %} 结束。

raw/endraw 与边界之间支持任意数量的空格。% 符号可以省略。

定义列表

支持紧凑的定义列表。

定义列表包含一个定义标题和数个定义内容,所有部分均为单行

多行的支持暂时不做支持,后续可自行通过插件系统实现。

语法识别规则为针对定义内容进行识别,定义内容以冒号 : 开头。

多个定义内容之间的空行将被忽略。

定义内容与开头冒号之间的空格将被忽略。

有多个定义标题的,写在一起即可。

我是标题
: 我是内容1
: 我是内容2

自定义 div

使用 ::: 包裹的内容视为自定义 div。

可以在 ::: 后面跟文本表示该 div 的类名。

结束的冒号 : 可以有多个。

脚注

支持单行脚注。

脚注的语法分为两个部分,一个为定义,一个为使用。

定义的语法为块级语法,跟链接的定义类似,但是开头为 ^

使用的语法为行内语法, 表述为 [^name],其中 name 为定义过的名称,如果未进行定义,则忽略之。

序号会自动进行调整。

上标

^^ 进行包裹的行内语法。渲染器采用 sup 标签进行输出。

下标

~ 进行包裹的行内语法。渲染器采用 sub 标签进行输出。

注意,如果使用 ~~,为删除线语法。嵌套的处理未做特殊处理,请避免嵌套这两个语法。

插入

++ 进行包裹的行内语法。渲染器采用 ins 标签进行输出。

标记

== 进行包裹的行内语法。渲染器采用 mark 标签进行输出。

GFM 语法中的自动链接增强语法默认不开启。另外 HTML 代码块支持度不够理想,不建议在编写 markdown 的时候过度依赖此特性。可以通过 raw 语法进行替代。

Renderer

renderer 可以进行渲染器的自定义,以下代码示例演示了一个自定义标题渲染方法:

const renderer = new zmd.Renderer()
// const _heading = renderer.heading
renderer.heading = function (text, level, slug) {
  return '<h'
    + level
    + (slug ? ' id="' + slug + '"' : '')
    + '>'
    + (slug ? '<a href="#' + slug + '" class="header-link"></a>' : '')
    + text
    + '</h'
    + level
    + '>\n'
}

zmd('## demo', {renderer})
zmd('###', {renderer})
<h2 id="demo"><a href="#demo" class="header-link"></a>demo</h2>

<h3></h3>
const renderer = new zmd.Renderer()
const _fence = renderer.fence
renderer.fence = function (code, lang, meta, escaped) {
  let out = _fence.call(renderer, code, lang, meta, escaped)
  const match = meta.match(/^ *\{([^}]+)\}/) || []
  const lines = getHLines(match[1], out.split('\n').length)
  let wrap = ''

  if (lines.length > 0) {
    wrap = '<div class="code-hl">\n'
    lines.forEach(item => {
      wrap += '<div class="code-hl-item" style="top:'
      wrap += ((item - 1) * 20 + 16)
      wrap += 'px"></div>\n'
    })
    out = wrap + out + '</div>'
  }

  return out
}

function getHLines(text, lines) {
  var ret = []
  if (text) {
    text.split(/ *, */).forEach(item => {
      if (item.indexOf('-') === -1) {
        var n = +item
        if (n && n <= lines) {
          ret.push(n)
        }
      } else {
        var nn = item.split(/ *- */)
        for (var i = +nn[0]; i <= +nn[1] && i <= lines; i++) {
          ret.push(i)
        }
      }
    })
  }
  return ret
}
zmd('```js {1,2}\nvar a\nvar b\nvar c\n```', {renderer})
<div class="code-hl">
<div class="code-hl-item" style="top:16px"></div>
<div class="code-hl-item" style="top:36px"></div>
<pre><code class="language-js">var a
var b
var c
</code></pre>
</div>
方法名说明参数备注
hr水平线
br换行
heading标题text, level, slug标题文本、级别、唯一标识
codeblock块级代码块code代码文本
fencefence 代码块code, lang, meta, escaped代码文本,语言、附加信息、是否已经转义
footnote脚注footnotes脚注的数组(详细说明见下方 脚注 说明)
raw原始文本text文本
text普通文本text文本
htmlHTML 文本text文本
table表格header, body表格标题和表格主体
tablecell表格单元格tag, content, align单元格标签,单元格内容、对齐方式
tablerow表格行contenttr 的内容
div自定义 divcontent, kls内容和类名
list列表content, order, start, task列表内容,是否为有序列表,列表开始值,是否包含任务列表
li列表项content, task列表项内容,是否为任务列表
dl定义列表content内容
dt定义列表标题content内容
dd定义列表项content内容
p段落content内容
blockquote块引用content内容
strong着重强调text文本
em普通强调text文本
code行内代码块text文本
ins插入text文本
mark标记text文本
del删除线text文本
sub下标text文本
sup上标text文本
link链接href, text, title链接目标,展示文本,标题
img图片src, alt, title图片源,辅助文本,标题
checkbox复选框checked是否选中
paragraph段落p 的别名
image图片img 的别名

Special Thanks

特别感谢 marked 项目,当前版本的 zmd 的核心参考。编译流程基本保持跟 marked 一致。

参考项目

TODO

  • 测试

    当前只针对 Slugger 对象进行了测试,具体测试文件为 test/slug.js

  • 语法覆盖率

    针对 GFM 语法规范进行检验性测试,直接严格比对,未处理单引号转换和 TAB 的差异。测试文件为 test/gfm.jstest/diff.js,有先后顺序,测试结果为 test/coverage.md

  • 命令行支持
  • 插件系统

License

MIT