marked 5.0.4 → 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/lib/marked.esm.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * marked v5.0.4 - a markdown parser
2
+ * marked v5.1.0 - a markdown parser
3
3
  * Copyright (c) 2011-2023, Christopher Jeffrey. (MIT Licensed)
4
4
  * https://github.com/markedjs/marked
5
5
  */
@@ -919,7 +919,7 @@ class Tokenizer {
919
919
 
920
920
  const nextChar = match[1] || match[2] || '';
921
921
 
922
- if (!nextChar || (nextChar && (prevChar === '' || this.rules.inline.punctuation.exec(prevChar)))) {
922
+ if (!nextChar || !prevChar || this.rules.inline.punctuation.exec(prevChar)) {
923
923
  const lLength = match[0].length - 1;
924
924
  let rDelim, rLength, delimTotal = lLength, midDelimTotal = 0;
925
925
 
@@ -953,7 +953,7 @@ class Tokenizer {
953
953
  // Remove extra characters. *a*** -> *a*
954
954
  rLength = Math.min(rLength, rLength + delimTotal + midDelimTotal);
955
955
 
956
- const raw = src.slice(0, lLength + match.index + (match[0].length - rDelim.length) + rLength);
956
+ const raw = src.slice(0, lLength + match.index + rLength + 1);
957
957
 
958
958
  // Create `em` if smallest delimiter has odd char count. *a***
959
959
  if (Math.min(lLength, rLength) % 2) {
@@ -1270,46 +1270,49 @@ const inline = {
1270
1270
  nolink: /^!?\[(ref)\](?:\[\])?/,
1271
1271
  reflinkSearch: 'reflink|nolink(?!\\()',
1272
1272
  emStrong: {
1273
- lDelim: /^(?:\*+(?:([punct_])|[^\s*]))|^_+(?:([punct*])|([^\s_]))/,
1274
- // (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.
1275
- // () Skip orphan inside strong () Consume to delim (1) #*** (2) a***#, a*** (3) #***a, ***a (4) ***# (5) #***# (6) a***a
1276
- rDelimAst: /^(?:[^_*\\]|\\.)*?\_\_(?:[^_*\\]|\\.)*?\*(?:[^_*\\]|\\.)*?(?=\_\_)|(?:[^*\\]|\\.)+(?=[^*])|[punct_](\*+)(?=[\s]|$)|(?:[^punct*_\s\\]|\\.)(\*+)(?=[punct_\s]|$)|[punct_\s](\*+)(?=[^punct*_\s])|[\s](\*+)(?=[punct_])|[punct_](\*+)(?=[punct_])|(?:[^punct*_\s\\]|\\.)(\*+)(?=[^punct*_\s])/,
1277
- rDelimUnd: /^(?:[^_*\\]|\\.)*?\*\*(?:[^_*\\]|\\.)*?\_(?:[^_*\\]|\\.)*?(?=\*\*)|(?:[^_\\]|\\.)+(?=[^_])|[punct*](\_+)(?=[\s]|$)|(?:[^punct*_\s\\]|\\.)(\_+)(?=[punct*\s]|$)|[punct*\s](\_+)(?=[^punct*_\s])|[\s](\_+)(?=[punct*])|[punct*](\_+)(?=[punct*])/ // ^- Not allowed for _
1273
+ lDelim: /^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/,
1274
+ // (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.
1275
+ // | Skip orphan inside strong | Consume to delim | (1) #*** | (2) a***#, a*** | (3) #***a, ***a | (4) ***# | (5) #***# | (6) a***a
1276
+ rDelimAst: /^[^_*]*?__[^_*]*?\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\*)[punct](\*+)(?=[\s]|$)|[^punct\s](\*+)(?!\*)(?=[punct\s]|$)|(?!\*)[punct\s](\*+)(?=[^punct\s])|[\s](\*+)(?!\*)(?=[punct])|(?!\*)[punct](\*+)(?!\*)(?=[punct])|[^punct\s](\*+)(?=[^punct\s])/,
1277
+ rDelimUnd: /^[^_*]*?\*\*[^_*]*?_[^_*]*?(?=\*\*)|[^_]+(?=[^_])|(?!_)[punct](_+)(?=[\s]|$)|[^punct\s](_+)(?!_)(?=[punct\s]|$)|(?!_)[punct\s](_+)(?=[^punct\s])|[\s](_+)(?!_)(?=[punct])|(?!_)[punct](_+)(?!_)(?=[punct])/ // ^- Not allowed for _
1278
1278
  },
1279
1279
  code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
1280
1280
  br: /^( {2,}|\\)\n(?!\s*$)/,
1281
1281
  del: noopTest,
1282
1282
  text: /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,
1283
- punctuation: /^([\spunctuation])/
1283
+ punctuation: /^((?![*_])[\spunctuation])/
1284
1284
  };
1285
1285
 
1286
- // list of punctuation marks from CommonMark spec
1287
- // without * and _ to handle the different emphasis markers * and _
1288
- 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';
1289
- inline._punctuation = '!"#$%&\'()+\\-.,/:;<=>?@\\[\\]`^{|}~' + inline._uc_punctuation;
1290
- inline.punctuation = edit(inline.punctuation).replace(/punctuation/g, inline._punctuation).getRegex();
1286
+ // list of unicode punctuation marks, plus any missing characters from CommonMark spec
1287
+ inline._punctuation = '\\p{P}$+<=>`^|~';
1288
+ inline.punctuation = edit(inline.punctuation, 'u').replace(/punctuation/g, inline._punctuation).getRegex();
1291
1289
 
1292
1290
  // sequences em should skip over [title](link), `code`, <html>
1293
1291
  inline.blockSkip = /\[[^[\]]*?\]\([^\(\)]*?\)|`[^`]*?`|<[^<>]*?>/g;
1294
- // lookbehind is not available on Safari as of version 16
1295
- // inline.escapedEmSt = /(?<=(?:^|[^\\)(?:\\[^])*)\\[*_]/g;
1296
- inline.escapedEmSt = /(?:^|[^\\])(?:\\\\)*\\[*_]/g;
1292
+ inline.anyPunctuation = /\\[punct]/g;
1293
+ inline._escapes = /\\([punct])/g;
1297
1294
 
1298
1295
  inline._comment = edit(block._comment).replace('(?:-->|$)', '-->').getRegex();
1299
1296
 
1300
- inline.emStrong.lDelim = edit(inline.emStrong.lDelim)
1297
+ inline.emStrong.lDelim = edit(inline.emStrong.lDelim, 'u')
1301
1298
  .replace(/punct/g, inline._punctuation)
1302
1299
  .getRegex();
1303
1300
 
1304
- inline.emStrong.rDelimAst = edit(inline.emStrong.rDelimAst, 'g')
1301
+ inline.emStrong.rDelimAst = edit(inline.emStrong.rDelimAst, 'gu')
1305
1302
  .replace(/punct/g, inline._punctuation)
1306
1303
  .getRegex();
1307
1304
 
1308
- inline.emStrong.rDelimUnd = edit(inline.emStrong.rDelimUnd, 'g')
1305
+ inline.emStrong.rDelimUnd = edit(inline.emStrong.rDelimUnd, 'gu')
1309
1306
  .replace(/punct/g, inline._punctuation)
1310
1307
  .getRegex();
1311
1308
 
1312
- inline._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g;
1309
+ inline.anyPunctuation = edit(inline.anyPunctuation, 'gu')
1310
+ .replace(/punct/g, inline._punctuation)
1311
+ .getRegex();
1312
+
1313
+ inline._escapes = edit(inline._escapes, 'gu')
1314
+ .replace(/punct/g, inline._punctuation)
1315
+ .getRegex();
1313
1316
 
1314
1317
  inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;
1315
1318
  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])?)+(?![-_])/;
@@ -1756,10 +1759,9 @@ class Lexer {
1756
1759
  maskedSrc = maskedSrc.slice(0, match.index) + '[' + 'a'.repeat(match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);
1757
1760
  }
1758
1761
 
1759
- // Mask out escaped em & strong delimiters
1760
- while ((match = this.tokenizer.rules.inline.escapedEmSt.exec(maskedSrc)) != null) {
1761
- maskedSrc = maskedSrc.slice(0, match.index + match[0].length - 2) + '++' + maskedSrc.slice(this.tokenizer.rules.inline.escapedEmSt.lastIndex);
1762
- this.tokenizer.rules.inline.escapedEmSt.lastIndex--;
1762
+ // Mask out escaped characters
1763
+ while ((match = this.tokenizer.rules.inline.anyPunctuation.exec(maskedSrc)) != null) {
1764
+ maskedSrc = maskedSrc.slice(0, match.index) + '++' + maskedSrc.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);
1763
1765
  }
1764
1766
 
1765
1767
  while (src) {
@@ -2510,169 +2512,375 @@ class Hooks {
2510
2512
  }
2511
2513
  }
2512
2514
 
2513
- function onError(silent, async, callback) {
2514
- return (e) => {
2515
- e.message += '\nPlease report this to https://github.com/markedjs/marked.';
2515
+ class Marked {
2516
+ defaults = getDefaults();
2517
+ options = this.setOptions;
2516
2518
 
2517
- if (silent) {
2518
- const msg = '<p>An error occurred:</p><pre>'
2519
- + escape(e.message + '', true)
2520
- + '</pre>';
2521
- if (async) {
2522
- return Promise.resolve(msg);
2523
- }
2524
- if (callback) {
2525
- callback(null, msg);
2526
- return;
2527
- }
2528
- return msg;
2529
- }
2519
+ parse = this.#parseMarkdown(Lexer.lex, Parser.parse);
2520
+ parseInline = this.#parseMarkdown(Lexer.lexInline, Parser.parseInline);
2530
2521
 
2531
- if (async) {
2532
- return Promise.reject(e);
2533
- }
2534
- if (callback) {
2535
- callback(e);
2536
- return;
2537
- }
2538
- throw e;
2539
- };
2540
- }
2541
-
2542
- function parseMarkdown(lexer, parser) {
2543
- return (src, opt, callback) => {
2544
- if (typeof opt === 'function') {
2545
- callback = opt;
2546
- opt = null;
2547
- }
2522
+ Parser = Parser;
2523
+ parser = Parser.parse;
2524
+ Renderer = Renderer;
2525
+ TextRenderer = TextRenderer;
2526
+ Lexer = Lexer;
2527
+ lexer = Lexer.lex;
2528
+ Tokenizer = Tokenizer;
2529
+ Slugger = Slugger;
2530
+ Hooks = Hooks;
2548
2531
 
2549
- const origOpt = { ...opt };
2550
- opt = { ...marked.defaults, ...origOpt };
2551
- const throwError = onError(opt.silent, opt.async, callback);
2532
+ constructor(...args) {
2533
+ this.use(...args);
2534
+ }
2552
2535
 
2553
- // throw error in case of non string input
2554
- if (typeof src === 'undefined' || src === null) {
2555
- return throwError(new Error('marked(): input parameter is undefined or null'));
2556
- }
2557
- if (typeof src !== 'string') {
2558
- return throwError(new Error('marked(): input parameter is of type '
2559
- + Object.prototype.toString.call(src) + ', string expected'));
2536
+ walkTokens(tokens, callback) {
2537
+ let values = [];
2538
+ for (const token of tokens) {
2539
+ values = values.concat(callback.call(this, token));
2540
+ switch (token.type) {
2541
+ case 'table': {
2542
+ for (const cell of token.header) {
2543
+ values = values.concat(this.walkTokens(cell.tokens, callback));
2544
+ }
2545
+ for (const row of token.rows) {
2546
+ for (const cell of row) {
2547
+ values = values.concat(this.walkTokens(cell.tokens, callback));
2548
+ }
2549
+ }
2550
+ break;
2551
+ }
2552
+ case 'list': {
2553
+ values = values.concat(this.walkTokens(token.items, callback));
2554
+ break;
2555
+ }
2556
+ default: {
2557
+ if (this.defaults.extensions && this.defaults.extensions.childTokens && this.defaults.extensions.childTokens[token.type]) { // Walk any extensions
2558
+ this.defaults.extensions.childTokens[token.type].forEach((childTokens) => {
2559
+ values = values.concat(this.walkTokens(token[childTokens], callback));
2560
+ });
2561
+ } else if (token.tokens) {
2562
+ values = values.concat(this.walkTokens(token.tokens, callback));
2563
+ }
2564
+ }
2565
+ }
2560
2566
  }
2567
+ return values;
2568
+ }
2561
2569
 
2562
- checkDeprecations(opt, callback);
2570
+ use(...args) {
2571
+ const extensions = this.defaults.extensions || { renderers: {}, childTokens: {} };
2563
2572
 
2564
- if (opt.hooks) {
2565
- opt.hooks.options = opt;
2566
- }
2573
+ args.forEach((pack) => {
2574
+ // copy options to new object
2575
+ const opts = { ...pack };
2567
2576
 
2568
- if (callback) {
2569
- const highlight = opt.highlight;
2570
- let tokens;
2577
+ // set async to true if it was set to true before
2578
+ opts.async = this.defaults.async || opts.async || false;
2571
2579
 
2572
- try {
2573
- if (opt.hooks) {
2574
- src = opt.hooks.preprocess(src);
2575
- }
2576
- tokens = lexer(src, opt);
2577
- } catch (e) {
2578
- return throwError(e);
2580
+ // ==-- Parse "addon" extensions --== //
2581
+ if (pack.extensions) {
2582
+ pack.extensions.forEach((ext) => {
2583
+ if (!ext.name) {
2584
+ throw new Error('extension name required');
2585
+ }
2586
+ if (ext.renderer) { // Renderer extensions
2587
+ const prevRenderer = extensions.renderers[ext.name];
2588
+ if (prevRenderer) {
2589
+ // Replace extension with func to run new extension but fall back if false
2590
+ extensions.renderers[ext.name] = function(...args) {
2591
+ let ret = ext.renderer.apply(this, args);
2592
+ if (ret === false) {
2593
+ ret = prevRenderer.apply(this, args);
2594
+ }
2595
+ return ret;
2596
+ };
2597
+ } else {
2598
+ extensions.renderers[ext.name] = ext.renderer;
2599
+ }
2600
+ }
2601
+ if (ext.tokenizer) { // Tokenizer Extensions
2602
+ if (!ext.level || (ext.level !== 'block' && ext.level !== 'inline')) {
2603
+ throw new Error("extension level must be 'block' or 'inline'");
2604
+ }
2605
+ if (extensions[ext.level]) {
2606
+ extensions[ext.level].unshift(ext.tokenizer);
2607
+ } else {
2608
+ extensions[ext.level] = [ext.tokenizer];
2609
+ }
2610
+ if (ext.start) { // Function to check for start of token
2611
+ if (ext.level === 'block') {
2612
+ if (extensions.startBlock) {
2613
+ extensions.startBlock.push(ext.start);
2614
+ } else {
2615
+ extensions.startBlock = [ext.start];
2616
+ }
2617
+ } else if (ext.level === 'inline') {
2618
+ if (extensions.startInline) {
2619
+ extensions.startInline.push(ext.start);
2620
+ } else {
2621
+ extensions.startInline = [ext.start];
2622
+ }
2623
+ }
2624
+ }
2625
+ }
2626
+ if (ext.childTokens) { // Child tokens to be visited by walkTokens
2627
+ extensions.childTokens[ext.name] = ext.childTokens;
2628
+ }
2629
+ });
2630
+ opts.extensions = extensions;
2579
2631
  }
2580
2632
 
2581
- const done = function(err) {
2582
- let out;
2583
-
2584
- if (!err) {
2585
- try {
2586
- if (opt.walkTokens) {
2587
- marked.walkTokens(tokens, opt.walkTokens);
2633
+ // ==-- Parse "overwrite" extensions --== //
2634
+ if (pack.renderer) {
2635
+ const renderer = this.defaults.renderer || new Renderer(this.defaults);
2636
+ for (const prop in pack.renderer) {
2637
+ const prevRenderer = renderer[prop];
2638
+ // Replace renderer with func to run extension, but fall back if false
2639
+ renderer[prop] = (...args) => {
2640
+ let ret = pack.renderer[prop].apply(renderer, args);
2641
+ if (ret === false) {
2642
+ ret = prevRenderer.apply(renderer, args);
2588
2643
  }
2589
- out = parser(tokens, opt);
2590
- if (opt.hooks) {
2591
- out = opt.hooks.postprocess(out);
2644
+ return ret;
2645
+ };
2646
+ }
2647
+ opts.renderer = renderer;
2648
+ }
2649
+ if (pack.tokenizer) {
2650
+ const tokenizer = this.defaults.tokenizer || new Tokenizer(this.defaults);
2651
+ for (const prop in pack.tokenizer) {
2652
+ const prevTokenizer = tokenizer[prop];
2653
+ // Replace tokenizer with func to run extension, but fall back if false
2654
+ tokenizer[prop] = (...args) => {
2655
+ let ret = pack.tokenizer[prop].apply(tokenizer, args);
2656
+ if (ret === false) {
2657
+ ret = prevTokenizer.apply(tokenizer, args);
2592
2658
  }
2593
- } catch (e) {
2594
- err = e;
2659
+ return ret;
2660
+ };
2661
+ }
2662
+ opts.tokenizer = tokenizer;
2663
+ }
2664
+
2665
+ // ==-- Parse Hooks extensions --== //
2666
+ if (pack.hooks) {
2667
+ const hooks = this.defaults.hooks || new Hooks();
2668
+ for (const prop in pack.hooks) {
2669
+ const prevHook = hooks[prop];
2670
+ if (Hooks.passThroughHooks.has(prop)) {
2671
+ hooks[prop] = (arg) => {
2672
+ if (this.defaults.async) {
2673
+ return Promise.resolve(pack.hooks[prop].call(hooks, arg)).then(ret => {
2674
+ return prevHook.call(hooks, ret);
2675
+ });
2676
+ }
2677
+
2678
+ const ret = pack.hooks[prop].call(hooks, arg);
2679
+ return prevHook.call(hooks, ret);
2680
+ };
2681
+ } else {
2682
+ hooks[prop] = (...args) => {
2683
+ let ret = pack.hooks[prop].apply(hooks, args);
2684
+ if (ret === false) {
2685
+ ret = prevHook.apply(hooks, args);
2686
+ }
2687
+ return ret;
2688
+ };
2595
2689
  }
2596
2690
  }
2691
+ opts.hooks = hooks;
2692
+ }
2597
2693
 
2598
- opt.highlight = highlight;
2694
+ // ==-- Parse WalkTokens extensions --== //
2695
+ if (pack.walkTokens) {
2696
+ const walkTokens = this.defaults.walkTokens;
2697
+ opts.walkTokens = function(token) {
2698
+ let values = [];
2699
+ values.push(pack.walkTokens.call(this, token));
2700
+ if (walkTokens) {
2701
+ values = values.concat(walkTokens.call(this, token));
2702
+ }
2703
+ return values;
2704
+ };
2705
+ }
2599
2706
 
2600
- return err
2601
- ? throwError(err)
2602
- : callback(null, out);
2603
- };
2707
+ this.defaults = { ...this.defaults, ...opts };
2708
+ });
2709
+
2710
+ return this;
2711
+ }
2712
+
2713
+ setOptions(opt) {
2714
+ this.defaults = { ...this.defaults, ...opt };
2715
+ return this;
2716
+ }
2717
+
2718
+ #parseMarkdown(lexer, parser) {
2719
+ return (src, opt, callback) => {
2720
+ if (typeof opt === 'function') {
2721
+ callback = opt;
2722
+ opt = null;
2723
+ }
2724
+
2725
+ const origOpt = { ...opt };
2726
+ opt = { ...this.defaults, ...origOpt };
2727
+ const throwError = this.#onError(opt.silent, opt.async, callback);
2728
+
2729
+ // throw error in case of non string input
2730
+ if (typeof src === 'undefined' || src === null) {
2731
+ return throwError(new Error('marked(): input parameter is undefined or null'));
2732
+ }
2733
+ if (typeof src !== 'string') {
2734
+ return throwError(new Error('marked(): input parameter is of type '
2735
+ + Object.prototype.toString.call(src) + ', string expected'));
2736
+ }
2737
+
2738
+ checkDeprecations(opt, callback);
2604
2739
 
2605
- if (!highlight || highlight.length < 3) {
2606
- return done();
2740
+ if (opt.hooks) {
2741
+ opt.hooks.options = opt;
2607
2742
  }
2608
2743
 
2609
- delete opt.highlight;
2744
+ if (callback) {
2745
+ const highlight = opt.highlight;
2746
+ let tokens;
2747
+
2748
+ try {
2749
+ if (opt.hooks) {
2750
+ src = opt.hooks.preprocess(src);
2751
+ }
2752
+ tokens = lexer(src, opt);
2753
+ } catch (e) {
2754
+ return throwError(e);
2755
+ }
2610
2756
 
2611
- if (!tokens.length) return done();
2757
+ const done = (err) => {
2758
+ let out;
2612
2759
 
2613
- let pending = 0;
2614
- marked.walkTokens(tokens, function(token) {
2615
- if (token.type === 'code') {
2616
- pending++;
2617
- setTimeout(() => {
2618
- highlight(token.text, token.lang, function(err, code) {
2619
- if (err) {
2620
- return done(err);
2760
+ if (!err) {
2761
+ try {
2762
+ if (opt.walkTokens) {
2763
+ this.walkTokens(tokens, opt.walkTokens);
2621
2764
  }
2622
- if (code != null && code !== token.text) {
2623
- token.text = code;
2624
- token.escaped = true;
2765
+ out = parser(tokens, opt);
2766
+ if (opt.hooks) {
2767
+ out = opt.hooks.postprocess(out);
2625
2768
  }
2769
+ } catch (e) {
2770
+ err = e;
2771
+ }
2772
+ }
2626
2773
 
2627
- pending--;
2628
- if (pending === 0) {
2629
- done();
2630
- }
2631
- });
2632
- }, 0);
2774
+ opt.highlight = highlight;
2775
+
2776
+ return err
2777
+ ? throwError(err)
2778
+ : callback(null, out);
2779
+ };
2780
+
2781
+ if (!highlight || highlight.length < 3) {
2782
+ return done();
2783
+ }
2784
+
2785
+ delete opt.highlight;
2786
+
2787
+ if (!tokens.length) return done();
2788
+
2789
+ let pending = 0;
2790
+ this.walkTokens(tokens, (token) => {
2791
+ if (token.type === 'code') {
2792
+ pending++;
2793
+ setTimeout(() => {
2794
+ highlight(token.text, token.lang, (err, code) => {
2795
+ if (err) {
2796
+ return done(err);
2797
+ }
2798
+ if (code != null && code !== token.text) {
2799
+ token.text = code;
2800
+ token.escaped = true;
2801
+ }
2802
+
2803
+ pending--;
2804
+ if (pending === 0) {
2805
+ done();
2806
+ }
2807
+ });
2808
+ }, 0);
2809
+ }
2810
+ });
2811
+
2812
+ if (pending === 0) {
2813
+ done();
2633
2814
  }
2634
- });
2635
2815
 
2636
- if (pending === 0) {
2637
- done();
2816
+ return;
2638
2817
  }
2639
2818
 
2640
- return;
2641
- }
2819
+ if (opt.async) {
2820
+ return Promise.resolve(opt.hooks ? opt.hooks.preprocess(src) : src)
2821
+ .then(src => lexer(src, opt))
2822
+ .then(tokens => opt.walkTokens ? Promise.all(this.walkTokens(tokens, opt.walkTokens)).then(() => tokens) : tokens)
2823
+ .then(tokens => parser(tokens, opt))
2824
+ .then(html => opt.hooks ? opt.hooks.postprocess(html) : html)
2825
+ .catch(throwError);
2826
+ }
2642
2827
 
2643
- if (opt.async) {
2644
- return Promise.resolve(opt.hooks ? opt.hooks.preprocess(src) : src)
2645
- .then(src => lexer(src, opt))
2646
- .then(tokens => opt.walkTokens ? Promise.all(marked.walkTokens(tokens, opt.walkTokens)).then(() => tokens) : tokens)
2647
- .then(tokens => parser(tokens, opt))
2648
- .then(html => opt.hooks ? opt.hooks.postprocess(html) : html)
2649
- .catch(throwError);
2650
- }
2828
+ try {
2829
+ if (opt.hooks) {
2830
+ src = opt.hooks.preprocess(src);
2831
+ }
2832
+ const tokens = lexer(src, opt);
2833
+ if (opt.walkTokens) {
2834
+ this.walkTokens(tokens, opt.walkTokens);
2835
+ }
2836
+ let html = parser(tokens, opt);
2837
+ if (opt.hooks) {
2838
+ html = opt.hooks.postprocess(html);
2839
+ }
2840
+ return html;
2841
+ } catch (e) {
2842
+ return throwError(e);
2843
+ }
2844
+ };
2845
+ }
2651
2846
 
2652
- try {
2653
- if (opt.hooks) {
2654
- src = opt.hooks.preprocess(src);
2847
+ #onError(silent, async, callback) {
2848
+ return (e) => {
2849
+ e.message += '\nPlease report this to https://github.com/markedjs/this.';
2850
+
2851
+ if (silent) {
2852
+ const msg = '<p>An error occurred:</p><pre>'
2853
+ + escape(e.message + '', true)
2854
+ + '</pre>';
2855
+ if (async) {
2856
+ return Promise.resolve(msg);
2857
+ }
2858
+ if (callback) {
2859
+ callback(null, msg);
2860
+ return;
2861
+ }
2862
+ return msg;
2655
2863
  }
2656
- const tokens = lexer(src, opt);
2657
- if (opt.walkTokens) {
2658
- marked.walkTokens(tokens, opt.walkTokens);
2864
+
2865
+ if (async) {
2866
+ return Promise.reject(e);
2659
2867
  }
2660
- let html = parser(tokens, opt);
2661
- if (opt.hooks) {
2662
- html = opt.hooks.postprocess(html);
2868
+ if (callback) {
2869
+ callback(e);
2870
+ return;
2663
2871
  }
2664
- return html;
2665
- } catch (e) {
2666
- return throwError(e);
2667
- }
2668
- };
2872
+ throw e;
2873
+ };
2874
+ }
2669
2875
  }
2670
2876
 
2877
+ const markedInstance = new Marked(defaults);
2878
+
2671
2879
  /**
2672
2880
  * Marked
2673
2881
  */
2674
2882
  function marked(src, opt, callback) {
2675
- return parseMarkdown(Lexer.lex, Parser.parse)(src, opt, callback);
2883
+ return markedInstance.parse(src, opt, callback);
2676
2884
  }
2677
2885
 
2678
2886
  /**
@@ -2681,7 +2889,8 @@ function marked(src, opt, callback) {
2681
2889
 
2682
2890
  marked.options =
2683
2891
  marked.setOptions = function(opt) {
2684
- marked.defaults = { ...marked.defaults, ...opt };
2892
+ markedInstance.setOptions(opt);
2893
+ marked.defaults = markedInstance.defaults;
2685
2894
  changeDefaults(marked.defaults);
2686
2895
  return marked;
2687
2896
  };
@@ -2695,144 +2904,10 @@ marked.defaults = defaults;
2695
2904
  */
2696
2905
 
2697
2906
  marked.use = function(...args) {
2698
- const extensions = marked.defaults.extensions || { renderers: {}, childTokens: {} };
2699
-
2700
- args.forEach((pack) => {
2701
- // copy options to new object
2702
- const opts = { ...pack };
2703
-
2704
- // set async to true if it was set to true before
2705
- opts.async = marked.defaults.async || opts.async || false;
2706
-
2707
- // ==-- Parse "addon" extensions --== //
2708
- if (pack.extensions) {
2709
- pack.extensions.forEach((ext) => {
2710
- if (!ext.name) {
2711
- throw new Error('extension name required');
2712
- }
2713
- if (ext.renderer) { // Renderer extensions
2714
- const prevRenderer = extensions.renderers[ext.name];
2715
- if (prevRenderer) {
2716
- // Replace extension with func to run new extension but fall back if false
2717
- extensions.renderers[ext.name] = function(...args) {
2718
- let ret = ext.renderer.apply(this, args);
2719
- if (ret === false) {
2720
- ret = prevRenderer.apply(this, args);
2721
- }
2722
- return ret;
2723
- };
2724
- } else {
2725
- extensions.renderers[ext.name] = ext.renderer;
2726
- }
2727
- }
2728
- if (ext.tokenizer) { // Tokenizer Extensions
2729
- if (!ext.level || (ext.level !== 'block' && ext.level !== 'inline')) {
2730
- throw new Error("extension level must be 'block' or 'inline'");
2731
- }
2732
- if (extensions[ext.level]) {
2733
- extensions[ext.level].unshift(ext.tokenizer);
2734
- } else {
2735
- extensions[ext.level] = [ext.tokenizer];
2736
- }
2737
- if (ext.start) { // Function to check for start of token
2738
- if (ext.level === 'block') {
2739
- if (extensions.startBlock) {
2740
- extensions.startBlock.push(ext.start);
2741
- } else {
2742
- extensions.startBlock = [ext.start];
2743
- }
2744
- } else if (ext.level === 'inline') {
2745
- if (extensions.startInline) {
2746
- extensions.startInline.push(ext.start);
2747
- } else {
2748
- extensions.startInline = [ext.start];
2749
- }
2750
- }
2751
- }
2752
- }
2753
- if (ext.childTokens) { // Child tokens to be visited by walkTokens
2754
- extensions.childTokens[ext.name] = ext.childTokens;
2755
- }
2756
- });
2757
- opts.extensions = extensions;
2758
- }
2759
-
2760
- // ==-- Parse "overwrite" extensions --== //
2761
- if (pack.renderer) {
2762
- const renderer = marked.defaults.renderer || new Renderer();
2763
- for (const prop in pack.renderer) {
2764
- const prevRenderer = renderer[prop];
2765
- // Replace renderer with func to run extension, but fall back if false
2766
- renderer[prop] = (...args) => {
2767
- let ret = pack.renderer[prop].apply(renderer, args);
2768
- if (ret === false) {
2769
- ret = prevRenderer.apply(renderer, args);
2770
- }
2771
- return ret;
2772
- };
2773
- }
2774
- opts.renderer = renderer;
2775
- }
2776
- if (pack.tokenizer) {
2777
- const tokenizer = marked.defaults.tokenizer || new Tokenizer();
2778
- for (const prop in pack.tokenizer) {
2779
- const prevTokenizer = tokenizer[prop];
2780
- // Replace tokenizer with func to run extension, but fall back if false
2781
- tokenizer[prop] = (...args) => {
2782
- let ret = pack.tokenizer[prop].apply(tokenizer, args);
2783
- if (ret === false) {
2784
- ret = prevTokenizer.apply(tokenizer, args);
2785
- }
2786
- return ret;
2787
- };
2788
- }
2789
- opts.tokenizer = tokenizer;
2790
- }
2791
-
2792
- // ==-- Parse Hooks extensions --== //
2793
- if (pack.hooks) {
2794
- const hooks = marked.defaults.hooks || new Hooks();
2795
- for (const prop in pack.hooks) {
2796
- const prevHook = hooks[prop];
2797
- if (Hooks.passThroughHooks.has(prop)) {
2798
- hooks[prop] = (arg) => {
2799
- if (marked.defaults.async) {
2800
- return Promise.resolve(pack.hooks[prop].call(hooks, arg)).then(ret => {
2801
- return prevHook.call(hooks, ret);
2802
- });
2803
- }
2804
-
2805
- const ret = pack.hooks[prop].call(hooks, arg);
2806
- return prevHook.call(hooks, ret);
2807
- };
2808
- } else {
2809
- hooks[prop] = (...args) => {
2810
- let ret = pack.hooks[prop].apply(hooks, args);
2811
- if (ret === false) {
2812
- ret = prevHook.apply(hooks, args);
2813
- }
2814
- return ret;
2815
- };
2816
- }
2817
- }
2818
- opts.hooks = hooks;
2819
- }
2820
-
2821
- // ==-- Parse WalkTokens extensions --== //
2822
- if (pack.walkTokens) {
2823
- const walkTokens = marked.defaults.walkTokens;
2824
- opts.walkTokens = function(token) {
2825
- let values = [];
2826
- values.push(pack.walkTokens.call(this, token));
2827
- if (walkTokens) {
2828
- values = values.concat(walkTokens.call(this, token));
2829
- }
2830
- return values;
2831
- };
2832
- }
2833
-
2834
- marked.setOptions(opts);
2835
- });
2907
+ markedInstance.use(...args);
2908
+ marked.defaults = markedInstance.defaults;
2909
+ changeDefaults(marked.defaults);
2910
+ return marked;
2836
2911
  };
2837
2912
 
2838
2913
  /**
@@ -2840,44 +2915,14 @@ marked.use = function(...args) {
2840
2915
  */
2841
2916
 
2842
2917
  marked.walkTokens = function(tokens, callback) {
2843
- let values = [];
2844
- for (const token of tokens) {
2845
- values = values.concat(callback.call(marked, token));
2846
- switch (token.type) {
2847
- case 'table': {
2848
- for (const cell of token.header) {
2849
- values = values.concat(marked.walkTokens(cell.tokens, callback));
2850
- }
2851
- for (const row of token.rows) {
2852
- for (const cell of row) {
2853
- values = values.concat(marked.walkTokens(cell.tokens, callback));
2854
- }
2855
- }
2856
- break;
2857
- }
2858
- case 'list': {
2859
- values = values.concat(marked.walkTokens(token.items, callback));
2860
- break;
2861
- }
2862
- default: {
2863
- if (marked.defaults.extensions && marked.defaults.extensions.childTokens && marked.defaults.extensions.childTokens[token.type]) { // Walk any extensions
2864
- marked.defaults.extensions.childTokens[token.type].forEach(function(childTokens) {
2865
- values = values.concat(marked.walkTokens(token[childTokens], callback));
2866
- });
2867
- } else if (token.tokens) {
2868
- values = values.concat(marked.walkTokens(token.tokens, callback));
2869
- }
2870
- }
2871
- }
2872
- }
2873
- return values;
2918
+ return markedInstance.walkTokens(tokens, callback);
2874
2919
  };
2875
2920
 
2876
2921
  /**
2877
2922
  * Parse Inline
2878
2923
  * @param {string} src
2879
2924
  */
2880
- marked.parseInline = parseMarkdown(Lexer.lexInline, Parser.parseInline);
2925
+ marked.parseInline = markedInstance.parseInline;
2881
2926
 
2882
2927
  /**
2883
2928
  * Expose
@@ -2902,4 +2947,4 @@ const parse = marked;
2902
2947
  const parser = Parser.parse;
2903
2948
  const lexer = Lexer.lex;
2904
2949
 
2905
- export { Hooks, Lexer, Parser, Renderer, Slugger, TextRenderer, Tokenizer, defaults, getDefaults, lexer, marked, options, parse, parseInline, parser, setOptions, use, walkTokens };
2950
+ export { Hooks, Lexer, Marked, Parser, Renderer, Slugger, TextRenderer, Tokenizer, defaults, getDefaults, lexer, marked, options, parse, parseInline, parser, setOptions, use, walkTokens };