marked 2.0.7 → 2.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
@@ -15,6 +15,7 @@ function getDefaults$1() {
15
15
  return {
16
16
  baseUrl: null,
17
17
  breaks: false,
18
+ extensions: null,
18
19
  gfm: true,
19
20
  headerIds: true,
20
21
  headerPrefix: '',
@@ -1474,9 +1475,21 @@ var Lexer_1 = class Lexer {
1474
1475
  if (this.options.pedantic) {
1475
1476
  src = src.replace(/^ +$/gm, '');
1476
1477
  }
1477
- let token, i, l, lastToken;
1478
+ let token, i, l, lastToken, cutSrc, lastParagraphClipped;
1478
1479
 
1479
1480
  while (src) {
1481
+ if (this.options?.extensions?.block
1482
+ && this.options.extensions.block.some((extTokenizer) => {
1483
+ if (token = extTokenizer.call(this, src, tokens)) {
1484
+ src = src.substring(token.raw.length);
1485
+ tokens.push(token);
1486
+ return true;
1487
+ }
1488
+ return false;
1489
+ })) {
1490
+ continue;
1491
+ }
1492
+
1480
1493
  // newline
1481
1494
  if (token = this.tokenizer.space(src)) {
1482
1495
  src = src.substring(token.raw.length);
@@ -1581,9 +1594,30 @@ var Lexer_1 = class Lexer {
1581
1594
  }
1582
1595
 
1583
1596
  // top-level paragraph
1584
- if (top && (token = this.tokenizer.paragraph(src))) {
1597
+ // prevent paragraph consuming extensions by clipping 'src' to extension start
1598
+ cutSrc = src;
1599
+ if (this.options.extensions?.startBlock) {
1600
+ let startIndex = Infinity;
1601
+ const tempSrc = src.slice(1);
1602
+ let tempStart;
1603
+ this.options.extensions.startBlock.forEach(function(getStartIndex) {
1604
+ tempStart = getStartIndex.call(this, tempSrc);
1605
+ if (typeof tempStart === 'number' && tempStart >= 0) { startIndex = Math.min(startIndex, tempStart); }
1606
+ });
1607
+ if (startIndex < Infinity && startIndex >= 0) {
1608
+ cutSrc = src.substring(0, startIndex + 1);
1609
+ }
1610
+ }
1611
+ if (top && (token = this.tokenizer.paragraph(cutSrc))) {
1612
+ lastToken = tokens[tokens.length - 1];
1613
+ if (lastParagraphClipped && lastToken.type === 'paragraph') {
1614
+ lastToken.raw += '\n' + token.raw;
1615
+ lastToken.text += '\n' + token.text;
1616
+ } else {
1617
+ tokens.push(token);
1618
+ }
1619
+ lastParagraphClipped = (cutSrc.length !== src.length);
1585
1620
  src = src.substring(token.raw.length);
1586
- tokens.push(token);
1587
1621
  continue;
1588
1622
  }
1589
1623
 
@@ -1680,7 +1714,7 @@ var Lexer_1 = class Lexer {
1680
1714
  * Lexing/Compiling
1681
1715
  */
1682
1716
  inlineTokens(src, tokens = [], inLink = false, inRawBlock = false) {
1683
- let token, lastToken;
1717
+ let token, lastToken, cutSrc;
1684
1718
 
1685
1719
  // String with links masked to avoid interference with em and strong
1686
1720
  let maskedSrc = src;
@@ -1714,6 +1748,19 @@ var Lexer_1 = class Lexer {
1714
1748
  }
1715
1749
  keepPrevChar = false;
1716
1750
 
1751
+ // extensions
1752
+ if (this.options?.extensions?.inline
1753
+ && this.options.extensions.inline.some((extTokenizer) => {
1754
+ if (token = extTokenizer.call(this, src, tokens)) {
1755
+ src = src.substring(token.raw.length);
1756
+ tokens.push(token);
1757
+ return true;
1758
+ }
1759
+ return false;
1760
+ })) {
1761
+ continue;
1762
+ }
1763
+
1717
1764
  // escape
1718
1765
  if (token = this.tokenizer.escape(src)) {
1719
1766
  src = src.substring(token.raw.length);
@@ -1726,7 +1773,7 @@ var Lexer_1 = class Lexer {
1726
1773
  src = src.substring(token.raw.length);
1727
1774
  inLink = token.inLink;
1728
1775
  inRawBlock = token.inRawBlock;
1729
- const lastToken = tokens[tokens.length - 1];
1776
+ lastToken = tokens[tokens.length - 1];
1730
1777
  if (lastToken && token.type === 'text' && lastToken.type === 'text') {
1731
1778
  lastToken.raw += token.raw;
1732
1779
  lastToken.text += token.text;
@@ -1749,7 +1796,7 @@ var Lexer_1 = class Lexer {
1749
1796
  // reflink, nolink
1750
1797
  if (token = this.tokenizer.reflink(src, this.tokens.links)) {
1751
1798
  src = src.substring(token.raw.length);
1752
- const lastToken = tokens[tokens.length - 1];
1799
+ lastToken = tokens[tokens.length - 1];
1753
1800
  if (token.type === 'link') {
1754
1801
  token.tokens = this.inlineTokens(token.text, [], true, inRawBlock);
1755
1802
  tokens.push(token);
@@ -1807,7 +1854,21 @@ var Lexer_1 = class Lexer {
1807
1854
  }
1808
1855
 
1809
1856
  // text
1810
- if (token = this.tokenizer.inlineText(src, inRawBlock, smartypants)) {
1857
+ // prevent inlineText consuming extensions by clipping 'src' to extension start
1858
+ cutSrc = src;
1859
+ if (this.options.extensions?.startInline) {
1860
+ let startIndex = Infinity;
1861
+ const tempSrc = src.slice(1);
1862
+ let tempStart;
1863
+ this.options.extensions.startInline.forEach(function(getStartIndex) {
1864
+ tempStart = getStartIndex.call(this, tempSrc);
1865
+ if (typeof tempStart === 'number' && tempStart >= 0) { startIndex = Math.min(startIndex, tempStart); }
1866
+ });
1867
+ if (startIndex < Infinity && startIndex >= 0) {
1868
+ cutSrc = src.substring(0, startIndex + 1);
1869
+ }
1870
+ }
1871
+ if (token = this.tokenizer.inlineText(cutSrc, inRawBlock, smartypants)) {
1811
1872
  src = src.substring(token.raw.length);
1812
1873
  if (token.raw.slice(-1) !== '_') { // Track prevChar before string of ____ started
1813
1874
  prevChar = token.raw.slice(-1);
@@ -2159,11 +2220,22 @@ var Parser_1 = class Parser {
2159
2220
  item,
2160
2221
  checked,
2161
2222
  task,
2162
- checkbox;
2223
+ checkbox,
2224
+ ret;
2163
2225
 
2164
2226
  const l = tokens.length;
2165
2227
  for (i = 0; i < l; i++) {
2166
2228
  token = tokens[i];
2229
+
2230
+ // Run any renderer extensions
2231
+ if (this.options.extensions?.renderers?.[token.type]) {
2232
+ ret = this.options.extensions.renderers[token.type].call(this, token);
2233
+ if (ret !== false || !['space', 'hr', 'heading', 'code', 'table', 'blockquote', 'list', 'html', 'paragraph', 'text'].includes(token.type)) {
2234
+ out += ret || '';
2235
+ continue;
2236
+ }
2237
+ }
2238
+
2167
2239
  switch (token.type) {
2168
2240
  case 'space': {
2169
2241
  continue;
@@ -2281,6 +2353,7 @@ var Parser_1 = class Parser {
2281
2353
  out += top ? this.renderer.paragraph(body) : body;
2282
2354
  continue;
2283
2355
  }
2356
+
2284
2357
  default: {
2285
2358
  const errMsg = 'Token with "' + token.type + '" type was not found.';
2286
2359
  if (this.options.silent) {
@@ -2303,11 +2376,22 @@ var Parser_1 = class Parser {
2303
2376
  renderer = renderer || this.renderer;
2304
2377
  let out = '',
2305
2378
  i,
2306
- token;
2379
+ token,
2380
+ ret;
2307
2381
 
2308
2382
  const l = tokens.length;
2309
2383
  for (i = 0; i < l; i++) {
2310
2384
  token = tokens[i];
2385
+
2386
+ // Run any renderer extensions
2387
+ if (this.options.extensions?.renderers?.[token.type]) {
2388
+ ret = this.options.extensions.renderers[token.type].call(this, token);
2389
+ if (ret !== false || !['escape', 'html', 'link', 'image', 'strong', 'em', 'codespan', 'br', 'del', 'text'].includes(token.type)) {
2390
+ out += ret || '';
2391
+ continue;
2392
+ }
2393
+ }
2394
+
2311
2395
  switch (token.type) {
2312
2396
  case 'escape': {
2313
2397
  out += renderer.text(token.text);
@@ -2507,46 +2591,114 @@ marked.defaults = defaults;
2507
2591
  * Use Extension
2508
2592
  */
2509
2593
 
2510
- marked.use = function(extension) {
2511
- const opts = merge({}, extension);
2512
- if (extension.renderer) {
2513
- const renderer = marked.defaults.renderer || new Renderer();
2514
- for (const prop in extension.renderer) {
2515
- const prevRenderer = renderer[prop];
2516
- renderer[prop] = (...args) => {
2517
- let ret = extension.renderer[prop].apply(renderer, args);
2518
- if (ret === false) {
2519
- ret = prevRenderer.apply(renderer, args);
2520
- }
2521
- return ret;
2522
- };
2594
+ marked.use = function(...args) {
2595
+ const opts = merge({}, ...args);
2596
+ const extensions = marked.defaults.extensions || { renderers: {}, childTokens: {} };
2597
+ let hasExtensions;
2598
+
2599
+ args.forEach((pack) => {
2600
+ // ==-- Parse "addon" extensions --== //
2601
+ if (pack.extensions) {
2602
+ hasExtensions = true;
2603
+ pack.extensions.forEach((ext) => {
2604
+ if (!ext.name) {
2605
+ throw new Error('extension name required');
2606
+ }
2607
+ if (ext.renderer) { // Renderer extensions
2608
+ const prevRenderer = extensions.renderers?.[ext.name];
2609
+ if (prevRenderer) {
2610
+ // Replace extension with func to run new extension but fall back if false
2611
+ extensions.renderers[ext.name] = function(...args) {
2612
+ let ret = ext.renderer.apply(this, args);
2613
+ if (ret === false) {
2614
+ ret = prevRenderer.apply(this, args);
2615
+ }
2616
+ return ret;
2617
+ };
2618
+ } else {
2619
+ extensions.renderers[ext.name] = ext.renderer;
2620
+ }
2621
+ }
2622
+ if (ext.tokenizer) { // Tokenizer Extensions
2623
+ if (!ext.level || (ext.level !== 'block' && ext.level !== 'inline')) {
2624
+ throw new Error("extension level must be 'block' or 'inline'");
2625
+ }
2626
+ if (extensions[ext.level]) {
2627
+ extensions[ext.level].unshift(ext.tokenizer);
2628
+ } else {
2629
+ extensions[ext.level] = [ext.tokenizer];
2630
+ }
2631
+ if (ext.start) { // Function to check for start of token
2632
+ if (ext.level === 'block') {
2633
+ if (extensions.startBlock) {
2634
+ extensions.startBlock.push(ext.start);
2635
+ } else {
2636
+ extensions.startBlock = [ext.start];
2637
+ }
2638
+ } else if (ext.level === 'inline') {
2639
+ if (extensions.startInline) {
2640
+ extensions.startInline.push(ext.start);
2641
+ } else {
2642
+ extensions.startInline = [ext.start];
2643
+ }
2644
+ }
2645
+ }
2646
+ }
2647
+ if (ext.childTokens) { // Child tokens to be visited by walkTokens
2648
+ extensions.childTokens[ext.name] = ext.childTokens;
2649
+ }
2650
+ });
2523
2651
  }
2524
- opts.renderer = renderer;
2525
- }
2526
- if (extension.tokenizer) {
2527
- const tokenizer = marked.defaults.tokenizer || new Tokenizer();
2528
- for (const prop in extension.tokenizer) {
2529
- const prevTokenizer = tokenizer[prop];
2530
- tokenizer[prop] = (...args) => {
2531
- let ret = extension.tokenizer[prop].apply(tokenizer, args);
2532
- if (ret === false) {
2533
- ret = prevTokenizer.apply(tokenizer, args);
2652
+
2653
+ // ==-- Parse "overwrite" extensions --== //
2654
+ if (pack.renderer) {
2655
+ const renderer = marked.defaults.renderer || new Renderer();
2656
+ for (const prop in pack.renderer) {
2657
+ const prevRenderer = renderer[prop];
2658
+ // Replace renderer with func to run extension, but fall back if false
2659
+ renderer[prop] = (...args) => {
2660
+ let ret = pack.renderer[prop].apply(renderer, args);
2661
+ if (ret === false) {
2662
+ ret = prevRenderer.apply(renderer, args);
2663
+ }
2664
+ return ret;
2665
+ };
2666
+ }
2667
+ opts.renderer = renderer;
2668
+ }
2669
+ if (pack.tokenizer) {
2670
+ const tokenizer = marked.defaults.tokenizer || new Tokenizer();
2671
+ for (const prop in pack.tokenizer) {
2672
+ const prevTokenizer = tokenizer[prop];
2673
+ // Replace tokenizer with func to run extension, but fall back if false
2674
+ tokenizer[prop] = (...args) => {
2675
+ let ret = pack.tokenizer[prop].apply(tokenizer, args);
2676
+ if (ret === false) {
2677
+ ret = prevTokenizer.apply(tokenizer, args);
2678
+ }
2679
+ return ret;
2680
+ };
2681
+ }
2682
+ opts.tokenizer = tokenizer;
2683
+ }
2684
+
2685
+ // ==-- Parse WalkTokens extensions --== //
2686
+ if (pack.walkTokens) {
2687
+ const walkTokens = marked.defaults.walkTokens;
2688
+ opts.walkTokens = (token) => {
2689
+ pack.walkTokens.call(this, token);
2690
+ if (walkTokens) {
2691
+ walkTokens(token);
2534
2692
  }
2535
- return ret;
2536
2693
  };
2537
2694
  }
2538
- opts.tokenizer = tokenizer;
2539
- }
2540
- if (extension.walkTokens) {
2541
- const walkTokens = marked.defaults.walkTokens;
2542
- opts.walkTokens = (token) => {
2543
- extension.walkTokens(token);
2544
- if (walkTokens) {
2545
- walkTokens(token);
2546
- }
2547
- };
2548
- }
2549
- marked.setOptions(opts);
2695
+
2696
+ if (hasExtensions) {
2697
+ opts.extensions = extensions;
2698
+ }
2699
+
2700
+ marked.setOptions(opts);
2701
+ });
2550
2702
  };
2551
2703
 
2552
2704
  /**
@@ -2573,7 +2725,12 @@ marked.walkTokens = function(tokens, callback) {
2573
2725
  break;
2574
2726
  }
2575
2727
  default: {
2576
- if (token.tokens) {
2728
+ if (marked.defaults?.extensions?.childTokens?.[token.type]) { // Walk any extensions
2729
+ marked.defaults?.extensions.childTokens[token.type].forEach(function(childTokens) {
2730
+ marked.walkTokens(token[childTokens], callback);
2731
+ });
2732
+ }
2733
+ if (token.tokens && !marked.defaults?.extensions?.childTokens[token.type]) {
2577
2734
  marked.walkTokens(token.tokens, callback);
2578
2735
  }
2579
2736
  }