marked.js

@require in Markdown Viewer Lite

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/34138/223779/markedjs.js

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