marked.js 36 KB

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