~codygarver/+junk/gnome-builder

« back to all changes in this revision

Viewing changes to data/markdown/marked.js

  • Committer: Cody Garver
  • Date: 2015-11-21 00:50:38 UTC
  • Revision ID: cody@elementary.io-20151121005038-8wygis63zt0ljqlz
Import https://github.com/chergert/gnome-builder 06e3158922a02a27f4abca250d70aa7b2970e06a

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * marked - a markdown parser
 
3
 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
 
4
 * https://github.com/chjj/marked
 
5
 */
 
6
 
 
7
;(function() {
 
8
 
 
9
/**
 
10
 * Block-Level Grammar
 
11
 */
 
12
 
 
13
var block = {
 
14
  newline: /^\n+/,
 
15
  code: /^( {4}[^\n]+\n*)+/,
 
16
  fences: noop,
 
17
  hr: /^( *[-*_]){3,} *(?:\n+|$)/,
 
18
  heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
 
19
  nptable: noop,
 
20
  lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
 
21
  blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
 
22
  list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
 
23
  html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
 
24
  def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
 
25
  table: noop,
 
26
  paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
 
27
  text: /^[^\n]+/
 
28
};
 
29
 
 
30
block.bullet = /(?:[*+-]|\d+\.)/;
 
31
block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
 
32
block.item = replace(block.item, 'gm')
 
33
  (/bull/g, block.bullet)
 
34
  ();
 
35
 
 
36
block.list = replace(block.list)
 
37
  (/bull/g, block.bullet)
 
38
  ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
 
39
  ('def', '\\n+(?=' + block.def.source + ')')
 
40
  ();
 
41
 
 
42
block.blockquote = replace(block.blockquote)
 
43
  ('def', block.def)
 
44
  ();
 
45
 
 
46
block._tag = '(?!(?:'
 
47
  + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
 
48
  + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
 
49
  + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
 
50
 
 
51
block.html = replace(block.html)
 
52
  ('comment', /<!--[\s\S]*?-->/)
 
53
  ('closed', /<(tag)[\s\S]+?<\/\1>/)
 
54
  ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
 
55
  (/tag/g, block._tag)
 
56
  ();
 
57
 
 
58
block.paragraph = replace(block.paragraph)
 
59
  ('hr', block.hr)
 
60
  ('heading', block.heading)
 
61
  ('lheading', block.lheading)
 
62
  ('blockquote', block.blockquote)
 
63
  ('tag', '<' + block._tag)
 
64
  ('def', block.def)
 
65
  ();
 
66
 
 
67
/**
 
68
 * Normal Block Grammar
 
69
 */
 
70
 
 
71
block.normal = merge({}, block);
 
72
 
 
73
/**
 
74
 * GFM Block Grammar
 
75
 */
 
76
 
 
77
block.gfm = merge({}, block.normal, {
 
78
  fences: /^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,
 
79
  paragraph: /^/
 
80
});
 
81
 
 
82
block.gfm.paragraph = replace(block.paragraph)
 
83
  ('(?!', '(?!'
 
84
    + block.gfm.fences.source.replace('\\1', '\\2') + '|'
 
85
    + block.list.source.replace('\\1', '\\3') + '|')
 
86
  ();
 
87
 
 
88
/**
 
89
 * GFM + Tables Block Grammar
 
90
 */
 
91
 
 
92
block.tables = merge({}, block.gfm, {
 
93
  nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
 
94
  table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
 
95
});
 
96
 
 
97
/**
 
98
 * Block Lexer
 
99
 */
 
100
 
 
101
function Lexer(options) {
 
102
  this.tokens = [];
 
103
  this.tokens.links = {};
 
104
  this.options = options || marked.defaults;
 
105
  this.rules = block.normal;
 
106
 
 
107
  if (this.options.gfm) {
 
108
    if (this.options.tables) {
 
109
      this.rules = block.tables;
 
110
    } else {
 
111
      this.rules = block.gfm;
 
112
    }
 
113
  }
 
114
}
 
115
 
 
116
/**
 
117
 * Expose Block Rules
 
118
 */
 
119
 
 
120
Lexer.rules = block;
 
121
 
 
122
/**
 
123
 * Static Lex Method
 
124
 */
 
125
 
 
126
Lexer.lex = function(src, options) {
 
127
  var lexer = new Lexer(options);
 
128
  return lexer.lex(src);
 
129
};
 
130
 
 
131
/**
 
132
 * Preprocessing
 
133
 */
 
134
 
 
135
Lexer.prototype.lex = function(src) {
 
136
  src = src
 
137
    .replace(/\r\n|\r/g, '\n')
 
138
    .replace(/\t/g, '    ')
 
139
    .replace(/\u00a0/g, ' ')
 
140
    .replace(/\u2424/g, '\n');
 
141
 
 
142
  return this.token(src, true);
 
143
};
 
144
 
 
145
/**
 
146
 * Lexing
 
147
 */
 
148
 
 
149
Lexer.prototype.token = function(src, top, bq) {
 
150
  var src = src.replace(/^ +$/gm, '')
 
151
    , next
 
152
    , loose
 
153
    , cap
 
154
    , bull
 
155
    , b
 
156
    , item
 
157
    , space
 
158
    , i
 
159
    , l;
 
160
 
 
161
  while (src) {
 
162
    // newline
 
163
    if (cap = this.rules.newline.exec(src)) {
 
164
      src = src.substring(cap[0].length);
 
165
      if (cap[0].length > 1) {
 
166
        this.tokens.push({
 
167
          type: 'space'
 
168
        });
 
169
      }
 
170
    }
 
171
 
 
172
    // code
 
173
    if (cap = this.rules.code.exec(src)) {
 
174
      src = src.substring(cap[0].length);
 
175
      cap = cap[0].replace(/^ {4}/gm, '');
 
176
      this.tokens.push({
 
177
        type: 'code',
 
178
        text: !this.options.pedantic
 
179
          ? cap.replace(/\n+$/, '')
 
180
          : cap
 
181
      });
 
182
      continue;
 
183
    }
 
184
 
 
185
    // fences (gfm)
 
186
    if (cap = this.rules.fences.exec(src)) {
 
187
      src = src.substring(cap[0].length);
 
188
      this.tokens.push({
 
189
        type: 'code',
 
190
        lang: cap[2],
 
191
        text: cap[3]
 
192
      });
 
193
      continue;
 
194
    }
 
195
 
 
196
    // heading
 
197
    if (cap = this.rules.heading.exec(src)) {
 
198
      src = src.substring(cap[0].length);
 
199
      this.tokens.push({
 
200
        type: 'heading',
 
201
        depth: cap[1].length,
 
202
        text: cap[2]
 
203
      });
 
204
      continue;
 
205
    }
 
206
 
 
207
    // table no leading pipe (gfm)
 
208
    if (top && (cap = this.rules.nptable.exec(src))) {
 
209
      src = src.substring(cap[0].length);
 
210
 
 
211
      item = {
 
212
        type: 'table',
 
213
        header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
 
214
        align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
 
215
        cells: cap[3].replace(/\n$/, '').split('\n')
 
216
      };
 
217
 
 
218
      for (i = 0; i < item.align.length; i++) {
 
219
        if (/^ *-+: *$/.test(item.align[i])) {
 
220
          item.align[i] = 'right';
 
221
        } else if (/^ *:-+: *$/.test(item.align[i])) {
 
222
          item.align[i] = 'center';
 
223
        } else if (/^ *:-+ *$/.test(item.align[i])) {
 
224
          item.align[i] = 'left';
 
225
        } else {
 
226
          item.align[i] = null;
 
227
        }
 
228
      }
 
229
 
 
230
      for (i = 0; i < item.cells.length; i++) {
 
231
        item.cells[i] = item.cells[i].split(/ *\| */);
 
232
      }
 
233
 
 
234
      this.tokens.push(item);
 
235
 
 
236
      continue;
 
237
    }
 
238
 
 
239
    // lheading
 
240
    if (cap = this.rules.lheading.exec(src)) {
 
241
      src = src.substring(cap[0].length);
 
242
      this.tokens.push({
 
243
        type: 'heading',
 
244
        depth: cap[2] === '=' ? 1 : 2,
 
245
        text: cap[1]
 
246
      });
 
247
      continue;
 
248
    }
 
249
 
 
250
    // hr
 
251
    if (cap = this.rules.hr.exec(src)) {
 
252
      src = src.substring(cap[0].length);
 
253
      this.tokens.push({
 
254
        type: 'hr'
 
255
      });
 
256
      continue;
 
257
    }
 
258
 
 
259
    // blockquote
 
260
    if (cap = this.rules.blockquote.exec(src)) {
 
261
      src = src.substring(cap[0].length);
 
262
 
 
263
      this.tokens.push({
 
264
        type: 'blockquote_start'
 
265
      });
 
266
 
 
267
      cap = cap[0].replace(/^ *> ?/gm, '');
 
268
 
 
269
      // Pass `top` to keep the current
 
270
      // "toplevel" state. This is exactly
 
271
      // how markdown.pl works.
 
272
      this.token(cap, top, true);
 
273
 
 
274
      this.tokens.push({
 
275
        type: 'blockquote_end'
 
276
      });
 
277
 
 
278
      continue;
 
279
    }
 
280
 
 
281
    // list
 
282
    if (cap = this.rules.list.exec(src)) {
 
283
      src = src.substring(cap[0].length);
 
284
      bull = cap[2];
 
285
 
 
286
      this.tokens.push({
 
287
        type: 'list_start',
 
288
        ordered: bull.length > 1
 
289
      });
 
290
 
 
291
      // Get each top-level item.
 
292
      cap = cap[0].match(this.rules.item);
 
293
 
 
294
      next = false;
 
295
      l = cap.length;
 
296
      i = 0;
 
297
 
 
298
      for (; i < l; i++) {
 
299
        item = cap[i];
 
300
 
 
301
        // Remove the list item's bullet
 
302
        // so it is seen as the next token.
 
303
        space = item.length;
 
304
        item = item.replace(/^ *([*+-]|\d+\.) +/, '');
 
305
 
 
306
        // Outdent whatever the
 
307
        // list item contains. Hacky.
 
308
        if (~item.indexOf('\n ')) {
 
309
          space -= item.length;
 
310
          item = !this.options.pedantic
 
311
            ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
 
312
            : item.replace(/^ {1,4}/gm, '');
 
313
        }
 
314
 
 
315
        // Determine whether the next list item belongs here.
 
316
        // Backpedal if it does not belong in this list.
 
317
        if (this.options.smartLists && i !== l - 1) {
 
318
          b = block.bullet.exec(cap[i + 1])[0];
 
319
          if (bull !== b && !(bull.length > 1 && b.length > 1)) {
 
320
            src = cap.slice(i + 1).join('\n') + src;
 
321
            i = l - 1;
 
322
          }
 
323
        }
 
324
 
 
325
        // Determine whether item is loose or not.
 
326
        // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
 
327
        // for discount behavior.
 
328
        loose = next || /\n\n(?!\s*$)/.test(item);
 
329
        if (i !== l - 1) {
 
330
          next = item.charAt(item.length - 1) === '\n';
 
331
          if (!loose) loose = next;
 
332
        }
 
333
 
 
334
        this.tokens.push({
 
335
          type: loose
 
336
            ? 'loose_item_start'
 
337
            : 'list_item_start'
 
338
        });
 
339
 
 
340
        // Recurse.
 
341
        this.token(item, false, bq);
 
342
 
 
343
        this.tokens.push({
 
344
          type: 'list_item_end'
 
345
        });
 
346
      }
 
347
 
 
348
      this.tokens.push({
 
349
        type: 'list_end'
 
350
      });
 
351
 
 
352
      continue;
 
353
    }
 
354
 
 
355
    // html
 
356
    if (cap = this.rules.html.exec(src)) {
 
357
      src = src.substring(cap[0].length);
 
358
      this.tokens.push({
 
359
        type: this.options.sanitize
 
360
          ? 'paragraph'
 
361
          : 'html',
 
362
        pre: cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style',
 
363
        text: cap[0]
 
364
      });
 
365
      continue;
 
366
    }
 
367
 
 
368
    // def
 
369
    if ((!bq && top) && (cap = this.rules.def.exec(src))) {
 
370
      src = src.substring(cap[0].length);
 
371
      this.tokens.links[cap[1].toLowerCase()] = {
 
372
        href: cap[2],
 
373
        title: cap[3]
 
374
      };
 
375
      continue;
 
376
    }
 
377
 
 
378
    // table (gfm)
 
379
    if (top && (cap = this.rules.table.exec(src))) {
 
380
      src = src.substring(cap[0].length);
 
381
 
 
382
      item = {
 
383
        type: 'table',
 
384
        header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
 
385
        align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
 
386
        cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
 
387
      };
 
388
 
 
389
      for (i = 0; i < item.align.length; i++) {
 
390
        if (/^ *-+: *$/.test(item.align[i])) {
 
391
          item.align[i] = 'right';
 
392
        } else if (/^ *:-+: *$/.test(item.align[i])) {
 
393
          item.align[i] = 'center';
 
394
        } else if (/^ *:-+ *$/.test(item.align[i])) {
 
395
          item.align[i] = 'left';
 
396
        } else {
 
397
          item.align[i] = null;
 
398
        }
 
399
      }
 
400
 
 
401
      for (i = 0; i < item.cells.length; i++) {
 
402
        item.cells[i] = item.cells[i]
 
403
          .replace(/^ *\| *| *\| *$/g, '')
 
404
          .split(/ *\| */);
 
405
      }
 
406
 
 
407
      this.tokens.push(item);
 
408
 
 
409
      continue;
 
410
    }
 
411
 
 
412
    // top-level paragraph
 
413
    if (top && (cap = this.rules.paragraph.exec(src))) {
 
414
      src = src.substring(cap[0].length);
 
415
      this.tokens.push({
 
416
        type: 'paragraph',
 
417
        text: cap[1].charAt(cap[1].length - 1) === '\n'
 
418
          ? cap[1].slice(0, -1)
 
419
          : cap[1]
 
420
      });
 
421
      continue;
 
422
    }
 
423
 
 
424
    // text
 
425
    if (cap = this.rules.text.exec(src)) {
 
426
      // Top-level should never reach here.
 
427
      src = src.substring(cap[0].length);
 
428
      this.tokens.push({
 
429
        type: 'text',
 
430
        text: cap[0]
 
431
      });
 
432
      continue;
 
433
    }
 
434
 
 
435
    if (src) {
 
436
      throw new
 
437
        Error('Infinite loop on byte: ' + src.charCodeAt(0));
 
438
    }
 
439
  }
 
440
 
 
441
  return this.tokens;
 
442
};
 
443
 
 
444
/**
 
445
 * Inline-Level Grammar
 
446
 */
 
447
 
 
448
var inline = {
 
449
  escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
 
450
  autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
 
451
  url: noop,
 
452
  tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
 
453
  link: /^!?\[(inside)\]\(href\)/,
 
454
  reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
 
455
  nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
 
456
  strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
 
457
  em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
 
458
  code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
 
459
  br: /^ {2,}\n(?!\s*$)/,
 
460
  del: noop,
 
461
  text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
 
462
};
 
463
 
 
464
inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
 
465
inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
 
466
 
 
467
inline.link = replace(inline.link)
 
468
  ('inside', inline._inside)
 
469
  ('href', inline._href)
 
470
  ();
 
471
 
 
472
inline.reflink = replace(inline.reflink)
 
473
  ('inside', inline._inside)
 
474
  ();
 
475
 
 
476
/**
 
477
 * Normal Inline Grammar
 
478
 */
 
479
 
 
480
inline.normal = merge({}, inline);
 
481
 
 
482
/**
 
483
 * Pedantic Inline Grammar
 
484
 */
 
485
 
 
486
inline.pedantic = merge({}, inline.normal, {
 
487
  strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
 
488
  em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
 
489
});
 
490
 
 
491
/**
 
492
 * GFM Inline Grammar
 
493
 */
 
494
 
 
495
inline.gfm = merge({}, inline.normal, {
 
496
  escape: replace(inline.escape)('])', '~|])')(),
 
497
  url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
 
498
  del: /^~~(?=\S)([\s\S]*?\S)~~/,
 
499
  text: replace(inline.text)
 
500
    (']|', '~]|')
 
501
    ('|', '|https?://|')
 
502
    ()
 
503
});
 
504
 
 
505
/**
 
506
 * GFM + Line Breaks Inline Grammar
 
507
 */
 
508
 
 
509
inline.breaks = merge({}, inline.gfm, {
 
510
  br: replace(inline.br)('{2,}', '*')(),
 
511
  text: replace(inline.gfm.text)('{2,}', '*')()
 
512
});
 
513
 
 
514
/**
 
515
 * Inline Lexer & Compiler
 
516
 */
 
517
 
 
518
function InlineLexer(links, options) {
 
519
  this.options = options || marked.defaults;
 
520
  this.links = links;
 
521
  this.rules = inline.normal;
 
522
  this.renderer = this.options.renderer || new Renderer;
 
523
  this.renderer.options = this.options;
 
524
 
 
525
  if (!this.links) {
 
526
    throw new
 
527
      Error('Tokens array requires a `links` property.');
 
528
  }
 
529
 
 
530
  if (this.options.gfm) {
 
531
    if (this.options.breaks) {
 
532
      this.rules = inline.breaks;
 
533
    } else {
 
534
      this.rules = inline.gfm;
 
535
    }
 
536
  } else if (this.options.pedantic) {
 
537
    this.rules = inline.pedantic;
 
538
  }
 
539
}
 
540
 
 
541
/**
 
542
 * Expose Inline Rules
 
543
 */
 
544
 
 
545
InlineLexer.rules = inline;
 
546
 
 
547
/**
 
548
 * Static Lexing/Compiling Method
 
549
 */
 
550
 
 
551
InlineLexer.output = function(src, links, options) {
 
552
  var inline = new InlineLexer(links, options);
 
553
  return inline.output(src);
 
554
};
 
555
 
 
556
/**
 
557
 * Lexing/Compiling
 
558
 */
 
559
 
 
560
InlineLexer.prototype.output = function(src) {
 
561
  var out = ''
 
562
    , link
 
563
    , text
 
564
    , href
 
565
    , cap;
 
566
 
 
567
  while (src) {
 
568
    // escape
 
569
    if (cap = this.rules.escape.exec(src)) {
 
570
      src = src.substring(cap[0].length);
 
571
      out += cap[1];
 
572
      continue;
 
573
    }
 
574
 
 
575
    // autolink
 
576
    if (cap = this.rules.autolink.exec(src)) {
 
577
      src = src.substring(cap[0].length);
 
578
      if (cap[2] === '@') {
 
579
        text = cap[1].charAt(6) === ':'
 
580
          ? this.mangle(cap[1].substring(7))
 
581
          : this.mangle(cap[1]);
 
582
        href = this.mangle('mailto:') + text;
 
583
      } else {
 
584
        text = escape(cap[1]);
 
585
        href = text;
 
586
      }
 
587
      out += this.renderer.link(href, null, text);
 
588
      continue;
 
589
    }
 
590
 
 
591
    // url (gfm)
 
592
    if (!this.inLink && (cap = this.rules.url.exec(src))) {
 
593
      src = src.substring(cap[0].length);
 
594
      text = escape(cap[1]);
 
595
      href = text;
 
596
      out += this.renderer.link(href, null, text);
 
597
      continue;
 
598
    }
 
599
 
 
600
    // tag
 
601
    if (cap = this.rules.tag.exec(src)) {
 
602
      if (!this.inLink && /^<a /i.test(cap[0])) {
 
603
        this.inLink = true;
 
604
      } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
 
605
        this.inLink = false;
 
606
      }
 
607
      src = src.substring(cap[0].length);
 
608
      out += this.options.sanitize
 
609
        ? escape(cap[0])
 
610
        : cap[0];
 
611
      continue;
 
612
    }
 
613
 
 
614
    // link
 
615
    if (cap = this.rules.link.exec(src)) {
 
616
      src = src.substring(cap[0].length);
 
617
      this.inLink = true;
 
618
      out += this.outputLink(cap, {
 
619
        href: cap[2],
 
620
        title: cap[3]
 
621
      });
 
622
      this.inLink = false;
 
623
      continue;
 
624
    }
 
625
 
 
626
    // reflink, nolink
 
627
    if ((cap = this.rules.reflink.exec(src))
 
628
        || (cap = this.rules.nolink.exec(src))) {
 
629
      src = src.substring(cap[0].length);
 
630
      link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
 
631
      link = this.links[link.toLowerCase()];
 
632
      if (!link || !link.href) {
 
633
        out += cap[0].charAt(0);
 
634
        src = cap[0].substring(1) + src;
 
635
        continue;
 
636
      }
 
637
      this.inLink = true;
 
638
      out += this.outputLink(cap, link);
 
639
      this.inLink = false;
 
640
      continue;
 
641
    }
 
642
 
 
643
    // strong
 
644
    if (cap = this.rules.strong.exec(src)) {
 
645
      src = src.substring(cap[0].length);
 
646
      out += this.renderer.strong(this.output(cap[2] || cap[1]));
 
647
      continue;
 
648
    }
 
649
 
 
650
    // em
 
651
    if (cap = this.rules.em.exec(src)) {
 
652
      src = src.substring(cap[0].length);
 
653
      out += this.renderer.em(this.output(cap[2] || cap[1]));
 
654
      continue;
 
655
    }
 
656
 
 
657
    // code
 
658
    if (cap = this.rules.code.exec(src)) {
 
659
      src = src.substring(cap[0].length);
 
660
      out += this.renderer.codespan(escape(cap[2], true));
 
661
      continue;
 
662
    }
 
663
 
 
664
    // br
 
665
    if (cap = this.rules.br.exec(src)) {
 
666
      src = src.substring(cap[0].length);
 
667
      out += this.renderer.br();
 
668
      continue;
 
669
    }
 
670
 
 
671
    // del (gfm)
 
672
    if (cap = this.rules.del.exec(src)) {
 
673
      src = src.substring(cap[0].length);
 
674
      out += this.renderer.del(this.output(cap[1]));
 
675
      continue;
 
676
    }
 
677
 
 
678
    // text
 
679
    if (cap = this.rules.text.exec(src)) {
 
680
      src = src.substring(cap[0].length);
 
681
      out += escape(this.smartypants(cap[0]));
 
682
      continue;
 
683
    }
 
684
 
 
685
    if (src) {
 
686
      throw new
 
687
        Error('Infinite loop on byte: ' + src.charCodeAt(0));
 
688
    }
 
689
  }
 
690
 
 
691
  return out;
 
692
};
 
693
 
 
694
/**
 
695
 * Compile Link
 
696
 */
 
697
 
 
698
InlineLexer.prototype.outputLink = function(cap, link) {
 
699
  var href = escape(link.href)
 
700
    , title = link.title ? escape(link.title) : null;
 
701
 
 
702
  return cap[0].charAt(0) !== '!'
 
703
    ? this.renderer.link(href, title, this.output(cap[1]))
 
704
    : this.renderer.image(href, title, escape(cap[1]));
 
705
};
 
706
 
 
707
/**
 
708
 * Smartypants Transformations
 
709
 */
 
710
 
 
711
InlineLexer.prototype.smartypants = function(text) {
 
712
  if (!this.options.smartypants) return text;
 
713
  return text
 
714
    // em-dashes
 
715
    .replace(/--/g, '\u2014')
 
716
    // opening singles
 
717
    .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
 
718
    // closing singles & apostrophes
 
719
    .replace(/'/g, '\u2019')
 
720
    // opening doubles
 
721
    .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
 
722
    // closing doubles
 
723
    .replace(/"/g, '\u201d')
 
724
    // ellipses
 
725
    .replace(/\.{3}/g, '\u2026');
 
726
};
 
727
 
 
728
/**
 
729
 * Mangle Links
 
730
 */
 
731
 
 
732
InlineLexer.prototype.mangle = function(text) {
 
733
  var out = ''
 
734
    , l = text.length
 
735
    , i = 0
 
736
    , ch;
 
737
 
 
738
  for (; i < l; i++) {
 
739
    ch = text.charCodeAt(i);
 
740
    if (Math.random() > 0.5) {
 
741
      ch = 'x' + ch.toString(16);
 
742
    }
 
743
    out += '&#' + ch + ';';
 
744
  }
 
745
 
 
746
  return out;
 
747
};
 
748
 
 
749
/**
 
750
 * Renderer
 
751
 */
 
752
 
 
753
function Renderer(options) {
 
754
  this.options = options || {};
 
755
}
 
756
 
 
757
Renderer.prototype.code = function(code, lang, escaped) {
 
758
  if (this.options.highlight) {
 
759
    var out = this.options.highlight(code, lang);
 
760
    if (out != null && out !== code) {
 
761
      escaped = true;
 
762
      code = out;
 
763
    }
 
764
  }
 
765
 
 
766
  if (!lang) {
 
767
    return '<pre><code>'
 
768
      + (escaped ? code : escape(code, true))
 
769
      + '\n</code></pre>';
 
770
  }
 
771
 
 
772
  return '<pre><code class="'
 
773
    + this.options.langPrefix
 
774
    + escape(lang, true)
 
775
    + '">'
 
776
    + (escaped ? code : escape(code, true))
 
777
    + '\n</code></pre>\n';
 
778
};
 
779
 
 
780
Renderer.prototype.blockquote = function(quote) {
 
781
  return '<blockquote>\n' + quote + '</blockquote>\n';
 
782
};
 
783
 
 
784
Renderer.prototype.html = function(html) {
 
785
  return html;
 
786
};
 
787
 
 
788
Renderer.prototype.heading = function(text, level, raw) {
 
789
  return '<h'
 
790
    + level
 
791
    + ' id="'
 
792
    + this.options.headerPrefix
 
793
    + raw.toLowerCase().replace(/[^\w]+/g, '-')
 
794
    + '">'
 
795
    + text
 
796
    + '</h'
 
797
    + level
 
798
    + '>\n';
 
799
};
 
800
 
 
801
Renderer.prototype.hr = function() {
 
802
  return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
 
803
};
 
804
 
 
805
Renderer.prototype.list = function(body, ordered) {
 
806
  var type = ordered ? 'ol' : 'ul';
 
807
  return '<' + type + '>\n' + body + '</' + type + '>\n';
 
808
};
 
809
 
 
810
Renderer.prototype.listitem = function(text) {
 
811
  return '<li>' + text + '</li>\n';
 
812
};
 
813
 
 
814
Renderer.prototype.paragraph = function(text) {
 
815
  return '<p>' + text + '</p>\n';
 
816
};
 
817
 
 
818
Renderer.prototype.table = function(header, body) {
 
819
  return '<table>\n'
 
820
    + '<thead>\n'
 
821
    + header
 
822
    + '</thead>\n'
 
823
    + '<tbody>\n'
 
824
    + body
 
825
    + '</tbody>\n'
 
826
    + '</table>\n';
 
827
};
 
828
 
 
829
Renderer.prototype.tablerow = function(content) {
 
830
  return '<tr>\n' + content + '</tr>\n';
 
831
};
 
832
 
 
833
Renderer.prototype.tablecell = function(content, flags) {
 
834
  var type = flags.header ? 'th' : 'td';
 
835
  var tag = flags.align
 
836
    ? '<' + type + ' style="text-align:' + flags.align + '">'
 
837
    : '<' + type + '>';
 
838
  return tag + content + '</' + type + '>\n';
 
839
};
 
840
 
 
841
// span level renderer
 
842
Renderer.prototype.strong = function(text) {
 
843
  return '<strong>' + text + '</strong>';
 
844
};
 
845
 
 
846
Renderer.prototype.em = function(text) {
 
847
  return '<em>' + text + '</em>';
 
848
};
 
849
 
 
850
Renderer.prototype.codespan = function(text) {
 
851
  return '<code>' + text + '</code>';
 
852
};
 
853
 
 
854
Renderer.prototype.br = function() {
 
855
  return this.options.xhtml ? '<br/>' : '<br>';
 
856
};
 
857
 
 
858
Renderer.prototype.del = function(text) {
 
859
  return '<del>' + text + '</del>';
 
860
};
 
861
 
 
862
Renderer.prototype.link = function(href, title, text) {
 
863
  if (this.options.sanitize) {
 
864
    try {
 
865
      var prot = decodeURIComponent(unescape(href))
 
866
        .replace(/[^\w:]/g, '')
 
867
        .toLowerCase();
 
868
    } catch (e) {
 
869
      return '';
 
870
    }
 
871
    if (prot.indexOf('javascript:') === 0) {
 
872
      return '';
 
873
    }
 
874
  }
 
875
  var out = '<a href="' + href + '"';
 
876
  if (title) {
 
877
    out += ' title="' + title + '"';
 
878
  }
 
879
  out += '>' + text + '</a>';
 
880
  return out;
 
881
};
 
882
 
 
883
Renderer.prototype.image = function(href, title, text) {
 
884
  var out = '<img src="' + href + '" alt="' + text + '"';
 
885
  if (title) {
 
886
    out += ' title="' + title + '"';
 
887
  }
 
888
  out += this.options.xhtml ? '/>' : '>';
 
889
  return out;
 
890
};
 
891
 
 
892
/**
 
893
 * Parsing & Compiling
 
894
 */
 
895
 
 
896
function Parser(options) {
 
897
  this.tokens = [];
 
898
  this.token = null;
 
899
  this.options = options || marked.defaults;
 
900
  this.options.renderer = this.options.renderer || new Renderer;
 
901
  this.renderer = this.options.renderer;
 
902
  this.renderer.options = this.options;
 
903
}
 
904
 
 
905
/**
 
906
 * Static Parse Method
 
907
 */
 
908
 
 
909
Parser.parse = function(src, options, renderer) {
 
910
  var parser = new Parser(options, renderer);
 
911
  return parser.parse(src);
 
912
};
 
913
 
 
914
/**
 
915
 * Parse Loop
 
916
 */
 
917
 
 
918
Parser.prototype.parse = function(src) {
 
919
  this.inline = new InlineLexer(src.links, this.options, this.renderer);
 
920
  this.tokens = src.reverse();
 
921
 
 
922
  var out = '';
 
923
  while (this.next()) {
 
924
    out += this.tok();
 
925
  }
 
926
 
 
927
  return out;
 
928
};
 
929
 
 
930
/**
 
931
 * Next Token
 
932
 */
 
933
 
 
934
Parser.prototype.next = function() {
 
935
  return this.token = this.tokens.pop();
 
936
};
 
937
 
 
938
/**
 
939
 * Preview Next Token
 
940
 */
 
941
 
 
942
Parser.prototype.peek = function() {
 
943
  return this.tokens[this.tokens.length - 1] || 0;
 
944
};
 
945
 
 
946
/**
 
947
 * Parse Text Tokens
 
948
 */
 
949
 
 
950
Parser.prototype.parseText = function() {
 
951
  var body = this.token.text;
 
952
 
 
953
  while (this.peek().type === 'text') {
 
954
    body += '\n' + this.next().text;
 
955
  }
 
956
 
 
957
  return this.inline.output(body);
 
958
};
 
959
 
 
960
/**
 
961
 * Parse Current Token
 
962
 */
 
963
 
 
964
Parser.prototype.tok = function() {
 
965
  switch (this.token.type) {
 
966
    case 'space': {
 
967
      return '';
 
968
    }
 
969
    case 'hr': {
 
970
      return this.renderer.hr();
 
971
    }
 
972
    case 'heading': {
 
973
      return this.renderer.heading(
 
974
        this.inline.output(this.token.text),
 
975
        this.token.depth,
 
976
        this.token.text);
 
977
    }
 
978
    case 'code': {
 
979
      return this.renderer.code(this.token.text,
 
980
        this.token.lang,
 
981
        this.token.escaped);
 
982
    }
 
983
    case 'table': {
 
984
      var header = ''
 
985
        , body = ''
 
986
        , i
 
987
        , row
 
988
        , cell
 
989
        , flags
 
990
        , j;
 
991
 
 
992
      // header
 
993
      cell = '';
 
994
      for (i = 0; i < this.token.header.length; i++) {
 
995
        flags = { header: true, align: this.token.align[i] };
 
996
        cell += this.renderer.tablecell(
 
997
          this.inline.output(this.token.header[i]),
 
998
          { header: true, align: this.token.align[i] }
 
999
        );
 
1000
      }
 
1001
      header += this.renderer.tablerow(cell);
 
1002
 
 
1003
      for (i = 0; i < this.token.cells.length; i++) {
 
1004
        row = this.token.cells[i];
 
1005
 
 
1006
        cell = '';
 
1007
        for (j = 0; j < row.length; j++) {
 
1008
          cell += this.renderer.tablecell(
 
1009
            this.inline.output(row[j]),
 
1010
            { header: false, align: this.token.align[j] }
 
1011
          );
 
1012
        }
 
1013
 
 
1014
        body += this.renderer.tablerow(cell);
 
1015
      }
 
1016
      return this.renderer.table(header, body);
 
1017
    }
 
1018
    case 'blockquote_start': {
 
1019
      var body = '';
 
1020
 
 
1021
      while (this.next().type !== 'blockquote_end') {
 
1022
        body += this.tok();
 
1023
      }
 
1024
 
 
1025
      return this.renderer.blockquote(body);
 
1026
    }
 
1027
    case 'list_start': {
 
1028
      var body = ''
 
1029
        , ordered = this.token.ordered;
 
1030
 
 
1031
      while (this.next().type !== 'list_end') {
 
1032
        body += this.tok();
 
1033
      }
 
1034
 
 
1035
      return this.renderer.list(body, ordered);
 
1036
    }
 
1037
    case 'list_item_start': {
 
1038
      var body = '';
 
1039
 
 
1040
      while (this.next().type !== 'list_item_end') {
 
1041
        body += this.token.type === 'text'
 
1042
          ? this.parseText()
 
1043
          : this.tok();
 
1044
      }
 
1045
 
 
1046
      return this.renderer.listitem(body);
 
1047
    }
 
1048
    case 'loose_item_start': {
 
1049
      var body = '';
 
1050
 
 
1051
      while (this.next().type !== 'list_item_end') {
 
1052
        body += this.tok();
 
1053
      }
 
1054
 
 
1055
      return this.renderer.listitem(body);
 
1056
    }
 
1057
    case 'html': {
 
1058
      var html = !this.token.pre && !this.options.pedantic
 
1059
        ? this.inline.output(this.token.text)
 
1060
        : this.token.text;
 
1061
      return this.renderer.html(html);
 
1062
    }
 
1063
    case 'paragraph': {
 
1064
      return this.renderer.paragraph(this.inline.output(this.token.text));
 
1065
    }
 
1066
    case 'text': {
 
1067
      return this.renderer.paragraph(this.parseText());
 
1068
    }
 
1069
  }
 
1070
};
 
1071
 
 
1072
/**
 
1073
 * Helpers
 
1074
 */
 
1075
 
 
1076
function escape(html, encode) {
 
1077
  return html
 
1078
    .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
 
1079
    .replace(/</g, '&lt;')
 
1080
    .replace(/>/g, '&gt;')
 
1081
    .replace(/"/g, '&quot;')
 
1082
    .replace(/'/g, '&#39;');
 
1083
}
 
1084
 
 
1085
function unescape(html) {
 
1086
  return html.replace(/&([#\w]+);/g, function(_, n) {
 
1087
    n = n.toLowerCase();
 
1088
    if (n === 'colon') return ':';
 
1089
    if (n.charAt(0) === '#') {
 
1090
      return n.charAt(1) === 'x'
 
1091
        ? String.fromCharCode(parseInt(n.substring(2), 16))
 
1092
        : String.fromCharCode(+n.substring(1));
 
1093
    }
 
1094
    return '';
 
1095
  });
 
1096
}
 
1097
 
 
1098
function replace(regex, opt) {
 
1099
  regex = regex.source;
 
1100
  opt = opt || '';
 
1101
  return function self(name, val) {
 
1102
    if (!name) return new RegExp(regex, opt);
 
1103
    val = val.source || val;
 
1104
    val = val.replace(/(^|[^\[])\^/g, '$1');
 
1105
    regex = regex.replace(name, val);
 
1106
    return self;
 
1107
  };
 
1108
}
 
1109
 
 
1110
function noop() {}
 
1111
noop.exec = noop;
 
1112
 
 
1113
function merge(obj) {
 
1114
  var i = 1
 
1115
    , target
 
1116
    , key;
 
1117
 
 
1118
  for (; i < arguments.length; i++) {
 
1119
    target = arguments[i];
 
1120
    for (key in target) {
 
1121
      if (Object.prototype.hasOwnProperty.call(target, key)) {
 
1122
        obj[key] = target[key];
 
1123
      }
 
1124
    }
 
1125
  }
 
1126
 
 
1127
  return obj;
 
1128
}
 
1129
 
 
1130
 
 
1131
/**
 
1132
 * Marked
 
1133
 */
 
1134
 
 
1135
function marked(src, opt, callback) {
 
1136
  if (callback || typeof opt === 'function') {
 
1137
    if (!callback) {
 
1138
      callback = opt;
 
1139
      opt = null;
 
1140
    }
 
1141
 
 
1142
    opt = merge({}, marked.defaults, opt || {});
 
1143
 
 
1144
    var highlight = opt.highlight
 
1145
      , tokens
 
1146
      , pending
 
1147
      , i = 0;
 
1148
 
 
1149
    try {
 
1150
      tokens = Lexer.lex(src, opt)
 
1151
    } catch (e) {
 
1152
      return callback(e);
 
1153
    }
 
1154
 
 
1155
    pending = tokens.length;
 
1156
 
 
1157
    var done = function(err) {
 
1158
      if (err) {
 
1159
        opt.highlight = highlight;
 
1160
        return callback(err);
 
1161
      }
 
1162
 
 
1163
      var out;
 
1164
 
 
1165
      try {
 
1166
        out = Parser.parse(tokens, opt);
 
1167
      } catch (e) {
 
1168
        err = e;
 
1169
      }
 
1170
 
 
1171
      opt.highlight = highlight;
 
1172
 
 
1173
      return err
 
1174
        ? callback(err)
 
1175
        : callback(null, out);
 
1176
    };
 
1177
 
 
1178
    if (!highlight || highlight.length < 3) {
 
1179
      return done();
 
1180
    }
 
1181
 
 
1182
    delete opt.highlight;
 
1183
 
 
1184
    if (!pending) return done();
 
1185
 
 
1186
    for (; i < tokens.length; i++) {
 
1187
      (function(token) {
 
1188
        if (token.type !== 'code') {
 
1189
          return --pending || done();
 
1190
        }
 
1191
        return highlight(token.text, token.lang, function(err, code) {
 
1192
          if (err) return done(err);
 
1193
          if (code == null || code === token.text) {
 
1194
            return --pending || done();
 
1195
          }
 
1196
          token.text = code;
 
1197
          token.escaped = true;
 
1198
          --pending || done();
 
1199
        });
 
1200
      })(tokens[i]);
 
1201
    }
 
1202
 
 
1203
    return;
 
1204
  }
 
1205
  try {
 
1206
    if (opt) opt = merge({}, marked.defaults, opt);
 
1207
    return Parser.parse(Lexer.lex(src, opt), opt);
 
1208
  } catch (e) {
 
1209
    e.message += '\nPlease report this to https://github.com/chjj/marked.';
 
1210
    if ((opt || marked.defaults).silent) {
 
1211
      return '<p>An error occured:</p><pre>'
 
1212
        + escape(e.message + '', true)
 
1213
        + '</pre>';
 
1214
    }
 
1215
    throw e;
 
1216
  }
 
1217
}
 
1218
 
 
1219
/**
 
1220
 * Options
 
1221
 */
 
1222
 
 
1223
marked.options =
 
1224
marked.setOptions = function(opt) {
 
1225
  merge(marked.defaults, opt);
 
1226
  return marked;
 
1227
};
 
1228
 
 
1229
marked.defaults = {
 
1230
  gfm: true,
 
1231
  tables: true,
 
1232
  breaks: false,
 
1233
  pedantic: false,
 
1234
  sanitize: false,
 
1235
  smartLists: false,
 
1236
  silent: false,
 
1237
  highlight: null,
 
1238
  langPrefix: 'lang-',
 
1239
  smartypants: false,
 
1240
  headerPrefix: '',
 
1241
  renderer: new Renderer,
 
1242
  xhtml: false
 
1243
};
 
1244
 
 
1245
/**
 
1246
 * Expose
 
1247
 */
 
1248
 
 
1249
marked.Parser = Parser;
 
1250
marked.parser = Parser.parse;
 
1251
 
 
1252
marked.Renderer = Renderer;
 
1253
 
 
1254
marked.Lexer = Lexer;
 
1255
marked.lexer = Lexer.lex;
 
1256
 
 
1257
marked.InlineLexer = InlineLexer;
 
1258
marked.inlineLexer = InlineLexer.output;
 
1259
 
 
1260
marked.parse = marked;
 
1261
 
 
1262
if (typeof module !== 'undefined' && typeof exports === 'object') {
 
1263
  module.exports = marked;
 
1264
} else if (typeof define === 'function' && define.amd) {
 
1265
  define(function() { return marked; });
 
1266
} else {
 
1267
  this.marked = marked;
 
1268
}
 
1269
 
 
1270
}).call(function() {
 
1271
  return this || (typeof window !== 'undefined' ? window : global);
 
1272
}());
 
1273