burp_cms 1.3.10 → 1.3.11

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