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