marked 5.0.5 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/marked.js CHANGED
@@ -5,179 +5,16 @@ import { Renderer } from './Renderer.js';
5
5
  import { TextRenderer } from './TextRenderer.js';
6
6
  import { Slugger } from './Slugger.js';
7
7
  import { Hooks } from './Hooks.js';
8
- import {
9
- checkDeprecations,
10
- escape
11
- } from './helpers.js';
12
- import {
13
- getDefaults,
14
- changeDefaults,
15
- defaults
16
- } from './defaults.js';
8
+ import { Marked } from './Instance.js';
9
+ import { changeDefaults, getDefaults, defaults } from './defaults.js';
17
10
 
18
- function onError(silent, async, callback) {
19
- return (e) => {
20
- e.message += '\nPlease report this to https://github.com/markedjs/marked.';
21
-
22
- if (silent) {
23
- const msg = '<p>An error occurred:</p><pre>'
24
- + escape(e.message + '', true)
25
- + '</pre>';
26
- if (async) {
27
- return Promise.resolve(msg);
28
- }
29
- if (callback) {
30
- callback(null, msg);
31
- return;
32
- }
33
- return msg;
34
- }
35
-
36
- if (async) {
37
- return Promise.reject(e);
38
- }
39
- if (callback) {
40
- callback(e);
41
- return;
42
- }
43
- throw e;
44
- };
45
- }
46
-
47
- function parseMarkdown(lexer, parser) {
48
- return (src, opt, callback) => {
49
- if (typeof opt === 'function') {
50
- callback = opt;
51
- opt = null;
52
- }
53
-
54
- const origOpt = { ...opt };
55
- opt = { ...marked.defaults, ...origOpt };
56
- const throwError = onError(opt.silent, opt.async, callback);
57
-
58
- // throw error in case of non string input
59
- if (typeof src === 'undefined' || src === null) {
60
- return throwError(new Error('marked(): input parameter is undefined or null'));
61
- }
62
- if (typeof src !== 'string') {
63
- return throwError(new Error('marked(): input parameter is of type '
64
- + Object.prototype.toString.call(src) + ', string expected'));
65
- }
66
-
67
- checkDeprecations(opt, callback);
68
-
69
- if (opt.hooks) {
70
- opt.hooks.options = opt;
71
- }
72
-
73
- if (callback) {
74
- const highlight = opt.highlight;
75
- let tokens;
76
-
77
- try {
78
- if (opt.hooks) {
79
- src = opt.hooks.preprocess(src);
80
- }
81
- tokens = lexer(src, opt);
82
- } catch (e) {
83
- return throwError(e);
84
- }
85
-
86
- const done = function(err) {
87
- let out;
88
-
89
- if (!err) {
90
- try {
91
- if (opt.walkTokens) {
92
- marked.walkTokens(tokens, opt.walkTokens);
93
- }
94
- out = parser(tokens, opt);
95
- if (opt.hooks) {
96
- out = opt.hooks.postprocess(out);
97
- }
98
- } catch (e) {
99
- err = e;
100
- }
101
- }
102
-
103
- opt.highlight = highlight;
104
-
105
- return err
106
- ? throwError(err)
107
- : callback(null, out);
108
- };
109
-
110
- if (!highlight || highlight.length < 3) {
111
- return done();
112
- }
113
-
114
- delete opt.highlight;
115
-
116
- if (!tokens.length) return done();
117
-
118
- let pending = 0;
119
- marked.walkTokens(tokens, function(token) {
120
- if (token.type === 'code') {
121
- pending++;
122
- setTimeout(() => {
123
- highlight(token.text, token.lang, function(err, code) {
124
- if (err) {
125
- return done(err);
126
- }
127
- if (code != null && code !== token.text) {
128
- token.text = code;
129
- token.escaped = true;
130
- }
131
-
132
- pending--;
133
- if (pending === 0) {
134
- done();
135
- }
136
- });
137
- }, 0);
138
- }
139
- });
140
-
141
- if (pending === 0) {
142
- done();
143
- }
144
-
145
- return;
146
- }
147
-
148
- if (opt.async) {
149
- return Promise.resolve(opt.hooks ? opt.hooks.preprocess(src) : src)
150
- .then(src => lexer(src, opt))
151
- .then(tokens => opt.walkTokens ? Promise.all(marked.walkTokens(tokens, opt.walkTokens)).then(() => tokens) : tokens)
152
- .then(tokens => parser(tokens, opt))
153
- .then(html => opt.hooks ? opt.hooks.postprocess(html) : html)
154
- .catch(throwError);
155
- }
156
-
157
- try {
158
- if (opt.hooks) {
159
- src = opt.hooks.preprocess(src);
160
- }
161
- const tokens = lexer(src, opt);
162
- if (opt.walkTokens) {
163
- marked.walkTokens(tokens, opt.walkTokens);
164
- }
165
- let html = parser(tokens, opt);
166
- if (opt.hooks) {
167
- html = opt.hooks.postprocess(html);
168
- }
169
- return html;
170
- } catch (e) {
171
- return throwError(e);
172
- }
173
- };
174
- }
11
+ const markedInstance = new Marked(defaults);
175
12
 
