1 | <div align="center">
|
2 | <div>
|
3 | <img width="300" src="https://github.com/yahtnif/static/raw/master/logo/smarkdown.svg?sanitize=true" alt="smarkdown">
|
4 | </div>
|
5 | </div>
|
6 |
|
7 | [![npm](https://badgen.net/npm/v/smarkdown)](https://www.npmjs.com/package/smarkdown)
|
8 | [![gzip size](https://img.badgesize.io/https://cdn.jsdelivr.net/npm/smarkdown/dist/smarkdown.min.js?compression=gzip)](https://cdn.jsdelivr.net/npm/smarkdown/dist/smarkdown.min.js)
|
9 | [![install size](https://badgen.net/packagephobia/install/smarkdown)](https://packagephobia.now.sh/result?p=smarkdown)
|
10 | [![downloads](https://badgen.net/npm/dt/smarkdown)](https://www.npmjs.com/package/smarkdown)
|
11 | [![Build Status](https://travis-ci.org/yahtnif/smarkdown.svg?branch=master)](https://travis-ci.org/yahtnif/smarkdown)
|
12 | [![LICENSE](https://img.shields.io/badge/license-Anti%20996-blue.svg)](https://github.com/996icu/996.ICU/blob/master/LICENSE)
|
13 |
|
14 | > Markdown parser, simplicity and extensibility. Fork of [marked](https://github.com/markedjs/marked) and [marked-ts](https://github.com/KostyaTretyak/marked-ts).
|
15 |
|
16 | ## Features
|
17 |
|
18 | - **Awesome:** ES6, TypeScript, Rollup, Jest...
|
19 | - **Extensible:** Add your own [extensions](#extensions)
|
20 | - **Fast:** Low-level compiler for parsing markdown without caching or blocking for long periods of time
|
21 | - **Lightweight:** It's 9kb of minified and gzipped
|
22 |
|
23 | ## Table of contents
|
24 |
|
25 | - [Install](#install)
|
26 | - [Usage](#usage)
|
27 | - [Options](#options)
|
28 | - [Extension](#extension)
|
29 | - [Renderer](#renderer)
|
30 | - [Comparison](#comparison)
|
31 | - [License](#license)
|
32 |
|
33 | ## Install
|
34 |
|
35 | ```sh
|
36 | yarn add smarkdown
|
37 | # or
|
38 | npm install smarkdown
|
39 | ```
|
40 |
|
41 | **browser (CDN):** [jsDelivr](https://www.jsdelivr.com/package/npm/smarkdown) | [unpkg](https://unpkg.com/smarkdown/)
|
42 |
|
43 | ## Usage
|
44 |
|
45 | Import the library as a module:
|
46 |
|
47 | ```js
|
48 | const Smarkdown = require('smarkdown')
|
49 | ```
|
50 |
|
51 | Or import the library with a script tag:
|
52 |
|
53 | ```html
|
54 | <script src="https://cdn.jsdelivr.net/npm/smarkdown/dist/smarkdown.min.js"></script>
|
55 | ```
|
56 |
|
57 | Example:
|
58 |
|
59 | ```js
|
60 | // Reset options
|
61 | // Smarkdown.resetOptions()
|
62 |
|
63 | // Set options
|
64 | Smarkdown.setOptions({
|
65 | breaks: true
|
66 | })
|
67 |
|
68 | const str = 'I am using **Smarkdown**.'
|
69 |
|
70 | console.log(Smarkdown.parse(str))
|
71 | // <p>I am using <strong>Smarkdown</strong>.</p>
|
72 |
|
73 | console.log(Smarkdown.parse(str, { nop: true }))
|
74 | // I am using <strong>Smarkdown</strong>.
|
75 | ```
|
76 |
|
77 | ### Syntax highlighting
|
78 |
|
79 | ```js
|
80 | // highlight.js
|
81 | const Smarkdown = require('smarkdown')
|
82 | const { highlight } = require('highlight.js')
|
83 |
|
84 | Smarkdown.setOptions({
|
85 | highlight: (code, lang) => {
|
86 | return lang && highlight.getLanguage(lang)
|
87 | ? highlight.highlight(lang, code).value
|
88 | : highlight.highlightAuto(code).value
|
89 | }
|
90 | })
|
91 | ```
|
92 |
|
93 | ```js
|
94 | // prismjs
|
95 | const Smarkdown = require('smarkdown')
|
96 | const Prism = require('prismjs')
|
97 | require('prismjs/components/prism-markdown')
|
98 |
|
99 | Smarkdown.setOptions({
|
100 | highlight: (code, lang) => {
|
101 | const language = Prism.languages[lang] ? lang : 'markdown'
|
102 |
|
103 | return Prism.highlight(code, Prism.languages[language], language)
|
104 | }
|
105 | })
|
106 | ```
|
107 |
|
108 | ## Options
|
109 |
|
110 | | Name | Type | Default | Note |
|
111 | | :-----------: | :-----------------: | :-----------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|
112 | | baseUrl | String | null | A prefix url for any relative link. |
|
113 | | breaks | Boolean | false | If true, add `<br>` on a single line break (copies GitHub). Requires `gfm` be `true`. |
|
114 | | disabledRules | Array | [] | If set to `['lheading']`, will disable headers of an underline-ish style. |
|
115 | | extra | Boolean | false | If true, enable `footnote`. Requires `gfm` be `true`. |
|
116 | | gfm | Boolean | true | If true, use approved [GitHub Flavored Markdown (GFM) specification](https://github.github.com/gfm/). |
|
117 | | headerId | Boolean \| String | false | Include an `id` attribute when emitting headings.<br>If true, for all headings.<br>If set to `on`, for “non-close” atx-style headings (## h2, etc).<br>If set to `off`, for “close” atx-style headings (## h2 ##, etc). |
|
118 | | headerPrefix | String | '' | A string to prefix the id attribute when emitting headings. |
|
119 | | highlight | Function | (code, lang) => string | A function to highlight code blocks, see [Syntax highlighting](#syntax-highlighting) |
|
120 | | langAttribute | Boolean | false | If `true`, add `data-lang` attribute to highlight block code. |
|
121 | | langPrefix | String | 'language-' | A string to prefix the className in a `<code>` block. Useful for syntax highlighting. |
|
122 | | linksInNewTab | Boolean \| Function | false | If true, open links in new tabs. |
|
123 | | mangle | Boolean | true | If true, autolinked email address is escaped with HTML character references. |
|
124 | | nop | Boolean | false | If `true`, an inline text will not be taken in paragraph. |
|
125 | | pedantic | Boolean | false | If true, conform to the original `markdown.pl` as much as possible. Don't fix original markdown bugs or behavior. Turns off and overrides `gfm`. |
|
126 | | renderer | Renderer | Renderer | An object containing functions to render tokens to HTML. See [Renderer](#renderer) for more details. |
|
127 | | sanitize | Boolean | false | If true, sanitize the HTML passed into `markdownString` with the `sanitizer` function. |
|
128 | | sanitizer | Function | null | A function to sanitize the HTML passed into `markdownString`. |
|
129 | | silent | Boolean | false | If true, the parser does not throw any exception. |
|
130 | | slug | Function | str => built_in_slug(str) | Slugify `id` attribute for heading and footnote. |
|
131 | | smartLists | Boolean | false | If true, use smarter list behavior than those found in `markdown.pl`. |
|
132 | | smartypants | Boolean | false | If true, use "smart" typographic punctuation for things like quotes and dashes. |
|
133 | | trimLinkText | Function | null | Useful for text truncation. |
|
134 | | xhtml | Boolean | false | Self-close the tags for void elements (<br/>, <img/>, etc.) with a "/" as required by XHTML. |
|
135 |
|
136 | ## Extension
|
137 |
|
138 | Using `Smarkdown.setRule(regExp, callback, [, options])`, which takes a regular expression as the first argument, and returns result `regExp.exec(string)` to `callback(execArr)`, which can be passed as a second argument.
|
139 |
|
140 | Extension options:
|
141 |
|
142 | | Name | Type | Default | inline | block |
|
143 | | :----------: | :------: | :-----: | :----: | :---: |
|
144 | | priority | Number | null | ✓ | ✓ |
|
145 | | checkPreChar | Function | null | ✓ | |
|
146 |
|
147 | ### Inline
|
148 |
|
149 | ```js
|
150 | /**
|
151 | * sub
|
152 | *
|
153 | * H~2~O
|
154 | * H<sub>2</sub>O
|
155 | */
|
156 | const subRegex = /~(?=\S)([\s\S]*?\S)~/
|
157 | Smarkdown.setRule(subRegex, function(execArr) {
|
158 | return `<sub>${this.output(execArr[1])}</sub>`
|
159 | })
|
160 |
|
161 | /**
|
162 | * sup
|
163 | *
|
164 | * 1^st^
|
165 | * 1<sup>st</sup>
|
166 | */
|
167 | const supRegex = /\^(?=\S)([\s\S]*?\S)\^/
|
168 | Smarkdown.setRule(supRegex, function(execArr) {
|
169 | return `<sup>${this.output(execArr[1])}</sup>`
|
170 | })
|
171 |
|
172 | /**
|
173 | * mark
|
174 | *
|
175 | * ==Experience== is the best teacher.
|
176 | * <mark>Experience</mark> is the best teacher.
|
177 | */
|
178 | const markRegex = /==(?=\S)([\s\S]*?\S)==/
|
179 | Smarkdown.setRule(markRegex, function(execArr) {
|
180 | return `<mark>${this.output(execArr[1])}</mark>`
|
181 | })
|
182 |
|
183 | /**
|
184 | * hashtag
|
185 | *
|
186 | * #tag
|
187 | * <span class="hashtag">tag</span>
|
188 | */
|
189 | const hashtagRegex = /#([^\s#]+)((?:\b)|(?=\s|$))/
|
190 | Smarkdown.setRule(
|
191 | hashtagRegex,
|
192 | function(execArr) {
|
193 | return `<span class="hashtag">${execArr[1]}</span>`
|
194 | },
|
195 | {
|
196 | checkPreChar(char) {
|
197 | return !char || /\s|\B/.test(char)
|
198 | }
|
199 | }
|
200 | )
|
201 |
|
202 | /**
|
203 | * ruby annotation
|
204 | *
|
205 | * [注音]{zhuyin}
|
206 | * <ruby>注音<rt>zhuyin</rt></ruby>
|
207 | */
|
208 | const rubyAnnotationRegex = /\[([^\[\]{}]+)\]\{([^\[\]{}]+)\}/
|
209 | Smarkdown.setRule(
|
210 | rubyAnnotationRegex,
|
211 | function(execArr) {
|
212 | return `<ruby>${execArr[1]}<rt>${execArr[2]}</rt></ruby>`
|
213 | },
|
214 | {
|
215 | priority: 1
|
216 | }
|
217 | )
|
218 |
|
219 | /**
|
220 | * small text
|
221 | *
|
222 | * --small text-- => <span class="small-text">small text</span>
|
223 | */
|
224 | const smallTextRegex = /--(?=\S)([\s\S]*?\S)--/
|
225 | Smarkdown.setRule(smallTextRegex, function(execArr) {
|
226 | return `<span class="small-text">${execArr[1]}</span>`
|
227 | })
|
228 |
|
229 | /**
|
230 | * large text
|
231 | *
|
232 | * ++large text++ => <span class="large-text is-1">large text</span>
|
233 | * +++large text+++ => <span class="large-text is-2">large text</span>
|
234 | * ++++large text++++ => <span class="large-text is-3">large text</span>
|
235 | */
|
236 | const largeTextRegex = /(\+{2,})(?=\S)([\s\S]*?\S)\+{2,}/
|
237 | Smarkdown.setRule(largeTextRegex, function(execArr) {
|
238 | let size = execArr[1].length - 1
|
239 |
|
240 | if (size > 3) {
|
241 | size = 3
|
242 | }
|
243 |
|
244 | return `<span class="large-text is-${size}">${execArr[2]}</span>`
|
245 | })
|
246 | ```
|
247 |
|
248 | ### Block
|
249 |
|
250 | ```js
|
251 | // block container
|
252 | const extRegex = /::: *([\w-_]+) *\n([\s\S]*?)\n:::\s?/
|
253 | Smarkdown.setRule(extRegex, execArr => {
|
254 | return `<div class="${execArr[1]}">${execArr[2]}</div>`
|
255 | })
|
256 |
|
257 | const str = `::: warning
|
258 | Lorem ipsum dolor sit amet, consectetur adipiscing elit lorem ipsum dolor.
|
259 | :::`
|
260 |
|
261 | console.log(Smarkdown.parse(str))
|
262 |
|
263 | // <div class="warning">Lorem ipsum dolor sit amet, consectetur adipiscing elit lorem ipsum dolor.</div>
|
264 | ```
|
265 |
|
266 | ### Unset
|
267 |
|
268 | ```js
|
269 | Smarkdown.unsetRule(regExp)
|
270 | ```
|
271 |
|
272 | ## Renderer
|
273 |
|
274 | ### Methods
|
275 |
|
276 | ```js
|
277 | //*** Block level renderer methods. ***
|
278 |
|
279 | blockquote(quote)
|
280 |
|
281 | code(code, lang, escaped)
|
282 |
|
283 | footnote(footnotes)
|
284 |
|
285 | heading(text, level, raw, ends)
|
286 |
|
287 | hr(text)
|
288 |
|
289 | html(html)
|
290 |
|
291 | list(body, ordered, start, isTaskList)
|
292 |
|
293 | listitem(text, checked)
|
294 |
|
295 | paragraph(text)
|
296 |
|
297 | table(header, body)
|
298 |
|
299 | tablerow(content)
|
300 |
|
301 | tablecell(content, flags)
|
302 |
|
303 | //*** Inline level renderer methods. ***
|
304 |
|
305 | br()
|
306 |
|
307 | codespan(text)
|
308 |
|
309 | del(text)
|
310 |
|
311 | em(text)
|
312 |
|
313 | fnref(refname)
|
314 |
|
315 | image(href, title, text)
|
316 |
|
317 | link(href, title, text)
|
318 |
|
319 | strong(text)
|
320 |
|
321 | text(text)
|
322 | ```
|
323 |
|
324 | ### Overriding Renderer methods
|
325 |
|
326 | ```js
|
327 | const Smarkdown = require('smarkdown')
|
328 |
|
329 | class NewRenderer extends Smarkdown.Renderer {
|
330 | // Overriding parent method.
|
331 | table(header, body) {
|
332 | if (body) body = '<tbody>' + body + '</tbody>'
|
333 |
|
334 | // add class .table to table
|
335 | return `
|
336 | <table class="table">
|
337 | <thead>
|
338 | ${header}</thead>
|
339 | ${body}</table>
|
340 | `
|
341 | }
|
342 | }
|
343 |
|
344 | Smarkdown.setOptions({ renderer: NewRenderer })
|
345 | // or pass new options to new Renderer
|
346 | Smarkdown.setOptions({ renderer: new NewRenderer(NewOptions) })
|
347 | ```
|
348 |
|
349 | ## Comparison
|
350 |
|
351 | | | Smarkdown | Marked | markdown-it |
|
352 | | :----------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|
353 | | Version | [![npm](https://badgen.net/npm/v/smarkdown)](https://www.npmjs.com/package/smarkdown) | [![npm](https://badgen.net/npm/v/marked)](https://www.npmjs.com/package/marked) | [![npm](https://badgen.net/npm/v/markdown-it)](https://www.npmjs.com/package/markdown-it) |
|
354 | | Minified & Gzipped | [![gzip size](https://img.badgesize.io/https://cdn.jsdelivr.net/npm/smarkdown/dist/smarkdown.min.js?compression=gzip)](https://cdn.jsdelivr.net/npm/smarkdown/dist/smarkdown.min.js) | [![gzip size](https://img.badgesize.io/https://cdn.jsdelivr.net/npm/marked/marked.min.js?compression=gzip)](https://cdn.jsdelivr.net/npm/marked/marked.min.js) | [![gzip size](https://img.badgesize.io/https://cdn.jsdelivr.net/npm/markdown-it/dist/markdown-it.min.js?compression=gzip)](https://cdn.jsdelivr.net/npm/markdown-it/dist/markdown-it.min.js) |
|
355 |
|
356 | ## License
|
357 |
|
358 | [Anti 996](./LICENSE)
|