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