176
13
  /**
177
14
  * Marked
178
15
  */
179
16
  export function marked(src, opt, callback) {
180
- return parseMarkdown(Lexer.lex, Parser.parse)(src, opt, callback);
17
+ return markedInstance.parse(src, opt, callback);
181
18
  }
182
19
 
183
20
  /**
@@ -186,7 +23,8 @@ export function marked(src, opt, callback) {
186
23
 
187
24
  marked.options =
188
25
  marked.setOptions = function(opt) {
189
- marked.defaults = { ...marked.defaults, ...opt };
26
+ markedInstance.setOptions(opt);
27
+ marked.defaults = markedInstance.defaults;
190
28
  changeDefaults(marked.defaults);
191
29
  return marked;
192
30
  };
@@ -200,144 +38,10 @@ marked.defaults = defaults;
200
38
  */
201
39
 
202
40
  marked.use = function(...args) {
203
- const extensions = marked.defaults.extensions || { renderers: {}, childTokens: {} };
204
-
205
- args.forEach((pack) => {
206
- // copy options to new object
207
- const opts = { ...pack };
208
-
209
- // set async to true if it was set to true before
210
- opts.async = marked.defaults.async || opts.async || false;
211
-
212
- // ==-- Parse "addon" extensions --== //
213
- if (pack.extensions) {
214
- pack.extensions.forEach((ext) => {
215
- if (!ext.name) {
216
- throw new Error('extension name required');
217
- }
218
- if (ext.renderer) { // Renderer extensions
219
- const prevRenderer = extensions.renderers[ext.name];
220
- if (prevRenderer) {
221
- // Replace extension with func to run new extension but fall back if false
222
- extensions.renderers[ext.name] = function(...args) {
223
- let ret = ext.renderer.apply(this, args);
224
- if (ret === false) {
225
- ret = prevRenderer.apply(this, args);
226
- }
227
- return ret;
228
- };
229
- } else {
230
- extensions.renderers[ext.name] = ext.renderer;
231
- }
232
- }
233
- if (ext.tokenizer) { // Tokenizer Extensions
234
- if (!ext.level || (ext.level !== 'block' && ext.level !== 'inline')) {
235
- throw new Error("extension level must be 'block' or 'inline'");
236
- }
237
- if (extensions[ext.level]) {
238
- extensions[ext.level].unshift(ext.tokenizer);
239
- } else {
240
- extensions[ext.level] = [ext.tokenizer];
241
- }
242
- if (ext.start) { // Function to check for start of token
243
- if (ext.level === 'block') {
244
- if (extensions.startBlock) {
245
- extensions.startBlock.push(ext.start);
246
- } else {
247
- extensions.startBlock = [ext.start];
248
- }
249
- } else if (ext.level === 'inline') {
250
- if (extensions.startInline) {
251
- extensions.startInline.push(ext.start);
252
- } else {
253
- extensions.startInline = [ext.start];
254
- }
255
- }
256
- }
257
- }
258
- if (ext.childTokens) { // Child tokens to be visited by walkTokens
259
- extensions.childTokens[ext.name] = ext.childTokens;
260
- }
261
- });
262
- opts.extensions = extensions;
263
- }
264
-
265
- // ==-- Parse "overwrite" extensions --== //
266
- if (pack.renderer) {
267
- const renderer = marked.defaults.renderer || new Renderer();
268
- for (const prop in pack.renderer) {
269
- const prevRenderer = renderer[prop];
270
- // Replace renderer with func to run extension, but fall back if false
271
- renderer[prop] = (...args) => {
272
- let ret = pack.renderer[prop].apply(renderer, args);
273
- if (ret === false) {
274
- ret = prevRenderer.apply(renderer, args);
275
- }
276
- return ret;
277
- };
278
- }
279
- opts.renderer = renderer;
280
- }
281
- if (pack.tokenizer) {
282
- const tokenizer = marked.defaults.tokenizer || new Tokenizer();
283
- for (const prop in pack.tokenizer) {
284
- const prevTokenizer = tokenizer[prop];
285
- // Replace tokenizer with func to run extension, but fall back if false
286
- tokenizer[prop] = (...args) => {
287
- let ret = pack.tokenizer[prop].apply(tokenizer, args);
288
- if (ret === false) {
289
- ret = prevTokenizer.apply(tokenizer, args);
290
- }
291
- return ret;
292
- };
293
- }
294
- opts.tokenizer = tokenizer;
295
- }
296
-
297
- // ==-- Parse Hooks extensions --== //
298
- if (pack.hooks) {
299
- const hooks = marked.defaults.hooks || new Hooks();
300
- for (const prop in pack.hooks) {
301
- const prevHook = hooks[prop];
302
- if (Hooks.passThroughHooks.has(prop)) {
303
- hooks[prop] = (arg) => {
304
- if (marked.defaults.async) {
305
- return Promise.resolve(pack.hooks[prop].call(hooks, arg)).then(ret => {
306
- return prevHook.call(hooks, ret);
307
- });
308
- }
309
-
310
- const ret = pack.hooks[prop].call(hooks, arg);
311
- return prevHook.call(hooks, ret);
312
- };
313
- } else {
314
- hooks[prop] = (...args) => {
315
- let ret = pack.hooks[prop].apply(hooks, args);
316
- if (ret === false) {
317
- ret = prevHook.apply(hooks, args);
318
- }
319
- return ret;
320
- };
321
- }
322
- }
323
- opts.hooks = hooks;
324
- }
325
-
326
- // ==-- Parse WalkTokens extensions --== //
327
- if (pack.walkTokens) {
328
- const walkTokens = marked.defaults.walkTokens;
329
- opts.walkTokens = function(token) {
330
- let values = [];
331
- values.push(pack.walkTokens.call(this, token));
332
- if (walkTokens) {
333
- values = values.concat(walkTokens.call(this, token));
334
- }
335
- return values;
336
- };
337
- }
338
-
339
- marked.setOptions(opts);
340
- });
41
+ markedInstance.use(...args);
42
+ marked.defaults = markedInstance.defaults;
43
+ changeDefaults(marked.defaults);
44
+ return marked;
341
45
  };
