marked 4.2.12 → 4.3.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
@@ -4,8 +4,8 @@ import { Tokenizer } from './Tokenizer.js';
4
4
  import { Renderer } from './Renderer.js';
5
5
  import { TextRenderer } from './TextRenderer.js';
6
6
  import { Slugger } from './Slugger.js';
7
+ import { Hooks } from './Hooks.js';
7
8
  import {
8
- merge,
9
9
  checkSanitizeDeprecation,
10
10
  escape
11
11
  } from './helpers.js';
@@ -15,122 +15,169 @@ import {
15
15
  defaults
16
16
  } from './defaults.js';
17
17
 
18
- /**
19
- * Marked
20
- */
21
- export function marked(src, opt, callback) {
22
- // throw error in case of non string input
23
- if (typeof src === 'undefined' || src === null) {
24
- throw new Error('marked(): input parameter is undefined or null');
25
- }
26
- if (typeof src !== 'string') {
27
- throw new Error('marked(): input parameter is of type '
28
- + Object.prototype.toString.call(src) + ', string expected');
29
- }
18
+ function onError(silent, async, callback) {
19
+ return (e) => {
20
+ e.message += '\nPlease report this to https://github.com/markedjs/marked.';
30
21
 
31
- if (typeof opt === 'function') {
32
- callback = opt;
33
- opt = null;
34
- }
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
+ }
35
46
 
36
- opt = merge({}, marked.defaults, opt || {});
37
- checkSanitizeDeprecation(opt);
47
+ function parseMarkdown(lexer, parser) {
48
+ return (src, opt, callback) => {
49
+ if (typeof opt === 'function') {
50
+ callback = opt;
51
+ opt = null;
52
+ }
38
53
 
39
- if (callback) {
40
- const highlight = opt.highlight;
41
- let tokens;
54
+ const origOpt = { ...opt };
55
+ opt = { ...marked.defaults, ...origOpt };
56
+ const throwError = onError(opt.silent, opt.async, callback);
42
57
 
43
- try {
44
- tokens = Lexer.lex(src, opt);
45
- } catch (e) {
46
- return callback(e);
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'));
47
65
  }
48
66
 
49
- const done = function(err) {
50
- let out;
67
+ checkSanitizeDeprecation(opt);
51
68
 
52
- if (!err) {
53
- try {
54
- if (opt.walkTokens) {
55
- marked.walkTokens(tokens, opt.walkTokens);
56
- }
57
- out = Parser.parse(tokens, opt);
58
- } catch (e) {
59
- err = e;
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);
60
80
  }
81
+ tokens = lexer(src, opt);
82
+ } catch (e) {
83
+ return throwError(e);
61
84
  }
62
85
 
63
- opt.highlight = highlight;
86
+ const done = function(err) {
87
+ let out;
64
88
 
65
- return err
66
- ? callback(err)
67
- : callback(null, out);
68
- };
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
+ }
69
102
 
70
- if (!highlight || highlight.length < 3) {
71
- return done();
72
- }
103
+ opt.highlight = highlight;
73
104
 
74
- delete opt.highlight;
105
+ return err
106
+ ? throwError(err)
107
+ : callback(null, out);
108
+ };
75
109
 
76
- if (!tokens.length) return done();
110
+ if (!highlight || highlight.length < 3) {
111
+ return done();
112
+ }
77
113
 
78
- let pending = 0;
79
- marked.walkTokens(tokens, function(token) {
80
- if (token.type === 'code') {
81
- pending++;
82
- setTimeout(() => {
83
- highlight(token.text, token.lang, function(err, code) {
84
- if (err) {
85
- return done(err);
86
- }
87
- if (code != null && code !== token.text) {
88
- token.text = code;
89
- token.escaped = true;
90
- }
114
+ delete opt.highlight;
91
115
 
92
- pending--;
93
- if (pending === 0) {
94
- done();
95
- }
96
- });
97
- }, 0);
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();
98
143
  }
99
- });
100
144
 
101
- if (pending === 0) {
102
- done();
145
+ return;
103
146
  }
104
147
 
105
- return;
106
- }
107
-
108
- function onError(e) {
109
- e.message += '\nPlease report this to https://github.com/markedjs/marked.';
110
- if (opt.silent) {
111
- return '<p>An error occurred:</p><pre>'
112
- + escape(e.message + '', true)
113
- + '</pre>';
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);
114
155
  }
115
- throw e;
116
- }
117
156
 
118
- try {
119
- const tokens = Lexer.lex(src, opt);
120
- if (opt.walkTokens) {
121
- if (opt.async) {
122
- return Promise.all(marked.walkTokens(tokens, opt.walkTokens))
123
- .then(() => {
124
- return Parser.parse(tokens, opt);
125
- })
126
- .catch(onError);
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);
127
168
  }
128
- marked.walkTokens(tokens, opt.walkTokens);
169
+ return html;
170
+ } catch (e) {
171
+ return throwError(e);
129
172
  }
130
- return Parser.parse(tokens, opt);
131
- } catch (e) {
132
- onError(e);
133
- }
173
+ };
174
+ }
175
+
176
+ /**
177
+ * Marked
178
+ */
179
+ export function marked(src, opt, callback) {
180
+ return parseMarkdown(Lexer.lex, Parser.parse)(src, opt, callback);
134
181
  }
