npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

zmdjs

v0.3.0

Published

Just a markdown parser

Downloads

7

Readme

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)

| 选项 | 类型 | 默认值 | 说明 | | ---- | ---- | ------ | ---- | | langPrefix| String | language- | 代码块给定语言时的 CSS 类名前缀 | | headerIds | Boolean | true | 是否给标题一个唯一标识 | | headerPrefix | String | '' | 标题唯一标识的前缀 | | footnote | Boolean | true | 是否开启脚注功能 | | highlight | Function | null | fence 代码块高亮方法 | | xhtml | Boolean | false | 使用 XHTML 语法 | | autourl | Boolean | false | 是否开启链接自动识别 | | divClass | String | '' | 自定义 div 的类名 | | ignoreBlankLine | Boolean | false | 忽略空行 | | encodeURI | Boolean | false | 是否对链接的 href 开启 encodeURI 转义 | | rfc3986 | Boolean | false | 是否对链接的 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 | 代码文本 | | fence | fence 代码块 | code, lang, meta, escaped | 代码文本,语言、附加信息、是否已经转义 | | footnote | 脚注 | footnotes | 脚注的数组(详细说明见下方 脚注 说明) | | raw | 原始文本 | text | 文本 | | text | 普通文本 | text | 文本 | | html | HTML 文本 | text | 文本 | | table | 表格 | header, body | 表格标题和表格主体 | | tablecell | 表格单元格 | tag, content, align | 单元格标签,单元格内容、对齐方式 | | tablerow | 表格行 | content | tr 的内容 | | div | 自定义 div | content, 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

  • [x] 测试

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

  • [x] 语法覆盖率

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

  • [ ] 命令行支持
  • [ ] 插件系统

License

MIT