marked.js 38 KB

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