342
46
 
343
47
  /**
@@ -345,44 +49,14 @@ marked.use = function(...args) {
345
49
  */
346
50
 
347
51
  marked.walkTokens = function(tokens, callback) {
348
- let values = [];
349
- for (const token of tokens) {
350
- values = values.concat(callback.call(marked, token));
351
- switch (token.type) {
352
- case 'table': {
353
- for (const cell of token.header) {
354
- values = values.concat(marked.walkTokens(cell.tokens, callback));
355
- }
356
- for (const row of token.rows) {
357
- for (const cell of row) {
358
- values = values.concat(marked.walkTokens(cell.tokens, callback));
359
- }
360
- }
361
- break;
362
- }
363
- case 'list': {
364
- values = values.concat(marked.walkTokens(token.items, callback));
365
- break;
366
- }
367
- default: {
368
- if (marked.defaults.extensions && marked.defaults.extensions.childTokens && marked.defaults.extensions.childTokens[token.type]) { // Walk any extensions
369
- marked.defaults.extensions.childTokens[token.type].forEach(function(childTokens) {
370
- values = values.concat(marked.walkTokens(token[childTokens], callback));
371
- });
372
- } else if (token.tokens) {
373
- values = values.concat(marked.walkTokens(token.tokens, callback));
374
- }
375
- }
376
- }
377
- }
378
- return values;
52
+ return markedInstance.walkTokens(tokens, callback);
379
53
  };
380
54
 
381
55
  /**
382
56
  * Parse Inline
383
57
  * @param {string} src
384
58
  */
385
- marked.parseInline = parseMarkdown(Lexer.lexInline, Parser.parseInline);
59
+ marked.parseInline = markedInstance.parseInline;
386
60
 