135
182
 
136
183
  /**
@@ -139,7 +186,7 @@ export function marked(src, opt, callback) {
139
186
 
140
187
  marked.options =
141
188
  marked.setOptions = function(opt) {
142
- merge(marked.defaults, opt);
189
+ marked.defaults = { ...marked.defaults, ...opt };
143
190
  changeDefaults(marked.defaults);
144
191
  return marked;
145
192
  };
@@ -157,10 +204,10 @@ marked.use = function(...args) {
157
204
 
158
205
  args.forEach((pack) => {
159
206
  // copy options to new object
160
- const opts = merge({}, pack);
207
+ const opts = { ...pack };
161
208
 
162
209
  // set async to true if it was set to true before
163
- opts.async = marked.defaults.async || opts.async;
210
+ opts.async = marked.defaults.async || opts.async || false;
164
211
 
165
212
  // ==-- Parse "addon" extensions --== //
166
213
  if (pack.extensions) {
@@ -247,6 +294,35 @@ marked.use = function(...args) {
247
294
  opts.tokenizer = tokenizer;
248
295
  }
249
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
+
250
326
  // ==-- Parse WalkTokens extensions --== //
251
327
  if (pack.walkTokens) {
252
328
  const walkTokens = marked.defaults.walkTokens;
@@ -306,35 +382,7 @@ marked.walkTokens = function(tokens, callback) {
306
382
  * Parse Inline
307
383
  * @param {string} src
308
384
  */
309
- marked.parseInline = function(src, opt) {
310
- // throw error in case of non string input
311
- if (typeof src === 'undefined' || src === null) {
312
- throw new Error('marked.parseInline(): input parameter is undefined or null');
313
- }
314
- if (typeof src !== 'string') {
315
- throw new Error('marked.parseInline(): input parameter is of type '
316
- + Object.prototype.toString.call(src) + ', string expected');
317
- }
318
-
319
- opt = merge({}, marked.defaults, opt || {});
320
- checkSanitizeDeprecation(opt);
321
-
322
- try {
323
- const tokens = Lexer.lexInline(src, opt);
324
- if (opt.walkTokens) {
325
- marked.walkTokens(tokens, opt.walkTokens);
326
- }
327
- return Parser.parseInline(tokens, opt);
328
- } catch (e) {
329
- e.message += '\nPlease report this to https://github.com/markedjs/marked.';
330
- if (opt.silent) {
331
- return '<p>An error occurred:</p><pre>'
332
- + escape(e.message + '', true)
333
- + '</pre>';
334
- }
335
- throw e;
336
- }
337
- };
385
+ marked.parseInline = parseMarkdown(Lexer.lexInline, Parser.parseInline);
338
386
 
339
387
  /**
340
388
  * Expose
@@ -347,6 +395,7 @@ marked.Lexer = Lexer;
347
395
  marked.lexer = Lexer.lex;
348
396
  marked.Tokenizer = Tokenizer;
349
397
  marked.Slugger = Slugger;
398
+ marked.Hooks = Hooks;
350
399
  marked.parse = marked;
351
400
 
352
401
  export const options = marked.options;
@@ -364,3 +413,4 @@ export { Tokenizer } from './Tokenizer.js';
364
413
  export { Renderer } from './Renderer.js';
365
414
  export { TextRenderer } from './TextRenderer.js';
366
415
  export { Slugger } from './Slugger.js';
416
+ export { Hooks } from './Hooks.js';
package/src/rules.js CHANGED
@@ -1,7 +1,6 @@
1
1
  import {
2
2
  noopTest,
3
- edit,
4
- merge
3
+ edit
5
4
  } from './helpers.js';
6
5
 
7
6
  /**
@@ -10,7 +9,7 @@ import {
10
9
  export const block = {
11
10
  newline: /^(?: *(?:\n|$))+/,
12
11
  code: /^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,
13
- fences: /^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?=\n|$)|$)/,
12
+ fences: /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,
14
13
  hr: /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,
15
14
  heading: /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,
16
15
  blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
@@ -85,17 +84,18 @@ block.blockquote = edit(block.blockquote)
85
84
  * Normal Block Grammar
86
85
  */