387
61
  /**
388
62
  * Expose
@@ -414,3 +88,4 @@ export { Renderer } from './Renderer.js';
414
88
  export { TextRenderer } from './TextRenderer.js';
415
89
  export { Slugger } from './Slugger.js';
416
90
  export { Hooks } from './Hooks.js';
91
+ export { Marked } from './Instance.js';
package/src/rules.js CHANGED
@@ -172,48 +172,49 @@ export const inline = {
172
172
  nolink: /^!?\[(ref)\](?:\[\])?/,
173
173
  reflinkSearch: 'reflink|nolink(?!\\()',
174
174
  emStrong: {
175
- lDelim: /^(?:\*+(?:([punct_])|[^\s*]))|^_+(?:([punct*])|([^\s_]))/,
176
- // (1) and (2) can only be a Right Delimiter. (3) and (4) can only be Left. (5) and (6) can be either Left or Right.
177
- // () Skip orphan inside strong () Consume to delim (1) #*** (2) a***#, a*** (3) #***a, ***a (4) ***# (5) #***# (6) a***a
178
- rDelimAst: /^[^_*]*?\_\_[^_*]*?\*[^_*]*?(?=\_\_)|[^*]+(?=[^*])|[punct_](\*+)(?=[\s]|$)|[^punct*_\s](\*+)(?=[punct_\s]|$)|[punct_\s](\*+)(?=[^punct*_\s])|[\s](\*+)(?=[punct_])|[punct_](\*+)(?=[punct_])|[^punct*_\s](\*+)(?=[^punct*_\s])/,
179
- rDelimUnd: /^[^_*]*?\*\*[^_*]*?\_[^_*]*?(?=\*\*)|[^_]+(?=[^_])|[punct*](\_+)(?=[\s]|$)|[^punct*_\s](\_+)(?=[punct*\s]|$)|[punct*\s](\_+)(?=[^punct*_\s])|[\s](\_+)(?=[punct*])|[punct*](\_+)(?=[punct*])/ // ^- Not allowed for _
175
+ lDelim: /^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/,
176
+ // (1) and (2) can only be a Right Delimiter. (3) and (4) can only be Left. (5) and (6) can be either Left or Right.
177
+ // | Skip orphan inside strong | Consume to delim | (1) #*** | (2) a***#, a*** | (3) #***a, ***a | (4) ***# | (5) #***# | (6) a***a
178
+ rDelimAst: /^[^_*]*?__[^_*]*?\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\*)[punct](\*+)(?=[\s]|$)|[^punct\s](\*+)(?!\*)(?=[punct\s]|$)|(?!\*)[punct\s](\*+)(?=[^punct\s])|[\s](\*+)(?!\*)(?=[punct])|(?!\*)[punct](\*+)(?!\*)(?=[punct])|[^punct\s](\*+)(?=[^punct\s])/,
179
+ rDelimUnd: /^[^_*]*?\*\*[^_*]*?_[^_*]*?(?=\*\*)|[^_]+(?=[^_])|(?!_)[punct](_+)(?=[\s]|$)|[^punct\s](_+)(?!_)(?=[punct\s]|$)|(?!_)[punct\s](_+)(?=[^punct\s])|[\s](_+)(?!_)(?=[punct])|(?!_)[punct](_+)(?!_)(?=[punct])/ // ^- Not allowed for _
180
180
  },
181
181
  code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
182
182
  br: /^( {2,}|\\)\n(?!\s*$)/,
183
183
  del: noopTest,
184
184
  text: /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,
185
- punctuation: /^([\spunctuation])/
185
+ punctuation: /^((?![*_])[\spunctuation])/
186
186
  };
187
187
 
188
- // list of punctuation marks from CommonMark spec
189
- // without * and _ to handle the different emphasis markers * and _
190
- inline._uc_punctuation = '\\u00A1\\u00A7\\u00AB\\u00B6\\u00B7\\u00BB\\u00BF\\u037E\\u0387\\u055A-\\u055F\\u0589\\u058A\\u05BE\\u05C0\\u05C3\\u05C6\\u05F3\\u05F4\\u0609\\u060A\\u060C\\u060D\\u061B\\u061E\\u061F\\u066A-\\u066D\\u06D4\\u0700-\\u070D\\u07F7-\\u07F9\\u0830-\\u083E\\u085E\\u0964\\u0965\\u0970\\u0AF0\\u0DF4\\u0E4F\\u0E5A\\u0E5B\\u0F04-\\u0F12\\u0F14\\u0F3A-\\u0F3D\\u0F85\\u0FD0-\\u0FD4\\u0FD9\\u0FDA\\u104A-\\u104F\\u10FB\\u1360-\\u1368\\u1400\\u166D\\u166E\\u169B\\u169C\\u16EB-\\u16ED\\u1735\\u1736\\u17D4-\\u17D6\\u17D8-\\u17DA\\u1800-\\u180A\\u1944\\u1945\\u1A1E\\u1A1F\\u1AA0-\\u1AA6\\u1AA8-\\u1AAD\\u1B5A-\\u1B60\\u1BFC-\\u1BFF\\u1C3B-\\u1C3F\\u1C7E\\u1C7F\\u1CC0-\\u1CC7\\u1CD3\\u2010-\\u2027\\u2030-\\u2043\\u2045-\\u2051\\u2053-\\u205E\\u207D\\u207E\\u208D\\u208E\\u2308-\\u230B\\u2329\\u232A\\u2768-\\u2775\\u27C5\\u27C6\\u27E6-\\u27EF\\u2983-\\u2998\\u29D8-\\u29DB\\u29FC\\u29FD\\u2CF9-\\u2CFC\\u2CFE\\u2CFF\\u2D70\\u2E00-\\u2E2E\\u2E30-\\u2E42\\u3001-\\u3003\\u3008-\\u3011\\u3014-\\u301F\\u3030\\u303D\\u30A0\\u30FB\\uA4FE\\uA4FF\\uA60D-\\uA60F\\uA673\\uA67E\\uA6F2-\\uA6F7\\uA874-\\uA877\\uA8CE\\uA8CF\\uA8F8-\\uA8FA\\uA8FC\\uA92E\\uA92F\\uA95F\\uA9C1-\\uA9CD\\uA9DE\\uA9DF\\uAA5C-\\uAA5F\\uAADE\\uAADF\\uAAF0\\uAAF1\\uABEB\\uFD3E\\uFD3F\\uFE10-\\uFE19\\uFE30-\\uFE52\\uFE54-\\uFE61\\uFE63\\uFE68\\uFE6A\\uFE6B\\uFF01-\\uFF03\\uFF05-\\uFF0A\\uFF0C-\\uFF0F\\uFF1A\\uFF1B\\uFF1F\\uFF20\\uFF3B-\\uFF3D\\uFF3F\\uFF5B\\uFF5D\\uFF5F-\\uFF65';
191
- inline._punctuation = '!"#$%&\'()+\\-.,/:;<=>?@\\[\\]`^{|}~\\\\' + inline._uc_punctuation;
192
- inline.punctuation = edit(inline.punctuation).replace(/punctuation/g, inline._punctuation).getRegex();
188
+ // list of unicode punctuation marks, plus any missing characters from CommonMark spec
189
+ inline._punctuation = '\\p{P}$+<=>`^|~';
190
+ inline.punctuation = edit(inline.punctuation, 'u').replace(/punctuation/g, inline._punctuation).getRegex();
193
191
 
194
192
  // sequences em should skip over [title](link), `code`, <html>
195
193
  inline.blockSkip = /\[[^[\]]*?\]\([^\(\)]*?\)|`[^`]*?`|<[^<>]*?>/g;
196
- inline.escapedPunct = /\\[punct_*]/g;
194
+ inline.anyPunctuation = /\\[punct]/g;
195
+ inline._escapes = /\\([punct])/g;
197
196
 
198
197
  inline._comment = edit(block._comment).replace('(?:-->|$)', '-->').getRegex();
199
198
 
200
- inline.emStrong.lDelim = edit(inline.emStrong.lDelim)
199
+ inline.emStrong.lDelim = edit(inline.emStrong.lDelim, 'u')
201
200
  .replace(/punct/g, inline._punctuation)
202
201
  .getRegex();
203
202
 
204
- inline.emStrong.rDelimAst = edit(inline.emStrong.rDelimAst, 'g')
203
+ inline.emStrong.rDelimAst = edit(inline.emStrong.rDelimAst, 'gu')
205
204
  .replace(/punct/g, inline._punctuation)
206
205
  .getRegex();
207
206
 
208
- inline.emStrong.rDelimUnd = edit(inline.emStrong.rDelimUnd, 'g')
207
+ inline.emStrong.rDelimUnd = edit(inline.emStrong.rDelimUnd, 'gu')
209
208
  .replace(/punct/g, inline._punctuation)
210
209
  .getRegex();
211
210
 
212
- inline.escapedPunct = edit(inline.escapedPunct, 'g')
211
+ inline.anyPunctuation = edit(inline.anyPunctuation, 'gu')
213
212
  .replace(/punct/g, inline._punctuation)
214
213
  .getRegex();
215
214
 
216
- inline._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g;
215
+ inline._escapes = edit(inline._escapes, 'gu')
216
+ .replace(/punct/g, inline._punctuation)
217
+ .getRegex();
217
218
 
218
219
  inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;
219
220
  inline._email = /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/;