87
86
 
88
- block.normal = merge({}, block);
87
+ block.normal = { ...block };
89
88
 
90
89
  /**
91
90
  * GFM Block Grammar
92
91
  */
93
92
 
94
- block.gfm = merge({}, block.normal, {
93
+ block.gfm = {
94
+ ...block.normal,
95
95
  table: '^ *([^\\n ].*\\|.*)\\n' // Header
96
96
  + ' {0,3}(?:\\| *)?(:?-+:? *(?:\\| *:?-+:? *)*)(?:\\| *)?' // Align
97
97
  + '(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)' // Cells
98
- });
98
+ };
99
99
 
100
100
  block.gfm.table = edit(block.gfm.table)
101
101
  .replace('hr', block.hr)
@@ -123,7 +123,8 @@ block.gfm.paragraph = edit(block._paragraph)
123
123
  * Pedantic grammar (original John Gruber's loose markdown specification)
124
124
  */
125
125
 
126
- block.pedantic = merge({}, block.normal, {
126
+ block.pedantic = {
127
+ ...block.normal,
127
128
  html: edit(
128
129
  '^ *(?:comment *(?:\\n|\\s*$)'
129
130
  + '|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)' // closed tag
@@ -147,7 +148,7 @@ block.pedantic = merge({}, block.normal, {
147
148
  .replace('|list', '')
148
149
  .replace('|html', '')
149
150
  .getRegex()
150
- });
151
+ };
151
152
 
152
153
  /**
153
154
  * Inline-Level Grammar
@@ -249,13 +250,14 @@ inline.reflinkSearch = edit(inline.reflinkSearch, 'g')
249
250
  * Normal Inline Grammar
250
251
  */
251
252
 
252
- inline.normal = merge({}, inline);
253
+ inline.normal = { ...inline };
253
254
 
254
255
  /**
255
256
  * Pedantic Inline Grammar
256
257
  */
257
258
 
258
- inline.pedantic = merge({}, inline.normal, {
259
+ inline.pedantic = {
260
+ ...inline.normal,
259
261
  strong: {
260
262
  start: /^__|\*\*/,
261
263
  middle: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
@@ -274,20 +276,21 @@ inline.pedantic = merge({}, inline.normal, {
274
276
  reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/)
275
277
  .replace('label', inline._label)
276
278
  .getRegex()
277
- });
279
+ };
278
280
 
279
281
  /**
280
282
  * GFM Inline Grammar
281
283
  */
282
284
 
283
- inline.gfm = merge({}, inline.normal, {
285
+ inline.gfm = {
286
+ ...inline.normal,
284
287
  escape: edit(inline.escape).replace('])', '~|])').getRegex(),
285
288
  _extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,
286
289
  url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
287
290
  _backpedal: /(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,
288
291
  del: /^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,
289
292
  text: /^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/
290
- });
293
+ };
291
294
 
292
295
  inline.gfm.url = edit(inline.gfm.url, 'i')
293
296
  .replace('email', inline.gfm._extended_email)
@@ -296,10 +299,11 @@ inline.gfm.url = edit(inline.gfm.url, 'i')
296
299
  * GFM + Line Breaks Inline Grammar
297
300
  */
298
301
 
299
- inline.breaks = merge({}, inline.gfm, {
302
+ inline.breaks = {
303
+ ...inline.gfm,
300
304
  br: edit(inline.br).replace('{2,}', '*').getRegex(),
301
305
  text: edit(inline.gfm.text)
302
306
  .replace('\\b_', '\\b_| {2,}\\n')
303
307
  .replace(/\{2,\}/g, '*')
304
308
  .getRegex()
305
- });
309
+ };