From 17d81796da405eabea098fc36965ab2b5cb96169 Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Mon, 6 Apr 2020 23:25:33 -0500 Subject: [PATCH 01/13] add tokenizer --- lib/marked.esm.js | 1132 +++++++++++++++++++++++++------------ lib/marked.js | 1182 ++++++++++++++++++++++++++------------- marked.min.js | 2 +- src/Lexer.js | 717 ++++-------------------- src/Tokenizer.js | 663 ++++++++++++++++++++++ src/defaults.js | 1 + src/marked.js | 3 + test/unit/Lexer-spec.js | 55 +- 8 files changed, 2348 insertions(+), 1407 deletions(-) create mode 100644 src/Tokenizer.js diff --git a/lib/marked.esm.js b/lib/marked.esm.js index 62d12ce289..3a2b95b78c 100644 --- a/lib/marked.esm.js +++ b/lib/marked.esm.js @@ -561,13 +561,705 @@ var rules = { }; const { defaults: defaults$1 } = defaults; -const { block: block$1, inline: inline$1 } = rules; const { rtrim: rtrim$1, splitCells: splitCells$1, escape: escape$1, findClosingBracket: findClosingBracket$1 } = helpers; +const { inline: inline$1 } = rules; + +/** + * Tokenizer + */ +var Tokenizer_1 = class Tokenizer { + constructor(options) { + this.options = options || defaults$1; + } + + space(obj) { + const cap = obj.lexer.rules.block.newline.exec(obj.src); + if (cap) { + obj.src = obj.src.substring(cap[0].length); + if (cap[0].length > 1) { + return { + type: 'space', + raw: cap[0] + }; + } + } + } + + code(obj) { + const cap = obj.lexer.rules.block.code.exec(obj.src); + if (cap) { + obj.src = obj.src.substring(cap[0].length); + const lastToken = obj.tokens[obj.tokens.length - 1]; + // An indented code block cannot interrupt a paragraph. + if (lastToken && lastToken.type === 'paragraph') { + obj.tokens.pop(); + lastToken.text += '\n' + cap[0].trimRight(); + lastToken.raw += '\n' + cap[0]; + return lastToken; + } else { + const text = cap[0].replace(/^ {4}/gm, ''); + return { + type: 'code', + raw: cap[0], + codeBlockStyle: 'indented', + text: !this.options.pedantic + ? rtrim$1(text, '\n') + : text + }; + } + } + } + + fences(obj) { + const cap = obj.lexer.rules.block.fences.exec(obj.src); + if (cap) { + obj.src = obj.src.substring(cap[0].length); + return { + type: 'code', + raw: cap[0], + lang: cap[2] ? cap[2].trim() : cap[2], + text: cap[3] || '' + }; + } + } + + heading(obj) { + const cap = obj.lexer.rules.block.heading.exec(obj.src); + if (cap) { + obj.src = obj.src.substring(cap[0].length); + return { + type: 'heading', + raw: cap[0], + depth: cap[1].length, + text: cap[2] + }; + } + } + + nptable(obj) { + const cap = obj.lexer.rules.block.nptable.exec(obj.src); + if (cap) { + const item = { + type: 'table', + header: splitCells$1(cap[1].replace(/^ *| *\| *$/g, '')), + align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), + cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [], + raw: cap[0] + }; + + if (item.header.length === item.align.length) { + obj.src = obj.src.substring(cap[0].length); + + let l = item.align.length; + let i; + for (i = 0; i < l; i++) { + if (/^ *-+: *$/.test(item.align[i])) { + item.align[i] = 'right'; + } else if (/^ *:-+: *$/.test(item.align[i])) { + item.align[i] = 'center'; + } else if (/^ *:-+ *$/.test(item.align[i])) { + item.align[i] = 'left'; + } else { + item.align[i] = null; + } + } + + l = item.cells.length; + for (i = 0; i < l; i++) { + item.cells[i] = splitCells$1(item.cells[i], item.header.length); + } + + return item; + } + } + } + + hr(obj) { + const cap = obj.lexer.rules.block.hr.exec(obj.src); + if (cap) { + obj.src = obj.src.substring(cap[0].length); + return { + type: 'hr', + raw: cap[0] + }; + } + } + + blockquote(obj) { + const cap = obj.lexer.rules.block.blockquote.exec(obj.src); + if (cap) { + obj.src = obj.src.substring(cap[0].length); + const text = cap[0].replace(/^ *> ?/gm, ''); + + return { + type: 'blockquote', + raw: cap[0], + tokens: obj.lexer.blockTokens([], text, obj.top) + }; + } + } + + list(obj) { + const cap = obj.lexer.rules.block.list.exec(obj.src); + if (cap) { + obj.src = obj.src.substring(cap[0].length); + let raw = cap[0]; + const bull = cap[2]; + const isordered = bull.length > 1; + + const list = { + type: 'list', + raw, + ordered: isordered, + start: isordered ? +bull : '', + loose: false, + items: [] + }; + + // Get each top-level item. + const itemMatch = cap[0].match(obj.lexer.rules.block.item); + + let next = false, + item, + space, + b, + addBack, + loose, + istask, + ischecked; + + const l = itemMatch.length; + for (let i = 0; i < l; i++) { + item = itemMatch[i]; + raw = item.trim(); + + // Remove the list item's bullet + // so it is seen as the next token. + space = item.length; + item = item.replace(/^ *([*+-]|\d+\.) */, ''); + + // Outdent whatever the + // list item contains. Hacky. + if (~item.indexOf('\n ')) { + space -= item.length; + item = !this.options.pedantic + ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') + : item.replace(/^ {1,4}/gm, ''); + } + + // Determine whether the next list item belongs here. + // Backpedal if it does not belong in this list. + if (i !== l - 1) { + b = obj.lexer.rules.block.bullet.exec(itemMatch[i + 1])[0]; + if (bull.length > 1 ? b.length === 1 + : (b.length > 1 || (this.options.smartLists && b !== bull))) { + addBack = itemMatch.slice(i + 1).join('\n'); + obj.src = addBack + obj.src; + list.raw = list.raw.substring(list.raw.length - addBack.length); + i = l - 1; + } + } + + // Determine whether item is loose or not. + // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/ + // for discount behavior. + loose = next || /\n\n(?!\s*$)/.test(item); + if (i !== l - 1) { + next = item.charAt(item.length - 1) === '\n'; + if (!loose) loose = next; + } + + if (loose) { + list.loose = true; + } + + // Check for task list items + istask = /^\[[ xX]\] /.test(item); + ischecked = undefined; + if (istask) { + ischecked = item[1] !== ' '; + item = item.replace(/^\[[ xX]\] +/, ''); + } + + list.items.push({ + raw, + task: istask, + checked: ischecked, + loose: loose, + tokens: obj.lexer.blockTokens([], item, false) + }); + } + + return list; + } + } + + html(obj) { + const cap = obj.lexer.rules.block.html.exec(obj.src); + if (cap) { + obj.src = obj.src.substring(cap[0].length); + return { + type: this.options.sanitize + ? 'paragraph' + : 'html', + raw: cap[0], + pre: !this.options.sanitizer + && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'), + text: this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape$1(cap[0])) : cap[0] + }; + } + } + + def(obj) { + const cap = obj.lexer.rules.block.def.exec(obj.src); + if (cap) { + obj.src = obj.src.substring(cap[0].length); + if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1); + const tag = cap[1].toLowerCase().replace(/\s+/g, ' '); + return { + tag, + href: cap[2], + title: cap[3] + }; + } + } + + table(obj) { + const cap = obj.lexer.rules.block.table.exec(obj.src); + if (cap) { + const item = { + type: 'table', + header: splitCells$1(cap[1].replace(/^ *| *\| *$/g, '')), + align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), + cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [] + }; + + if (item.header.length === item.align.length) { + obj.src = obj.src.substring(cap[0].length); + item.raw = cap[0]; + + let l = item.align.length; + let i; + for (i = 0; i < l; i++) { + if (/^ *-+: *$/.test(item.align[i])) { + item.align[i] = 'right'; + } else if (/^ *:-+: *$/.test(item.align[i])) { + item.align[i] = 'center'; + } else if (/^ *:-+ *$/.test(item.align[i])) { + item.align[i] = 'left'; + } else { + item.align[i] = null; + } + } + + l = item.cells.length; + for (i = 0; i < l; i++) { + item.cells[i] = splitCells$1( + item.cells[i].replace(/^ *\| *| *\| *$/g, ''), + item.header.length); + } + + return item; + } + } + } + + lheading(obj) { + const cap = obj.lexer.rules.block.lheading.exec(obj.src); + if (cap) { + obj.src = obj.src.substring(cap[0].length); + return { + type: 'heading', + raw: cap[0], + depth: cap[2].charAt(0) === '=' ? 1 : 2, + text: cap[1] + }; + } + } + + paragraph(obj) { + const cap = obj.lexer.rules.block.paragraph.exec(obj.src); + if (cap) { + obj.src = obj.src.substring(cap[0].length); + return { + type: 'paragraph', + raw: cap[0], + text: cap[1].charAt(cap[1].length - 1) === '\n' + ? cap[1].slice(0, -1) + : cap[1] + }; + } + } + + text(obj) { + const cap = obj.lexer.rules.block.text.exec(obj.src); + if (cap) { + obj.src = obj.src.substring(cap[0].length); + return { + type: 'text', + raw: cap[0], + text: cap[0] + }; + } + } + + escape(obj) { + const cap = obj.lexer.rules.inline.escape.exec(obj.src); + if (cap) { + obj.src = obj.src.substring(cap[0].length); + const text = escape$1(cap[1]); + obj.out += text; + return { + type: 'escape', + raw: cap[0], + text + }; + } + } + + // FIXME: inLink and inRawBlock should be on this + tag(obj) { + const cap = obj.lexer.rules.inline.tag.exec(obj.src); + if (cap) { + if (!obj.lexer.inLink && /^/i.test(cap[0])) { + obj.lexer.inLink = false; + } + if (!obj.lexer.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { + obj.lexer.inRawBlock = true; + } else if (obj.lexer.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { + obj.lexer.inRawBlock = false; + } + + obj.src = obj.src.substring(cap[0].length); + const text = this.options.sanitize + ? (this.options.sanitizer + ? this.options.sanitizer(cap[0]) + : escape$1(cap[0])) + : cap[0]; + obj.out += text; + return { + type: this.options.sanitize + ? 'text' + : 'html', + raw: cap[0], + text + }; + } + } + + link(obj) { + const cap = obj.lexer.rules.inline.link.exec(obj.src); + if (cap) { + const lastParenIndex = findClosingBracket$1(cap[2], '()'); + if (lastParenIndex > -1) { + const start = cap[0].indexOf('!') === 0 ? 5 : 4; + const linkLen = start + cap[1].length + lastParenIndex; + cap[2] = cap[2].substring(0, lastParenIndex); + cap[0] = cap[0].substring(0, linkLen).trim(); + cap[3] = ''; + } + obj.src = obj.src.substring(cap[0].length); + obj.lexer.inLink = true; + let href = cap[2]; + let title = ''; + if (this.options.pedantic) { + const link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href); + + if (link) { + href = link[1]; + title = link[3]; + } else { + title = ''; + } + } else { + title = cap[3] ? cap[3].slice(1, -1) : ''; + } + href = href.trim().replace(/^<([\s\S]*)>$/, '$1'); + const link = this.outputLink(cap, { + href: this.escapes(href), + title: this.escapes(title) + }, obj.tokens, cap[0], obj); + obj.lexer.inLink = false; + obj.out += link.text; + return link.token; + } + } + + reflink(obj) { + let cap; + if ((cap = obj.lexer.rules.inline.reflink.exec(obj.src)) + || (cap = obj.lexer.rules.inline.nolink.exec(obj.src))) { + obj.src = obj.src.substring(cap[0].length); + let link = (cap[2] || cap[1]).replace(/\s+/g, ' '); + link = obj.lexer.tokens.links[link.toLowerCase()]; + if (!link || !link.href) { + const text = cap[0].charAt(0); + obj.out += text; + obj.src = cap[0].substring(1) + obj.src; + return { + type: 'text', + raw: text, + text + }; + } + obj.lexer.inLink = true; + const linkToken = this.outputLink(cap, link, obj.tokens, cap[0], obj); + obj.out += linkToken.text; + obj.lexer.inLink = false; + return linkToken.token; + } + } + + strong(obj) { + const cap = obj.lexer.rules.inline.strong.exec(obj.src); + if (cap) { + obj.src = obj.src.substring(cap[0].length); + const newTokens = obj.tokens ? [] : null; + const text = obj.lexer.inlineOutput(cap[4] || cap[3] || cap[2] || cap[1], newTokens); + + obj.out += text; + return { + type: 'strong', + raw: cap[0], + text, + tokens: newTokens + }; + } + } + + em(obj) { + const cap = obj.lexer.rules.inline.em.exec(obj.src); + if (cap) { + obj.src = obj.src.substring(cap[0].length); + const newTokens = obj.tokens ? [] : null; + const text = obj.lexer.inlineOutput(cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1], newTokens); + + obj.out += text; + return { + type: 'em', + raw: cap[0], + text, + tokens: newTokens + }; + } + } + + codespan(obj) { + const cap = obj.lexer.rules.inline.code.exec(obj.src); + if (cap) { + obj.src = obj.src.substring(cap[0].length); + const text = escape$1(cap[2].trim(), true); + obj.out += text; + return { + type: 'codespan', + raw: cap[0], + text + }; + } + } + + br(obj) { + const cap = obj.lexer.rules.inline.br.exec(obj.src); + if (cap) { + obj.src = obj.src.substring(cap[0].length); + obj.out += '\n'; + return { + type: 'br', + raw: cap[0] + }; + } + } + + del(obj) { + const cap = obj.lexer.rules.inline.del.exec(obj.src); + if (cap) { + obj.src = obj.src.substring(cap[0].length); + const newTokens = obj.tokens ? [] : null; + const text = obj.lexer.inlineOutput(cap[1], newTokens); + obj.out += text; + return { + type: 'del', + raw: cap[0], + text, + tokens: newTokens + }; + } + } + + autolink(obj) { + const cap = obj.lexer.rules.inline.autolink.exec(obj.src); + if (cap) { + obj.src = obj.src.substring(cap[0].length); + let text, href; + if (cap[2] === '@') { + text = escape$1(this.options.mangle ? this.mangle(cap[1]) : cap[1]); + href = 'mailto:' + text; + } else { + text = escape$1(cap[1]); + href = text; + } + obj.out += text; + return { + type: 'link', + raw: cap[0], + text, + href, + tokens: [ + { + type: 'text', + raw: text, + text + } + ] + }; + } + } + + url(obj) { + let cap; + if (!obj.lexer.inLink && (cap = obj.lexer.rules.inline.url.exec(obj.src))) { + let text, href; + if (cap[2] === '@') { + text = escape$1(this.options.mangle ? this.mangle(cap[0]) : cap[0]); + href = 'mailto:' + text; + } else { + // do extended autolink path validation + let prevCapZero; + do { + prevCapZero = cap[0]; + cap[0] = obj.lexer.rules.inline._backpedal.exec(cap[0])[0]; + } while (prevCapZero !== cap[0]); + text = escape$1(cap[0]); + if (cap[1] === 'www.') { + href = 'http://' + text; + } else { + href = text; + } + } + obj.src = obj.src.substring(cap[0].length); + obj.out += text; + return { + type: 'link', + raw: cap[0], + text, + href, + tokens: [ + { + type: 'text', + raw: text, + text + } + ] + }; + } + } + + inlineText(obj) { + const cap = obj.lexer.rules.inline.text.exec(obj.src); + if (cap) { + obj.src = obj.src.substring(cap[0].length); + let text; + if (obj.lexer.inRawBlock) { + text = this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape$1(cap[0])) : cap[0]; + } else { + text = escape$1(this.options.smartypants ? this.smartypants(cap[0]) : cap[0]); + } + obj.out += text; + return { + type: 'text', + raw: cap[0], + text + }; + } + } + + escapes(text) { + return text ? text.replace(inline$1._escapes, '$1') : text; + } + + /** + * tokenize Link + */ + outputLink(cap, link, tokens, raw, obj) { + const href = link.href; + const title = link.title ? escape$1(link.title) : null; + const newTokens = tokens ? [] : null; + let token, text; + + if (cap[0].charAt(0) !== '!') { + text = obj.lexer.inlineOutput(cap[1], newTokens); + token = { + type: 'link', + raw, + text, + href, + title, + tokens: newTokens + }; + } else { + text = escape$1(cap[1]); + token = { + type: 'image', + raw, + text, + href, + title + }; + } + return { token, text }; + } + + /** + * Smartypants Transformations + */ + smartypants(text) { + return text + // em-dashes + .replace(/---/g, '\u2014') + // en-dashes + .replace(/--/g, '\u2013') + // opening singles + .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018') + // closing singles & apostrophes + .replace(/'/g, '\u2019') + // opening doubles + .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c') + // closing doubles + .replace(/"/g, '\u201d') + // ellipses + .replace(/\.{3}/g, '\u2026'); + } + + /** + * Mangle Links + */ + mangle(text) { + let out = '', + i, + ch; + + const l = text.length; + for (i = 0; i < l; i++) { + ch = text.charCodeAt(i); + if (Math.random() > 0.5) { + ch = 'x' + ch.toString(16); + } + out += '&#' + ch + ';'; + } + + return out; + } +}; + +const { defaults: defaults$2 } = defaults; +const { block: block$1, inline: inline$2 } = rules; /** * Block Lexer @@ -576,21 +1268,24 @@ var Lexer_1 = class Lexer { constructor(options) { this.tokens = []; this.tokens.links = Object.create(null); - this.options = options || defaults$1; + this.options = options || defaults$2; + this.options.tokenizer = this.options.tokenizer || new Tokenizer_1(); + this.tokenizer = this.options.tokenizer; + this.tokenizer.options = this.options; this.rules = { block: block$1.normal, - inline: inline$1.normal + inline: inline$2.normal }; if (this.options.pedantic) { this.rules.block = block$1.pedantic; - this.rules.inline = inline$1.pedantic; + this.rules.inline = inline$2.pedantic; } else if (this.options.gfm) { this.rules.block = block$1.gfm; if (this.options.breaks) { - this.rules.inline = inline$1.breaks; + this.rules.inline = inline$2.breaks; } else { - this.rules.inline = inline$1.gfm; + this.rules.inline = inline$2.gfm; } } } @@ -601,7 +1296,7 @@ var Lexer_1 = class Lexer { static get rules() { return { block: block$1, - inline: inline$1 + inline: inline$2 }; } @@ -653,112 +1348,38 @@ var Lexer_1 = class Lexer { while (src) { // newline - if (cap = this.rules.block.newline.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - if (cap[0].length > 1) { - tokens.push({ - type: 'space', - raw - }); - } + if (token = this.tokenizer.space(obj)) { + tokens.push(token); + continue; } // code - if (cap = this.rules.block.code.exec(src)) { - lastToken = tokens[tokens.length - 1]; - src = src.substring(cap[0].length); - raw = cap[0]; - // An indented code block cannot interrupt a paragraph. - if (lastToken && lastToken.type === 'paragraph') { - lastToken.text += '\n' + cap[0].trimRight(); - lastToken.raw += '\n' + raw; - } else { - cap = cap[0].replace(/^ {4}/gm, ''); - tokens.push({ - type: 'code', - raw, - codeBlockStyle: 'indented', - text: !this.options.pedantic - ? rtrim$1(cap, '\n') - : cap - }); - } + if (token = this.tokenizer.code(obj)) { + tokens.push(token); continue; } // fences - if (cap = this.rules.block.fences.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: 'code', - raw, - lang: cap[2] ? cap[2].trim() : cap[2], - text: cap[3] || '' - }); + if (token = this.tokenizer.fences(obj)) { + tokens.push(token); continue; } // heading - if (cap = this.rules.block.heading.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: 'heading', - raw, - depth: cap[1].length, - text: cap[2] - }); + if (token = this.tokenizer.heading(obj)) { + tokens.push(token); continue; } // table no leading pipe (gfm) - if (cap = this.rules.block.nptable.exec(src)) { - item = { - type: 'table', - header: splitCells$1(cap[1].replace(/^ *| *\| *$/g, '')), - align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), - cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [] - }; - - if (item.header.length === item.align.length) { - src = src.substring(cap[0].length); - raw = cap[0]; - item.raw = raw; - - l = item.align.length; - for (i = 0; i < l; i++) { - if (/^ *-+: *$/.test(item.align[i])) { - item.align[i] = 'right'; - } else if (/^ *:-+: *$/.test(item.align[i])) { - item.align[i] = 'center'; - } else if (/^ *:-+ *$/.test(item.align[i])) { - item.align[i] = 'left'; - } else { - item.align[i] = null; - } - } - - l = item.cells.length; - for (i = 0; i < l; i++) { - item.cells[i] = splitCells$1(item.cells[i], item.header.length); - } - - tokens.push(item); - - continue; - } + if (token = this.tokenizer.nptable(obj)) { + tokens.push(token); + continue; } // hr - if (cap = this.rules.block.hr.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: 'hr', - raw - }); + if (token = this.tokenizer.hr(obj)) { + tokens.push(token); continue; } @@ -867,118 +1488,51 @@ var Lexer_1 = class Lexer { } // html - if (cap = this.rules.block.html.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: this.options.sanitize - ? 'paragraph' - : 'html', - raw, - pre: !this.options.sanitizer - && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'), - text: this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape$1(cap[0])) : cap[0] - }); + if (token = this.tokenizer.html(obj)) { + tokens.push(token); continue; } // def - if (top && (cap = this.rules.block.def.exec(src))) { - src = src.substring(cap[0].length); - if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1); - tag = cap[1].toLowerCase().replace(/\s+/g, ' '); - if (!this.tokens.links[tag]) { - this.tokens.links[tag] = { - href: cap[2], - title: cap[3] + if (top && (token = this.tokenizer.def(obj))) { + if (!this.tokens.links[token.tag]) { + this.tokens.links[token.tag] = { + href: token.href, + title: token.title }; } continue; } // table (gfm) - if (cap = this.rules.block.table.exec(src)) { - item = { - type: 'table', - header: splitCells$1(cap[1].replace(/^ *| *\| *$/g, '')), - align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), - cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [] - }; - - if (item.header.length === item.align.length) { - src = src.substring(cap[0].length); - item.raw = cap[0]; - - l = item.align.length; - for (i = 0; i < l; i++) { - if (/^ *-+: *$/.test(item.align[i])) { - item.align[i] = 'right'; - } else if (/^ *:-+: *$/.test(item.align[i])) { - item.align[i] = 'center'; - } else if (/^ *:-+ *$/.test(item.align[i])) { - item.align[i] = 'left'; - } else { - item.align[i] = null; - } - } - - l = item.cells.length; - for (i = 0; i < l; i++) { - item.cells[i] = splitCells$1( - item.cells[i].replace(/^ *\| *| *\| *$/g, ''), - item.header.length); - } - - tokens.push(item); - - continue; - } + if (token = this.tokenizer.table(obj)) { + tokens.push(token); + continue; } // lheading - if (cap = this.rules.block.lheading.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: 'heading', - raw, - depth: cap[2].charAt(0) === '=' ? 1 : 2, - text: cap[1] - }); + if (token = this.tokenizer.lheading(obj)) { + tokens.push(token); continue; } // top-level paragraph - if (top && (cap = this.rules.block.paragraph.exec(src))) { - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: 'paragraph', - raw, - text: cap[1].charAt(cap[1].length - 1) === '\n' - ? cap[1].slice(0, -1) - : cap[1] - }); + if (top && (token = this.tokenizer.paragraph(obj))) { + tokens.push(token); continue; } // text - if (cap = this.rules.block.text.exec(src)) { - // Top-level should never reach here. - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: 'text', - raw, - text: cap[0] - }); + if (token = this.tokenizer.text(obj)) { + tokens.push(token); continue; } - if (src) { - const errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0); + if (obj.src) { + const errMsg = 'Infinite loop on byte: ' + obj.src.charCodeAt(0); if (this.options.silent) { console.error(errMsg); + break; } else { throw new Error(errMsg); } @@ -1067,108 +1621,28 @@ var Lexer_1 = class Lexer { linkLen, raw; - while (src) { + while (obj.src) { // escape - if (cap = this.rules.inline.escape.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - text = escape$1(cap[1]); - out += text; - tokens.push({ - type: 'escape', - raw, - text - }); + if (token = this.tokenizer.escape(obj)) { + tokens.push(token); continue; } // tag - if (cap = this.rules.inline.tag.exec(src)) { - if (!this.inLink && /^/i.test(cap[0])) { - this.inLink = false; - } - if (!this.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { - this.inRawBlock = true; - } else if (this.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { - this.inRawBlock = false; - } - - src = src.substring(cap[0].length); - raw = cap[0]; - text = this.options.sanitize - ? (this.options.sanitizer - ? this.options.sanitizer(cap[0]) - : escape$1(cap[0])) - : cap[0]; - tokens.push({ - type: this.options.sanitize - ? 'text' - : 'html', - raw, - text - }); - out += text; + if (token = this.tokenizer.tag(obj)) { + tokens.push(token); continue; } // link - if (cap = this.rules.inline.link.exec(src)) { - lastParenIndex = findClosingBracket$1(cap[2], '()'); - if (lastParenIndex > -1) { - start = cap[0].indexOf('!') === 0 ? 5 : 4; - linkLen = start + cap[1].length + lastParenIndex; - cap[2] = cap[2].substring(0, lastParenIndex); - cap[0] = cap[0].substring(0, linkLen).trim(); - cap[3] = ''; - } - src = src.substring(cap[0].length); - raw = cap[0]; - this.inLink = true; - href = cap[2]; - if (this.options.pedantic) { - link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href); - - if (link) { - href = link[1]; - title = link[3]; - } else { - title = ''; - } - } else { - title = cap[3] ? cap[3].slice(1, -1) : ''; - } - href = href.trim().replace(/^<([\s\S]*)>$/, '$1'); - out += this.outputLink(cap, { - href: this.escapes(href), - title: this.escapes(title) - }, tokens, raw); - this.inLink = false; + if (token = this.tokenizer.link(obj)) { + tokens.push(token); continue; } // reflink, nolink - if ((cap = this.rules.inline.reflink.exec(src)) - || (cap = this.rules.inline.nolink.exec(src))) { - src = src.substring(cap[0].length); - raw = cap[0]; - link = (cap[2] || cap[1]).replace(/\s+/g, ' '); - link = this.tokens.links[link.toLowerCase()]; - if (!link || !link.href) { - text = cap[0].charAt(0); - out += text; - tokens.push({ - type: 'text', - raw: text, - text - }); - src = cap[0].substring(1) + src; - continue; - } - this.inLink = true; - out += this.outputLink(cap, link, tokens, raw); - this.inLink = false; + if (token = this.tokenizer.reflink(obj)) { + tokens.push(token); continue; } @@ -1206,28 +1680,14 @@ var Lexer_1 = class Lexer { } // code - if (cap = this.rules.inline.code.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - text = escape$1(cap[2].trim(), true); - tokens.push({ - type: 'codespan', - raw, - text - }); - out += text; + if (token = this.tokenizer.codespan(obj)) { + tokens.push(token); continue; } // br - if (cap = this.rules.inline.br.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: 'br', - raw - }); - out += '\n'; + if (token = this.tokenizer.br(obj)) { + tokens.push(token); continue; } @@ -1248,92 +1708,28 @@ var Lexer_1 = class Lexer { } // autolink - if (cap = this.rules.inline.autolink.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - if (cap[2] === '@') { - text = escape$1(this.options.mangle ? this.mangle(cap[1]) : cap[1]); - href = 'mailto:' + text; - } else { - text = escape$1(cap[1]); - href = text; - } - tokens.push({ - type: 'link', - raw, - text, - href, - tokens: [ - { - type: 'text', - raw: text, - text - } - ] - }); - out += text; + if (token = this.tokenizer.autolink(obj)) { + tokens.push(token); continue; } // url (gfm) - if (!this.inLink && (cap = this.rules.inline.url.exec(src))) { - if (cap[2] === '@') { - text = escape$1(this.options.mangle ? this.mangle(cap[0]) : cap[0]); - href = 'mailto:' + text; - } else { - // do extended autolink path validation - do { - prevCapZero = cap[0]; - cap[0] = this.rules.inline._backpedal.exec(cap[0])[0]; - } while (prevCapZero !== cap[0]); - text = escape$1(cap[0]); - if (cap[1] === 'www.') { - href = 'http://' + text; - } else { - href = text; - } - } - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: 'link', - raw, - text, - href, - tokens: [ - { - type: 'text', - raw: text, - text - } - ] - }); - out += text; + if (token = this.tokenizer.url(obj)) { + tokens.push(token); continue; } // text - if (cap = this.rules.inline.text.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - if (this.inRawBlock) { - text = this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape$1(cap[0])) : cap[0]; - } else { - text = escape$1(this.options.smartypants ? this.smartypants(cap[0]) : cap[0]); - } - tokens.push({ - type: 'text', - raw, - text - }); - out += text; + if (token = this.tokenizer.inlineText(obj)) { + tokens.push(token); continue; } - if (src) { - const errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0); + if (obj.src) { + const errMsg = 'Infinite loop on byte: ' + obj.src.charCodeAt(0); if (this.options.silent) { console.error(errMsg); + break; } else { throw new Error(errMsg); } @@ -1421,7 +1817,7 @@ var Lexer_1 = class Lexer { } }; -const { defaults: defaults$2 } = defaults; +const { defaults: defaults$3 } = defaults; const { cleanUrl: cleanUrl$1, escape: escape$2 @@ -1432,7 +1828,7 @@ const { */ var Renderer_1 = class Renderer { constructor(options) { - this.options = options || defaults$2; + this.options = options || defaults$3; } code(code, infostring, escaped) { @@ -1663,7 +2059,7 @@ var Slugger_1 = class Slugger { } }; -const { defaults: defaults$3 } = defaults; +const { defaults: defaults$4 } = defaults; const { unescape: unescape$1 } = helpers; @@ -1673,7 +2069,7 @@ const { */ var Parser_1 = class Parser { constructor(options) { - this.options = options || defaults$3; + this.options = options || defaults$4; this.options.renderer = this.options.renderer || new Renderer_1(); this.renderer = this.options.renderer; this.renderer.options = this.options; @@ -1924,7 +2320,7 @@ const { const { getDefaults, changeDefaults, - defaults: defaults$4 + defaults: defaults$5 } = defaults; /** @@ -2037,7 +2433,7 @@ marked.setOptions = function(opt) { marked.getDefaults = getDefaults; -marked.defaults = defaults$4; +marked.defaults = defaults$5; /** * Expose @@ -2052,6 +2448,8 @@ marked.TextRenderer = TextRenderer_1; marked.Lexer = Lexer_1; marked.lexer = Lexer_1.lex; +marked.Tokenizer = Tokenizer_1; + marked.Slugger = Slugger_1; marked.parse = marked; diff --git a/lib/marked.js b/lib/marked.js index a2d17f5b6c..0750fc777a 100644 --- a/lib/marked.js +++ b/lib/marked.js @@ -510,12 +510,731 @@ }; var defaults$1 = defaults.defaults; - var block$1 = rules.block, - inline$1 = rules.inline; var rtrim$1 = helpers.rtrim, splitCells$1 = helpers.splitCells, - escape$1 = helpers.escape, + _escape = helpers.escape, findClosingBracket$1 = helpers.findClosingBracket; + var inline$1 = rules.inline; + /** + * Tokenizer + */ + + var Tokenizer_1 = /*#__PURE__*/function () { + function Tokenizer(options) { + this.options = options || defaults$1; + } + + var _proto = Tokenizer.prototype; + + _proto.space = function space(obj) { + var cap = obj.lexer.rules.block.newline.exec(obj.src); + + if (cap) { + obj.src = obj.src.substring(cap[0].length); + + if (cap[0].length > 1) { + return { + type: 'space', + raw: cap[0] + }; + } + } + }; + + _proto.code = function code(obj) { + var cap = obj.lexer.rules.block.code.exec(obj.src); + + if (cap) { + obj.src = obj.src.substring(cap[0].length); + var lastToken = obj.tokens[obj.tokens.length - 1]; // An indented code block cannot interrupt a paragraph. + + if (lastToken && lastToken.type === 'paragraph') { + obj.tokens.pop(); + lastToken.text += '\n' + cap[0].trimRight(); + lastToken.raw += '\n' + cap[0]; + return lastToken; + } else { + var text = cap[0].replace(/^ {4}/gm, ''); + return { + type: 'code', + raw: cap[0], + codeBlockStyle: 'indented', + text: !this.options.pedantic ? rtrim$1(text, '\n') : text + }; + } + } + }; + + _proto.fences = function fences(obj) { + var cap = obj.lexer.rules.block.fences.exec(obj.src); + + if (cap) { + obj.src = obj.src.substring(cap[0].length); + return { + type: 'code', + raw: cap[0], + lang: cap[2] ? cap[2].trim() : cap[2], + text: cap[3] || '' + }; + } + }; + + _proto.heading = function heading(obj) { + var cap = obj.lexer.rules.block.heading.exec(obj.src); + + if (cap) { + obj.src = obj.src.substring(cap[0].length); + return { + type: 'heading', + raw: cap[0], + depth: cap[1].length, + text: cap[2] + }; + } + }; + + _proto.nptable = function nptable(obj) { + var cap = obj.lexer.rules.block.nptable.exec(obj.src); + + if (cap) { + var item = { + type: 'table', + header: splitCells$1(cap[1].replace(/^ *| *\| *$/g, '')), + align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), + cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [], + raw: cap[0] + }; + + if (item.header.length === item.align.length) { + obj.src = obj.src.substring(cap[0].length); + var l = item.align.length; + var i; + + for (i = 0; i < l; i++) { + if (/^ *-+: *$/.test(item.align[i])) { + item.align[i] = 'right'; + } else if (/^ *:-+: *$/.test(item.align[i])) { + item.align[i] = 'center'; + } else if (/^ *:-+ *$/.test(item.align[i])) { + item.align[i] = 'left'; + } else { + item.align[i] = null; + } + } + + l = item.cells.length; + + for (i = 0; i < l; i++) { + item.cells[i] = splitCells$1(item.cells[i], item.header.length); + } + + return item; + } + } + }; + + _proto.hr = function hr(obj) { + var cap = obj.lexer.rules.block.hr.exec(obj.src); + + if (cap) { + obj.src = obj.src.substring(cap[0].length); + return { + type: 'hr', + raw: cap[0] + }; + } + }; + + _proto.blockquote = function blockquote(obj) { + var cap = obj.lexer.rules.block.blockquote.exec(obj.src); + + if (cap) { + obj.src = obj.src.substring(cap[0].length); + var text = cap[0].replace(/^ *> ?/gm, ''); + return { + type: 'blockquote', + raw: cap[0], + tokens: obj.lexer.blockTokens([], text, obj.top) + }; + } + }; + + _proto.list = function list(obj) { + var cap = obj.lexer.rules.block.list.exec(obj.src); + + if (cap) { + obj.src = obj.src.substring(cap[0].length); + var raw = cap[0]; + var bull = cap[2]; + var isordered = bull.length > 1; + var list = { + type: 'list', + raw: raw, + ordered: isordered, + start: isordered ? +bull : '', + loose: false, + items: [] + }; // Get each top-level item. + + var itemMatch = cap[0].match(obj.lexer.rules.block.item); + var next = false, + item, + space, + b, + addBack, + loose, + istask, + ischecked; + var l = itemMatch.length; + + for (var i = 0; i < l; i++) { + item = itemMatch[i]; + raw = item.trim(); // Remove the list item's bullet + // so it is seen as the next token. + + space = item.length; + item = item.replace(/^ *([*+-]|\d+\.) */, ''); // Outdent whatever the + // list item contains. Hacky. + + if (~item.indexOf('\n ')) { + space -= item.length; + item = !this.options.pedantic ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') : item.replace(/^ {1,4}/gm, ''); + } // Determine whether the next list item belongs here. + // Backpedal if it does not belong in this list. + + + if (i !== l - 1) { + b = obj.lexer.rules.block.bullet.exec(itemMatch[i + 1])[0]; + + if (bull.length > 1 ? b.length === 1 : b.length > 1 || this.options.smartLists && b !== bull) { + addBack = itemMatch.slice(i + 1).join('\n'); + obj.src = addBack + obj.src; + list.raw = list.raw.substring(list.raw.length - addBack.length); + i = l - 1; + } + } // Determine whether item is loose or not. + // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/ + // for discount behavior. + + + loose = next || /\n\n(?!\s*$)/.test(item); + + if (i !== l - 1) { + next = item.charAt(item.length - 1) === '\n'; + if (!loose) loose = next; + } + + if (loose) { + list.loose = true; + } // Check for task list items + + + istask = /^\[[ xX]\] /.test(item); + ischecked = undefined; + + if (istask) { + ischecked = item[1] !== ' '; + item = item.replace(/^\[[ xX]\] +/, ''); + } + + list.items.push({ + raw: raw, + task: istask, + checked: ischecked, + loose: loose, + tokens: obj.lexer.blockTokens([], item, false) + }); + } + + return list; + } + }; + + _proto.html = function html(obj) { + var cap = obj.lexer.rules.block.html.exec(obj.src); + + if (cap) { + obj.src = obj.src.substring(cap[0].length); + return { + type: this.options.sanitize ? 'paragraph' : 'html', + raw: cap[0], + pre: !this.options.sanitizer && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'), + text: this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0] + }; + } + }; + + _proto.def = function def(obj) { + var cap = obj.lexer.rules.block.def.exec(obj.src); + + if (cap) { + obj.src = obj.src.substring(cap[0].length); + if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1); + var tag = cap[1].toLowerCase().replace(/\s+/g, ' '); + return { + tag: tag, + href: cap[2], + title: cap[3] + }; + } + }; + + _proto.table = function table(obj) { + var cap = obj.lexer.rules.block.table.exec(obj.src); + + if (cap) { + var item = { + type: 'table', + header: splitCells$1(cap[1].replace(/^ *| *\| *$/g, '')), + align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), + cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [] + }; + + if (item.header.length === item.align.length) { + obj.src = obj.src.substring(cap[0].length); + item.raw = cap[0]; + var l = item.align.length; + var i; + + for (i = 0; i < l; i++) { + if (/^ *-+: *$/.test(item.align[i])) { + item.align[i] = 'right'; + } else if (/^ *:-+: *$/.test(item.align[i])) { + item.align[i] = 'center'; + } else if (/^ *:-+ *$/.test(item.align[i])) { + item.align[i] = 'left'; + } else { + item.align[i] = null; + } + } + + l = item.cells.length; + + for (i = 0; i < l; i++) { + item.cells[i] = splitCells$1(item.cells[i].replace(/^ *\| *| *\| *$/g, ''), item.header.length); + } + + return item; + } + } + }; + + _proto.lheading = function lheading(obj) { + var cap = obj.lexer.rules.block.lheading.exec(obj.src); + + if (cap) { + obj.src = obj.src.substring(cap[0].length); + return { + type: 'heading', + raw: cap[0], + depth: cap[2].charAt(0) === '=' ? 1 : 2, + text: cap[1] + }; + } + }; + + _proto.paragraph = function paragraph(obj) { + var cap = obj.lexer.rules.block.paragraph.exec(obj.src); + + if (cap) { + obj.src = obj.src.substring(cap[0].length); + return { + type: 'paragraph', + raw: cap[0], + text: cap[1].charAt(cap[1].length - 1) === '\n' ? cap[1].slice(0, -1) : cap[1] + }; + } + }; + + _proto.text = function text(obj) { + var cap = obj.lexer.rules.block.text.exec(obj.src); + + if (cap) { + obj.src = obj.src.substring(cap[0].length); + return { + type: 'text', + raw: cap[0], + text: cap[0] + }; + } + }; + + _proto.escape = function escape(obj) { + var cap = obj.lexer.rules.inline.escape.exec(obj.src); + + if (cap) { + obj.src = obj.src.substring(cap[0].length); + + var text = _escape(cap[1]); + + obj.out += text; + return { + type: 'escape', + raw: cap[0], + text: text + }; + } + } // FIXME: inLink and inRawBlock should be on this + ; + + _proto.tag = function tag(obj) { + var cap = obj.lexer.rules.inline.tag.exec(obj.src); + + if (cap) { + if (!obj.lexer.inLink && /^/i.test(cap[0])) { + obj.lexer.inLink = false; + } + + if (!obj.lexer.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { + obj.lexer.inRawBlock = true; + } else if (obj.lexer.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { + obj.lexer.inRawBlock = false; + } + + obj.src = obj.src.substring(cap[0].length); + var text = this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0]; + obj.out += text; + return { + type: this.options.sanitize ? 'text' : 'html', + raw: cap[0], + text: text + }; + } + }; + + _proto.link = function link(obj) { + var cap = obj.lexer.rules.inline.link.exec(obj.src); + + if (cap) { + var lastParenIndex = findClosingBracket$1(cap[2], '()'); + + if (lastParenIndex > -1) { + var start = cap[0].indexOf('!') === 0 ? 5 : 4; + var linkLen = start + cap[1].length + lastParenIndex; + cap[2] = cap[2].substring(0, lastParenIndex); + cap[0] = cap[0].substring(0, linkLen).trim(); + cap[3] = ''; + } + + obj.src = obj.src.substring(cap[0].length); + obj.lexer.inLink = true; + var href = cap[2]; + var title = ''; + + if (this.options.pedantic) { + var _link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href); + + if (_link) { + href = _link[1]; + title = _link[3]; + } else { + title = ''; + } + } else { + title = cap[3] ? cap[3].slice(1, -1) : ''; + } + + href = href.trim().replace(/^<([\s\S]*)>$/, '$1'); + var link = this.outputLink(cap, { + href: this.escapes(href), + title: this.escapes(title) + }, obj.tokens, cap[0], obj); + obj.lexer.inLink = false; + obj.out += link.text; + return link.token; + } + }; + + _proto.reflink = function reflink(obj) { + var cap; + + if ((cap = obj.lexer.rules.inline.reflink.exec(obj.src)) || (cap = obj.lexer.rules.inline.nolink.exec(obj.src))) { + obj.src = obj.src.substring(cap[0].length); + var link = (cap[2] || cap[1]).replace(/\s+/g, ' '); + link = obj.lexer.tokens.links[link.toLowerCase()]; + + if (!link || !link.href) { + var text = cap[0].charAt(0); + obj.out += text; + obj.src = cap[0].substring(1) + obj.src; + return { + type: 'text', + raw: text, + text: text + }; + } + + obj.lexer.inLink = true; + var linkToken = this.outputLink(cap, link, obj.tokens, cap[0], obj); + obj.out += linkToken.text; + obj.lexer.inLink = false; + return linkToken.token; + } + }; + + _proto.strong = function strong(obj) { + var cap = obj.lexer.rules.inline.strong.exec(obj.src); + + if (cap) { + obj.src = obj.src.substring(cap[0].length); + var newTokens = obj.tokens ? [] : null; + var text = obj.lexer.inlineOutput(cap[4] || cap[3] || cap[2] || cap[1], newTokens); + obj.out += text; + return { + type: 'strong', + raw: cap[0], + text: text, + tokens: newTokens + }; + } + }; + + _proto.em = function em(obj) { + var cap = obj.lexer.rules.inline.em.exec(obj.src); + + if (cap) { + obj.src = obj.src.substring(cap[0].length); + var newTokens = obj.tokens ? [] : null; + var text = obj.lexer.inlineOutput(cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1], newTokens); + obj.out += text; + return { + type: 'em', + raw: cap[0], + text: text, + tokens: newTokens + }; + } + }; + + _proto.codespan = function codespan(obj) { + var cap = obj.lexer.rules.inline.code.exec(obj.src); + + if (cap) { + obj.src = obj.src.substring(cap[0].length); + + var text = _escape(cap[2].trim(), true); + + obj.out += text; + return { + type: 'codespan', + raw: cap[0], + text: text + }; + } + }; + + _proto.br = function br(obj) { + var cap = obj.lexer.rules.inline.br.exec(obj.src); + + if (cap) { + obj.src = obj.src.substring(cap[0].length); + obj.out += '\n'; + return { + type: 'br', + raw: cap[0] + }; + } + }; + + _proto.del = function del(obj) { + var cap = obj.lexer.rules.inline.del.exec(obj.src); + + if (cap) { + obj.src = obj.src.substring(cap[0].length); + var newTokens = obj.tokens ? [] : null; + var text = obj.lexer.inlineOutput(cap[1], newTokens); + obj.out += text; + return { + type: 'del', + raw: cap[0], + text: text, + tokens: newTokens + }; + } + }; + + _proto.autolink = function autolink(obj) { + var cap = obj.lexer.rules.inline.autolink.exec(obj.src); + + if (cap) { + obj.src = obj.src.substring(cap[0].length); + var text, href; + + if (cap[2] === '@') { + text = _escape(this.options.mangle ? this.mangle(cap[1]) : cap[1]); + href = 'mailto:' + text; + } else { + text = _escape(cap[1]); + href = text; + } + + obj.out += text; + return { + type: 'link', + raw: cap[0], + text: text, + href: href, + tokens: [{ + type: 'text', + raw: text, + text: text + }] + }; + } + }; + + _proto.url = function url(obj) { + var cap; + + if (!obj.lexer.inLink && (cap = obj.lexer.rules.inline.url.exec(obj.src))) { + var text, href; + + if (cap[2] === '@') { + text = _escape(this.options.mangle ? this.mangle(cap[0]) : cap[0]); + href = 'mailto:' + text; + } else { + // do extended autolink path validation + var prevCapZero; + + do { + prevCapZero = cap[0]; + cap[0] = obj.lexer.rules.inline._backpedal.exec(cap[0])[0]; + } while (prevCapZero !== cap[0]); + + text = _escape(cap[0]); + + if (cap[1] === 'www.') { + href = 'http://' + text; + } else { + href = text; + } + } + + obj.src = obj.src.substring(cap[0].length); + obj.out += text; + return { + type: 'link', + raw: cap[0], + text: text, + href: href, + tokens: [{ + type: 'text', + raw: text, + text: text + }] + }; + } + }; + + _proto.inlineText = function inlineText(obj) { + var cap = obj.lexer.rules.inline.text.exec(obj.src); + + if (cap) { + obj.src = obj.src.substring(cap[0].length); + var text; + + if (obj.lexer.inRawBlock) { + text = this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0]; + } else { + text = _escape(this.options.smartypants ? this.smartypants(cap[0]) : cap[0]); + } + + obj.out += text; + return { + type: 'text', + raw: cap[0], + text: text + }; + } + }; + + _proto.escapes = function escapes(text) { + return text ? text.replace(inline$1._escapes, '$1') : text; + } + /** + * tokenize Link + */ + ; + + _proto.outputLink = function outputLink(cap, link, tokens, raw, obj) { + var href = link.href; + var title = link.title ? _escape(link.title) : null; + var newTokens = tokens ? [] : null; + var token, text; + + if (cap[0].charAt(0) !== '!') { + text = obj.lexer.inlineOutput(cap[1], newTokens); + token = { + type: 'link', + raw: raw, + text: text, + href: href, + title: title, + tokens: newTokens + }; + } else { + text = _escape(cap[1]); + token = { + type: 'image', + raw: raw, + text: text, + href: href, + title: title + }; + } + + return { + token: token, + text: text + }; + } + /** + * Smartypants Transformations + */ + ; + + _proto.smartypants = function smartypants(text) { + return text // em-dashes + .replace(/---/g, "\u2014") // en-dashes + .replace(/--/g, "\u2013") // opening singles + .replace(/(^|[-\u2014/(\[{"\s])'/g, "$1\u2018") // closing singles & apostrophes + .replace(/'/g, "\u2019") // opening doubles + .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, "$1\u201C") // closing doubles + .replace(/"/g, "\u201D") // ellipses + .replace(/\.{3}/g, "\u2026"); + } + /** + * Mangle Links + */ + ; + + _proto.mangle = function mangle(text) { + var out = '', + i, + ch; + var l = text.length; + + for (i = 0; i < l; i++) { + ch = text.charCodeAt(i); + + if (Math.random() > 0.5) { + ch = 'x' + ch.toString(16); + } + + out += '&#' + ch + ';'; + } + + return out; + }; + + return Tokenizer; + }(); + + var defaults$2 = defaults.defaults; + var block$1 = rules.block, + inline$2 = rules.inline; /** * Block Lexer */ @@ -524,22 +1243,25 @@ function Lexer(options) { this.tokens = []; this.tokens.links = Object.create(null); - this.options = options || defaults$1; + this.options = options || defaults$2; + this.options.tokenizer = this.options.tokenizer || new Tokenizer_1(); + this.tokenizer = this.options.tokenizer; + this.tokenizer.options = this.options; this.rules = { block: block$1.normal, - inline: inline$1.normal + inline: inline$2.normal }; if (this.options.pedantic) { this.rules.block = block$1.pedantic; - this.rules.inline = inline$1.pedantic; + this.rules.inline = inline$2.pedantic; } else if (this.options.gfm) { this.rules.block = block$1.gfm; if (this.options.breaks) { - this.rules.inline = inline$1.breaks; + this.rules.inline = inline$2.breaks; } else { - this.rules.inline = inline$1.gfm; + this.rules.inline = inline$2.gfm; } } } @@ -578,117 +1300,48 @@ top = true; } - src = src.replace(/^ +$/gm, ''); - var next, loose, cap, bull, b, item, list, space, i, tag, l, isordered, istask, ischecked, lastToken, addBack, raw; + var obj = { + tokens: tokens, + src: src.replace(/^ +$/gm, ''), + top: top, + lexer: this + }; + var token; - while (src) { + while (obj.src) { // newline - if (cap = this.rules.block.newline.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - - if (cap[0].length > 1) { - tokens.push({ - type: 'space', - raw: raw - }); - } + if (token = this.tokenizer.space(obj)) { + tokens.push(token); + continue; } // code - if (cap = this.rules.block.code.exec(src)) { - lastToken = tokens[tokens.length - 1]; - src = src.substring(cap[0].length); - raw = cap[0]; // An indented code block cannot interrupt a paragraph. - - if (lastToken && lastToken.type === 'paragraph') { - lastToken.text += '\n' + cap[0].trimRight(); - lastToken.raw += '\n' + raw; - } else { - cap = cap[0].replace(/^ {4}/gm, ''); - tokens.push({ - type: 'code', - raw: raw, - codeBlockStyle: 'indented', - text: !this.options.pedantic ? rtrim$1(cap, '\n') : cap - }); - } - + if (token = this.tokenizer.code(obj)) { + tokens.push(token); continue; } // fences - if (cap = this.rules.block.fences.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: 'code', - raw: raw, - lang: cap[2] ? cap[2].trim() : cap[2], - text: cap[3] || '' - }); + if (token = this.tokenizer.fences(obj)) { + tokens.push(token); continue; } // heading - if (cap = this.rules.block.heading.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: 'heading', - raw: raw, - depth: cap[1].length, - text: cap[2] - }); + if (token = this.tokenizer.heading(obj)) { + tokens.push(token); continue; } // table no leading pipe (gfm) - if (cap = this.rules.block.nptable.exec(src)) { - item = { - type: 'table', - header: splitCells$1(cap[1].replace(/^ *| *\| *$/g, '')), - align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), - cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [] - }; - - if (item.header.length === item.align.length) { - src = src.substring(cap[0].length); - raw = cap[0]; - item.raw = raw; - l = item.align.length; - - for (i = 0; i < l; i++) { - if (/^ *-+: *$/.test(item.align[i])) { - item.align[i] = 'right'; - } else if (/^ *:-+: *$/.test(item.align[i])) { - item.align[i] = 'center'; - } else if (/^ *:-+ *$/.test(item.align[i])) { - item.align[i] = 'left'; - } else { - item.align[i] = null; - } - } - - l = item.cells.length; - - for (i = 0; i < l; i++) { - item.cells[i] = splitCells$1(item.cells[i], item.header.length); - } - - tokens.push(item); - continue; - } + if (token = this.tokenizer.nptable(obj)) { + tokens.push(token); + continue; } // hr - if (cap = this.rules.block.hr.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: 'hr', - raw: raw - }); + if (token = this.tokenizer.hr(obj)) { + tokens.push(token); continue; } // blockquote @@ -788,28 +1441,17 @@ } // html - if (cap = this.rules.block.html.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: this.options.sanitize ? 'paragraph' : 'html', - raw: raw, - pre: !this.options.sanitizer && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'), - text: this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape$1(cap[0]) : cap[0] - }); + if (token = this.tokenizer.html(obj)) { + tokens.push(token); continue; } // def - if (top && (cap = this.rules.block.def.exec(src))) { - src = src.substring(cap[0].length); - if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1); - tag = cap[1].toLowerCase().replace(/\s+/g, ' '); - - if (!this.tokens.links[tag]) { - this.tokens.links[tag] = { - href: cap[2], - title: cap[3] + if (top && (token = this.tokenizer.def(obj))) { + if (!this.tokens.links[token.tag]) { + this.tokens.links[token.tag] = { + href: token.href, + title: token.title }; } @@ -817,85 +1459,35 @@ } // table (gfm) - if (cap = this.rules.block.table.exec(src)) { - item = { - type: 'table', - header: splitCells$1(cap[1].replace(/^ *| *\| *$/g, '')), - align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), - cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [] - }; - - if (item.header.length === item.align.length) { - src = src.substring(cap[0].length); - item.raw = cap[0]; - l = item.align.length; - - for (i = 0; i < l; i++) { - if (/^ *-+: *$/.test(item.align[i])) { - item.align[i] = 'right'; - } else if (/^ *:-+: *$/.test(item.align[i])) { - item.align[i] = 'center'; - } else if (/^ *:-+ *$/.test(item.align[i])) { - item.align[i] = 'left'; - } else { - item.align[i] = null; - } - } - - l = item.cells.length; - - for (i = 0; i < l; i++) { - item.cells[i] = splitCells$1(item.cells[i].replace(/^ *\| *| *\| *$/g, ''), item.header.length); - } - - tokens.push(item); - continue; - } + if (token = this.tokenizer.table(obj)) { + tokens.push(token); + continue; } // lheading - if (cap = this.rules.block.lheading.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: 'heading', - raw: raw, - depth: cap[2].charAt(0) === '=' ? 1 : 2, - text: cap[1] - }); + if (token = this.tokenizer.lheading(obj)) { + tokens.push(token); continue; } // top-level paragraph - if (top && (cap = this.rules.block.paragraph.exec(src))) { - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: 'paragraph', - raw: raw, - text: cap[1].charAt(cap[1].length - 1) === '\n' ? cap[1].slice(0, -1) : cap[1] - }); + if (top && (token = this.tokenizer.paragraph(obj))) { + tokens.push(token); continue; } // text - if (cap = this.rules.block.text.exec(src)) { - // Top-level should never reach here. - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: 'text', - raw: raw, - text: cap[0] - }); + if (token = this.tokenizer.text(obj)) { + tokens.push(token); continue; } - if (src) { - var errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0); + if (obj.src) { + var errMsg = 'Infinite loop on byte: ' + obj.src.charCodeAt(0); if (this.options.silent) { console.error(errMsg); + break; } else { throw new Error(errMsg); } @@ -992,108 +1584,28 @@ linkLen, raw; - while (src) { + while (obj.src) { // escape - if (cap = this.rules.inline.escape.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - text = escape$1(cap[1]); - out += text; - tokens.push({ - type: 'escape', - raw: raw, - text: text - }); + if (token = this.tokenizer.escape(obj)) { + tokens.push(token); continue; } // tag - if (cap = this.rules.inline.tag.exec(src)) { - if (!this.inLink && /^/i.test(cap[0])) { - this.inLink = false; - } - - if (!this.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { - this.inRawBlock = true; - } else if (this.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { - this.inRawBlock = false; - } - - src = src.substring(cap[0].length); - raw = cap[0]; - text = this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape$1(cap[0]) : cap[0]; - tokens.push({ - type: this.options.sanitize ? 'text' : 'html', - raw: raw, - text: text - }); - out += text; + if (token = this.tokenizer.tag(obj)) { + tokens.push(token); continue; } // link - if (cap = this.rules.inline.link.exec(src)) { - lastParenIndex = findClosingBracket$1(cap[2], '()'); - - if (lastParenIndex > -1) { - start = cap[0].indexOf('!') === 0 ? 5 : 4; - linkLen = start + cap[1].length + lastParenIndex; - cap[2] = cap[2].substring(0, lastParenIndex); - cap[0] = cap[0].substring(0, linkLen).trim(); - cap[3] = ''; - } - - src = src.substring(cap[0].length); - raw = cap[0]; - this.inLink = true; - href = cap[2]; - - if (this.options.pedantic) { - link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href); - - if (link) { - href = link[1]; - title = link[3]; - } else { - title = ''; - } - } else { - title = cap[3] ? cap[3].slice(1, -1) : ''; - } - - href = href.trim().replace(/^<([\s\S]*)>$/, '$1'); - out += this.outputLink(cap, { - href: this.escapes(href), - title: this.escapes(title) - }, tokens, raw); - this.inLink = false; + if (token = this.tokenizer.link(obj)) { + tokens.push(token); continue; } // reflink, nolink - if ((cap = this.rules.inline.reflink.exec(src)) || (cap = this.rules.inline.nolink.exec(src))) { - src = src.substring(cap[0].length); - raw = cap[0]; - link = (cap[2] || cap[1]).replace(/\s+/g, ' '); - link = this.tokens.links[link.toLowerCase()]; - - if (!link || !link.href) { - text = cap[0].charAt(0); - out += text; - tokens.push({ - type: 'text', - raw: text, - text: text - }); - src = cap[0].substring(1) + src; - continue; - } - - this.inLink = true; - out += this.outputLink(cap, link, tokens, raw); - this.inLink = false; + if (token = this.tokenizer.reflink(obj)) { + tokens.push(token); continue; } // strong @@ -1130,28 +1642,14 @@ } // code - if (cap = this.rules.inline.code.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - text = escape$1(cap[2].trim(), true); - tokens.push({ - type: 'codespan', - raw: raw, - text: text - }); - out += text; + if (token = this.tokenizer.codespan(obj)) { + tokens.push(token); continue; } // br - if (cap = this.rules.inline.br.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: 'br', - raw: raw - }); - out += '\n'; + if (token = this.tokenizer.br(obj)) { + tokens.push(token); continue; } // del (gfm) @@ -1172,96 +1670,29 @@ } // autolink - if (cap = this.rules.inline.autolink.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - - if (cap[2] === '@') { - text = escape$1(this.options.mangle ? this.mangle(cap[1]) : cap[1]); - href = 'mailto:' + text; - } else { - text = escape$1(cap[1]); - href = text; - } - - tokens.push({ - type: 'link', - raw: raw, - text: text, - href: href, - tokens: [{ - type: 'text', - raw: text, - text: text - }] - }); - out += text; + if (token = this.tokenizer.autolink(obj)) { + tokens.push(token); continue; } // url (gfm) - if (!this.inLink && (cap = this.rules.inline.url.exec(src))) { - if (cap[2] === '@') { - text = escape$1(this.options.mangle ? this.mangle(cap[0]) : cap[0]); - href = 'mailto:' + text; - } else { - // do extended autolink path validation - do { - prevCapZero = cap[0]; - cap[0] = this.rules.inline._backpedal.exec(cap[0])[0]; - } while (prevCapZero !== cap[0]); - - text = escape$1(cap[0]); - - if (cap[1] === 'www.') { - href = 'http://' + text; - } else { - href = text; - } - } - - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: 'link', - raw: raw, - text: text, - href: href, - tokens: [{ - type: 'text', - raw: text, - text: text - }] - }); - out += text; + if (token = this.tokenizer.url(obj)) { + tokens.push(token); continue; } // text - if (cap = this.rules.inline.text.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - - if (this.inRawBlock) { - text = this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape$1(cap[0]) : cap[0]; - } else { - text = escape$1(this.options.smartypants ? this.smartypants(cap[0]) : cap[0]); - } - - tokens.push({ - type: 'text', - raw: raw, - text: text - }); - out += text; + if (token = this.tokenizer.inlineText(obj)) { + tokens.push(token); continue; } - if (src) { - var errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0); + if (obj.src) { + var errMsg = 'Infinite loop on byte: ' + obj.src.charCodeAt(0); if (this.options.silent) { console.error(errMsg); + break; } else { throw new Error(errMsg); } @@ -1352,7 +1783,7 @@ get: function get() { return { block: block$1, - inline: inline$1 + inline: inline$2 }; } }]); @@ -1360,16 +1791,16 @@ return Lexer; }(); - var defaults$2 = defaults.defaults; + var defaults$3 = defaults.defaults; var cleanUrl$1 = helpers.cleanUrl, - escape$2 = helpers.escape; + escape$1 = helpers.escape; /** * Renderer */ var Renderer_1 = /*#__PURE__*/function () { function Renderer(options) { - this.options = options || defaults$2; + this.options = options || defaults$3; } var _proto = Renderer.prototype; @@ -1387,10 +1818,10 @@ } if (!lang) { - return '
' + (escaped ? _code : escape$2(_code, true)) + '
'; + return '
' + (escaped ? _code : escape$1(_code, true)) + '
'; } - return '
' + (escaped ? _code : escape$2(_code, true)) + '
\n'; + return '
' + (escaped ? _code : escape$1(_code, true)) + '
\n'; }; _proto.blockquote = function blockquote(quote) { @@ -1475,7 +1906,7 @@ return text; } - var out = '
An error occurred:

' + escape$3(e.message + '', true) + '
'; + return '

An error occurred:

' + escape$2(e.message + '', true) + '
'; } throw e; @@ -2029,7 +2460,7 @@ }; marked.getDefaults = getDefaults; - marked.defaults = defaults$4; + marked.defaults = defaults$5; /** * Expose */ @@ -2040,6 +2471,7 @@ marked.TextRenderer = TextRenderer_1; marked.Lexer = Lexer_1; marked.lexer = Lexer_1.lex; + marked.Tokenizer = Tokenizer_1; marked.Slugger = Slugger_1; marked.parse = marked; var marked_1 = marked; diff --git a/marked.min.js b/marked.min.js index 085feedc0b..3ff5ab9b28 100644 --- a/marked.min.js +++ b/marked.min.js @@ -3,4 +3,4 @@ * Copyright (c) 2011-2020, Christopher Jeffrey. (MIT Licensed) * https://github.com/markedjs/marked */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).marked=t()}(this,function(){"use strict";function i(e,t){for(var n=0;n"']/),s=/[&<>"']/g,l=/[<>"']|&(?!#?\w+;)/,a=/[<>"']|&(?!#?\w+;)/g,o={"&":"&","<":"<",">":">",'"':""","'":"'"};var c=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;function h(e){return e.replace(c,function(e,t){return"colon"===(t=t.toLowerCase())?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""})}var u=/(^|[^\[])\^/g;var p=/[^\w:]/g,g=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;var f={},d=/^[^:]+:\/*[^/]*$/,b=/^([^:]+:)[\s\S]*$/,k=/^([^:]+:\/*[^/]*)[\s\S]*$/;function m(e,t){f[" "+e]||(d.test(e)?f[" "+e]=e+"/":f[" "+e]=x(e,"/",!0));var n=-1===(e=f[" "+e]).indexOf(":");return"//"===t.substring(0,2)?n?t:e.replace(b,"$1")+t:"/"===t.charAt(0)?n?t:e.replace(k,"$1")+t:e+t}function x(e,t,n){var r=e.length;if(0===r)return"";for(var s=0;st)n.splice(t);else for(;n.length ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:"^ {0,3}(?:<(script|pre|style)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?\\?>\\n*|\\n*|\\n*|)[\\s\\S]*?(?:\\n{2,}|$)|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$))",def:/^ {0,3}\[(label)\]: *\n? *]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,nptable:R,table:R,lheading:/^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,_paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html)[^\n]+)*)/,text:/^[^\n]+/,_label:/(?!\s*\])(?:\\[\[\]]|[^\[\]])+/,_title:/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/};I.def=Z(I.def).replace("label",I._label).replace("title",I._title).getRegex(),I.bullet=/(?:[*+-]|\d{1,9}\.)/,I.item=/^( *)(bull) ?[^\n]*(?:\n(?!\1bull ?)[^\n]*)*/,I.item=Z(I.item,"gm").replace(/bull/g,I.bullet).getRegex(),I.list=Z(I.list).replace(/bull/g,I.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+I.def.source+")").getRegex(),I._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",I._comment=//,I.html=Z(I.html,"i").replace("comment",I._comment).replace("tag",I._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),I.paragraph=Z(I._paragraph).replace("hr",I.hr).replace("heading"," {0,3}#{1,6} ").replace("|lheading","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",I._tag).getRegex(),I.blockquote=Z(I.blockquote).replace("paragraph",I.paragraph).getRegex(),I.normal=q({},I),I.gfm=q({},I.normal,{nptable:"^ *([^|\\n ].*\\|.*)\\n *([-:]+ *\\|[-| :]*)(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)",table:"^ *\\|(.+)\\n *\\|?( *[-:]+[-| :]*)(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)"}),I.gfm.nptable=Z(I.gfm.nptable).replace("hr",I.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",I._tag).getRegex(),I.gfm.table=Z(I.gfm.table).replace("hr",I.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",I._tag).getRegex(),I.pedantic=q({},I.normal,{html:Z("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",I._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,fences:R,paragraph:Z(I.normal._paragraph).replace("hr",I.hr).replace("heading"," *#{1,6} *[^\n]").replace("lheading",I.lheading).replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").getRegex()});var L={escape:/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:R,tag:"^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^",link:/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,strong:/^__([^\s_])__(?!_)|^\*\*([^\s*])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/,em:/^_([^\s_])_(?!_)|^\*([^\s*<\[])\*(?!\*)|^_([^\s<][\s\S]*?[^\s_])_(?!_|[^\spunctuation])|^_([^\s_<][\s\S]*?[^\s])_(?!_|[^\spunctuation])|^\*([^\s<"][\s\S]*?[^\s\*])\*(?!\*|[^\spunctuation])|^\*([^\s*"<\[][\s\S]*?[^\s])\*(?!\*)/,code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:R,text:/^(`+|[^`])(?:[\s\S]*?(?:(?=[\\?@\\[^_{|}~"};L.em=Z(L.em).replace(/punctuation/g,L._punctuation).getRegex(),L._escapes=/\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g,L._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,L._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])?)+(?![-_])/,L.autolink=Z(L.autolink).replace("scheme",L._scheme).replace("email",L._email).getRegex(),L._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,L.tag=Z(L.tag).replace("comment",I._comment).replace("attribute",L._attribute).getRegex(),L._label=/(?:\[[^\[\]]*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,L._href=/<(?:\\[<>]?|[^\s<>\\])*>|[^\s\x00-\x1f]*/,L._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,L.link=Z(L.link).replace("label",L._label).replace("href",L._href).replace("title",L._title).getRegex(),L.reflink=Z(L.reflink).replace("label",L._label).getRegex(),L.normal=q({},L),L.pedantic=q({},L.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,link:Z(/^!?\[(label)\]\((.*?)\)/).replace("label",L._label).getRegex(),reflink:Z(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",L._label).getRegex()}),L.gfm=q({},L.normal,{escape:Z(L.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^~+(?=\S)([\s\S]*?\S)~+/,text:/^(`+|[^`])(?:[\s\S]*?(?:(?=[\\ ?/gm,""),t.push({type:"blockquote",raw:x,tokens:this.blockTokens(i,[],n)});else if(i=this.rules.block.list.exec(e))for(e=e.substring(i[0].length),c={type:"list",raw:x=i[0],ordered:f=1<(l=i[2]).length,start:f?+l:"",loose:!1,items:[]},t.push(c),r=!1,g=(i=i[0].match(this.rules.block.item)).length,u=0;u/i.test(a[0])&&(this.inLink=!1),!this.inRawBlock&&/^<(pre|code|kbd|script)(\s|>)/i.test(a[0])?this.inRawBlock=!0:this.inRawBlock&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(a[0])&&(this.inRawBlock=!1),e=e.substring(a[0].length),u=a[0],r=this.options.sanitize?this.options.sanitizer?this.options.sanitizer(a[0]):P(a[0]):a[0],t.push({type:this.options.sanitize?"text":"html",raw:u,text:r}),p+=r;else if(a=this.rules.inline.link.exec(e))-1<(c=B(a[2],"()"))&&(h=(0===a[0].indexOf("!")?5:4)+a[1].length+c,a[2]=a[2].substring(0,c),a[0]=a[0].substring(0,h).trim(),a[3]=""),e=e.substring(a[0].length),u=a[0],this.inLink=!0,i=a[2],l=this.options.pedantic?(n=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(i))?(i=n[1],n[3]):"":a[3]?a[3].slice(1,-1):"",i=i.trim().replace(/^<([\s\S]*)>$/,"$1"),p+=this.outputLink(a,{href:this.escapes(i),title:this.escapes(l)},t,u),this.inLink=!1;else if((a=this.rules.inline.reflink.exec(e))||(a=this.rules.inline.nolink.exec(e))){if(e=e.substring(a[0].length),u=a[0],n=(a[2]||a[1]).replace(/\s+/g," "),!(n=this.tokens.links[n.toLowerCase()])||!n.href){p+=r=a[0].charAt(0),t.push({type:"text",raw:r,text:r}),e=a[0].substring(1)+e;continue}this.inLink=!0,p+=this.outputLink(a,n,t,u),this.inLink=!1}else if(a=this.rules.inline.strong.exec(e))e=e.substring(a[0].length),u=a[0],s=t?[]:null,r=this.inlineTokens(a[4]||a[3]||a[2]||a[1],s),t.push({type:"strong",raw:u,text:r,tokens:s}),p+=r;else if(a=this.rules.inline.em.exec(e))e=e.substring(a[0].length),u=a[0],s=t?[]:null,r=this.inlineTokens(a[6]||a[5]||a[4]||a[3]||a[2]||a[1],s),t.push({type:"em",raw:u,text:r,tokens:s}),p+=r;else if(a=this.rules.inline.code.exec(e))e=e.substring(a[0].length),u=a[0],r=P(a[2].trim(),!0),t.push({type:"codespan",raw:u,text:r}),p+=r;else if(a=this.rules.inline.br.exec(e))e=e.substring(a[0].length),u=a[0],t.push({type:"br",raw:u}),p+="\n";else if(a=this.rules.inline.del.exec(e))e=e.substring(a[0].length),u=a[0],s=t?[]:null,r=this.inlineTokens(a[1],s),t.push({type:"del",raw:u,text:r,tokens:s}),p+=r;else if(a=this.rules.inline.autolink.exec(e))e=e.substring(a[0].length),u=a[0],i="@"===a[2]?"mailto:"+(r=P(this.options.mangle?this.mangle(a[1]):a[1])):r=P(a[1]),t.push({type:"link",raw:u,text:r,href:i,tokens:[{type:"text",raw:r,text:r}]}),p+=r;else if(this.inLink||!(a=this.rules.inline.url.exec(e))){if(a=this.rules.inline.text.exec(e))e=e.substring(a[0].length),u=a[0],r=this.inRawBlock?this.options.sanitize?this.options.sanitizer?this.options.sanitizer(a[0]):P(a[0]):a[0]:P(this.options.smartypants?this.smartypants(a[0]):a[0]),t.push({type:"text",raw:u,text:r}),p+=r;else if(e){var g="Infinite loop on byte: "+e.charCodeAt(0);if(!this.options.silent)throw new Error(g);console.error(g)}}else{if("@"===a[2])i="mailto:"+(r=P(this.options.mangle?this.mangle(a[0]):a[0]));else{for(;o=a[0],a[0]=this.rules.inline._backpedal.exec(a[0])[0],o!==a[0];);r=P(a[0]),i="www."===a[1]?"http://"+r:r}e=e.substring(a[0].length),u=a[0],t.push({type:"link",raw:u,text:r,href:i,tokens:[{type:"text",raw:r,text:r}]}),p+=r}return p},s.escapes=function(e){return e?e.replace(D._escapes,"$1"):e},s.outputLink=function(e,t,n,r){var s=t.href,i=t.title?P(t.title):null,l=n?[]:null;if("!"!==e[0].charAt(0)){var a=this.inlineTokens(e[1],l);return n.push({type:"link",raw:r,text:a,href:s,title:i,tokens:l}),a}var o=P(e[1]);return n.push({type:"image",raw:r,text:o,href:s,title:i}),o},s.smartypants=function(e){return e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")},s.mangle=function(e){var t,n,r="",s=e.length;for(t=0;t'+(n?e:X(e,!0))+"\n":"
"+(n?e:X(e,!0))+"
"},t.blockquote=function(e){return"
\n"+e+"
\n"},t.html=function(e){return e},t.heading=function(e,t,n,r){return this.options.headerIds?"'+e+"\n":""+e+"\n"},t.hr=function(){return this.options.xhtml?"
\n":"
\n"},t.list=function(e,t,n){var r=t?"ol":"ul";return"<"+r+(t&&1!==n?' start="'+n+'"':"")+">\n"+e+"\n"},t.listitem=function(e){return"
  • "+e+"
  • \n"},t.checkbox=function(e){return" "},t.paragraph=function(e){return"

    "+e+"

    \n"},t.table=function(e,t){return"\n\n"+e+"\n"+(t=t&&""+t+"")+"
    \n"},t.tablerow=function(e){return"\n"+e+"\n"},t.tablecell=function(e,t){var n=t.header?"th":"td";return(t.align?"<"+n+' align="'+t.align+'">':"<"+n+">")+e+"\n"},t.strong=function(e){return""+e+""},t.em=function(e){return""+e+""},t.codespan=function(e){return""+e+""},t.br=function(){return this.options.xhtml?"
    ":"
    "},t.del=function(e){return""+e+""},t.link=function(e,t,n){if(null===(e=N(this.options.sanitize,this.options.baseUrl,e)))return n;var r='
    "},t.image=function(e,t,n){if(null===(e=N(this.options.sanitize,this.options.baseUrl,e)))return n;var r=''+n+'":">"},t.text=function(e){return e},e}(),M=function(){function e(){}var t=e.prototype;return t.strong=function(e){return e},t.em=function(e){return e},t.codespan=function(e){return e},t.del=function(e){return e},t.html=function(e){return e},t.text=function(e){return e},t.link=function(e,t,n){return""+n},t.image=function(e,t,n){return""+n},t.br=function(){return""},e}(),V=function(){function e(){this.seen={}}return e.prototype.slug=function(e){var t=e.toLowerCase().trim().replace(/<[!\/a-z].*?>/gi,"").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g,"").replace(/\s/g,"-");if(this.seen.hasOwnProperty(t))for(var n=t;this.seen[n]++,t=n+"-"+this.seen[n],this.seen.hasOwnProperty(t););return this.seen[t]=0,t},e}(),H=t.defaults,J=_,K=function(){function n(e){this.options=e||H,this.options.renderer=this.options.renderer||new G,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new M,this.slugger=new V}n.parse=function(e,t){return new n(t).parse(e)};var e=n.prototype;return e.parse=function(e,t){void 0===t&&(t=!0);var n,r,s,i,l,a,o,c,h,u,p,g,f,d,b,k,m,x,w="",_=e.length;for(n=0;n<_;n++)switch((u=e[n]).type){case"space":continue;case"hr":w+=this.renderer.hr();continue;case"heading":w+=this.renderer.heading(this.parseInline(u.tokens),u.depth,J(this.parseInline(u.tokens,this.textRenderer)),this.slugger);continue;case"code":w+=this.renderer.code(u.text,u.lang,u.escaped);continue;case"table":for(o=c="",i=u.header.length,r=0;rAn error occurred:

    "+Y(e.message+"",!0)+"
    ";throw e}}return re.options=re.setOptions=function(e){return Q(re.defaults,e),te(re.defaults),re},re.getDefaults=ee,re.defaults=ne,re.Parser=K,re.parser=K.parse,re.Renderer=G,re.TextRenderer=M,re.Lexer=U,re.lexer=U.lex,re.Slugger=V,re.parse=re}); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).marked=t()}(this,function(){"use strict";function i(e,t){for(var n=0;n"']/),s=/[&<>"']/g,l=/[<>"']|&(?!#?\w+;)/,a=/[<>"']|&(?!#?\w+;)/g,o={"&":"&","<":"<",">":">",'"':""","'":"'"};var c=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;function h(e){return e.replace(c,function(e,t){return"colon"===(t=t.toLowerCase())?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""})}var u=/(^|[^\[])\^/g;var p=/[^\w:]/g,g=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;var f={},d=/^[^:]+:\/*[^/]*$/,b=/^([^:]+:)[\s\S]*$/,k=/^([^:]+:\/*[^/]*)[\s\S]*$/;function m(e,t){f[" "+e]||(d.test(e)?f[" "+e]=e+"/":f[" "+e]=x(e,"/",!0));var n=-1===(e=f[" "+e]).indexOf(":");return"//"===t.substring(0,2)?n?t:e.replace(b,"$1")+t:"/"===t.charAt(0)?n?t:e.replace(k,"$1")+t:e+t}function x(e,t,n){var r=e.length;if(0===r)return"";for(var s=0;st)n.splice(t);else for(;n.length ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:"^ {0,3}(?:<(script|pre|style)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?\\?>\\n*|\\n*|\\n*|)[\\s\\S]*?(?:\\n{2,}|$)|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$))",def:/^ {0,3}\[(label)\]: *\n? *]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,nptable:R,table:R,lheading:/^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,_paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html)[^\n]+)*)/,text:/^[^\n]+/,_label:/(?!\s*\])(?:\\[\[\]]|[^\[\]])+/,_title:/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/};I.def=Z(I.def).replace("label",I._label).replace("title",I._title).getRegex(),I.bullet=/(?:[*+-]|\d{1,9}\.)/,I.item=/^( *)(bull) ?[^\n]*(?:\n(?!\1bull ?)[^\n]*)*/,I.item=Z(I.item,"gm").replace(/bull/g,I.bullet).getRegex(),I.list=Z(I.list).replace(/bull/g,I.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+I.def.source+")").getRegex(),I._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",I._comment=//,I.html=Z(I.html,"i").replace("comment",I._comment).replace("tag",I._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),I.paragraph=Z(I._paragraph).replace("hr",I.hr).replace("heading"," {0,3}#{1,6} ").replace("|lheading","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",I._tag).getRegex(),I.blockquote=Z(I.blockquote).replace("paragraph",I.paragraph).getRegex(),I.normal=q({},I),I.gfm=q({},I.normal,{nptable:"^ *([^|\\n ].*\\|.*)\\n *([-:]+ *\\|[-| :]*)(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)",table:"^ *\\|(.+)\\n *\\|?( *[-:]+[-| :]*)(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)"}),I.gfm.nptable=Z(I.gfm.nptable).replace("hr",I.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",I._tag).getRegex(),I.gfm.table=Z(I.gfm.table).replace("hr",I.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",I._tag).getRegex(),I.pedantic=q({},I.normal,{html:Z("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",I._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,fences:R,paragraph:Z(I.normal._paragraph).replace("hr",I.hr).replace("heading"," *#{1,6} *[^\n]").replace("lheading",I.lheading).replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").getRegex()});var L={escape:/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:R,tag:"^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^",link:/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,strong:/^__([^\s_])__(?!_)|^\*\*([^\s*])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/,em:/^_([^\s_])_(?!_)|^\*([^\s*<\[])\*(?!\*)|^_([^\s<][\s\S]*?[^\s_])_(?!_|[^\spunctuation])|^_([^\s_<][\s\S]*?[^\s])_(?!_|[^\spunctuation])|^\*([^\s<"][\s\S]*?[^\s\*])\*(?!\*|[^\spunctuation])|^\*([^\s*"<\[][\s\S]*?[^\s])\*(?!\*)/,code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:R,text:/^(`+|[^`])(?:[\s\S]*?(?:(?=[\\?@\\[^_{|}~"};L.em=Z(L.em).replace(/punctuation/g,L._punctuation).getRegex(),L._escapes=/\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g,L._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,L._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])?)+(?![-_])/,L.autolink=Z(L.autolink).replace("scheme",L._scheme).replace("email",L._email).getRegex(),L._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,L.tag=Z(L.tag).replace("comment",I._comment).replace("attribute",L._attribute).getRegex(),L._label=/(?:\[[^\[\]]*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,L._href=/<(?:\\[<>]?|[^\s<>\\])*>|[^\s\x00-\x1f]*/,L._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,L.link=Z(L.link).replace("label",L._label).replace("href",L._href).replace("title",L._title).getRegex(),L.reflink=Z(L.reflink).replace("label",L._label).getRegex(),L.normal=q({},L),L.pedantic=q({},L.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,link:Z(/^!?\[(label)\]\((.*?)\)/).replace("label",L._label).getRegex(),reflink:Z(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",L._label).getRegex()}),L.gfm=q({},L.normal,{escape:Z(L.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^~+(?=\S)([\s\S]*?\S)~+/,text:/^(`+|[^`])(?:[\s\S]*?(?:(?=[\\ ?/gm,""),t.push({type:"blockquote",raw:x,tokens:this.blockTokens(i,[],n)});else if(i=this.rules.block.list.exec(e))for(e=e.substring(i[0].length),c={type:"list",raw:x=i[0],ordered:f=1<(l=i[2]).length,start:f?+l:"",loose:!1,items:[]},t.push(c),r=!1,g=(i=i[0].match(this.rules.block.item)).length,u=0;u/i.test(a[0])&&(this.inLink=!1),!this.inRawBlock&&/^<(pre|code|kbd|script)(\s|>)/i.test(a[0])?this.inRawBlock=!0:this.inRawBlock&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(a[0])&&(this.inRawBlock=!1),e=e.substring(a[0].length),u=a[0],r=this.options.sanitize?this.options.sanitizer?this.options.sanitizer(a[0]):P(a[0]):a[0],t.push({type:this.options.sanitize?"text":"html",raw:u,text:r}),p+=r;else if(a=this.rules.inline.link.exec(e))-1<(c=B(a[2],"()"))&&(h=(0===a[0].indexOf("!")?5:4)+a[1].length+c,a[2]=a[2].substring(0,c),a[0]=a[0].substring(0,h).trim(),a[3]=""),e=e.substring(a[0].length),u=a[0],this.inLink=!0,i=a[2],l=this.options.pedantic?(n=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(i))?(i=n[1],n[3]):"":a[3]?a[3].slice(1,-1):"",i=i.trim().replace(/^<([\s\S]*)>$/,"$1"),p+=this.outputLink(a,{href:this.escapes(i),title:this.escapes(l)},t,u),this.inLink=!1;else if((a=this.rules.inline.reflink.exec(e))||(a=this.rules.inline.nolink.exec(e))){if(e=e.substring(a[0].length),u=a[0],n=(a[2]||a[1]).replace(/\s+/g," "),!(n=this.tokens.links[n.toLowerCase()])||!n.href){p+=r=a[0].charAt(0),t.push({type:"text",raw:r,text:r}),e=a[0].substring(1)+e;continue}this.inLink=!0,p+=this.outputLink(a,n,t,u),this.inLink=!1}else if(a=this.rules.inline.strong.exec(e))e=e.substring(a[0].length),u=a[0],s=t?[]:null,r=this.inlineTokens(a[4]||a[3]||a[2]||a[1],s),t.push({type:"strong",raw:u,text:r,tokens:s}),p+=r;else if(a=this.rules.inline.em.exec(e))e=e.substring(a[0].length),u=a[0],s=t?[]:null,r=this.inlineTokens(a[6]||a[5]||a[4]||a[3]||a[2]||a[1],s),t.push({type:"em",raw:u,text:r,tokens:s}),p+=r;else if(a=this.rules.inline.code.exec(e))e=e.substring(a[0].length),u=a[0],r=P(a[2].trim(),!0),t.push({type:"codespan",raw:u,text:r}),p+=r;else if(a=this.rules.inline.br.exec(e))e=e.substring(a[0].length),u=a[0],t.push({type:"br",raw:u}),p+="\n";else if(a=this.rules.inline.del.exec(e))e=e.substring(a[0].length),u=a[0],s=t?[]:null,r=this.inlineTokens(a[1],s),t.push({type:"del",raw:u,text:r,tokens:s}),p+=r;else if(a=this.rules.inline.autolink.exec(e))e=e.substring(a[0].length),u=a[0],i="@"===a[2]?"mailto:"+(r=P(this.options.mangle?this.mangle(a[1]):a[1])):r=P(a[1]),t.push({type:"link",raw:u,text:r,href:i,tokens:[{type:"text",raw:r,text:r}]}),p+=r;else if(this.inLink||!(a=this.rules.inline.url.exec(e))){if(a=this.rules.inline.text.exec(e))e=e.substring(a[0].length),u=a[0],r=this.inRawBlock?this.options.sanitize?this.options.sanitizer?this.options.sanitizer(a[0]):P(a[0]):a[0]:P(this.options.smartypants?this.smartypants(a[0]):a[0]),t.push({type:"text",raw:u,text:r}),p+=r;else if(e){var g="Infinite loop on byte: "+e.charCodeAt(0);if(!this.options.silent)throw new Error(g);console.error(g)}}else{if("@"===a[2])i="mailto:"+(r=P(this.options.mangle?this.mangle(a[0]):a[0]));else{for(;o=a[0],a[0]=this.rules.inline._backpedal.exec(a[0])[0],o!==a[0];);r=P(a[0]),i="www."===a[1]?"http://"+r:r}e=e.substring(a[0].length),u=a[0],t.push({type:"link",raw:u,text:r,href:i,tokens:[{type:"text",raw:r,text:r}]}),p+=r}return p},s.escapes=function(e){return e?e.replace(D._escapes,"$1"):e},s.outputLink=function(e,t,n,r){var s=t.href,i=t.title?P(t.title):null,l=n?[]:null;if("!"!==e[0].charAt(0)){var a=this.inlineTokens(e[1],l);return n.push({type:"link",raw:r,text:a,href:s,title:i,tokens:l}),a}var o=P(e[1]);return n.push({type:"image",raw:r,text:o,href:s,title:i}),o},s.smartypants=function(e){return e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")},s.mangle=function(e){var t,n,r="",s=e.length;for(t=0;t'+(n?e:X(e,!0))+"\n":"
    "+(n?e:X(e,!0))+"
    "},t.blockquote=function(e){return"
    \n"+e+"
    \n"},t.html=function(e){return e},t.heading=function(e,t,n,r){return this.options.headerIds?"'+e+"\n":""+e+"\n"},t.hr=function(){return this.options.xhtml?"
    \n":"
    \n"},t.list=function(e,t,n){var r=t?"ol":"ul";return"<"+r+(t&&1!==n?' start="'+n+'"':"")+">\n"+e+"\n"},t.listitem=function(e){return"
  • "+e+"
  • \n"},t.checkbox=function(e){return" "},t.paragraph=function(e){return"

    "+e+"

    \n"},t.table=function(e,t){return"\n\n"+e+"\n"+(t=t&&""+t+"")+"
    \n"},t.tablerow=function(e){return"\n"+e+"\n"},t.tablecell=function(e,t){var n=t.header?"th":"td";return(t.align?"<"+n+' align="'+t.align+'">':"<"+n+">")+e+"\n"},t.strong=function(e){return""+e+""},t.em=function(e){return""+e+""},t.codespan=function(e){return""+e+""},t.br=function(){return this.options.xhtml?"
    ":"
    "},t.del=function(e){return""+e+""},t.link=function(e,t,n){if(null===(e=N(this.options.sanitize,this.options.baseUrl,e)))return n;var r='
    "},t.image=function(e,t,n){if(null===(e=N(this.options.sanitize,this.options.baseUrl,e)))return n;var r=''+n+'":">"},t.text=function(e){return e},e}(),M=function(){function e(){}var t=e.prototype;return t.strong=function(e){return e},t.em=function(e){return e},t.codespan=function(e){return e},t.del=function(e){return e},t.html=function(e){return e},t.text=function(e){return e},t.link=function(e,t,n){return""+n},t.image=function(e,t,n){return""+n},t.br=function(){return""},e}(),V=function(){function e(){this.seen={}}return e.prototype.slug=function(e){var t=e.toLowerCase().trim().replace(/<[!\/a-z].*?>/gi,"").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g,"").replace(/\s/g,"-");if(this.seen.hasOwnProperty(t))for(var n=t;this.seen[n]++,t=n+"-"+this.seen[n],this.seen.hasOwnProperty(t););return this.seen[t]=0,t},e}(),H=t.defaults,J=_,K=function(){function n(e){this.options=e||H,this.options.renderer=this.options.renderer||new G,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new M,this.slugger=new V}n.parse=function(e,t){return new n(t).parse(e)};var e=n.prototype;return e.parse=function(e,t){void 0===t&&(t=!0);var n,r,s,i,l,a,o,c,h,u,p,g,f,d,b,k,m,x,w="",_=e.length;for(n=0;n<_;n++)switch((u=e[n]).type){case"space":continue;case"hr":w+=this.renderer.hr();continue;case"heading":w+=this.renderer.heading(this.parseInline(u.tokens),u.depth,J(this.parseInline(u.tokens,this.textRenderer)),this.slugger);continue;case"code":w+=this.renderer.code(u.text,u.lang,u.escaped);continue;case"table":for(o=c="",i=u.header.length,r=0;rAn error occurred:

    "+Y(e.message+"",!0)+"
    ";throw e}}return re.options=re.setOptions=function(e){return Q(re.defaults,e),te(re.defaults),re},re.getDefaults=ee,re.defaults=ne,re.Parser=K,re.parser=K.parse,re.Renderer=G,re.TextRenderer=M,re.Lexer=U,re.lexer=U.lex,re.Slugger=V,re.parse=re}); diff --git a/src/Lexer.js b/src/Lexer.js index b119241591..7ad44a2a3a 100644 --- a/src/Lexer.js +++ b/src/Lexer.js @@ -1,11 +1,5 @@ +const Tokenizer = require('./Tokenizer.js'); const { defaults } = require('./defaults.js'); -const { block, inline } = require('./rules.js'); -const { - rtrim, - splitCells, - escape, - findClosingBracket -} = require('./helpers.js'); /** * Block Lexer @@ -15,32 +9,17 @@ module.exports = class Lexer { this.tokens = []; this.tokens.links = Object.create(null); this.options = options || defaults; - this.rules = { - block: block.normal, - inline: inline.normal - }; - - if (this.options.pedantic) { - this.rules.block = block.pedantic; - this.rules.inline = inline.pedantic; - } else if (this.options.gfm) { - this.rules.block = block.gfm; - if (this.options.breaks) { - this.rules.inline = inline.breaks; - } else { - this.rules.inline = inline.gfm; - } - } + this.options.tokenizer = this.options.tokenizer || new Tokenizer(); + this.tokenizer = this.options.tokenizer; + this.tokenizer.options = this.options; + this.tokenizer.initialize(); } /** * Expose Block Rules */ static get rules() { - return { - block, - inline - }; + return Tokenizer.rules; } /** @@ -59,7 +38,7 @@ module.exports = class Lexer { .replace(/\r\n|\r/g, '\n') .replace(/\t/g, ' '); - this.blockTokens(src, this.tokens); + this.blockTokens(src, this.tokens, true); this.inline(this.tokens); @@ -69,347 +48,113 @@ module.exports = class Lexer { /** * Lexing */ - blockTokens(src, tokens, top = true) { + blockTokens(src, tokens = [], top = true) { src = src.replace(/^ +$/gm, ''); - let next, - loose, - cap, - bull, - b, - item, - list, - space, - i, - tag, - l, - isordered, - istask, - ischecked, - lastToken, - addBack, - raw; + let token; while (src) { // newline - if (cap = this.rules.block.newline.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - if (cap[0].length > 1) { - tokens.push({ - type: 'space', - raw - }); + if (token = this.tokenizer.space(this, src, tokens, top)) { + src = src.substring(token.raw.length); + if (token.type) { + tokens.push(token); } + continue; } // code - if (cap = this.rules.block.code.exec(src)) { - lastToken = tokens[tokens.length - 1]; - src = src.substring(cap[0].length); - raw = cap[0]; - // An indented code block cannot interrupt a paragraph. - if (lastToken && lastToken.type === 'paragraph') { - lastToken.text += '\n' + cap[0].trimRight(); - lastToken.raw += '\n' + raw; - } else { - cap = cap[0].replace(/^ {4}/gm, ''); - tokens.push({ - type: 'code', - raw, - codeBlockStyle: 'indented', - text: !this.options.pedantic - ? rtrim(cap, '\n') - : cap - }); - } + if (token = this.tokenizer.code(this, src, tokens, top)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // fences - if (cap = this.rules.block.fences.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: 'code', - raw, - lang: cap[2] ? cap[2].trim() : cap[2], - text: cap[3] || '' - }); + if (token = this.tokenizer.fences(this, src, tokens, top)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // heading - if (cap = this.rules.block.heading.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: 'heading', - raw, - depth: cap[1].length, - text: cap[2] - }); + if (token = this.tokenizer.heading(this, src, tokens, top)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // table no leading pipe (gfm) - if (cap = this.rules.block.nptable.exec(src)) { - item = { - type: 'table', - header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')), - align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), - cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [] - }; - - if (item.header.length === item.align.length) { - src = src.substring(cap[0].length); - raw = cap[0]; - item.raw = raw; - - l = item.align.length; - for (i = 0; i < l; i++) { - if (/^ *-+: *$/.test(item.align[i])) { - item.align[i] = 'right'; - } else if (/^ *:-+: *$/.test(item.align[i])) { - item.align[i] = 'center'; - } else if (/^ *:-+ *$/.test(item.align[i])) { - item.align[i] = 'left'; - } else { - item.align[i] = null; - } - } - - l = item.cells.length; - for (i = 0; i < l; i++) { - item.cells[i] = splitCells(item.cells[i], item.header.length); - } - - tokens.push(item); - - continue; - } + if (token = this.tokenizer.nptable(this, src, tokens, top)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; } // hr - if (cap = this.rules.block.hr.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: 'hr', - raw - }); + if (token = this.tokenizer.hr(this, src, tokens, top)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // blockquote - if (cap = this.rules.block.blockquote.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - - cap = cap[0].replace(/^ *> ?/gm, ''); - - tokens.push({ - type: 'blockquote', - raw, - tokens: this.blockTokens(cap, [], top) - }); - + if (token = this.tokenizer.blockquote(this, src, tokens, top)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // list - if (cap = this.rules.block.list.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - bull = cap[2]; - isordered = bull.length > 1; - - list = { - type: 'list', - raw, - ordered: isordered, - start: isordered ? +bull : '', - loose: false, - items: [] - }; - - tokens.push(list); - - // Get each top-level item. - cap = cap[0].match(this.rules.block.item); - - next = false; - - l = cap.length; - for (i = 0; i < l; i++) { - item = cap[i]; - raw = item.trim(); - - // Remove the list item's bullet - // so it is seen as the next token. - space = item.length; - item = item.replace(/^ *([*+-]|\d+\.) */, ''); - - // Outdent whatever the - // list item contains. Hacky. - if (~item.indexOf('\n ')) { - space -= item.length; - item = !this.options.pedantic - ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') - : item.replace(/^ {1,4}/gm, ''); - } - - // Determine whether the next list item belongs here. - // Backpedal if it does not belong in this list. - if (i !== l - 1) { - b = block.bullet.exec(cap[i + 1])[0]; - if (bull.length > 1 ? b.length === 1 - : (b.length > 1 || (this.options.smartLists && b !== bull))) { - addBack = cap.slice(i + 1).join('\n'); - src = addBack + src; - list.raw = list.raw.substring(list.raw.length - addBack.length); - i = l - 1; - } - } - - // Determine whether item is loose or not. - // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/ - // for discount behavior. - loose = next || /\n\n(?!\s*$)/.test(item); - if (i !== l - 1) { - next = item.charAt(item.length - 1) === '\n'; - if (!loose) loose = next; - } - - if (loose) { - list.loose = true; - } - - // Check for task list items - istask = /^\[[ xX]\] /.test(item); - ischecked = undefined; - if (istask) { - ischecked = item[1] !== ' '; - item = item.replace(/^\[[ xX]\] +/, ''); - } - - list.items.push({ - raw, - task: istask, - checked: ischecked, - loose: loose, - tokens: this.blockTokens(item, [], false) - }); - } - + if (token = this.tokenizer.list(this, src, tokens, top)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // html - if (cap = this.rules.block.html.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: this.options.sanitize - ? 'paragraph' - : 'html', - raw, - pre: !this.options.sanitizer - && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'), - text: this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape(cap[0])) : cap[0] - }); + if (token = this.tokenizer.html(this, src, tokens, top)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // def - if (top && (cap = this.rules.block.def.exec(src))) { - src = src.substring(cap[0].length); - if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1); - tag = cap[1].toLowerCase().replace(/\s+/g, ' '); - if (!this.tokens.links[tag]) { - this.tokens.links[tag] = { - href: cap[2], - title: cap[3] + if (top && (token = this.tokenizer.def(this, src, tokens, top))) { + src = src.substring(token.raw.length); + if (!this.tokens.links[token.tag]) { + this.tokens.links[token.tag] = { + href: token.href, + title: token.title }; } continue; } // table (gfm) - if (cap = this.rules.block.table.exec(src)) { - item = { - type: 'table', - header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')), - align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), - cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [] - }; - - if (item.header.length === item.align.length) { - src = src.substring(cap[0].length); - item.raw = cap[0]; - - l = item.align.length; - for (i = 0; i < l; i++) { - if (/^ *-+: *$/.test(item.align[i])) { - item.align[i] = 'right'; - } else if (/^ *:-+: *$/.test(item.align[i])) { - item.align[i] = 'center'; - } else if (/^ *:-+ *$/.test(item.align[i])) { - item.align[i] = 'left'; - } else { - item.align[i] = null; - } - } - - l = item.cells.length; - for (i = 0; i < l; i++) { - item.cells[i] = splitCells( - item.cells[i].replace(/^ *\| *| *\| *$/g, ''), - item.header.length); - } - - tokens.push(item); - - continue; - } + if (token = this.tokenizer.table(this, src, tokens, top)) { + src = src.substring(token.raw.length); + tokens.push(token); + continue; } // lheading - if (cap = this.rules.block.lheading.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: 'heading', - raw, - depth: cap[2].charAt(0) === '=' ? 1 : 2, - text: cap[1] - }); + if (token = this.tokenizer.lheading(this, src, tokens, top)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // top-level paragraph - if (top && (cap = this.rules.block.paragraph.exec(src))) { - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: 'paragraph', - raw, - text: cap[1].charAt(cap[1].length - 1) === '\n' - ? cap[1].slice(0, -1) - : cap[1] - }); + if (top && (token = this.tokenizer.paragraph(this, src, tokens, top))) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // text - if (cap = this.rules.block.text.exec(src)) { - // Top-level should never reach here. - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: 'text', - raw, - text: cap[0] - }); + if (token = this.tokenizer.text(this, src, tokens, top)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } @@ -417,6 +162,7 @@ module.exports = class Lexer { const errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0); if (this.options.silent) { console.error(errMsg); + break; } else { throw new Error(errMsg); } @@ -494,280 +240,91 @@ module.exports = class Lexer { /** * Lexing/Compiling */ - inlineTokens(src, tokens) { - let out = '', - link, - text, - newTokens, - href, - title, - cap, - prevCapZero, - lastParenIndex, - start, - linkLen, - raw; + inlineTokens(src, tokens = []) { + let token; while (src) { // escape - if (cap = this.rules.inline.escape.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - text = escape(cap[1]); - out += text; - tokens.push({ - type: 'escape', - raw, - text - }); + if (token = this.tokenizer.escape(this, src, tokens)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // tag - if (cap = this.rules.inline.tag.exec(src)) { - if (!this.inLink && /^
    /i.test(cap[0])) { - this.inLink = false; - } - if (!this.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { - this.inRawBlock = true; - } else if (this.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { - this.inRawBlock = false; - } - - src = src.substring(cap[0].length); - raw = cap[0]; - text = this.options.sanitize - ? (this.options.sanitizer - ? this.options.sanitizer(cap[0]) - : escape(cap[0])) - : cap[0]; - tokens.push({ - type: this.options.sanitize - ? 'text' - : 'html', - raw, - text - }); - out += text; + if (token = this.tokenizer.tag(this, src, tokens)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // link - if (cap = this.rules.inline.link.exec(src)) { - lastParenIndex = findClosingBracket(cap[2], '()'); - if (lastParenIndex > -1) { - start = cap[0].indexOf('!') === 0 ? 5 : 4; - linkLen = start + cap[1].length + lastParenIndex; - cap[2] = cap[2].substring(0, lastParenIndex); - cap[0] = cap[0].substring(0, linkLen).trim(); - cap[3] = ''; - } - src = src.substring(cap[0].length); - raw = cap[0]; - this.inLink = true; - href = cap[2]; - if (this.options.pedantic) { - link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href); - - if (link) { - href = link[1]; - title = link[3]; - } else { - title = ''; - } - } else { - title = cap[3] ? cap[3].slice(1, -1) : ''; - } - href = href.trim().replace(/^<([\s\S]*)>$/, '$1'); - out += this.outputLink(cap, { - href: this.escapes(href), - title: this.escapes(title) - }, tokens, raw); - this.inLink = false; + if (token = this.tokenizer.link(this, src, tokens)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // reflink, nolink - if ((cap = this.rules.inline.reflink.exec(src)) - || (cap = this.rules.inline.nolink.exec(src))) { - src = src.substring(cap[0].length); - raw = cap[0]; - link = (cap[2] || cap[1]).replace(/\s+/g, ' '); - link = this.tokens.links[link.toLowerCase()]; - if (!link || !link.href) { - text = cap[0].charAt(0); - out += text; - tokens.push({ - type: 'text', - raw: text, - text - }); - src = cap[0].substring(1) + src; - continue; - } - this.inLink = true; - out += this.outputLink(cap, link, tokens, raw); - this.inLink = false; + if (token = this.tokenizer.reflink(this, src, tokens)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // strong - if (cap = this.rules.inline.strong.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - newTokens = tokens ? [] : null; - text = this.inlineTokens(cap[4] || cap[3] || cap[2] || cap[1], newTokens); - - tokens.push({ - type: 'strong', - raw, - text, - tokens: newTokens - }); - out += text; + if (token = this.tokenizer.strong(this, src, tokens)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // em - if (cap = this.rules.inline.em.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - newTokens = tokens ? [] : null; - text = this.inlineTokens(cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1], newTokens); - tokens.push({ - type: 'em', - raw, - text, - tokens: newTokens - }); - out += text; + if (token = this.tokenizer.em(this, src, tokens)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // code - if (cap = this.rules.inline.code.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - text = escape(cap[2].trim(), true); - tokens.push({ - type: 'codespan', - raw, - text - }); - out += text; + if (token = this.tokenizer.codespan(this, src, tokens)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // br - if (cap = this.rules.inline.br.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: 'br', - raw - }); - out += '\n'; + if (token = this.tokenizer.br(this, src, tokens)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // del (gfm) - if (cap = this.rules.inline.del.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - newTokens = tokens ? [] : null; - text = this.inlineTokens(cap[1], newTokens); - tokens.push({ - type: 'del', - raw, - text, - tokens: newTokens - }); - out += text; + if (token = this.tokenizer.del(this, src, tokens)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // autolink - if (cap = this.rules.inline.autolink.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - if (cap[2] === '@') { - text = escape(this.options.mangle ? this.mangle(cap[1]) : cap[1]); - href = 'mailto:' + text; - } else { - text = escape(cap[1]); - href = text; - } - tokens.push({ - type: 'link', - raw, - text, - href, - tokens: [ - { - type: 'text', - raw: text, - text - } - ] - }); - out += text; + if (token = this.tokenizer.autolink(this, src, tokens)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // url (gfm) - if (!this.inLink && (cap = this.rules.inline.url.exec(src))) { - if (cap[2] === '@') { - text = escape(this.options.mangle ? this.mangle(cap[0]) : cap[0]); - href = 'mailto:' + text; - } else { - // do extended autolink path validation - do { - prevCapZero = cap[0]; - cap[0] = this.rules.inline._backpedal.exec(cap[0])[0]; - } while (prevCapZero !== cap[0]); - text = escape(cap[0]); - if (cap[1] === 'www.') { - href = 'http://' + text; - } else { - href = text; - } - } - src = src.substring(cap[0].length); - raw = cap[0]; - tokens.push({ - type: 'link', - raw, - text, - href, - tokens: [ - { - type: 'text', - raw: text, - text - } - ] - }); - out += text; + if (token = this.tokenizer.url(this, src, tokens)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // text - if (cap = this.rules.inline.text.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - if (this.inRawBlock) { - text = this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape(cap[0])) : cap[0]; - } else { - text = escape(this.options.smartypants ? this.smartypants(cap[0]) : cap[0]); - } - tokens.push({ - type: 'text', - raw, - text - }); - out += text; + if (token = this.tokenizer.inlineText(this, src, tokens)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } @@ -775,89 +332,13 @@ module.exports = class Lexer { const errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0); if (this.options.silent) { console.error(errMsg); + break; } else { throw new Error(errMsg); } } } - return out; - } - - escapes(text) { - return text ? text.replace(inline._escapes, '$1') : text; - } - - /** - * tokenize Link - */ - outputLink(cap, link, tokens, raw) { - const href = link.href; - const title = link.title ? escape(link.title) : null; - const newTokens = tokens ? [] : null; - - if (cap[0].charAt(0) !== '!') { - const text = this.inlineTokens(cap[1], newTokens); - tokens.push({ - type: 'link', - raw, - text, - href, - title, - tokens: newTokens - }); - return text; - } else { - const text = escape(cap[1]); - tokens.push({ - type: 'image', - raw, - text, - href, - title - }); - return text; - } - } - - /** - * Smartypants Transformations - */ - smartypants(text) { - return text - // em-dashes - .replace(/---/g, '\u2014') - // en-dashes - .replace(/--/g, '\u2013') - // opening singles - .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018') - // closing singles & apostrophes - .replace(/'/g, '\u2019') - // opening doubles - .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c') - // closing doubles - .replace(/"/g, '\u201d') - // ellipses - .replace(/\.{3}/g, '\u2026'); - } - - /** - * Mangle Links - */ - mangle(text) { - let out = '', - i, - ch; - - const l = text.length; - for (i = 0; i < l; i++) { - ch = text.charCodeAt(i); - if (Math.random() > 0.5) { - ch = 'x' + ch.toString(16); - } - out += '&#' + ch + ';'; - } - - return out; + return tokens; } }; diff --git a/src/Tokenizer.js b/src/Tokenizer.js new file mode 100644 index 0000000000..c8ca37f404 --- /dev/null +++ b/src/Tokenizer.js @@ -0,0 +1,663 @@ +const { defaults } = require('./defaults.js'); +const { + rtrim, + splitCells, + escape, + findClosingBracket +} = require('./helpers.js'); +const { block, inline } = require('./rules.js'); + +function outputLink(cap, link, tokens, raw, lexer) { + const href = link.href; + const title = link.title ? escape(link.title) : null; + + if (cap[0].charAt(0) !== '!') { + return { + type: 'link', + raw, + href, + title, + tokens: lexer.inlineTokens(cap[1]) + }; + } else { + return { + type: 'image', + raw, + text: escape(cap[1]), + href, + title + }; + } +} + +/** + * Tokenizer + */ +module.exports = class Tokenizer { + constructor(options) { + this.options = options || defaults; + this.initialize(); + } + + initialize() { + this.inLink = false; + this.inRawBlock = false; + + this.rules = { + block: block.normal, + inline: inline.normal + }; + + if (this.options.pedantic) { + this.rules.block = block.pedantic; + this.rules.inline = inline.pedantic; + } else if (this.options.gfm) { + this.rules.block = block.gfm; + if (this.options.breaks) { + this.rules.inline = inline.breaks; + } else { + this.rules.inline = inline.gfm; + } + } + } + + /** + * Expose Block Rules + */ + static get rules() { + return { + block, + inline + }; + } + + space(lexer, src, tokens, top) { + const cap = this.rules.block.newline.exec(src); + if (cap) { + if (cap[0].length > 1) { + return { + type: 'space', + raw: cap[0] + }; + } + return { raw: '\n' }; + } + } + + code(lexer, src, tokens, top) { + const cap = this.rules.block.code.exec(src); + if (cap) { + const lastToken = tokens[tokens.length - 1]; + // An indented code block cannot interrupt a paragraph. + if (lastToken && lastToken.type === 'paragraph') { + tokens.pop(); + lastToken.text += '\n' + cap[0].trimRight(); + lastToken.raw += '\n' + cap[0]; + return lastToken; + } else { + const text = cap[0].replace(/^ {4}/gm, ''); + return { + type: 'code', + raw: cap[0], + codeBlockStyle: 'indented', + text: !this.options.pedantic + ? rtrim(text, '\n') + : text + }; + } + } + } + + fences(lexer, src, tokens, top) { + const cap = this.rules.block.fences.exec(src); + if (cap) { + return { + type: 'code', + raw: cap[0], + lang: cap[2] ? cap[2].trim() : cap[2], + text: cap[3] || '' + }; + } + } + + heading(lexer, src, tokens, top) { + const cap = this.rules.block.heading.exec(src); + if (cap) { + return { + type: 'heading', + raw: cap[0], + depth: cap[1].length, + text: cap[2] + }; + } + } + + nptable(lexer, src, tokens, top) { + const cap = this.rules.block.nptable.exec(src); + if (cap) { + const item = { + type: 'table', + header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')), + align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), + cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [], + raw: cap[0] + }; + + if (item.header.length === item.align.length) { + let l = item.align.length; + let i; + for (i = 0; i < l; i++) { + if (/^ *-+: *$/.test(item.align[i])) { + item.align[i] = 'right'; + } else if (/^ *:-+: *$/.test(item.align[i])) { + item.align[i] = 'center'; + } else if (/^ *:-+ *$/.test(item.align[i])) { + item.align[i] = 'left'; + } else { + item.align[i] = null; + } + } + + l = item.cells.length; + for (i = 0; i < l; i++) { + item.cells[i] = splitCells(item.cells[i], item.header.length); + } + + return item; + } + } + } + + hr(lexer, src, tokens, top) { + const cap = this.rules.block.hr.exec(src); + if (cap) { + return { + type: 'hr', + raw: cap[0] + }; + } + } + + blockquote(lexer, src, tokens, top) { + const cap = this.rules.block.blockquote.exec(src); + if (cap) { + const text = cap[0].replace(/^ *> ?/gm, ''); + + return { + type: 'blockquote', + raw: cap[0], + tokens: lexer.blockTokens(text, [], top) + }; + } + } + + list(lexer, src, tokens, top) { + const cap = this.rules.block.list.exec(src); + if (cap) { + let raw = cap[0]; + const bull = cap[2]; + const isordered = bull.length > 1; + + const list = { + type: 'list', + raw, + ordered: isordered, + start: isordered ? +bull : '', + loose: false, + items: [] + }; + + // Get each top-level item. + const itemMatch = cap[0].match(this.rules.block.item); + + let next = false, + item, + space, + b, + addBack, + loose, + istask, + ischecked; + + const l = itemMatch.length; + for (let i = 0; i < l; i++) { + item = itemMatch[i]; + raw = item; + + // Remove the list item's bullet + // so it is seen as the next token. + space = item.length; + item = item.replace(/^ *([*+-]|\d+\.) */, ''); + + // Outdent whatever the + // list item contains. Hacky. + if (~item.indexOf('\n ')) { + space -= item.length; + item = !this.options.pedantic + ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') + : item.replace(/^ {1,4}/gm, ''); + } + + // Determine whether the next list item belongs here. + // Backpedal if it does not belong in this list. + if (i !== l - 1) { + b = this.rules.block.bullet.exec(itemMatch[i + 1])[0]; + if (bull.length > 1 ? b.length === 1 + : (b.length > 1 || (this.options.smartLists && b !== bull))) { + addBack = itemMatch.slice(i + 1).join('\n'); + list.raw = list.raw.substring(0, list.raw.length - addBack.length); + i = l - 1; + } + } + + // Determine whether item is loose or not. + // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/ + // for discount behavior. + loose = next || /\n\n(?!\s*$)/.test(item); + if (i !== l - 1) { + next = item.charAt(item.length - 1) === '\n'; + if (!loose) loose = next; + } + + if (loose) { + list.loose = true; + } + + // Check for task list items + istask = /^\[[ xX]\] /.test(item); + ischecked = undefined; + if (istask) { + ischecked = item[1] !== ' '; + item = item.replace(/^\[[ xX]\] +/, ''); + } + + list.items.push({ + raw, + task: istask, + checked: ischecked, + loose: loose, + tokens: lexer.blockTokens(item, [], false) + }); + } + + return list; + } + } + + html(lexer, src, tokens, top) { + const cap = this.rules.block.html.exec(src); + if (cap) { + return { + type: this.options.sanitize + ? 'paragraph' + : 'html', + raw: cap[0], + pre: !this.options.sanitizer + && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'), + text: this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape(cap[0])) : cap[0] + }; + } + } + + def(lexer, src, tokens, top) { + const cap = this.rules.block.def.exec(src); + if (cap) { + if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1); + const tag = cap[1].toLowerCase().replace(/\s+/g, ' '); + return { + tag, + raw: cap[0], + href: cap[2], + title: cap[3] + }; + } + } + + table(lexer, src, tokens, top) { + const cap = this.rules.block.table.exec(src); + if (cap) { + const item = { + type: 'table', + header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')), + align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), + cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [] + }; + + if (item.header.length === item.align.length) { + item.raw = cap[0]; + + let l = item.align.length; + let i; + for (i = 0; i < l; i++) { + if (/^ *-+: *$/.test(item.align[i])) { + item.align[i] = 'right'; + } else if (/^ *:-+: *$/.test(item.align[i])) { + item.align[i] = 'center'; + } else if (/^ *:-+ *$/.test(item.align[i])) { + item.align[i] = 'left'; + } else { + item.align[i] = null; + } + } + + l = item.cells.length; + for (i = 0; i < l; i++) { + item.cells[i] = splitCells( + item.cells[i].replace(/^ *\| *| *\| *$/g, ''), + item.header.length); + } + + return item; + } + } + } + + lheading(lexer, src, tokens, top) { + const cap = this.rules.block.lheading.exec(src); + if (cap) { + return { + type: 'heading', + raw: cap[0], + depth: cap[2].charAt(0) === '=' ? 1 : 2, + text: cap[1] + }; + } + } + + paragraph(lexer, src, tokens, top) { + const cap = this.rules.block.paragraph.exec(src); + if (cap) { + return { + type: 'paragraph', + raw: cap[0], + text: cap[1].charAt(cap[1].length - 1) === '\n' + ? cap[1].slice(0, -1) + : cap[1] + }; + } + } + + text(lexer, src, tokens, top) { + const cap = this.rules.block.text.exec(src); + if (cap) { + return { + type: 'text', + raw: cap[0], + text: cap[0] + }; + } + } + + escape(lexer, src, tokens, top) { + const cap = this.rules.inline.escape.exec(src); + if (cap) { + return { + type: 'escape', + raw: cap[0], + text: escape(cap[1]) + }; + } + } + + tag(lexer, src, tokens, top) { + const cap = this.rules.inline.tag.exec(src); + if (cap) { + if (!this.inLink && /^/i.test(cap[0])) { + this.inLink = false; + } + if (!this.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { + this.inRawBlock = true; + } else if (this.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { + this.inRawBlock = false; + } + + return { + type: this.options.sanitize + ? 'text' + : 'html', + raw: cap[0], + text: this.options.sanitize + ? (this.options.sanitizer + ? this.options.sanitizer(cap[0]) + : escape(cap[0])) + : cap[0] + }; + } + } + + link(lexer, src, tokens, top) { + const cap = this.rules.inline.link.exec(src); + if (cap) { + const lastParenIndex = findClosingBracket(cap[2], '()'); + if (lastParenIndex > -1) { + const start = cap[0].indexOf('!') === 0 ? 5 : 4; + const linkLen = start + cap[1].length + lastParenIndex; + cap[2] = cap[2].substring(0, lastParenIndex); + cap[0] = cap[0].substring(0, linkLen).trim(); + cap[3] = ''; + } + this.inLink = true; + let href = cap[2]; + let title = ''; + if (this.options.pedantic) { + const link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href); + + if (link) { + href = link[1]; + title = link[3]; + } else { + title = ''; + } + } else { + title = cap[3] ? cap[3].slice(1, -1) : ''; + } + href = href.trim().replace(/^<([\s\S]*)>$/, '$1'); + const token = outputLink(cap, { + href: href ? href.replace(this.rules.inline._escapes, '$1') : href, + title: title ? title.replace(this.rules.inline._escapes, '$1') : title + }, tokens, cap[0], lexer); + this.inLink = false; + return token; + } + } + + reflink(lexer, src, tokens, top) { + let cap; + if ((cap = this.rules.inline.reflink.exec(src)) + || (cap = this.rules.inline.nolink.exec(src))) { + let link = (cap[2] || cap[1]).replace(/\s+/g, ' '); + link = lexer.tokens.links[link.toLowerCase()]; + if (!link || !link.href) { + const text = cap[0].charAt(0); + return { + type: 'text', + raw: text, + text + }; + } + this.inLink = true; + const token = outputLink(cap, link, tokens, cap[0], lexer); + this.inLink = false; + return token; + } + } + + strong(lexer, src, tokens, top) { + const cap = this.rules.inline.strong.exec(src); + if (cap) { + return { + type: 'strong', + raw: cap[0], + tokens: lexer.inlineTokens(cap[4] || cap[3] || cap[2] || cap[1]) + }; + } + } + + em(lexer, src, tokens, top) { + const cap = this.rules.inline.em.exec(src); + if (cap) { + return { + type: 'em', + raw: cap[0], + tokens: lexer.inlineTokens(cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1]) + }; + } + } + + codespan(lexer, src, tokens, top) { + const cap = this.rules.inline.code.exec(src); + if (cap) { + return { + type: 'codespan', + raw: cap[0], + text: escape(cap[2].trim(), true) + }; + } + } + + br(lexer, src, tokens, top) { + const cap = this.rules.inline.br.exec(src); + if (cap) { + return { + type: 'br', + raw: cap[0] + }; + } + } + + del(lexer, src, tokens, top) { + const cap = this.rules.inline.del.exec(src); + if (cap) { + return { + type: 'del', + raw: cap[0], + tokens: lexer.inlineTokens(cap[1]) + }; + } + } + + autolink(lexer, src, tokens, top) { + const cap = this.rules.inline.autolink.exec(src); + if (cap) { + let text, href; + if (cap[2] === '@') { + text = escape(this.options.mangle ? this.mangle(cap[1]) : cap[1]); + href = 'mailto:' + text; + } else { + text = escape(cap[1]); + href = text; + } + + return { + type: 'link', + raw: cap[0], + text, + href, + tokens: [ + { + type: 'text', + raw: text, + text + } + ] + }; + } + } + + url(lexer, src, tokens, top) { + let cap; + if (!this.inLink && (cap = this.rules.inline.url.exec(src))) { + let text, href; + if (cap[2] === '@') { + text = escape(this.options.mangle ? this.mangle(cap[0]) : cap[0]); + href = 'mailto:' + text; + } else { + // do extended autolink path validation + let prevCapZero; + do { + prevCapZero = cap[0]; + cap[0] = this.rules.inline._backpedal.exec(cap[0])[0]; + } while (prevCapZero !== cap[0]); + text = escape(cap[0]); + if (cap[1] === 'www.') { + href = 'http://' + text; + } else { + href = text; + } + } + return { + type: 'link', + raw: cap[0], + text, + href, + tokens: [ + { + type: 'text', + raw: text, + text + } + ] + }; + } + } + + inlineText(lexer, src, tokens, top) { + const cap = this.rules.inline.text.exec(src); + if (cap) { + let text; + if (this.inRawBlock) { + text = this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape(cap[0])) : cap[0]; + } else { + text = escape(this.options.smartypants ? this.smartypants(cap[0]) : cap[0]); + } + return { + type: 'text', + raw: cap[0], + text + }; + } + } + + /** + * Smartypants Transformations + */ + smartypants(text) { + return text + // em-dashes + .replace(/---/g, '\u2014') + // en-dashes + .replace(/--/g, '\u2013') + // opening singles + .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018') + // closing singles & apostrophes + .replace(/'/g, '\u2019') + // opening doubles + .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c') + // closing doubles + .replace(/"/g, '\u201d') + // ellipses + .replace(/\.{3}/g, '\u2026'); + } + + /** + * Mangle Links + */ + mangle(text) { + let out = '', + i, + ch; + + const l = text.length; + for (i = 0; i < l; i++) { + ch = text.charCodeAt(i); + if (Math.random() > 0.5) { + ch = 'x' + ch.toString(16); + } + out += '&#' + ch + ';'; + } + + return out; + } +}; diff --git a/src/defaults.js b/src/defaults.js index 8d0be95580..0153bb4334 100644 --- a/src/defaults.js +++ b/src/defaults.js @@ -15,6 +15,7 @@ function getDefaults() { silent: false, smartLists: false, smartypants: false, + tokenizer: null, xhtml: false }; } diff --git a/src/marked.js b/src/marked.js index b575eec23d..8a77ddcef6 100644 --- a/src/marked.js +++ b/src/marked.js @@ -1,5 +1,6 @@ const Lexer = require('./Lexer.js'); const Parser = require('./Parser.js'); +const Tokenizer = require('./Tokenizer.js'); const Renderer = require('./Renderer.js'); const TextRenderer = require('./TextRenderer.js'); const Slugger = require('./Slugger.js'); @@ -139,6 +140,8 @@ marked.TextRenderer = TextRenderer; marked.Lexer = Lexer; marked.lexer = Lexer.lex; +marked.Tokenizer = Tokenizer; + marked.Slugger = Slugger; marked.parse = marked; diff --git a/test/unit/Lexer-spec.js b/test/unit/Lexer-spec.js index 0d334358a0..dd0bdfef2c 100644 --- a/test/unit/Lexer-spec.js +++ b/test/unit/Lexer-spec.js @@ -9,15 +9,12 @@ function expectTokens({ md, options, tokens = [], links = {} }) { expect(actual).toEqual(expected); } -function expectInlineTokens({ md, options, output = jasmine.any(String), tokens = jasmine.any(Array), links = {} }) { +function expectInlineTokens({ md, options, tokens = jasmine.any(Array), links = {} }) { const lexer = new Lexer(options); lexer.tokens.links = links; const outTokens = []; - const outOutput = lexer.inlineTokens(md, outTokens); - expect({ - output: outOutput, - tokens: outTokens - }).toEqual({ output, tokens }); + lexer.inlineTokens(md, outTokens); + expect(outTokens).toEqual(tokens); } function expectInline({ token, options, tokens }) { @@ -321,7 +318,7 @@ a | b }] }, { - raw: '- item 2', + raw: '- item 2\n', task: false, checked: undefined, loose: false, @@ -355,7 +352,7 @@ a | b raw: '1. item 1' }), jasmine.objectContaining({ - raw: '2. item 2' + raw: '2. item 2\n' }) ] }) @@ -380,7 +377,7 @@ a | b raw: '2. item 1' }), jasmine.objectContaining({ - raw: '3. item 2' + raw: '3. item 2\n' }) ] }) @@ -422,7 +419,7 @@ a | b checked: false }), jasmine.objectContaining({ - raw: '- [x] item 2', + raw: '- [x] item 2\n', task: true, checked: true }) @@ -504,7 +501,7 @@ a | b }); describe('inline', () => { - describe('tokens', () => { + describe('inline', () => { it('paragraph', () => { expectInline({ token: { type: 'paragraph', text: 'text' }, @@ -563,11 +560,10 @@ a | b }); }); - describe('output', () => { + describe('inlineTokens', () => { it('escape', () => { expectInlineTokens({ md: '\\>', - output: '>', tokens: [ { type: 'escape', raw: '\\>', text: '>' } ] @@ -577,7 +573,6 @@ a | b it('html', () => { expectInlineTokens({ md: '
    html
    ', - output: '
    html
    ', tokens: [ { type: 'html', raw: '
    ', text: '
    ' }, { type: 'text', raw: 'html', text: 'html' }, @@ -590,7 +585,6 @@ a | b expectInlineTokens({ md: '
    html
    ', options: { sanitize: true }, - output: '<div>html</div>', tokens: [ { type: 'text', raw: '
    ', text: '<div>' }, { type: 'text', raw: 'html', text: 'html' }, @@ -602,12 +596,10 @@ a | b it('link', () => { expectInlineTokens({ md: '[link](https://example.com)', - output: 'link', tokens: [ { type: 'link', raw: '[link](https://example.com)', - text: 'link', href: 'https://example.com', title: null, tokens: [ @@ -621,12 +613,10 @@ a | b it('link title', () => { expectInlineTokens({ md: '[link](https://example.com "title")', - output: 'link', tokens: [ { type: 'link', raw: '[link](https://example.com "title")', - text: 'link', href: 'https://example.com', title: 'title', tokens: [ @@ -640,7 +630,6 @@ a | b it('image', () => { expectInlineTokens({ md: '![image](https://example.com/image.png)', - output: 'image', tokens: [ { type: 'image', @@ -656,7 +645,6 @@ a | b it('image title', () => { expectInlineTokens({ md: '![image](https://example.com/image.png "title")', - output: 'image', tokens: [ { type: 'image', @@ -676,12 +664,10 @@ a | b links: { link: { href: 'https://example.com', title: 'title' } }, - output: 'link', tokens: [ { type: 'link', raw: '[link][]', - text: 'link', href: 'https://example.com', title: 'title', tokens: [{ @@ -700,12 +686,10 @@ a | b links: { link: { href: 'https://example.com', title: 'title' } }, - output: 'link', tokens: [ { type: 'link', raw: '[link]', - text: 'link', href: 'https://example.com', title: 'title', tokens: [{ @@ -721,7 +705,6 @@ a | b it('no def', () => { expectInlineTokens({ md: '[link]', - output: '[link]', tokens: [ { type: 'text', raw: '[', text: '[' }, { type: 'text', raw: 'link]', text: 'link]' } @@ -733,12 +716,10 @@ a | b it('strong', () => { expectInlineTokens({ md: '**strong**', - output: 'strong', tokens: [ { type: 'strong', raw: '**strong**', - text: 'strong', tokens: [ { type: 'text', raw: 'strong', text: 'strong' } ] @@ -750,12 +731,10 @@ a | b it('em', () => { expectInlineTokens({ md: '*em*', - output: 'em', tokens: [ { type: 'em', raw: '*em*', - text: 'em', tokens: [ { type: 'text', raw: 'em', text: 'em' } ] @@ -767,7 +746,6 @@ a | b it('code', () => { expectInlineTokens({ md: '`code`', - output: 'code', tokens: [ { type: 'codespan', raw: '`code`', text: 'code' } ] @@ -778,7 +756,6 @@ a | b expectInlineTokens({ md: 'a\nb', options: { gfm: true, breaks: true }, - output: 'a\nb', tokens: jasmine.arrayContaining([ { type: 'br', raw: '\n' } ]) @@ -788,12 +765,10 @@ a | b it('del', () => { expectInlineTokens({ md: '~~del~~', - output: 'del', tokens: [ { type: 'del', raw: '~~del~~', - text: 'del', tokens: [ { type: 'text', raw: 'del', text: 'del' } ] @@ -806,7 +781,6 @@ a | b it('autolink', () => { expectInlineTokens({ md: '', - output: 'https://example.com', tokens: [ { type: 'link', @@ -825,7 +799,6 @@ a | b expectInlineTokens({ md: '', options: { mangle: false }, - output: 'test@example.com', tokens: [ { type: 'link', @@ -844,7 +817,6 @@ a | b expectInlineTokens({ md: '', options: { mangle: true }, - output: jasmine.stringMatching('&#'), tokens: [ { type: 'link', @@ -866,7 +838,6 @@ a | b it('url', () => { expectInlineTokens({ md: 'https://example.com', - output: 'https://example.com', tokens: [ { type: 'link', @@ -885,7 +856,6 @@ a | b expectInlineTokens({ md: 'test@example.com', options: { gfm: true, mangle: false }, - output: 'test@example.com', tokens: [ { type: 'link', @@ -904,7 +874,6 @@ a | b expectInlineTokens({ md: 'test@example.com', options: { gfm: true, mangle: true }, - output: jasmine.stringMatching('&#'), tokens: [ { type: 'link', @@ -927,7 +896,6 @@ a | b it('text', () => { expectInlineTokens({ md: 'text', - output: 'text', tokens: [ { type: 'text', @@ -943,7 +911,6 @@ a | b expectInlineTokens({ md: "'single quotes'", options: { smartypants: true }, - output: '‘single quotes’', tokens: [ { type: 'text', @@ -958,7 +925,6 @@ a | b expectInlineTokens({ md: '"double quotes"', options: { smartypants: true }, - output: '“double quotes”', tokens: [ { type: 'text', @@ -973,7 +939,6 @@ a | b expectInlineTokens({ md: 'ellipses...', options: { smartypants: true }, - output: 'ellipses…', tokens: [ { type: 'text', @@ -988,7 +953,6 @@ a | b expectInlineTokens({ md: 'en--dash', options: { smartypants: true }, - output: 'en–dash', tokens: [ { type: 'text', @@ -1003,7 +967,6 @@ a | b expectInlineTokens({ md: 'em---dash', options: { smartypants: true }, - output: 'em—dash', tokens: [ { type: 'text', From b63156f938fd732b73f8c3d0bcd522ac388b108a Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Tue, 7 Apr 2020 11:43:11 -0500 Subject: [PATCH 02/13] update docs --- docs/USING_PRO.md | 79 +++++++++++++++++++++++++++++++++++++++++++++-- docs/index.html | 1 + src/Tokenizer.js | 24 +++++++------- 3 files changed, 89 insertions(+), 15 deletions(-) diff --git a/docs/USING_PRO.md b/docs/USING_PRO.md index 23fb7b3158..7bca5b9a9b 100644 --- a/docs/USING_PRO.md +++ b/docs/USING_PRO.md @@ -16,7 +16,7 @@ const marked = require('marked'); const renderer = new marked.Renderer(); // Override function -renderer.heading = function (text, level) { +renderer.heading = function(text, level) { const escapedText = text.toLowerCase().replace(/[^\w]+/g, '-'); return ` @@ -58,7 +58,7 @@ console.log(marked('# heading+', { renderer })); - tablerow(*string* content) - tablecell(*string* content, *object* flags) -`slugger` has the `slug` method to create an unique id from value: +`slugger` has the `slug` method to create a unique id from value: ```js slugger.slug('foo') // foo @@ -89,9 +89,82 @@ slugger.slug('foo-1') // foo-1-2 - image(*string* href, *string* title, *string* text) - text(*string* text) +

    The tokenizer

    + +The tokenizer defines how to turn markdown text into tokens. + +**Example:** Overriding default `codespan` tokenizer to include latex. + +```js +// Create reference instance +const marked = require('marked'); + +// Get reference +const tokenizer = new marked.Tokenizer(); +const originalCodespan = tokenizer.codespan; +// Override function +tokenizer.codespan = function(lexer, src) { + const match = src.match(/\$+([^\$\n]+?)\$+/); + if (match) { + return { + type: 'codespan', + raw: match[0], + text: match[1].trim() + }; + } + return originalCodespan.apply(this, arguments); +}; + +// Run marked +console.log(marked('$ latext code $', { tokenizer })); +``` + +**Output:** + +```html +

    latext code

    +``` + +### Block level tokenizer methods + +- space(*Lxer* lexer, *string* src, *array* tokens, *bool* top) +- code(*Lxer* lexer, *string* src, *array* tokens, *bool* top) +- fences(*Lxer* lexer, *string* src, *array* tokens, *bool* top) +- heading(*Lxer* lexer, *string* src, *array* tokens, *bool* top) +- nptable(*Lxer* lexer, *string* src, *array* tokens, *bool* top) +- hr(*Lxer* lexer, *string* src, *array* tokens, *bool* top) +- blockquote(*Lxer* lexer, *string* src, *array* tokens, *bool* top) +- list(*Lxer* lexer, *string* src, *array* tokens, *bool* top) +- html(*Lxer* lexer, *string* src, *array* tokens, *bool* top) +- def(*Lxer* lexer, *string* src, *array* tokens, *bool* top) +- table(*Lxer* lexer, *string* src, *array* tokens, *bool* top) +- lheading(*Lxer* lexer, *string* src, *array* tokens, *bool* top) +- paragraph(*Lxer* lexer, *string* src, *array* tokens, *bool* top) +- text(*Lxer* lexer, *string* src, *array* tokens, *bool* top) + +### Inline level tokenizer methods + +- escape(*Lxer* lexer, *string* src, *array* tokens) +- tag(*Lxer* lexer, *string* src, *array* tokens) +- link(*Lxer* lexer, *string* src, *array* tokens) +- reflink(*Lxer* lexer, *string* src, *array* tokens) +- strong(*Lxer* lexer, *string* src, *array* tokens) +- em(*Lxer* lexer, *string* src, *array* tokens) +- codespan(*Lxer* lexer, *string* src, *array* tokens) +- br(*Lxer* lexer, *string* src, *array* tokens) +- del(*Lxer* lexer, *string* src, *array* tokens) +- autolink(*Lxer* lexer, *string* src, *array* tokens) +- url(*Lxer* lexer, *string* src, *array* tokens) +- inlineText(*Lxer* lexer, *string* src, *array* tokens) + +### Other tokenizer methods + +- smartypants(*string* text) +- mangle(*string* text) +

    The lexer

    -The lexer turns a markdown string into tokens. +The lexer takes a markdown string and calls the tokenizer functions.

    The parser

    diff --git a/docs/index.html b/docs/index.html index 6aed62796c..9d68e7bb41 100644 --- a/docs/index.html +++ b/docs/index.html @@ -155,6 +155,7 @@

    Marked.js Documentation

    Extensibility diff --git a/src/Tokenizer.js b/src/Tokenizer.js index c8ca37f404..66b33c8d76 100644 --- a/src/Tokenizer.js +++ b/src/Tokenizer.js @@ -388,7 +388,7 @@ module.exports = class Tokenizer { } } - escape(lexer, src, tokens, top) { + escape(lexer, src, tokens) { const cap = this.rules.inline.escape.exec(src); if (cap) { return { @@ -399,7 +399,7 @@ module.exports = class Tokenizer { } } - tag(lexer, src, tokens, top) { + tag(lexer, src, tokens) { const cap = this.rules.inline.tag.exec(src); if (cap) { if (!this.inLink && /^ Date: Tue, 7 Apr 2020 11:44:40 -0500 Subject: [PATCH 03/13] fix typo --- docs/USING_PRO.md | 52 +++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/USING_PRO.md b/docs/USING_PRO.md index 7bca5b9a9b..de9f45f53e 100644 --- a/docs/USING_PRO.md +++ b/docs/USING_PRO.md @@ -127,35 +127,35 @@ console.log(marked('$ latext code $', { tokenizer })); ### Block level tokenizer methods -- space(*Lxer* lexer, *string* src, *array* tokens, *bool* top) -- code(*Lxer* lexer, *string* src, *array* tokens, *bool* top) -- fences(*Lxer* lexer, *string* src, *array* tokens, *bool* top) -- heading(*Lxer* lexer, *string* src, *array* tokens, *bool* top) -- nptable(*Lxer* lexer, *string* src, *array* tokens, *bool* top) -- hr(*Lxer* lexer, *string* src, *array* tokens, *bool* top) -- blockquote(*Lxer* lexer, *string* src, *array* tokens, *bool* top) -- list(*Lxer* lexer, *string* src, *array* tokens, *bool* top) -- html(*Lxer* lexer, *string* src, *array* tokens, *bool* top) -- def(*Lxer* lexer, *string* src, *array* tokens, *bool* top) -- table(*Lxer* lexer, *string* src, *array* tokens, *bool* top) -- lheading(*Lxer* lexer, *string* src, *array* tokens, *bool* top) -- paragraph(*Lxer* lexer, *string* src, *array* tokens, *bool* top) -- text(*Lxer* lexer, *string* src, *array* tokens, *bool* top) +- space(*Lexer* lexer, *string* src, *array* tokens, *bool* top) +- code(*Lexer* lexer, *string* src, *array* tokens, *bool* top) +- fences(*Lexer* lexer, *string* src, *array* tokens, *bool* top) +- heading(*Lexer* lexer, *string* src, *array* tokens, *bool* top) +- nptable(*Lexer* lexer, *string* src, *array* tokens, *bool* top) +- hr(*Lexer* lexer, *string* src, *array* tokens, *bool* top) +- blockquote(*Lexer* lexer, *string* src, *array* tokens, *bool* top) +- list(*Lexer* lexer, *string* src, *array* tokens, *bool* top) +- html(*Lexer* lexer, *string* src, *array* tokens, *bool* top) +- def(*Lexer* lexer, *string* src, *array* tokens, *bool* top) +- table(*Lexer* lexer, *string* src, *array* tokens, *bool* top) +- lheading(*Lexer* lexer, *string* src, *array* tokens, *bool* top) +- paragraph(*Lexer* lexer, *string* src, *array* tokens, *bool* top) +- text(*Lexer* lexer, *string* src, *array* tokens, *bool* top) ### Inline level tokenizer methods -- escape(*Lxer* lexer, *string* src, *array* tokens) -- tag(*Lxer* lexer, *string* src, *array* tokens) -- link(*Lxer* lexer, *string* src, *array* tokens) -- reflink(*Lxer* lexer, *string* src, *array* tokens) -- strong(*Lxer* lexer, *string* src, *array* tokens) -- em(*Lxer* lexer, *string* src, *array* tokens) -- codespan(*Lxer* lexer, *string* src, *array* tokens) -- br(*Lxer* lexer, *string* src, *array* tokens) -- del(*Lxer* lexer, *string* src, *array* tokens) -- autolink(*Lxer* lexer, *string* src, *array* tokens) -- url(*Lxer* lexer, *string* src, *array* tokens) -- inlineText(*Lxer* lexer, *string* src, *array* tokens) +- escape(*Lexer* lexer, *string* src, *array* tokens) +- tag(*Lexer* lexer, *string* src, *array* tokens) +- link(*Lexer* lexer, *string* src, *array* tokens) +- reflink(*Lexer* lexer, *string* src, *array* tokens) +- strong(*Lexer* lexer, *string* src, *array* tokens) +- em(*Lexer* lexer, *string* src, *array* tokens) +- codespan(*Lexer* lexer, *string* src, *array* tokens) +- br(*Lexer* lexer, *string* src, *array* tokens) +- del(*Lexer* lexer, *string* src, *array* tokens) +- autolink(*Lexer* lexer, *string* src, *array* tokens) +- url(*Lexer* lexer, *string* src, *array* tokens) +- inlineText(*Lexer* lexer, *string* src, *array* tokens) ### Other tokenizer methods From 48f2ee899a95b331306d15e52692c69877a041ec Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Wed, 8 Apr 2020 13:06:43 -0500 Subject: [PATCH 04/13] build --- lib/marked.esm.js | 705 +++++++++++++++------------------------------ lib/marked.js | 709 ++++++++++++++++------------------------------ marked.min.js | 2 +- 3 files changed, 473 insertions(+), 943 deletions(-) diff --git a/lib/marked.esm.js b/lib/marked.esm.js index 3a2b95b78c..73e95b803f 100644 --- a/lib/marked.esm.js +++ b/lib/marked.esm.js @@ -31,6 +31,7 @@ function getDefaults() { silent: false, smartLists: false, smartypants: false, + tokenizer: null, xhtml: false }; } @@ -567,7 +568,30 @@ const { escape: escape$1, findClosingBracket: findClosingBracket$1 } = helpers; -const { inline: inline$1 } = rules; +const { block: block$1, inline: inline$1 } = rules; + +function outputLink(cap, link, tokens, raw, lexer) { + const href = link.href; + const title = link.title ? escape$1(link.title) : null; + + if (cap[0].charAt(0) !== '!') { + return { + type: 'link', + raw, + href, + title, + tokens: lexer.inlineTokens(cap[1]) + }; + } else { + return { + type: 'image', + raw, + text: escape$1(cap[1]), + href, + title + }; + } +} /** * Tokenizer @@ -575,29 +599,61 @@ const { inline: inline$1 } = rules; var Tokenizer_1 = class Tokenizer { constructor(options) { this.options = options || defaults$1; + this.initialize(); } - space(obj) { - const cap = obj.lexer.rules.block.newline.exec(obj.src); + initialize() { + this.inLink = false; + this.inRawBlock = false; + + this.rules = { + block: block$1.normal, + inline: inline$1.normal + }; + + if (this.options.pedantic) { + this.rules.block = block$1.pedantic; + this.rules.inline = inline$1.pedantic; + } else if (this.options.gfm) { + this.rules.block = block$1.gfm; + if (this.options.breaks) { + this.rules.inline = inline$1.breaks; + } else { + this.rules.inline = inline$1.gfm; + } + } + } + + /** + * Expose Block Rules + */ + static get rules() { + return { + block: block$1, + inline: inline$1 + }; + } + + space(lexer, src, tokens, top) { + const cap = this.rules.block.newline.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); if (cap[0].length > 1) { return { type: 'space', raw: cap[0] }; } + return { raw: '\n' }; } } - code(obj) { - const cap = obj.lexer.rules.block.code.exec(obj.src); + code(lexer, src, tokens, top) { + const cap = this.rules.block.code.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); - const lastToken = obj.tokens[obj.tokens.length - 1]; + const lastToken = tokens[tokens.length - 1]; // An indented code block cannot interrupt a paragraph. if (lastToken && lastToken.type === 'paragraph') { - obj.tokens.pop(); + tokens.pop(); lastToken.text += '\n' + cap[0].trimRight(); lastToken.raw += '\n' + cap[0]; return lastToken; @@ -615,10 +671,9 @@ var Tokenizer_1 = class Tokenizer { } } - fences(obj) { - const cap = obj.lexer.rules.block.fences.exec(obj.src); + fences(lexer, src, tokens, top) { + const cap = this.rules.block.fences.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); return { type: 'code', raw: cap[0], @@ -628,10 +683,9 @@ var Tokenizer_1 = class Tokenizer { } } - heading(obj) { - const cap = obj.lexer.rules.block.heading.exec(obj.src); + heading(lexer, src, tokens, top) { + const cap = this.rules.block.heading.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); return { type: 'heading', raw: cap[0], @@ -641,8 +695,8 @@ var Tokenizer_1 = class Tokenizer { } } - nptable(obj) { - const cap = obj.lexer.rules.block.nptable.exec(obj.src); + nptable(lexer, src, tokens, top) { + const cap = this.rules.block.nptable.exec(src); if (cap) { const item = { type: 'table', @@ -653,8 +707,6 @@ var Tokenizer_1 = class Tokenizer { }; if (item.header.length === item.align.length) { - obj.src = obj.src.substring(cap[0].length); - let l = item.align.length; let i; for (i = 0; i < l; i++) { @@ -679,10 +731,9 @@ var Tokenizer_1 = class Tokenizer { } } - hr(obj) { - const cap = obj.lexer.rules.block.hr.exec(obj.src); + hr(lexer, src, tokens, top) { + const cap = this.rules.block.hr.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); return { type: 'hr', raw: cap[0] @@ -690,24 +741,22 @@ var Tokenizer_1 = class Tokenizer { } } - blockquote(obj) { - const cap = obj.lexer.rules.block.blockquote.exec(obj.src); + blockquote(lexer, src, tokens, top) { + const cap = this.rules.block.blockquote.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); const text = cap[0].replace(/^ *> ?/gm, ''); return { type: 'blockquote', raw: cap[0], - tokens: obj.lexer.blockTokens([], text, obj.top) + tokens: lexer.blockTokens(text, [], top) }; } } - list(obj) { - const cap = obj.lexer.rules.block.list.exec(obj.src); + list(lexer, src, tokens, top) { + const cap = this.rules.block.list.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); let raw = cap[0]; const bull = cap[2]; const isordered = bull.length > 1; @@ -722,7 +771,7 @@ var Tokenizer_1 = class Tokenizer { }; // Get each top-level item. - const itemMatch = cap[0].match(obj.lexer.rules.block.item); + const itemMatch = cap[0].match(this.rules.block.item); let next = false, item, @@ -736,7 +785,7 @@ var Tokenizer_1 = class Tokenizer { const l = itemMatch.length; for (let i = 0; i < l; i++) { item = itemMatch[i]; - raw = item.trim(); + raw = item; // Remove the list item's bullet // so it is seen as the next token. @@ -755,12 +804,11 @@ var Tokenizer_1 = class Tokenizer { // Determine whether the next list item belongs here. // Backpedal if it does not belong in this list. if (i !== l - 1) { - b = obj.lexer.rules.block.bullet.exec(itemMatch[i + 1])[0]; + b = this.rules.block.bullet.exec(itemMatch[i + 1])[0]; if (bull.length > 1 ? b.length === 1 : (b.length > 1 || (this.options.smartLists && b !== bull))) { addBack = itemMatch.slice(i + 1).join('\n'); - obj.src = addBack + obj.src; - list.raw = list.raw.substring(list.raw.length - addBack.length); + list.raw = list.raw.substring(0, list.raw.length - addBack.length); i = l - 1; } } @@ -791,7 +839,7 @@ var Tokenizer_1 = class Tokenizer { task: istask, checked: ischecked, loose: loose, - tokens: obj.lexer.blockTokens([], item, false) + tokens: lexer.blockTokens(item, [], false) }); } @@ -799,10 +847,9 @@ var Tokenizer_1 = class Tokenizer { } } - html(obj) { - const cap = obj.lexer.rules.block.html.exec(obj.src); + html(lexer, src, tokens, top) { + const cap = this.rules.block.html.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); return { type: this.options.sanitize ? 'paragraph' @@ -815,22 +862,22 @@ var Tokenizer_1 = class Tokenizer { } } - def(obj) { - const cap = obj.lexer.rules.block.def.exec(obj.src); + def(lexer, src, tokens, top) { + const cap = this.rules.block.def.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1); const tag = cap[1].toLowerCase().replace(/\s+/g, ' '); return { tag, + raw: cap[0], href: cap[2], title: cap[3] }; } } - table(obj) { - const cap = obj.lexer.rules.block.table.exec(obj.src); + table(lexer, src, tokens, top) { + const cap = this.rules.block.table.exec(src); if (cap) { const item = { type: 'table', @@ -840,7 +887,6 @@ var Tokenizer_1 = class Tokenizer { }; if (item.header.length === item.align.length) { - obj.src = obj.src.substring(cap[0].length); item.raw = cap[0]; let l = item.align.length; @@ -869,10 +915,9 @@ var Tokenizer_1 = class Tokenizer { } } - lheading(obj) { - const cap = obj.lexer.rules.block.lheading.exec(obj.src); + lheading(lexer, src, tokens, top) { + const cap = this.rules.block.lheading.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); return { type: 'heading', raw: cap[0], @@ -882,10 +927,9 @@ var Tokenizer_1 = class Tokenizer { } } - paragraph(obj) { - const cap = obj.lexer.rules.block.paragraph.exec(obj.src); + paragraph(lexer, src, tokens, top) { + const cap = this.rules.block.paragraph.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); return { type: 'paragraph', raw: cap[0], @@ -896,10 +940,9 @@ var Tokenizer_1 = class Tokenizer { } } - text(obj) { - const cap = obj.lexer.rules.block.text.exec(obj.src); + text(lexer, src, tokens, top) { + const cap = this.rules.block.text.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); return { type: 'text', raw: cap[0], @@ -908,54 +951,47 @@ var Tokenizer_1 = class Tokenizer { } } - escape(obj) { - const cap = obj.lexer.rules.inline.escape.exec(obj.src); + escape(lexer, src, tokens) { + const cap = this.rules.inline.escape.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); - const text = escape$1(cap[1]); - obj.out += text; return { type: 'escape', raw: cap[0], - text + text: escape$1(cap[1]) }; } } - // FIXME: inLink and inRawBlock should be on this - tag(obj) { - const cap = obj.lexer.rules.inline.tag.exec(obj.src); + tag(lexer, src, tokens) { + const cap = this.rules.inline.tag.exec(src); if (cap) { - if (!obj.lexer.inLink && /^/i.test(cap[0])) { - obj.lexer.inLink = false; + if (!this.inLink && /^/i.test(cap[0])) { + this.inLink = false; } - if (!obj.lexer.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { - obj.lexer.inRawBlock = true; - } else if (obj.lexer.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { - obj.lexer.inRawBlock = false; + if (!this.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { + this.inRawBlock = true; + } else if (this.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { + this.inRawBlock = false; } - obj.src = obj.src.substring(cap[0].length); - const text = this.options.sanitize - ? (this.options.sanitizer - ? this.options.sanitizer(cap[0]) - : escape$1(cap[0])) - : cap[0]; - obj.out += text; return { type: this.options.sanitize ? 'text' : 'html', raw: cap[0], - text + text: this.options.sanitize + ? (this.options.sanitizer + ? this.options.sanitizer(cap[0]) + : escape$1(cap[0])) + : cap[0] }; } } - link(obj) { - const cap = obj.lexer.rules.inline.link.exec(obj.src); + link(lexer, src, tokens) { + const cap = this.rules.inline.link.exec(src); if (cap) { const lastParenIndex = findClosingBracket$1(cap[2], '()'); if (lastParenIndex > -1) { @@ -965,8 +1001,7 @@ var Tokenizer_1 = class Tokenizer { cap[0] = cap[0].substring(0, linkLen).trim(); cap[3] = ''; } - obj.src = obj.src.substring(cap[0].length); - obj.lexer.inLink = true; + this.inLink = true; let href = cap[2]; let title = ''; if (this.options.pedantic) { @@ -982,94 +1017,72 @@ var Tokenizer_1 = class Tokenizer { title = cap[3] ? cap[3].slice(1, -1) : ''; } href = href.trim().replace(/^<([\s\S]*)>$/, '$1'); - const link = this.outputLink(cap, { - href: this.escapes(href), - title: this.escapes(title) - }, obj.tokens, cap[0], obj); - obj.lexer.inLink = false; - obj.out += link.text; - return link.token; + const token = outputLink(cap, { + href: href ? href.replace(this.rules.inline._escapes, '$1') : href, + title: title ? title.replace(this.rules.inline._escapes, '$1') : title + }, tokens, cap[0], lexer); + this.inLink = false; + return token; } } - reflink(obj) { + reflink(lexer, src, tokens) { let cap; - if ((cap = obj.lexer.rules.inline.reflink.exec(obj.src)) - || (cap = obj.lexer.rules.inline.nolink.exec(obj.src))) { - obj.src = obj.src.substring(cap[0].length); + if ((cap = this.rules.inline.reflink.exec(src)) + || (cap = this.rules.inline.nolink.exec(src))) { let link = (cap[2] || cap[1]).replace(/\s+/g, ' '); - link = obj.lexer.tokens.links[link.toLowerCase()]; + link = lexer.tokens.links[link.toLowerCase()]; if (!link || !link.href) { const text = cap[0].charAt(0); - obj.out += text; - obj.src = cap[0].substring(1) + obj.src; return { type: 'text', raw: text, text }; } - obj.lexer.inLink = true; - const linkToken = this.outputLink(cap, link, obj.tokens, cap[0], obj); - obj.out += linkToken.text; - obj.lexer.inLink = false; - return linkToken.token; + this.inLink = true; + const token = outputLink(cap, link, tokens, cap[0], lexer); + this.inLink = false; + return token; } } - strong(obj) { - const cap = obj.lexer.rules.inline.strong.exec(obj.src); + strong(lexer, src, tokens) { + const cap = this.rules.inline.strong.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); - const newTokens = obj.tokens ? [] : null; - const text = obj.lexer.inlineOutput(cap[4] || cap[3] || cap[2] || cap[1], newTokens); - - obj.out += text; return { type: 'strong', raw: cap[0], - text, - tokens: newTokens + tokens: lexer.inlineTokens(cap[4] || cap[3] || cap[2] || cap[1]) }; } } - em(obj) { - const cap = obj.lexer.rules.inline.em.exec(obj.src); + em(lexer, src, tokens) { + const cap = this.rules.inline.em.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); - const newTokens = obj.tokens ? [] : null; - const text = obj.lexer.inlineOutput(cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1], newTokens); - - obj.out += text; return { type: 'em', raw: cap[0], - text, - tokens: newTokens + tokens: lexer.inlineTokens(cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1]) }; } } - codespan(obj) { - const cap = obj.lexer.rules.inline.code.exec(obj.src); + codespan(lexer, src, tokens) { + const cap = this.rules.inline.code.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); - const text = escape$1(cap[2].trim(), true); - obj.out += text; return { type: 'codespan', raw: cap[0], - text + text: escape$1(cap[2].trim(), true) }; } } - br(obj) { - const cap = obj.lexer.rules.inline.br.exec(obj.src); + br(lexer, src, tokens) { + const cap = this.rules.inline.br.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); - obj.out += '\n'; return { type: 'br', raw: cap[0] @@ -1077,26 +1090,20 @@ var Tokenizer_1 = class Tokenizer { } } - del(obj) { - const cap = obj.lexer.rules.inline.del.exec(obj.src); + del(lexer, src, tokens) { + const cap = this.rules.inline.del.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); - const newTokens = obj.tokens ? [] : null; - const text = obj.lexer.inlineOutput(cap[1], newTokens); - obj.out += text; return { type: 'del', raw: cap[0], - text, - tokens: newTokens + tokens: lexer.inlineTokens(cap[1]) }; } } - autolink(obj) { - const cap = obj.lexer.rules.inline.autolink.exec(obj.src); + autolink(lexer, src, tokens) { + const cap = this.rules.inline.autolink.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); let text, href; if (cap[2] === '@') { text = escape$1(this.options.mangle ? this.mangle(cap[1]) : cap[1]); @@ -1105,7 +1112,7 @@ var Tokenizer_1 = class Tokenizer { text = escape$1(cap[1]); href = text; } - obj.out += text; + return { type: 'link', raw: cap[0], @@ -1122,9 +1129,9 @@ var Tokenizer_1 = class Tokenizer { } } - url(obj) { + url(lexer, src, tokens) { let cap; - if (!obj.lexer.inLink && (cap = obj.lexer.rules.inline.url.exec(obj.src))) { + if (!this.inLink && (cap = this.rules.inline.url.exec(src))) { let text, href; if (cap[2] === '@') { text = escape$1(this.options.mangle ? this.mangle(cap[0]) : cap[0]); @@ -1134,7 +1141,7 @@ var Tokenizer_1 = class Tokenizer { let prevCapZero; do { prevCapZero = cap[0]; - cap[0] = obj.lexer.rules.inline._backpedal.exec(cap[0])[0]; + cap[0] = this.rules.inline._backpedal.exec(cap[0])[0]; } while (prevCapZero !== cap[0]); text = escape$1(cap[0]); if (cap[1] === 'www.') { @@ -1143,8 +1150,6 @@ var Tokenizer_1 = class Tokenizer { href = text; } } - obj.src = obj.src.substring(cap[0].length); - obj.out += text; return { type: 'link', raw: cap[0], @@ -1161,17 +1166,15 @@ var Tokenizer_1 = class Tokenizer { } } - inlineText(obj) { - const cap = obj.lexer.rules.inline.text.exec(obj.src); + inlineText(lexer, src, tokens) { + const cap = this.rules.inline.text.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); let text; - if (obj.lexer.inRawBlock) { + if (this.inRawBlock) { text = this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape$1(cap[0])) : cap[0]; } else { text = escape$1(this.options.smartypants ? this.smartypants(cap[0]) : cap[0]); } - obj.out += text; return { type: 'text', raw: cap[0], @@ -1180,42 +1183,6 @@ var Tokenizer_1 = class Tokenizer { } } - escapes(text) { - return text ? text.replace(inline$1._escapes, '$1') : text; - } - - /** - * tokenize Link - */ - outputLink(cap, link, tokens, raw, obj) { - const href = link.href; - const title = link.title ? escape$1(link.title) : null; - const newTokens = tokens ? [] : null; - let token, text; - - if (cap[0].charAt(0) !== '!') { - text = obj.lexer.inlineOutput(cap[1], newTokens); - token = { - type: 'link', - raw, - text, - href, - title, - tokens: newTokens - }; - } else { - text = escape$1(cap[1]); - token = { - type: 'image', - raw, - text, - href, - title - }; - } - return { token, text }; - } - /** * Smartypants Transformations */ @@ -1259,7 +1226,6 @@ var Tokenizer_1 = class Tokenizer { }; const { defaults: defaults$2 } = defaults; -const { block: block$1, inline: inline$2 } = rules; /** * Block Lexer @@ -1272,32 +1238,14 @@ var Lexer_1 = class Lexer { this.options.tokenizer = this.options.tokenizer || new Tokenizer_1(); this.tokenizer = this.options.tokenizer; this.tokenizer.options = this.options; - this.rules = { - block: block$1.normal, - inline: inline$2.normal - }; - - if (this.options.pedantic) { - this.rules.block = block$1.pedantic; - this.rules.inline = inline$2.pedantic; - } else if (this.options.gfm) { - this.rules.block = block$1.gfm; - if (this.options.breaks) { - this.rules.inline = inline$2.breaks; - } else { - this.rules.inline = inline$2.gfm; - } - } + this.tokenizer.initialize(); } /** * Expose Block Rules */ static get rules() { - return { - block: block$1, - inline: inline$2 - }; + return Tokenizer_1.rules; } /** @@ -1316,7 +1264,7 @@ var Lexer_1 = class Lexer { .replace(/\r\n|\r/g, '\n') .replace(/\t/g, ' '); - this.blockTokens(src, this.tokens); + this.blockTokens(src, this.tokens, true); this.inline(this.tokens); @@ -1326,175 +1274,79 @@ var Lexer_1 = class Lexer { /** * Lexing */ - blockTokens(src, tokens, top = true) { + blockTokens(src, tokens = [], top = true) { src = src.replace(/^ +$/gm, ''); - let next, - loose, - cap, - bull, - b, - item, - list, - space, - i, - tag, - l, - isordered, - istask, - ischecked, - lastToken, - addBack, - raw; + let token; while (src) { // newline - if (token = this.tokenizer.space(obj)) { - tokens.push(token); + if (token = this.tokenizer.space(this, src, tokens, top)) { + src = src.substring(token.raw.length); + if (token.type) { + tokens.push(token); + } continue; } // code - if (token = this.tokenizer.code(obj)) { + if (token = this.tokenizer.code(this, src, tokens, top)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // fences - if (token = this.tokenizer.fences(obj)) { + if (token = this.tokenizer.fences(this, src, tokens, top)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // heading - if (token = this.tokenizer.heading(obj)) { + if (token = this.tokenizer.heading(this, src, tokens, top)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // table no leading pipe (gfm) - if (token = this.tokenizer.nptable(obj)) { + if (token = this.tokenizer.nptable(this, src, tokens, top)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // hr - if (token = this.tokenizer.hr(obj)) { + if (token = this.tokenizer.hr(this, src, tokens, top)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // blockquote - if (cap = this.rules.block.blockquote.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - - cap = cap[0].replace(/^ *> ?/gm, ''); - - tokens.push({ - type: 'blockquote', - raw, - tokens: this.blockTokens(cap, [], top) - }); - + if (token = this.tokenizer.blockquote(this, src, tokens, top)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // list - if (cap = this.rules.block.list.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - bull = cap[2]; - isordered = bull.length > 1; - - list = { - type: 'list', - raw, - ordered: isordered, - start: isordered ? +bull : '', - loose: false, - items: [] - }; - - tokens.push(list); - - // Get each top-level item. - cap = cap[0].match(this.rules.block.item); - - next = false; - - l = cap.length; - for (i = 0; i < l; i++) { - item = cap[i]; - raw = item.trim(); - - // Remove the list item's bullet - // so it is seen as the next token. - space = item.length; - item = item.replace(/^ *([*+-]|\d+\.) */, ''); - - // Outdent whatever the - // list item contains. Hacky. - if (~item.indexOf('\n ')) { - space -= item.length; - item = !this.options.pedantic - ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') - : item.replace(/^ {1,4}/gm, ''); - } - - // Determine whether the next list item belongs here. - // Backpedal if it does not belong in this list. - if (i !== l - 1) { - b = block$1.bullet.exec(cap[i + 1])[0]; - if (bull.length > 1 ? b.length === 1 - : (b.length > 1 || (this.options.smartLists && b !== bull))) { - addBack = cap.slice(i + 1).join('\n'); - src = addBack + src; - list.raw = list.raw.substring(list.raw.length - addBack.length); - i = l - 1; - } - } - - // Determine whether item is loose or not. - // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/ - // for discount behavior. - loose = next || /\n\n(?!\s*$)/.test(item); - if (i !== l - 1) { - next = item.charAt(item.length - 1) === '\n'; - if (!loose) loose = next; - } - - if (loose) { - list.loose = true; - } - - // Check for task list items - istask = /^\[[ xX]\] /.test(item); - ischecked = undefined; - if (istask) { - ischecked = item[1] !== ' '; - item = item.replace(/^\[[ xX]\] +/, ''); - } - - list.items.push({ - raw, - task: istask, - checked: ischecked, - loose: loose, - tokens: this.blockTokens(item, [], false) - }); - } - + if (token = this.tokenizer.list(this, src, tokens, top)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // html - if (token = this.tokenizer.html(obj)) { + if (token = this.tokenizer.html(this, src, tokens, top)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // def - if (top && (token = this.tokenizer.def(obj))) { + if (top && (token = this.tokenizer.def(this, src, tokens, top))) { + src = src.substring(token.raw.length); if (!this.tokens.links[token.tag]) { this.tokens.links[token.tag] = { href: token.href, @@ -1505,31 +1357,35 @@ var Lexer_1 = class Lexer { } // table (gfm) - if (token = this.tokenizer.table(obj)) { + if (token = this.tokenizer.table(this, src, tokens, top)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // lheading - if (token = this.tokenizer.lheading(obj)) { + if (token = this.tokenizer.lheading(this, src, tokens, top)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // top-level paragraph - if (top && (token = this.tokenizer.paragraph(obj))) { + if (top && (token = this.tokenizer.paragraph(this, src, tokens, top))) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // text - if (token = this.tokenizer.text(obj)) { + if (token = this.tokenizer.text(this, src, tokens, top)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } - if (obj.src) { - const errMsg = 'Infinite loop on byte: ' + obj.src.charCodeAt(0); + if (src) { + const errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0); if (this.options.silent) { console.error(errMsg); break; @@ -1607,126 +1463,96 @@ var Lexer_1 = class Lexer { /** * Lexing/Compiling */ - inlineTokens(src, tokens) { - let out = '', - link, - text, - newTokens, - href, - title, - cap, - prevCapZero, - lastParenIndex, - start, - linkLen, - raw; + inlineTokens(src, tokens = []) { + let token; - while (obj.src) { + while (src) { // escape - if (token = this.tokenizer.escape(obj)) { + if (token = this.tokenizer.escape(this, src, tokens)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // tag - if (token = this.tokenizer.tag(obj)) { + if (token = this.tokenizer.tag(this, src, tokens)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // link - if (token = this.tokenizer.link(obj)) { + if (token = this.tokenizer.link(this, src, tokens)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // reflink, nolink - if (token = this.tokenizer.reflink(obj)) { + if (token = this.tokenizer.reflink(this, src, tokens)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // strong - if (cap = this.rules.inline.strong.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - newTokens = tokens ? [] : null; - text = this.inlineTokens(cap[4] || cap[3] || cap[2] || cap[1], newTokens); - - tokens.push({ - type: 'strong', - raw, - text, - tokens: newTokens - }); - out += text; + if (token = this.tokenizer.strong(this, src, tokens)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // em - if (cap = this.rules.inline.em.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - newTokens = tokens ? [] : null; - text = this.inlineTokens(cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1], newTokens); - tokens.push({ - type: 'em', - raw, - text, - tokens: newTokens - }); - out += text; + if (token = this.tokenizer.em(this, src, tokens)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // code - if (token = this.tokenizer.codespan(obj)) { + if (token = this.tokenizer.codespan(this, src, tokens)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // br - if (token = this.tokenizer.br(obj)) { + if (token = this.tokenizer.br(this, src, tokens)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // del (gfm) - if (cap = this.rules.inline.del.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - newTokens = tokens ? [] : null; - text = this.inlineTokens(cap[1], newTokens); - tokens.push({ - type: 'del', - raw, - text, - tokens: newTokens - }); - out += text; + if (token = this.tokenizer.del(this, src, tokens)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // autolink - if (token = this.tokenizer.autolink(obj)) { + if (token = this.tokenizer.autolink(this, src, tokens)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // url (gfm) - if (token = this.tokenizer.url(obj)) { + if (token = this.tokenizer.url(this, src, tokens)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // text - if (token = this.tokenizer.inlineText(obj)) { + if (token = this.tokenizer.inlineText(this, src, tokens)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } - if (obj.src) { - const errMsg = 'Infinite loop on byte: ' + obj.src.charCodeAt(0); + if (src) { + const errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0); if (this.options.silent) { console.error(errMsg); break; @@ -1736,84 +1562,7 @@ var Lexer_1 = class Lexer { } } - return out; - } - - escapes(text) { - return text ? text.replace(inline$1._escapes, '$1') : text; - } - - /** - * tokenize Link - */ - outputLink(cap, link, tokens, raw) { - const href = link.href; - const title = link.title ? escape$1(link.title) : null; - const newTokens = tokens ? [] : null; - - if (cap[0].charAt(0) !== '!') { - const text = this.inlineTokens(cap[1], newTokens); - tokens.push({ - type: 'link', - raw, - text, - href, - title, - tokens: newTokens - }); - return text; - } else { - const text = escape$1(cap[1]); - tokens.push({ - type: 'image', - raw, - text, - href, - title - }); - return text; - } - } - - /** - * Smartypants Transformations - */ - smartypants(text) { - return text - // em-dashes - .replace(/---/g, '\u2014') - // en-dashes - .replace(/--/g, '\u2013') - // opening singles - .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018') - // closing singles & apostrophes - .replace(/'/g, '\u2019') - // opening doubles - .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c') - // closing doubles - .replace(/"/g, '\u201d') - // ellipses - .replace(/\.{3}/g, '\u2026'); - } - - /** - * Mangle Links - */ - mangle(text) { - let out = '', - i, - ch; - - const l = text.length; - for (i = 0; i < l; i++) { - ch = text.charCodeAt(i); - if (Math.random() > 0.5) { - ch = 'x' + ch.toString(16); - } - out += '&#' + ch + ';'; - } - - return out; + return tokens; } }; diff --git a/lib/marked.js b/lib/marked.js index 0750fc777a..3b0d20fc49 100644 --- a/lib/marked.js +++ b/lib/marked.js @@ -53,6 +53,7 @@ silent: false, smartLists: false, smartypants: false, + tokenizer: null, xhtml: false }; } @@ -514,42 +515,95 @@ splitCells$1 = helpers.splitCells, _escape = helpers.escape, findClosingBracket$1 = helpers.findClosingBracket; - var inline$1 = rules.inline; + var block$1 = rules.block, + inline$1 = rules.inline; + + function outputLink(cap, link, tokens, raw, lexer) { + var href = link.href; + var title = link.title ? _escape(link.title) : null; + + if (cap[0].charAt(0) !== '!') { + return { + type: 'link', + raw: raw, + href: href, + title: title, + tokens: lexer.inlineTokens(cap[1]) + }; + } else { + return { + type: 'image', + raw: raw, + text: _escape(cap[1]), + href: href, + title: title + }; + } + } /** * Tokenizer */ + var Tokenizer_1 = /*#__PURE__*/function () { function Tokenizer(options) { this.options = options || defaults$1; + this.initialize(); } var _proto = Tokenizer.prototype; - _proto.space = function space(obj) { - var cap = obj.lexer.rules.block.newline.exec(obj.src); + _proto.initialize = function initialize() { + this.inLink = false; + this.inRawBlock = false; + this.rules = { + block: block$1.normal, + inline: inline$1.normal + }; - if (cap) { - obj.src = obj.src.substring(cap[0].length); + if (this.options.pedantic) { + this.rules.block = block$1.pedantic; + this.rules.inline = inline$1.pedantic; + } else if (this.options.gfm) { + this.rules.block = block$1.gfm; + if (this.options.breaks) { + this.rules.inline = inline$1.breaks; + } else { + this.rules.inline = inline$1.gfm; + } + } + } + /** + * Expose Block Rules + */ + ; + + _proto.space = function space(lexer, src, tokens, top) { + var cap = this.rules.block.newline.exec(src); + + if (cap) { if (cap[0].length > 1) { return { type: 'space', raw: cap[0] }; } + + return { + raw: '\n' + }; } }; - _proto.code = function code(obj) { - var cap = obj.lexer.rules.block.code.exec(obj.src); + _proto.code = function code(lexer, src, tokens, top) { + var cap = this.rules.block.code.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); - var lastToken = obj.tokens[obj.tokens.length - 1]; // An indented code block cannot interrupt a paragraph. + var lastToken = tokens[tokens.length - 1]; // An indented code block cannot interrupt a paragraph. if (lastToken && lastToken.type === 'paragraph') { - obj.tokens.pop(); + tokens.pop(); lastToken.text += '\n' + cap[0].trimRight(); lastToken.raw += '\n' + cap[0]; return lastToken; @@ -565,11 +619,10 @@ } }; - _proto.fences = function fences(obj) { - var cap = obj.lexer.rules.block.fences.exec(obj.src); + _proto.fences = function fences(lexer, src, tokens, top) { + var cap = this.rules.block.fences.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); return { type: 'code', raw: cap[0], @@ -579,11 +632,10 @@ } }; - _proto.heading = function heading(obj) { - var cap = obj.lexer.rules.block.heading.exec(obj.src); + _proto.heading = function heading(lexer, src, tokens, top) { + var cap = this.rules.block.heading.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); return { type: 'heading', raw: cap[0], @@ -593,8 +645,8 @@ } }; - _proto.nptable = function nptable(obj) { - var cap = obj.lexer.rules.block.nptable.exec(obj.src); + _proto.nptable = function nptable(lexer, src, tokens, top) { + var cap = this.rules.block.nptable.exec(src); if (cap) { var item = { @@ -606,7 +658,6 @@ }; if (item.header.length === item.align.length) { - obj.src = obj.src.substring(cap[0].length); var l = item.align.length; var i; @@ -633,11 +684,10 @@ } }; - _proto.hr = function hr(obj) { - var cap = obj.lexer.rules.block.hr.exec(obj.src); + _proto.hr = function hr(lexer, src, tokens, top) { + var cap = this.rules.block.hr.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); return { type: 'hr', raw: cap[0] @@ -645,25 +695,23 @@ } }; - _proto.blockquote = function blockquote(obj) { - var cap = obj.lexer.rules.block.blockquote.exec(obj.src); + _proto.blockquote = function blockquote(lexer, src, tokens, top) { + var cap = this.rules.block.blockquote.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); var text = cap[0].replace(/^ *> ?/gm, ''); return { type: 'blockquote', raw: cap[0], - tokens: obj.lexer.blockTokens([], text, obj.top) + tokens: lexer.blockTokens(text, [], top) }; } }; - _proto.list = function list(obj) { - var cap = obj.lexer.rules.block.list.exec(obj.src); + _proto.list = function list(lexer, src, tokens, top) { + var cap = this.rules.block.list.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); var raw = cap[0]; var bull = cap[2]; var isordered = bull.length > 1; @@ -676,7 +724,7 @@ items: [] }; // Get each top-level item. - var itemMatch = cap[0].match(obj.lexer.rules.block.item); + var itemMatch = cap[0].match(this.rules.block.item); var next = false, item, space, @@ -689,7 +737,7 @@ for (var i = 0; i < l; i++) { item = itemMatch[i]; - raw = item.trim(); // Remove the list item's bullet + raw = item; // Remove the list item's bullet // so it is seen as the next token. space = item.length; @@ -704,12 +752,11 @@ if (i !== l - 1) { - b = obj.lexer.rules.block.bullet.exec(itemMatch[i + 1])[0]; + b = this.rules.block.bullet.exec(itemMatch[i + 1])[0]; if (bull.length > 1 ? b.length === 1 : b.length > 1 || this.options.smartLists && b !== bull) { addBack = itemMatch.slice(i + 1).join('\n'); - obj.src = addBack + obj.src; - list.raw = list.raw.substring(list.raw.length - addBack.length); + list.raw = list.raw.substring(0, list.raw.length - addBack.length); i = l - 1; } } // Determine whether item is loose or not. @@ -742,7 +789,7 @@ task: istask, checked: ischecked, loose: loose, - tokens: obj.lexer.blockTokens([], item, false) + tokens: lexer.blockTokens(item, [], false) }); } @@ -750,11 +797,10 @@ } }; - _proto.html = function html(obj) { - var cap = obj.lexer.rules.block.html.exec(obj.src); + _proto.html = function html(lexer, src, tokens, top) { + var cap = this.rules.block.html.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); return { type: this.options.sanitize ? 'paragraph' : 'html', raw: cap[0], @@ -764,23 +810,23 @@ } }; - _proto.def = function def(obj) { - var cap = obj.lexer.rules.block.def.exec(obj.src); + _proto.def = function def(lexer, src, tokens, top) { + var cap = this.rules.block.def.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1); var tag = cap[1].toLowerCase().replace(/\s+/g, ' '); return { tag: tag, + raw: cap[0], href: cap[2], title: cap[3] }; } }; - _proto.table = function table(obj) { - var cap = obj.lexer.rules.block.table.exec(obj.src); + _proto.table = function table(lexer, src, tokens, top) { + var cap = this.rules.block.table.exec(src); if (cap) { var item = { @@ -791,7 +837,6 @@ }; if (item.header.length === item.align.length) { - obj.src = obj.src.substring(cap[0].length); item.raw = cap[0]; var l = item.align.length; var i; @@ -819,11 +864,10 @@ } }; - _proto.lheading = function lheading(obj) { - var cap = obj.lexer.rules.block.lheading.exec(obj.src); + _proto.lheading = function lheading(lexer, src, tokens, top) { + var cap = this.rules.block.lheading.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); return { type: 'heading', raw: cap[0], @@ -833,11 +877,10 @@ } }; - _proto.paragraph = function paragraph(obj) { - var cap = obj.lexer.rules.block.paragraph.exec(obj.src); + _proto.paragraph = function paragraph(lexer, src, tokens, top) { + var cap = this.rules.block.paragraph.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); return { type: 'paragraph', raw: cap[0], @@ -846,11 +889,10 @@ } }; - _proto.text = function text(obj) { - var cap = obj.lexer.rules.block.text.exec(obj.src); + _proto.text = function text(lexer, src, tokens, top) { + var cap = this.rules.block.text.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); return { type: 'text', raw: cap[0], @@ -859,53 +901,44 @@ } }; - _proto.escape = function escape(obj) { - var cap = obj.lexer.rules.inline.escape.exec(obj.src); + _proto.escape = function escape(lexer, src, tokens) { + var cap = this.rules.inline.escape.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); - - var text = _escape(cap[1]); - - obj.out += text; return { type: 'escape', raw: cap[0], - text: text + text: _escape(cap[1]) }; } - } // FIXME: inLink and inRawBlock should be on this - ; + }; - _proto.tag = function tag(obj) { - var cap = obj.lexer.rules.inline.tag.exec(obj.src); + _proto.tag = function tag(lexer, src, tokens) { + var cap = this.rules.inline.tag.exec(src); if (cap) { - if (!obj.lexer.inLink && /^/i.test(cap[0])) { - obj.lexer.inLink = false; + if (!this.inLink && /^/i.test(cap[0])) { + this.inLink = false; } - if (!obj.lexer.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { - obj.lexer.inRawBlock = true; - } else if (obj.lexer.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { - obj.lexer.inRawBlock = false; + if (!this.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { + this.inRawBlock = true; + } else if (this.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { + this.inRawBlock = false; } - obj.src = obj.src.substring(cap[0].length); - var text = this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0]; - obj.out += text; return { type: this.options.sanitize ? 'text' : 'html', raw: cap[0], - text: text + text: this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0] }; } }; - _proto.link = function link(obj) { - var cap = obj.lexer.rules.inline.link.exec(obj.src); + _proto.link = function link(lexer, src, tokens) { + var cap = this.rules.inline.link.exec(src); if (cap) { var lastParenIndex = findClosingBracket$1(cap[2], '()'); @@ -918,17 +951,16 @@ cap[3] = ''; } - obj.src = obj.src.substring(cap[0].length); - obj.lexer.inLink = true; + this.inLink = true; var href = cap[2]; var title = ''; if (this.options.pedantic) { - var _link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href); + var link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href); - if (_link) { - href = _link[1]; - title = _link[3]; + if (link) { + href = link[1]; + title = link[3]; } else { title = ''; } @@ -937,28 +969,24 @@ } href = href.trim().replace(/^<([\s\S]*)>$/, '$1'); - var link = this.outputLink(cap, { - href: this.escapes(href), - title: this.escapes(title) - }, obj.tokens, cap[0], obj); - obj.lexer.inLink = false; - obj.out += link.text; - return link.token; + var token = outputLink(cap, { + href: href ? href.replace(this.rules.inline._escapes, '$1') : href, + title: title ? title.replace(this.rules.inline._escapes, '$1') : title + }, tokens, cap[0], lexer); + this.inLink = false; + return token; } }; - _proto.reflink = function reflink(obj) { + _proto.reflink = function reflink(lexer, src, tokens) { var cap; - if ((cap = obj.lexer.rules.inline.reflink.exec(obj.src)) || (cap = obj.lexer.rules.inline.nolink.exec(obj.src))) { - obj.src = obj.src.substring(cap[0].length); + if ((cap = this.rules.inline.reflink.exec(src)) || (cap = this.rules.inline.nolink.exec(src))) { var link = (cap[2] || cap[1]).replace(/\s+/g, ' '); - link = obj.lexer.tokens.links[link.toLowerCase()]; + link = lexer.tokens.links[link.toLowerCase()]; if (!link || !link.href) { var text = cap[0].charAt(0); - obj.out += text; - obj.src = cap[0].substring(1) + obj.src; return { type: 'text', raw: text, @@ -966,71 +994,53 @@ }; } - obj.lexer.inLink = true; - var linkToken = this.outputLink(cap, link, obj.tokens, cap[0], obj); - obj.out += linkToken.text; - obj.lexer.inLink = false; - return linkToken.token; + this.inLink = true; + var token = outputLink(cap, link, tokens, cap[0], lexer); + this.inLink = false; + return token; } }; - _proto.strong = function strong(obj) { - var cap = obj.lexer.rules.inline.strong.exec(obj.src); + _proto.strong = function strong(lexer, src, tokens) { + var cap = this.rules.inline.strong.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); - var newTokens = obj.tokens ? [] : null; - var text = obj.lexer.inlineOutput(cap[4] || cap[3] || cap[2] || cap[1], newTokens); - obj.out += text; return { type: 'strong', raw: cap[0], - text: text, - tokens: newTokens + tokens: lexer.inlineTokens(cap[4] || cap[3] || cap[2] || cap[1]) }; } }; - _proto.em = function em(obj) { - var cap = obj.lexer.rules.inline.em.exec(obj.src); + _proto.em = function em(lexer, src, tokens) { + var cap = this.rules.inline.em.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); - var newTokens = obj.tokens ? [] : null; - var text = obj.lexer.inlineOutput(cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1], newTokens); - obj.out += text; return { type: 'em', raw: cap[0], - text: text, - tokens: newTokens + tokens: lexer.inlineTokens(cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1]) }; } }; - _proto.codespan = function codespan(obj) { - var cap = obj.lexer.rules.inline.code.exec(obj.src); + _proto.codespan = function codespan(lexer, src, tokens) { + var cap = this.rules.inline.code.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); - - var text = _escape(cap[2].trim(), true); - - obj.out += text; return { type: 'codespan', raw: cap[0], - text: text + text: _escape(cap[2].trim(), true) }; } }; - _proto.br = function br(obj) { - var cap = obj.lexer.rules.inline.br.exec(obj.src); + _proto.br = function br(lexer, src, tokens) { + var cap = this.rules.inline.br.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); - obj.out += '\n'; return { type: 'br', raw: cap[0] @@ -1038,28 +1048,22 @@ } }; - _proto.del = function del(obj) { - var cap = obj.lexer.rules.inline.del.exec(obj.src); + _proto.del = function del(lexer, src, tokens) { + var cap = this.rules.inline.del.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); - var newTokens = obj.tokens ? [] : null; - var text = obj.lexer.inlineOutput(cap[1], newTokens); - obj.out += text; return { type: 'del', raw: cap[0], - text: text, - tokens: newTokens + tokens: lexer.inlineTokens(cap[1]) }; } }; - _proto.autolink = function autolink(obj) { - var cap = obj.lexer.rules.inline.autolink.exec(obj.src); + _proto.autolink = function autolink(lexer, src, tokens) { + var cap = this.rules.inline.autolink.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); var text, href; if (cap[2] === '@') { @@ -1070,7 +1074,6 @@ href = text; } - obj.out += text; return { type: 'link', raw: cap[0], @@ -1085,10 +1088,10 @@ } }; - _proto.url = function url(obj) { + _proto.url = function url(lexer, src, tokens) { var cap; - if (!obj.lexer.inLink && (cap = obj.lexer.rules.inline.url.exec(obj.src))) { + if (!this.inLink && (cap = this.rules.inline.url.exec(src))) { var text, href; if (cap[2] === '@') { @@ -1100,7 +1103,7 @@ do { prevCapZero = cap[0]; - cap[0] = obj.lexer.rules.inline._backpedal.exec(cap[0])[0]; + cap[0] = this.rules.inline._backpedal.exec(cap[0])[0]; } while (prevCapZero !== cap[0]); text = _escape(cap[0]); @@ -1112,8 +1115,6 @@ } } - obj.src = obj.src.substring(cap[0].length); - obj.out += text; return { type: 'link', raw: cap[0], @@ -1128,67 +1129,24 @@ } }; - _proto.inlineText = function inlineText(obj) { - var cap = obj.lexer.rules.inline.text.exec(obj.src); + _proto.inlineText = function inlineText(lexer, src, tokens) { + var cap = this.rules.inline.text.exec(src); if (cap) { - obj.src = obj.src.substring(cap[0].length); var text; - if (obj.lexer.inRawBlock) { + if (this.inRawBlock) { text = this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0]; } else { text = _escape(this.options.smartypants ? this.smartypants(cap[0]) : cap[0]); } - obj.out += text; return { type: 'text', raw: cap[0], text: text }; } - }; - - _proto.escapes = function escapes(text) { - return text ? text.replace(inline$1._escapes, '$1') : text; - } - /** - * tokenize Link - */ - ; - - _proto.outputLink = function outputLink(cap, link, tokens, raw, obj) { - var href = link.href; - var title = link.title ? _escape(link.title) : null; - var newTokens = tokens ? [] : null; - var token, text; - - if (cap[0].charAt(0) !== '!') { - text = obj.lexer.inlineOutput(cap[1], newTokens); - token = { - type: 'link', - raw: raw, - text: text, - href: href, - title: title, - tokens: newTokens - }; - } else { - text = _escape(cap[1]); - token = { - type: 'image', - raw: raw, - text: text, - href: href, - title: title - }; - } - - return { - token: token, - text: text - }; } /** * Smartypants Transformations @@ -1229,12 +1187,20 @@ return out; }; + _createClass(Tokenizer, null, [{ + key: "rules", + get: function get() { + return { + block: block$1, + inline: inline$1 + }; + } + }]); + return Tokenizer; }(); var defaults$2 = defaults.defaults; - var block$1 = rules.block, - inline$2 = rules.inline; /** * Block Lexer */ @@ -1247,23 +1213,7 @@ this.options.tokenizer = this.options.tokenizer || new Tokenizer_1(); this.tokenizer = this.options.tokenizer; this.tokenizer.options = this.options; - this.rules = { - block: block$1.normal, - inline: inline$2.normal - }; - - if (this.options.pedantic) { - this.rules.block = block$1.pedantic; - this.rules.inline = inline$2.pedantic; - } else if (this.options.gfm) { - this.rules.block = block$1.gfm; - - if (this.options.breaks) { - this.rules.inline = inline$2.breaks; - } else { - this.rules.inline = inline$2.gfm; - } - } + this.tokenizer.initialize(); } /** * Expose Block Rules @@ -1286,7 +1236,7 @@ _proto.lex = function lex(src) { src = src.replace(/\r\n|\r/g, '\n').replace(/\t/g, ' '); - this.blockTokens(src, this.tokens); + this.blockTokens(src, this.tokens, true); this.inline(this.tokens); return this.tokens; } @@ -1296,158 +1246,89 @@ ; _proto.blockTokens = function blockTokens(src, tokens, top) { + if (tokens === void 0) { + tokens = []; + } + if (top === void 0) { top = true; } - var obj = { - tokens: tokens, - src: src.replace(/^ +$/gm, ''), - top: top, - lexer: this - }; + src = src.replace(/^ +$/gm, ''); var token; - while (obj.src) { + while (src) { // newline - if (token = this.tokenizer.space(obj)) { - tokens.push(token); + if (token = this.tokenizer.space(this, src, tokens, top)) { + src = src.substring(token.raw.length); + + if (token.type) { + tokens.push(token); + } + continue; } // code - if (token = this.tokenizer.code(obj)) { + if (token = this.tokenizer.code(this, src, tokens, top)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // fences - if (token = this.tokenizer.fences(obj)) { + if (token = this.tokenizer.fences(this, src, tokens, top)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // heading - if (token = this.tokenizer.heading(obj)) { + if (token = this.tokenizer.heading(this, src, tokens, top)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // table no leading pipe (gfm) - if (token = this.tokenizer.nptable(obj)) { + if (token = this.tokenizer.nptable(this, src, tokens, top)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // hr - if (token = this.tokenizer.hr(obj)) { + if (token = this.tokenizer.hr(this, src, tokens, top)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // blockquote - if (cap = this.rules.block.blockquote.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - cap = cap[0].replace(/^ *> ?/gm, ''); - tokens.push({ - type: 'blockquote', - raw: raw, - tokens: this.blockTokens(cap, [], top) - }); + if (token = this.tokenizer.blockquote(this, src, tokens, top)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // list - if (cap = this.rules.block.list.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - bull = cap[2]; - isordered = bull.length > 1; - list = { - type: 'list', - raw: raw, - ordered: isordered, - start: isordered ? +bull : '', - loose: false, - items: [] - }; - tokens.push(list); // Get each top-level item. - - cap = cap[0].match(this.rules.block.item); - next = false; - l = cap.length; - - for (i = 0; i < l; i++) { - item = cap[i]; - raw = item.trim(); // Remove the list item's bullet - // so it is seen as the next token. - - space = item.length; - item = item.replace(/^ *([*+-]|\d+\.) */, ''); // Outdent whatever the - // list item contains. Hacky. - - if (~item.indexOf('\n ')) { - space -= item.length; - item = !this.options.pedantic ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') : item.replace(/^ {1,4}/gm, ''); - } // Determine whether the next list item belongs here. - // Backpedal if it does not belong in this list. - - - if (i !== l - 1) { - b = block$1.bullet.exec(cap[i + 1])[0]; - - if (bull.length > 1 ? b.length === 1 : b.length > 1 || this.options.smartLists && b !== bull) { - addBack = cap.slice(i + 1).join('\n'); - src = addBack + src; - list.raw = list.raw.substring(list.raw.length - addBack.length); - i = l - 1; - } - } // Determine whether item is loose or not. - // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/ - // for discount behavior. - - - loose = next || /\n\n(?!\s*$)/.test(item); - - if (i !== l - 1) { - next = item.charAt(item.length - 1) === '\n'; - if (!loose) loose = next; - } - - if (loose) { - list.loose = true; - } // Check for task list items - - - istask = /^\[[ xX]\] /.test(item); - ischecked = undefined; - - if (istask) { - ischecked = item[1] !== ' '; - item = item.replace(/^\[[ xX]\] +/, ''); - } - - list.items.push({ - raw: raw, - task: istask, - checked: ischecked, - loose: loose, - tokens: this.blockTokens(item, [], false) - }); - } - + if (token = this.tokenizer.list(this, src, tokens, top)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // html - if (token = this.tokenizer.html(obj)) { + if (token = this.tokenizer.html(this, src, tokens, top)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // def - if (top && (token = this.tokenizer.def(obj))) { + if (top && (token = this.tokenizer.def(this, src, tokens, top))) { + src = src.substring(token.raw.length); + if (!this.tokens.links[token.tag]) { this.tokens.links[token.tag] = { href: token.href, @@ -1459,31 +1340,35 @@ } // table (gfm) - if (token = this.tokenizer.table(obj)) { + if (token = this.tokenizer.table(this, src, tokens, top)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // lheading - if (token = this.tokenizer.lheading(obj)) { + if (token = this.tokenizer.lheading(this, src, tokens, top)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // top-level paragraph - if (top && (token = this.tokenizer.paragraph(obj))) { + if (top && (token = this.tokenizer.paragraph(this, src, tokens, top))) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // text - if (token = this.tokenizer.text(obj)) { + if (token = this.tokenizer.text(this, src, tokens, top)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } - if (obj.src) { - var errMsg = 'Infinite loop on byte: ' + obj.src.charCodeAt(0); + if (src) { + var errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0); if (this.options.silent) { console.error(errMsg); @@ -1571,124 +1456,99 @@ ; _proto.inlineTokens = function inlineTokens(src, tokens) { - var out = '', - link, - text, - newTokens, - href, - title, - cap, - prevCapZero, - lastParenIndex, - start, - linkLen, - raw; + if (tokens === void 0) { + tokens = []; + } - while (obj.src) { + var token; + + while (src) { // escape - if (token = this.tokenizer.escape(obj)) { + if (token = this.tokenizer.escape(this, src, tokens)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // tag - if (token = this.tokenizer.tag(obj)) { + if (token = this.tokenizer.tag(this, src, tokens)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // link - if (token = this.tokenizer.link(obj)) { + if (token = this.tokenizer.link(this, src, tokens)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // reflink, nolink - if (token = this.tokenizer.reflink(obj)) { + if (token = this.tokenizer.reflink(this, src, tokens)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // strong - if (cap = this.rules.inline.strong.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - newTokens = tokens ? [] : null; - text = this.inlineTokens(cap[4] || cap[3] || cap[2] || cap[1], newTokens); - tokens.push({ - type: 'strong', - raw: raw, - text: text, - tokens: newTokens - }); - out += text; + if (token = this.tokenizer.strong(this, src, tokens)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // em - if (cap = this.rules.inline.em.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - newTokens = tokens ? [] : null; - text = this.inlineTokens(cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1], newTokens); - tokens.push({ - type: 'em', - raw: raw, - text: text, - tokens: newTokens - }); - out += text; + if (token = this.tokenizer.em(this, src, tokens)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // code - if (token = this.tokenizer.codespan(obj)) { + if (token = this.tokenizer.codespan(this, src, tokens)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // br - if (token = this.tokenizer.br(obj)) { + if (token = this.tokenizer.br(this, src, tokens)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // del (gfm) - if (cap = this.rules.inline.del.exec(src)) { - src = src.substring(cap[0].length); - raw = cap[0]; - newTokens = tokens ? [] : null; - text = this.inlineTokens(cap[1], newTokens); - tokens.push({ - type: 'del', - raw: raw, - text: text, - tokens: newTokens - }); - out += text; + if (token = this.tokenizer.del(this, src, tokens)) { + src = src.substring(token.raw.length); + tokens.push(token); continue; } // autolink - if (token = this.tokenizer.autolink(obj)) { + if (token = this.tokenizer.autolink(this, src, tokens)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // url (gfm) - if (token = this.tokenizer.url(obj)) { + if (token = this.tokenizer.url(this, src, tokens)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } // text - if (token = this.tokenizer.inlineText(obj)) { + if (token = this.tokenizer.inlineText(this, src, tokens)) { + src = src.substring(token.raw.length); tokens.push(token); continue; } - if (obj.src) { - var errMsg = 'Infinite loop on byte: ' + obj.src.charCodeAt(0); + if (src) { + var errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0); if (this.options.silent) { console.error(errMsg); @@ -1699,92 +1559,13 @@ } } - return out; - }; - - _proto.escapes = function escapes(text) { - return text ? text.replace(inline$1._escapes, '$1') : text; - } - /** - * tokenize Link - */ - ; - - _proto.outputLink = function outputLink(cap, link, tokens, raw) { - var href = link.href; - var title = link.title ? escape$1(link.title) : null; - var newTokens = tokens ? [] : null; - - if (cap[0].charAt(0) !== '!') { - var text = this.inlineTokens(cap[1], newTokens); - tokens.push({ - type: 'link', - raw: raw, - text: text, - href: href, - title: title, - tokens: newTokens - }); - return text; - } else { - var _text = escape$1(cap[1]); - - tokens.push({ - type: 'image', - raw: raw, - text: _text, - href: href, - title: title - }); - return _text; - } - } - /** - * Smartypants Transformations - */ - ; - - _proto.smartypants = function smartypants(text) { - return text // em-dashes - .replace(/---/g, "\u2014") // en-dashes - .replace(/--/g, "\u2013") // opening singles - .replace(/(^|[-\u2014/(\[{"\s])'/g, "$1\u2018") // closing singles & apostrophes - .replace(/'/g, "\u2019") // opening doubles - .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, "$1\u201C") // closing doubles - .replace(/"/g, "\u201D") // ellipses - .replace(/\.{3}/g, "\u2026"); - } - /** - * Mangle Links - */ - ; - - _proto.mangle = function mangle(text) { - var out = '', - i, - ch; - var l = text.length; - - for (i = 0; i < l; i++) { - ch = text.charCodeAt(i); - - if (Math.random() > 0.5) { - ch = 'x' + ch.toString(16); - } - - out += '&#' + ch + ';'; - } - - return out; + return tokens; }; _createClass(Lexer, null, [{ key: "rules", get: function get() { - return { - block: block$1, - inline: inline$2 - }; + return Tokenizer_1.rules; } }]); diff --git a/marked.min.js b/marked.min.js index 3ff5ab9b28..61d34f66e8 100644 --- a/marked.min.js +++ b/marked.min.js @@ -3,4 +3,4 @@ * Copyright (c) 2011-2020, Christopher Jeffrey. (MIT Licensed) * https://github.com/markedjs/marked */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).marked=t()}(this,function(){"use strict";function i(e,t){for(var n=0;n"']/),s=/[&<>"']/g,l=/[<>"']|&(?!#?\w+;)/,a=/[<>"']|&(?!#?\w+;)/g,o={"&":"&","<":"<",">":">",'"':""","'":"'"};var c=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;function h(e){return e.replace(c,function(e,t){return"colon"===(t=t.toLowerCase())?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""})}var u=/(^|[^\[])\^/g;var p=/[^\w:]/g,g=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;var f={},d=/^[^:]+:\/*[^/]*$/,b=/^([^:]+:)[\s\S]*$/,k=/^([^:]+:\/*[^/]*)[\s\S]*$/;function m(e,t){f[" "+e]||(d.test(e)?f[" "+e]=e+"/":f[" "+e]=x(e,"/",!0));var n=-1===(e=f[" "+e]).indexOf(":");return"//"===t.substring(0,2)?n?t:e.replace(b,"$1")+t:"/"===t.charAt(0)?n?t:e.replace(k,"$1")+t:e+t}function x(e,t,n){var r=e.length;if(0===r)return"";for(var s=0;st)n.splice(t);else for(;n.length ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:"^ {0,3}(?:<(script|pre|style)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?\\?>\\n*|\\n*|\\n*|)[\\s\\S]*?(?:\\n{2,}|$)|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$))",def:/^ {0,3}\[(label)\]: *\n? *]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,nptable:R,table:R,lheading:/^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,_paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html)[^\n]+)*)/,text:/^[^\n]+/,_label:/(?!\s*\])(?:\\[\[\]]|[^\[\]])+/,_title:/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/};I.def=Z(I.def).replace("label",I._label).replace("title",I._title).getRegex(),I.bullet=/(?:[*+-]|\d{1,9}\.)/,I.item=/^( *)(bull) ?[^\n]*(?:\n(?!\1bull ?)[^\n]*)*/,I.item=Z(I.item,"gm").replace(/bull/g,I.bullet).getRegex(),I.list=Z(I.list).replace(/bull/g,I.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+I.def.source+")").getRegex(),I._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",I._comment=//,I.html=Z(I.html,"i").replace("comment",I._comment).replace("tag",I._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),I.paragraph=Z(I._paragraph).replace("hr",I.hr).replace("heading"," {0,3}#{1,6} ").replace("|lheading","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",I._tag).getRegex(),I.blockquote=Z(I.blockquote).replace("paragraph",I.paragraph).getRegex(),I.normal=q({},I),I.gfm=q({},I.normal,{nptable:"^ *([^|\\n ].*\\|.*)\\n *([-:]+ *\\|[-| :]*)(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)",table:"^ *\\|(.+)\\n *\\|?( *[-:]+[-| :]*)(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)"}),I.gfm.nptable=Z(I.gfm.nptable).replace("hr",I.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",I._tag).getRegex(),I.gfm.table=Z(I.gfm.table).replace("hr",I.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",I._tag).getRegex(),I.pedantic=q({},I.normal,{html:Z("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",I._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,fences:R,paragraph:Z(I.normal._paragraph).replace("hr",I.hr).replace("heading"," *#{1,6} *[^\n]").replace("lheading",I.lheading).replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").getRegex()});var L={escape:/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:R,tag:"^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^",link:/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,strong:/^__([^\s_])__(?!_)|^\*\*([^\s*])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/,em:/^_([^\s_])_(?!_)|^\*([^\s*<\[])\*(?!\*)|^_([^\s<][\s\S]*?[^\s_])_(?!_|[^\spunctuation])|^_([^\s_<][\s\S]*?[^\s])_(?!_|[^\spunctuation])|^\*([^\s<"][\s\S]*?[^\s\*])\*(?!\*|[^\spunctuation])|^\*([^\s*"<\[][\s\S]*?[^\s])\*(?!\*)/,code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:R,text:/^(`+|[^`])(?:[\s\S]*?(?:(?=[\\?@\\[^_{|}~"};L.em=Z(L.em).replace(/punctuation/g,L._punctuation).getRegex(),L._escapes=/\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g,L._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,L._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])?)+(?![-_])/,L.autolink=Z(L.autolink).replace("scheme",L._scheme).replace("email",L._email).getRegex(),L._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,L.tag=Z(L.tag).replace("comment",I._comment).replace("attribute",L._attribute).getRegex(),L._label=/(?:\[[^\[\]]*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,L._href=/<(?:\\[<>]?|[^\s<>\\])*>|[^\s\x00-\x1f]*/,L._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,L.link=Z(L.link).replace("label",L._label).replace("href",L._href).replace("title",L._title).getRegex(),L.reflink=Z(L.reflink).replace("label",L._label).getRegex(),L.normal=q({},L),L.pedantic=q({},L.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,link:Z(/^!?\[(label)\]\((.*?)\)/).replace("label",L._label).getRegex(),reflink:Z(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",L._label).getRegex()}),L.gfm=q({},L.normal,{escape:Z(L.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^~+(?=\S)([\s\S]*?\S)~+/,text:/^(`+|[^`])(?:[\s\S]*?(?:(?=[\\ ?/gm,""),t.push({type:"blockquote",raw:x,tokens:this.blockTokens(i,[],n)});else if(i=this.rules.block.list.exec(e))for(e=e.substring(i[0].length),c={type:"list",raw:x=i[0],ordered:f=1<(l=i[2]).length,start:f?+l:"",loose:!1,items:[]},t.push(c),r=!1,g=(i=i[0].match(this.rules.block.item)).length,u=0;u/i.test(a[0])&&(this.inLink=!1),!this.inRawBlock&&/^<(pre|code|kbd|script)(\s|>)/i.test(a[0])?this.inRawBlock=!0:this.inRawBlock&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(a[0])&&(this.inRawBlock=!1),e=e.substring(a[0].length),u=a[0],r=this.options.sanitize?this.options.sanitizer?this.options.sanitizer(a[0]):P(a[0]):a[0],t.push({type:this.options.sanitize?"text":"html",raw:u,text:r}),p+=r;else if(a=this.rules.inline.link.exec(e))-1<(c=B(a[2],"()"))&&(h=(0===a[0].indexOf("!")?5:4)+a[1].length+c,a[2]=a[2].substring(0,c),a[0]=a[0].substring(0,h).trim(),a[3]=""),e=e.substring(a[0].length),u=a[0],this.inLink=!0,i=a[2],l=this.options.pedantic?(n=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(i))?(i=n[1],n[3]):"":a[3]?a[3].slice(1,-1):"",i=i.trim().replace(/^<([\s\S]*)>$/,"$1"),p+=this.outputLink(a,{href:this.escapes(i),title:this.escapes(l)},t,u),this.inLink=!1;else if((a=this.rules.inline.reflink.exec(e))||(a=this.rules.inline.nolink.exec(e))){if(e=e.substring(a[0].length),u=a[0],n=(a[2]||a[1]).replace(/\s+/g," "),!(n=this.tokens.links[n.toLowerCase()])||!n.href){p+=r=a[0].charAt(0),t.push({type:"text",raw:r,text:r}),e=a[0].substring(1)+e;continue}this.inLink=!0,p+=this.outputLink(a,n,t,u),this.inLink=!1}else if(a=this.rules.inline.strong.exec(e))e=e.substring(a[0].length),u=a[0],s=t?[]:null,r=this.inlineTokens(a[4]||a[3]||a[2]||a[1],s),t.push({type:"strong",raw:u,text:r,tokens:s}),p+=r;else if(a=this.rules.inline.em.exec(e))e=e.substring(a[0].length),u=a[0],s=t?[]:null,r=this.inlineTokens(a[6]||a[5]||a[4]||a[3]||a[2]||a[1],s),t.push({type:"em",raw:u,text:r,tokens:s}),p+=r;else if(a=this.rules.inline.code.exec(e))e=e.substring(a[0].length),u=a[0],r=P(a[2].trim(),!0),t.push({type:"codespan",raw:u,text:r}),p+=r;else if(a=this.rules.inline.br.exec(e))e=e.substring(a[0].length),u=a[0],t.push({type:"br",raw:u}),p+="\n";else if(a=this.rules.inline.del.exec(e))e=e.substring(a[0].length),u=a[0],s=t?[]:null,r=this.inlineTokens(a[1],s),t.push({type:"del",raw:u,text:r,tokens:s}),p+=r;else if(a=this.rules.inline.autolink.exec(e))e=e.substring(a[0].length),u=a[0],i="@"===a[2]?"mailto:"+(r=P(this.options.mangle?this.mangle(a[1]):a[1])):r=P(a[1]),t.push({type:"link",raw:u,text:r,href:i,tokens:[{type:"text",raw:r,text:r}]}),p+=r;else if(this.inLink||!(a=this.rules.inline.url.exec(e))){if(a=this.rules.inline.text.exec(e))e=e.substring(a[0].length),u=a[0],r=this.inRawBlock?this.options.sanitize?this.options.sanitizer?this.options.sanitizer(a[0]):P(a[0]):a[0]:P(this.options.smartypants?this.smartypants(a[0]):a[0]),t.push({type:"text",raw:u,text:r}),p+=r;else if(e){var g="Infinite loop on byte: "+e.charCodeAt(0);if(!this.options.silent)throw new Error(g);console.error(g)}}else{if("@"===a[2])i="mailto:"+(r=P(this.options.mangle?this.mangle(a[0]):a[0]));else{for(;o=a[0],a[0]=this.rules.inline._backpedal.exec(a[0])[0],o!==a[0];);r=P(a[0]),i="www."===a[1]?"http://"+r:r}e=e.substring(a[0].length),u=a[0],t.push({type:"link",raw:u,text:r,href:i,tokens:[{type:"text",raw:r,text:r}]}),p+=r}return p},s.escapes=function(e){return e?e.replace(D._escapes,"$1"):e},s.outputLink=function(e,t,n,r){var s=t.href,i=t.title?P(t.title):null,l=n?[]:null;if("!"!==e[0].charAt(0)){var a=this.inlineTokens(e[1],l);return n.push({type:"link",raw:r,text:a,href:s,title:i,tokens:l}),a}var o=P(e[1]);return n.push({type:"image",raw:r,text:o,href:s,title:i}),o},s.smartypants=function(e){return e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")},s.mangle=function(e){var t,n,r="",s=e.length;for(t=0;t'+(n?e:X(e,!0))+"\n":"
    "+(n?e:X(e,!0))+"
    "},t.blockquote=function(e){return"
    \n"+e+"
    \n"},t.html=function(e){return e},t.heading=function(e,t,n,r){return this.options.headerIds?"'+e+"\n":""+e+"\n"},t.hr=function(){return this.options.xhtml?"
    \n":"
    \n"},t.list=function(e,t,n){var r=t?"ol":"ul";return"<"+r+(t&&1!==n?' start="'+n+'"':"")+">\n"+e+"\n"},t.listitem=function(e){return"
  • "+e+"
  • \n"},t.checkbox=function(e){return" "},t.paragraph=function(e){return"

    "+e+"

    \n"},t.table=function(e,t){return"\n\n"+e+"\n"+(t=t&&""+t+"")+"
    \n"},t.tablerow=function(e){return"\n"+e+"\n"},t.tablecell=function(e,t){var n=t.header?"th":"td";return(t.align?"<"+n+' align="'+t.align+'">':"<"+n+">")+e+"\n"},t.strong=function(e){return""+e+""},t.em=function(e){return""+e+""},t.codespan=function(e){return""+e+""},t.br=function(){return this.options.xhtml?"
    ":"
    "},t.del=function(e){return""+e+""},t.link=function(e,t,n){if(null===(e=N(this.options.sanitize,this.options.baseUrl,e)))return n;var r='
    "},t.image=function(e,t,n){if(null===(e=N(this.options.sanitize,this.options.baseUrl,e)))return n;var r=''+n+'":">"},t.text=function(e){return e},e}(),M=function(){function e(){}var t=e.prototype;return t.strong=function(e){return e},t.em=function(e){return e},t.codespan=function(e){return e},t.del=function(e){return e},t.html=function(e){return e},t.text=function(e){return e},t.link=function(e,t,n){return""+n},t.image=function(e,t,n){return""+n},t.br=function(){return""},e}(),V=function(){function e(){this.seen={}}return e.prototype.slug=function(e){var t=e.toLowerCase().trim().replace(/<[!\/a-z].*?>/gi,"").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g,"").replace(/\s/g,"-");if(this.seen.hasOwnProperty(t))for(var n=t;this.seen[n]++,t=n+"-"+this.seen[n],this.seen.hasOwnProperty(t););return this.seen[t]=0,t},e}(),H=t.defaults,J=_,K=function(){function n(e){this.options=e||H,this.options.renderer=this.options.renderer||new G,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new M,this.slugger=new V}n.parse=function(e,t){return new n(t).parse(e)};var e=n.prototype;return e.parse=function(e,t){void 0===t&&(t=!0);var n,r,s,i,l,a,o,c,h,u,p,g,f,d,b,k,m,x,w="",_=e.length;for(n=0;n<_;n++)switch((u=e[n]).type){case"space":continue;case"hr":w+=this.renderer.hr();continue;case"heading":w+=this.renderer.heading(this.parseInline(u.tokens),u.depth,J(this.parseInline(u.tokens,this.textRenderer)),this.slugger);continue;case"code":w+=this.renderer.code(u.text,u.lang,u.escaped);continue;case"table":for(o=c="",i=u.header.length,r=0;rAn error occurred:

    "+Y(e.message+"",!0)+"
    ";throw e}}return re.options=re.setOptions=function(e){return Q(re.defaults,e),te(re.defaults),re},re.getDefaults=ee,re.defaults=ne,re.Parser=K,re.parser=K.parse,re.Renderer=G,re.TextRenderer=M,re.Lexer=U,re.lexer=U.lex,re.Slugger=V,re.parse=re}); +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).marked=t()}(this,function(){"use strict";function r(e,t){for(var n=0;n"']/),l=/[&<>"']/g,a=/[<>"']|&(?!#?\w+;)/,o=/[<>"']|&(?!#?\w+;)/g,h={"&":"&","<":"<",">":">",'"':""","'":"'"};var c=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;function u(e){return e.replace(c,function(e,t){return"colon"===(t=t.toLowerCase())?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""})}var p=/(^|[^\[])\^/g;var g=/[^\w:]/g,f=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;var d={},k=/^[^:]+:\/*[^/]*$/,b=/^([^:]+:)[\s\S]*$/,m=/^([^:]+:\/*[^/]*)[\s\S]*$/;function x(e,t){d[" "+e]||(k.test(e)?d[" "+e]=e+"/":d[" "+e]=w(e,"/",!0));var n=-1===(e=d[" "+e]).indexOf(":");return"//"===t.substring(0,2)?n?t:e.replace(b,"$1")+t:"/"===t.charAt(0)?n?t:e.replace(m,"$1")+t:e+t}function w(e,t,n){var r=e.length;if(0===r)return"";for(var i=0;it)n.splice(t);else for(;n.length ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:"^ {0,3}(?:<(script|pre|style)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?\\?>\\n*|\\n*|\\n*|)[\\s\\S]*?(?:\\n{2,}|$)|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$))",def:/^ {0,3}\[(label)\]: *\n? *]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,nptable:Z,table:Z,lheading:/^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,_paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html)[^\n]+)*)/,text:/^[^\n]+/,_label:/(?!\s*\])(?:\\[\[\]]|[^\[\]])+/,_title:/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/};T.def=q(T.def).replace("label",T._label).replace("title",T._title).getRegex(),T.bullet=/(?:[*+-]|\d{1,9}\.)/,T.item=/^( *)(bull) ?[^\n]*(?:\n(?!\1bull ?)[^\n]*)*/,T.item=q(T.item,"gm").replace(/bull/g,T.bullet).getRegex(),T.list=q(T.list).replace(/bull/g,T.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+T.def.source+")").getRegex(),T._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",T._comment=//,T.html=q(T.html,"i").replace("comment",T._comment).replace("tag",T._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),T.paragraph=q(T._paragraph).replace("hr",T.hr).replace("heading"," {0,3}#{1,6} ").replace("|lheading","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",T._tag).getRegex(),T.blockquote=q(T.blockquote).replace("paragraph",T.paragraph).getRegex(),T.normal=I({},T),T.gfm=I({},T.normal,{nptable:"^ *([^|\\n ].*\\|.*)\\n *([-:]+ *\\|[-| :]*)(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)",table:"^ *\\|(.+)\\n *\\|?( *[-:]+[-| :]*)(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)"}),T.gfm.nptable=q(T.gfm.nptable).replace("hr",T.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",T._tag).getRegex(),T.gfm.table=q(T.gfm.table).replace("hr",T.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",T._tag).getRegex(),T.pedantic=I({},T.normal,{html:q("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",T._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,fences:Z,paragraph:q(T.normal._paragraph).replace("hr",T.hr).replace("heading"," *#{1,6} *[^\n]").replace("lheading",T.lheading).replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").getRegex()});var L={escape:/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:Z,tag:"^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^",link:/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,strong:/^__([^\s_])__(?!_)|^\*\*([^\s*])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/,em:/^_([^\s_])_(?!_)|^\*([^\s*<\[])\*(?!\*)|^_([^\s<][\s\S]*?[^\s_])_(?!_|[^\spunctuation])|^_([^\s_<][\s\S]*?[^\s])_(?!_|[^\spunctuation])|^\*([^\s<"][\s\S]*?[^\s\*])\*(?!\*|[^\spunctuation])|^\*([^\s*"<\[][\s\S]*?[^\s])\*(?!\*)/,code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:Z,text:/^(`+|[^`])(?:[\s\S]*?(?:(?=[\\?@\\[^_{|}~"};L.em=q(L.em).replace(/punctuation/g,L._punctuation).getRegex(),L._escapes=/\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g,L._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,L._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])?)+(?![-_])/,L.autolink=q(L.autolink).replace("scheme",L._scheme).replace("email",L._email).getRegex(),L._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,L.tag=q(L.tag).replace("comment",T._comment).replace("attribute",L._attribute).getRegex(),L._label=/(?:\[[^\[\]]*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,L._href=/<(?:\\[<>]?|[^\s<>\\])*>|[^\s\x00-\x1f]*/,L._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,L.link=q(L.link).replace("label",L._label).replace("href",L._href).replace("title",L._title).getRegex(),L.reflink=q(L.reflink).replace("label",L._label).getRegex(),L.normal=I({},L),L.pedantic=I({},L.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,link:q(/^!?\[(label)\]\((.*?)\)/).replace("label",L._label).getRegex(),reflink:q(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",L._label).getRegex()}),L.gfm=I({},L.normal,{escape:q(L.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^~+(?=\S)([\s\S]*?\S)~+/,text:/^(`+|[^`])(?:[\s\S]*?(?:(?=[\\ ?/gm,"");return{type:"blockquote",raw:i[0],tokens:e.blockTokens(s,[],r)}}},t.list=function(e,t,n,r){var i=this.rules.block.list.exec(t);if(i){for(var s,l,a,o,h,c,u,p=i[0],g=i[2],f=1/i.test(n[0])&&(this.inLink=!1),!this.inRawBlock&&/^<(pre|code|kbd|script)(\s|>)/i.test(n[0])?this.inRawBlock=!0:this.inRawBlock&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(n[0])&&(this.inRawBlock=!1),{type:this.options.sanitize?"text":"html",raw:n[0],text:this.options.sanitize?this.options.sanitizer?this.options.sanitizer(n[0]):j(n[0]):n[0]}},t.link=function(e,t,n){var r=this.rules.inline.link.exec(t);if(r){var i=P(r[2],"()");if(-1$/,"$1"))?l.replace(this.rules.inline._escapes,"$1"):l,title:a?a.replace(this.rules.inline._escapes,"$1"):a},0,r[0],e);return this.inLink=!1,h}},t.reflink=function(e,t){var n;if((n=this.rules.inline.reflink.exec(t))||(n=this.rules.inline.nolink.exec(t))){var r=(n[2]||n[1]).replace(/\s+/g," ");if(!(r=e.tokens.links[r.toLowerCase()])||!r.href){var i=n[0].charAt(0);return{type:"text",raw:i,text:i}}this.inLink=!0;var s=F(n,r,0,n[0],e);return this.inLink=!1,s}},t.strong=function(e,t){var n=this.rules.inline.strong.exec(t);if(n)return{type:"strong",raw:n[0],tokens:e.inlineTokens(n[4]||n[3]||n[2]||n[1])}},t.em=function(e,t){var n=this.rules.inline.em.exec(t);if(n)return{type:"em",raw:n[0],tokens:e.inlineTokens(n[6]||n[5]||n[4]||n[3]||n[2]||n[1])}},t.codespan=function(e,t){var n=this.rules.inline.code.exec(t);if(n)return{type:"codespan",raw:n[0],text:j(n[2].trim(),!0)}},t.br=function(e,t){var n=this.rules.inline.br.exec(t);if(n)return{type:"br",raw:n[0]}},t.del=function(e,t){var n=this.rules.inline.del.exec(t);if(n)return{type:"del",raw:n[0],tokens:e.inlineTokens(n[1])}},t.autolink=function(e,t){var n,r,i=this.rules.inline.autolink.exec(t);if(i)return r="@"===i[2]?"mailto:"+(n=j(this.options.mangle?this.mangle(i[1]):i[1])):n=j(i[1]),{type:"link",raw:i[0],text:n,href:r,tokens:[{type:"text",raw:n,text:n}]}},t.url=function(e,t){var n;if(!this.inLink&&(n=this.rules.inline.url.exec(t))){var r,i;if("@"===n[2])i="mailto:"+(r=j(this.options.mangle?this.mangle(n[0]):n[0]));else{for(var s;s=n[0],n[0]=this.rules.inline._backpedal.exec(n[0])[0],s!==n[0];);r=j(n[0]),i="www."===n[1]?"http://"+r:r}return{type:"link",raw:n[0],text:r,href:i,tokens:[{type:"text",raw:r,text:r}]}}},t.inlineText=function(e,t){var n,r=this.rules.inline.text.exec(t);if(r)return n=this.inRawBlock?this.options.sanitize?this.options.sanitizer?this.options.sanitizer(r[0]):j(r[0]):r[0]:j(this.options.smartypants?this.smartypants(r[0]):r[0]),{type:"text",raw:r[0],text:n}},t.smartypants=function(e){return e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")},t.mangle=function(e){var t,n,r="",i=e.length;for(t=0;t'+(n?e:H(e,!0))+"\n":"
    "+(n?e:H(e,!0))+"
    "},t.blockquote=function(e){return"
    \n"+e+"
    \n"},t.html=function(e){return e},t.heading=function(e,t,n,r){return this.options.headerIds?"'+e+"\n":""+e+"\n"},t.hr=function(){return this.options.xhtml?"
    \n":"
    \n"},t.list=function(e,t,n){var r=t?"ol":"ul";return"<"+r+(t&&1!==n?' start="'+n+'"':"")+">\n"+e+"\n"},t.listitem=function(e){return"
  • "+e+"
  • \n"},t.checkbox=function(e){return" "},t.paragraph=function(e){return"

    "+e+"

    \n"},t.table=function(e,t){return"\n\n"+e+"\n"+(t=t&&""+t+"")+"
    \n"},t.tablerow=function(e){return"\n"+e+"\n"},t.tablecell=function(e,t){var n=t.header?"th":"td";return(t.align?"<"+n+' align="'+t.align+'">':"<"+n+">")+e+"\n"},t.strong=function(e){return""+e+""},t.em=function(e){return""+e+""},t.codespan=function(e){return""+e+""},t.br=function(){return this.options.xhtml?"
    ":"
    "},t.del=function(e){return""+e+""},t.link=function(e,t,n){if(null===(e=V(this.options.sanitize,this.options.baseUrl,e)))return n;var r='
    "},t.image=function(e,t,n){if(null===(e=V(this.options.sanitize,this.options.baseUrl,e)))return n;var r=''+n+'":">"},t.text=function(e){return e},e}(),K=function(){function e(){}var t=e.prototype;return t.strong=function(e){return e},t.em=function(e){return e},t.codespan=function(e){return e},t.del=function(e){return e},t.html=function(e){return e},t.text=function(e){return e},t.link=function(e,t,n){return""+n},t.image=function(e,t,n){return""+n},t.br=function(){return""},e}(),Q=function(){function e(){this.seen={}}return e.prototype.slug=function(e){var t=e.toLowerCase().trim().replace(/<[!\/a-z].*?>/gi,"").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g,"").replace(/\s/g,"-");if(this.seen.hasOwnProperty(t))for(var n=t;this.seen[n]++,t=n+"-"+this.seen[n],this.seen.hasOwnProperty(t););return this.seen[t]=0,t},e}(),W=t.defaults,Y=_,ee=function(){function n(e){this.options=e||W,this.options.renderer=this.options.renderer||new J,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new K,this.slugger=new Q}n.parse=function(e,t){return new n(t).parse(e)};var e=n.prototype;return e.parse=function(e,t){void 0===t&&(t=!0);var n,r,i,s,l,a,o,h,c,u,p,g,f,d,k,b,m,x,w="",v=e.length;for(n=0;nAn error occurred:

    "+re(e.message+"",!0)+"
    ";throw e}}return ae.options=ae.setOptions=function(e){return te(ae.defaults,e),se(ae.defaults),ae},ae.getDefaults=ie,ae.defaults=le,ae.Parser=ee,ae.parser=ee.parse,ae.Renderer=J,ae.TextRenderer=K,ae.Lexer=G,ae.lexer=G.lex,ae.Tokenizer=N,ae.Slugger=Q,ae.parse=ae}); \ No newline at end of file From 4947ce507859b0475646793e87ce6cd0e4a04141 Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Tue, 14 Apr 2020 13:23:41 -0500 Subject: [PATCH 05/13] only send needed variables to tokenizer --- docs/USING_PRO.md | 52 ++++++++-------- src/Lexer.js | 72 ++++++++++++++--------- src/Tokenizer.js | 101 +++++++++++++++----------------- test/specs/new/double_link.html | 10 ++++ test/specs/new/double_link.md | 12 ++++ test/unit/Lexer-spec.js | 18 ++++-- 6 files changed, 154 insertions(+), 111 deletions(-) diff --git a/docs/USING_PRO.md b/docs/USING_PRO.md index de9f45f53e..9d92e8ef97 100644 --- a/docs/USING_PRO.md +++ b/docs/USING_PRO.md @@ -127,35 +127,35 @@ console.log(marked('$ latext code $', { tokenizer })); ### Block level tokenizer methods -- space(*Lexer* lexer, *string* src, *array* tokens, *bool* top) -- code(*Lexer* lexer, *string* src, *array* tokens, *bool* top) -- fences(*Lexer* lexer, *string* src, *array* tokens, *bool* top) -- heading(*Lexer* lexer, *string* src, *array* tokens, *bool* top) -- nptable(*Lexer* lexer, *string* src, *array* tokens, *bool* top) -- hr(*Lexer* lexer, *string* src, *array* tokens, *bool* top) -- blockquote(*Lexer* lexer, *string* src, *array* tokens, *bool* top) -- list(*Lexer* lexer, *string* src, *array* tokens, *bool* top) -- html(*Lexer* lexer, *string* src, *array* tokens, *bool* top) -- def(*Lexer* lexer, *string* src, *array* tokens, *bool* top) -- table(*Lexer* lexer, *string* src, *array* tokens, *bool* top) -- lheading(*Lexer* lexer, *string* src, *array* tokens, *bool* top) -- paragraph(*Lexer* lexer, *string* src, *array* tokens, *bool* top) -- text(*Lexer* lexer, *string* src, *array* tokens, *bool* top) +- space(*string* src) +- code(*string* src, *array* tokens) +- fences(*string* src) +- heading(*string* src) +- nptable(*string* src) +- hr(*string* src) +- blockquote(*string* src) +- list(*string* src) +- html(*string* src) +- def(*string* src) +- table(*string* src) +- lheading(*string* src) +- paragraph(*string* src) +- text(*string* src) ### Inline level tokenizer methods -- escape(*Lexer* lexer, *string* src, *array* tokens) -- tag(*Lexer* lexer, *string* src, *array* tokens) -- link(*Lexer* lexer, *string* src, *array* tokens) -- reflink(*Lexer* lexer, *string* src, *array* tokens) -- strong(*Lexer* lexer, *string* src, *array* tokens) -- em(*Lexer* lexer, *string* src, *array* tokens) -- codespan(*Lexer* lexer, *string* src, *array* tokens) -- br(*Lexer* lexer, *string* src, *array* tokens) -- del(*Lexer* lexer, *string* src, *array* tokens) -- autolink(*Lexer* lexer, *string* src, *array* tokens) -- url(*Lexer* lexer, *string* src, *array* tokens) -- inlineText(*Lexer* lexer, *string* src, *array* tokens) +- escape(*string* src) +- tag(*string* src, *bool* inLink, *bool* inRawBlock) +- link(*string* src) +- reflink(*string* src, *object* links) +- strong(*string* src) +- em(*string* src) +- codespan(*string* src) +- br(*string* src) +- del(*string* src) +- autolink(*string* src) +- url(*string* src) +- inlineText(*string* src, *bool* inRawBlock) ### Other tokenizer methods diff --git a/src/Lexer.js b/src/Lexer.js index 7ad44a2a3a..6c5e06a705 100644 --- a/src/Lexer.js +++ b/src/Lexer.js @@ -50,11 +50,11 @@ module.exports = class Lexer { */ blockTokens(src, tokens = [], top = true) { src = src.replace(/^ +$/gm, ''); - let token; + let token, i, l; while (src) { // newline - if (token = this.tokenizer.space(this, src, tokens, top)) { + if (token = this.tokenizer.space(src)) { src = src.substring(token.raw.length); if (token.type) { tokens.push(token); @@ -63,63 +63,68 @@ module.exports = class Lexer { } // code - if (token = this.tokenizer.code(this, src, tokens, top)) { + if (token = this.tokenizer.code(src, tokens)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // fences - if (token = this.tokenizer.fences(this, src, tokens, top)) { + if (token = this.tokenizer.fences(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // heading - if (token = this.tokenizer.heading(this, src, tokens, top)) { + if (token = this.tokenizer.heading(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // table no leading pipe (gfm) - if (token = this.tokenizer.nptable(this, src, tokens, top)) { + if (token = this.tokenizer.nptable(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // hr - if (token = this.tokenizer.hr(this, src, tokens, top)) { + if (token = this.tokenizer.hr(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // blockquote - if (token = this.tokenizer.blockquote(this, src, tokens, top)) { + if (token = this.tokenizer.blockquote(src)) { src = src.substring(token.raw.length); + token.tokens = this.blockTokens(token.text, [], top); tokens.push(token); continue; } // list - if (token = this.tokenizer.list(this, src, tokens, top)) { + if (token = this.tokenizer.list(src)) { src = src.substring(token.raw.length); + l = token.items.length; + for (i = 0; i < l; i++) { + token.items[i].tokens = this.blockTokens(token.items[i].text, [], false); + } tokens.push(token); continue; } // html - if (token = this.tokenizer.html(this, src, tokens, top)) { + if (token = this.tokenizer.html(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // def - if (top && (token = this.tokenizer.def(this, src, tokens, top))) { + if (top && (token = this.tokenizer.def(src))) { src = src.substring(token.raw.length); if (!this.tokens.links[token.tag]) { this.tokens.links[token.tag] = { @@ -131,28 +136,28 @@ module.exports = class Lexer { } // table (gfm) - if (token = this.tokenizer.table(this, src, tokens, top)) { + if (token = this.tokenizer.table(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // lheading - if (token = this.tokenizer.lheading(this, src, tokens, top)) { + if (token = this.tokenizer.lheading(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // top-level paragraph - if (top && (token = this.tokenizer.paragraph(this, src, tokens, top))) { + if (top && (token = this.tokenizer.paragraph(src))) { src = src.substring(token.raw.length); tokens.push(token); continue; } // text - if (token = this.tokenizer.text(this, src, tokens, top)) { + if (token = this.tokenizer.text(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; @@ -240,89 +245,100 @@ module.exports = class Lexer { /** * Lexing/Compiling */ - inlineTokens(src, tokens = []) { + inlineTokens(src, tokens = [], inLink = false, inRawBlock = false) { let token; while (src) { // escape - if (token = this.tokenizer.escape(this, src, tokens)) { + if (token = this.tokenizer.escape(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // tag - if (token = this.tokenizer.tag(this, src, tokens)) { + if (token = this.tokenizer.tag(src, inLink, inRawBlock)) { src = src.substring(token.raw.length); + inLink = token.inLink; + inRawBlock = token.inRawBlock; tokens.push(token); continue; } // link - if (token = this.tokenizer.link(this, src, tokens)) { + if (token = this.tokenizer.link(src)) { src = src.substring(token.raw.length); + if (token.type === 'link') { + token.tokens = this.inlineTokens(token.text, [], true, inRawBlock); + } tokens.push(token); continue; } // reflink, nolink - if (token = this.tokenizer.reflink(this, src, tokens)) { + if (token = this.tokenizer.reflink(src, this.tokens.links)) { src = src.substring(token.raw.length); + if (token.type === 'link') { + token.tokens = this.inlineTokens(token.text, [], true, inRawBlock); + } tokens.push(token); continue; } // strong - if (token = this.tokenizer.strong(this, src, tokens)) { + if (token = this.tokenizer.strong(src)) { src = src.substring(token.raw.length); + token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock); tokens.push(token); continue; } // em - if (token = this.tokenizer.em(this, src, tokens)) { + if (token = this.tokenizer.em(src)) { src = src.substring(token.raw.length); + token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock); tokens.push(token); continue; } // code - if (token = this.tokenizer.codespan(this, src, tokens)) { + if (token = this.tokenizer.codespan(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // br - if (token = this.tokenizer.br(this, src, tokens)) { + if (token = this.tokenizer.br(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // del (gfm) - if (token = this.tokenizer.del(this, src, tokens)) { + if (token = this.tokenizer.del(src)) { src = src.substring(token.raw.length); + token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock); tokens.push(token); continue; } // autolink - if (token = this.tokenizer.autolink(this, src, tokens)) { + if (token = this.tokenizer.autolink(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // url (gfm) - if (token = this.tokenizer.url(this, src, tokens)) { + if (!inLink && (token = this.tokenizer.url(src))) { src = src.substring(token.raw.length); tokens.push(token); continue; } // text - if (token = this.tokenizer.inlineText(this, src, tokens)) { + if (token = this.tokenizer.inlineText(src, inRawBlock)) { src = src.substring(token.raw.length); tokens.push(token); continue; diff --git a/src/Tokenizer.js b/src/Tokenizer.js index 66b33c8d76..9432b8f60a 100644 --- a/src/Tokenizer.js +++ b/src/Tokenizer.js @@ -7,7 +7,7 @@ const { } = require('./helpers.js'); const { block, inline } = require('./rules.js'); -function outputLink(cap, link, tokens, raw, lexer) { +function outputLink(cap, link, raw) { const href = link.href; const title = link.title ? escape(link.title) : null; @@ -17,7 +17,7 @@ function outputLink(cap, link, tokens, raw, lexer) { raw, href, title, - tokens: lexer.inlineTokens(cap[1]) + text: cap[1] }; } else { return { @@ -40,9 +40,6 @@ module.exports = class Tokenizer { } initialize() { - this.inLink = false; - this.inRawBlock = false; - this.rules = { block: block.normal, inline: inline.normal @@ -71,7 +68,7 @@ module.exports = class Tokenizer { }; } - space(lexer, src, tokens, top) { + space(src) { const cap = this.rules.block.newline.exec(src); if (cap) { if (cap[0].length > 1) { @@ -84,7 +81,7 @@ module.exports = class Tokenizer { } } - code(lexer, src, tokens, top) { + code(src, tokens) { const cap = this.rules.block.code.exec(src); if (cap) { const lastToken = tokens[tokens.length - 1]; @@ -108,7 +105,7 @@ module.exports = class Tokenizer { } } - fences(lexer, src, tokens, top) { + fences(src) { const cap = this.rules.block.fences.exec(src); if (cap) { return { @@ -120,7 +117,7 @@ module.exports = class Tokenizer { } } - heading(lexer, src, tokens, top) { + heading(src) { const cap = this.rules.block.heading.exec(src); if (cap) { return { @@ -132,7 +129,7 @@ module.exports = class Tokenizer { } } - nptable(lexer, src, tokens, top) { + nptable(src) { const cap = this.rules.block.nptable.exec(src); if (cap) { const item = { @@ -168,7 +165,7 @@ module.exports = class Tokenizer { } } - hr(lexer, src, tokens, top) { + hr(src) { const cap = this.rules.block.hr.exec(src); if (cap) { return { @@ -178,7 +175,7 @@ module.exports = class Tokenizer { } } - blockquote(lexer, src, tokens, top) { + blockquote(src) { const cap = this.rules.block.blockquote.exec(src); if (cap) { const text = cap[0].replace(/^ *> ?/gm, ''); @@ -186,12 +183,12 @@ module.exports = class Tokenizer { return { type: 'blockquote', raw: cap[0], - tokens: lexer.blockTokens(text, [], top) + text }; } } - list(lexer, src, tokens, top) { + list(src) { const cap = this.rules.block.list.exec(src); if (cap) { let raw = cap[0]; @@ -276,7 +273,7 @@ module.exports = class Tokenizer { task: istask, checked: ischecked, loose: loose, - tokens: lexer.blockTokens(item, [], false) + text: item }); } @@ -284,7 +281,7 @@ module.exports = class Tokenizer { } } - html(lexer, src, tokens, top) { + html(src) { const cap = this.rules.block.html.exec(src); if (cap) { return { @@ -299,7 +296,7 @@ module.exports = class Tokenizer { } } - def(lexer, src, tokens, top) { + def(src) { const cap = this.rules.block.def.exec(src); if (cap) { if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1); @@ -313,7 +310,7 @@ module.exports = class Tokenizer { } } - table(lexer, src, tokens, top) { + table(src) { const cap = this.rules.block.table.exec(src); if (cap) { const item = { @@ -352,7 +349,7 @@ module.exports = class Tokenizer { } } - lheading(lexer, src, tokens, top) { + lheading(src) { const cap = this.rules.block.lheading.exec(src); if (cap) { return { @@ -364,7 +361,7 @@ module.exports = class Tokenizer { } } - paragraph(lexer, src, tokens, top) { + paragraph(src) { const cap = this.rules.block.paragraph.exec(src); if (cap) { return { @@ -377,7 +374,7 @@ module.exports = class Tokenizer { } } - text(lexer, src, tokens, top) { + text(src) { const cap = this.rules.block.text.exec(src); if (cap) { return { @@ -388,7 +385,7 @@ module.exports = class Tokenizer { } } - escape(lexer, src, tokens) { + escape(src) { const cap = this.rules.inline.escape.exec(src); if (cap) { return { @@ -399,18 +396,18 @@ module.exports = class Tokenizer { } } - tag(lexer, src, tokens) { + tag(src, inLink, inRawBlock) { const cap = this.rules.inline.tag.exec(src); if (cap) { - if (!this.inLink && /^
    /i.test(cap[0])) { - this.inLink = false; + if (!inLink && /^/i.test(cap[0])) { + inLink = false; } - if (!this.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { - this.inRawBlock = true; - } else if (this.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { - this.inRawBlock = false; + if (!inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { + inRawBlock = true; + } else if (inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { + inRawBlock = false; } return { @@ -418,6 +415,8 @@ module.exports = class Tokenizer { ? 'text' : 'html', raw: cap[0], + inLink, + inRawBlock, text: this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) @@ -427,7 +426,7 @@ module.exports = class Tokenizer { } } - link(lexer, src, tokens) { + link(src) { const cap = this.rules.inline.link.exec(src); if (cap) { const lastParenIndex = findClosingBracket(cap[2], '()'); @@ -438,7 +437,6 @@ module.exports = class Tokenizer { cap[0] = cap[0].substring(0, linkLen).trim(); cap[3] = ''; } - this.inLink = true; let href = cap[2]; let title = ''; if (this.options.pedantic) { @@ -457,18 +455,17 @@ module.exports = class Tokenizer { const token = outputLink(cap, { href: href ? href.replace(this.rules.inline._escapes, '$1') : href, title: title ? title.replace(this.rules.inline._escapes, '$1') : title - }, tokens, cap[0], lexer); - this.inLink = false; + }, cap[0]); return token; } } - reflink(lexer, src, tokens) { + reflink(src, links) { let cap; if ((cap = this.rules.inline.reflink.exec(src)) || (cap = this.rules.inline.nolink.exec(src))) { let link = (cap[2] || cap[1]).replace(/\s+/g, ' '); - link = lexer.tokens.links[link.toLowerCase()]; + link = links[link.toLowerCase()]; if (!link || !link.href) { const text = cap[0].charAt(0); return { @@ -477,36 +474,34 @@ module.exports = class Tokenizer { text }; } - this.inLink = true; - const token = outputLink(cap, link, tokens, cap[0], lexer); - this.inLink = false; + const token = outputLink(cap, link, cap[0]); return token; } } - strong(lexer, src, tokens) { + strong(src) { const cap = this.rules.inline.strong.exec(src); if (cap) { return { type: 'strong', raw: cap[0], - tokens: lexer.inlineTokens(cap[4] || cap[3] || cap[2] || cap[1]) + text: cap[4] || cap[3] || cap[2] || cap[1] }; } } - em(lexer, src, tokens) { + em(src) { const cap = this.rules.inline.em.exec(src); if (cap) { return { type: 'em', raw: cap[0], - tokens: lexer.inlineTokens(cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1]) + text: cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1] }; } } - codespan(lexer, src, tokens) { + codespan(src) { const cap = this.rules.inline.code.exec(src); if (cap) { return { @@ -517,7 +512,7 @@ module.exports = class Tokenizer { } } - br(lexer, src, tokens) { + br(src) { const cap = this.rules.inline.br.exec(src); if (cap) { return { @@ -527,18 +522,18 @@ module.exports = class Tokenizer { } } - del(lexer, src, tokens) { + del(src) { const cap = this.rules.inline.del.exec(src); if (cap) { return { type: 'del', raw: cap[0], - tokens: lexer.inlineTokens(cap[1]) + text: cap[1] }; } } - autolink(lexer, src, tokens) { + autolink(src) { const cap = this.rules.inline.autolink.exec(src); if (cap) { let text, href; @@ -566,9 +561,9 @@ module.exports = class Tokenizer { } } - url(lexer, src, tokens) { + url(src) { let cap; - if (!this.inLink && (cap = this.rules.inline.url.exec(src))) { + if (cap = this.rules.inline.url.exec(src)) { let text, href; if (cap[2] === '@') { text = escape(this.options.mangle ? this.mangle(cap[0]) : cap[0]); @@ -603,11 +598,11 @@ module.exports = class Tokenizer { } } - inlineText(lexer, src, tokens) { + inlineText(src, inRawBlock) { const cap = this.rules.inline.text.exec(src); if (cap) { let text; - if (this.inRawBlock) { + if (inRawBlock) { text = this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape(cap[0])) : cap[0]; } else { text = escape(this.options.smartypants ? this.smartypants(cap[0]) : cap[0]); diff --git a/test/specs/new/double_link.html b/test/specs/new/double_link.html index ff68395a3a..78858b22bf 100644 --- a/test/specs/new/double_link.html +++ b/test/specs/new/double_link.html @@ -2,4 +2,14 @@

    Already linked: http://example.com/.

    +

    Already linked: http://example.com/.

    +

    Already linked: http://example.com/.

    + +

    Already linked: http://example.com/.

    + +

    Already linked: http://example.com/.

    + +

    Already linked: http://example.com/.

    + +

    Already linked: http://example.com/.

    diff --git a/test/specs/new/double_link.md b/test/specs/new/double_link.md index 50216736c1..895d22f6d9 100644 --- a/test/specs/new/double_link.md +++ b/test/specs/new/double_link.md @@ -2,4 +2,16 @@ Already linked: [http://example.com/](http://example.com/). +Already linked: http://example.com/. + Already linked: **http://example.com/**. + +Already linked: *http://example.com/*. + +Already linked: ~~http://example.com/~~. + +Already linked: [http://example.com/]. + +Already linked: [http://example.com/][]. + +[http://example.com/]: http://example.com/ diff --git a/test/unit/Lexer-spec.js b/test/unit/Lexer-spec.js index dd0bdfef2c..d8a802061b 100644 --- a/test/unit/Lexer-spec.js +++ b/test/unit/Lexer-spec.js @@ -276,6 +276,7 @@ a | b { type: 'blockquote', raw: '> blockquote', + text: 'blockquote', tokens: [{ type: 'paragraph', raw: 'blockquote', @@ -310,6 +311,7 @@ a | b task: false, checked: undefined, loose: false, + text: 'item 1', tokens: [{ type: 'text', raw: 'item 1', @@ -322,6 +324,7 @@ a | b task: false, checked: undefined, loose: false, + text: 'item 2\n', tokens: [{ type: 'text', raw: 'item 2', @@ -574,9 +577,9 @@ a | b expectInlineTokens({ md: '
    html
    ', tokens: [ - { type: 'html', raw: '
    ', text: '
    ' }, + { type: 'html', raw: '
    ', inLink: false, inRawBlock: false, text: '
    ' }, { type: 'text', raw: 'html', text: 'html' }, - { type: 'html', raw: '
    ', text: '
    ' } + { type: 'html', raw: '
    ', inLink: false, inRawBlock: false, text: '
    ' } ] }); }); @@ -586,9 +589,9 @@ a | b md: '
    html
    ', options: { sanitize: true }, tokens: [ - { type: 'text', raw: '
    ', text: '<div>' }, + { type: 'text', raw: '
    ', inLink: false, inRawBlock: false, text: '<div>' }, { type: 'text', raw: 'html', text: 'html' }, - { type: 'text', raw: '
    ', text: '</div>' } + { type: 'text', raw: '
    ', inLink: false, inRawBlock: false, text: '</div>' } ] }); }); @@ -602,6 +605,7 @@ a | b raw: '[link](https://example.com)', href: 'https://example.com', title: null, + text: 'link', tokens: [ { type: 'text', raw: 'link', text: 'link' } ] @@ -619,6 +623,7 @@ a | b raw: '[link](https://example.com "title")', href: 'https://example.com', title: 'title', + text: 'link', tokens: [ { type: 'text', raw: 'link', text: 'link' } ] @@ -670,6 +675,7 @@ a | b raw: '[link][]', href: 'https://example.com', title: 'title', + text: 'link', tokens: [{ type: 'text', raw: 'link', @@ -692,6 +698,7 @@ a | b raw: '[link]', href: 'https://example.com', title: 'title', + text: 'link', tokens: [{ type: 'text', raw: 'link', @@ -720,6 +727,7 @@ a | b { type: 'strong', raw: '**strong**', + text: 'strong', tokens: [ { type: 'text', raw: 'strong', text: 'strong' } ] @@ -735,6 +743,7 @@ a | b { type: 'em', raw: '*em*', + text: 'em', tokens: [ { type: 'text', raw: 'em', text: 'em' } ] @@ -769,6 +778,7 @@ a | b { type: 'del', raw: '~~del~~', + text: 'del', tokens: [ { type: 'text', raw: 'del', text: 'del' } ] From bc378f15886842fca638fc0797e42f38c6a7761f Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Tue, 14 Apr 2020 14:33:36 -0500 Subject: [PATCH 06/13] build --- lib/marked.esm.js | 173 ++++++++++++++++++++++-------------------- lib/marked.js | 186 ++++++++++++++++++++++++++-------------------- marked.min.js | 2 +- 3 files changed, 199 insertions(+), 162 deletions(-) diff --git a/lib/marked.esm.js b/lib/marked.esm.js index 9e6ec2fb42..4bf96ca4cd 100644 --- a/lib/marked.esm.js +++ b/lib/marked.esm.js @@ -570,7 +570,7 @@ const { } = helpers; const { block: block$1, inline: inline$1 } = rules; -function outputLink(cap, link, tokens, raw, lexer) { +function outputLink(cap, link, raw) { const href = link.href; const title = link.title ? escape$1(link.title) : null; @@ -580,7 +580,7 @@ function outputLink(cap, link, tokens, raw, lexer) { raw, href, title, - tokens: lexer.inlineTokens(cap[1]) + text: cap[1] }; } else { return { @@ -603,9 +603,6 @@ var Tokenizer_1 = class Tokenizer { } initialize() { - this.inLink = false; - this.inRawBlock = false; - this.rules = { block: block$1.normal, inline: inline$1.normal @@ -634,7 +631,7 @@ var Tokenizer_1 = class Tokenizer { }; } - space(lexer, src, tokens, top) { + space(src) { const cap = this.rules.block.newline.exec(src); if (cap) { if (cap[0].length > 1) { @@ -647,7 +644,7 @@ var Tokenizer_1 = class Tokenizer { } } - code(lexer, src, tokens, top) { + code(src, tokens) { const cap = this.rules.block.code.exec(src); if (cap) { const lastToken = tokens[tokens.length - 1]; @@ -671,7 +668,7 @@ var Tokenizer_1 = class Tokenizer { } } - fences(lexer, src, tokens, top) { + fences(src) { const cap = this.rules.block.fences.exec(src); if (cap) { return { @@ -683,7 +680,7 @@ var Tokenizer_1 = class Tokenizer { } } - heading(lexer, src, tokens, top) { + heading(src) { const cap = this.rules.block.heading.exec(src); if (cap) { return { @@ -695,7 +692,7 @@ var Tokenizer_1 = class Tokenizer { } } - nptable(lexer, src, tokens, top) { + nptable(src) { const cap = this.rules.block.nptable.exec(src); if (cap) { const item = { @@ -731,7 +728,7 @@ var Tokenizer_1 = class Tokenizer { } } - hr(lexer, src, tokens, top) { + hr(src) { const cap = this.rules.block.hr.exec(src); if (cap) { return { @@ -741,7 +738,7 @@ var Tokenizer_1 = class Tokenizer { } } - blockquote(lexer, src, tokens, top) { + blockquote(src) { const cap = this.rules.block.blockquote.exec(src); if (cap) { const text = cap[0].replace(/^ *> ?/gm, ''); @@ -749,12 +746,12 @@ var Tokenizer_1 = class Tokenizer { return { type: 'blockquote', raw: cap[0], - tokens: lexer.blockTokens(text, [], top) + text }; } } - list(lexer, src, tokens, top) { + list(src) { const cap = this.rules.block.list.exec(src); if (cap) { let raw = cap[0]; @@ -839,7 +836,7 @@ var Tokenizer_1 = class Tokenizer { task: istask, checked: ischecked, loose: loose, - tokens: lexer.blockTokens(item, [], false) + text: item }); } @@ -847,7 +844,7 @@ var Tokenizer_1 = class Tokenizer { } } - html(lexer, src, tokens, top) { + html(src) { const cap = this.rules.block.html.exec(src); if (cap) { return { @@ -862,7 +859,7 @@ var Tokenizer_1 = class Tokenizer { } } - def(lexer, src, tokens, top) { + def(src) { const cap = this.rules.block.def.exec(src); if (cap) { if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1); @@ -876,7 +873,7 @@ var Tokenizer_1 = class Tokenizer { } } - table(lexer, src, tokens, top) { + table(src) { const cap = this.rules.block.table.exec(src); if (cap) { const item = { @@ -915,7 +912,7 @@ var Tokenizer_1 = class Tokenizer { } } - lheading(lexer, src, tokens, top) { + lheading(src) { const cap = this.rules.block.lheading.exec(src); if (cap) { return { @@ -927,7 +924,7 @@ var Tokenizer_1 = class Tokenizer { } } - paragraph(lexer, src, tokens, top) { + paragraph(src) { const cap = this.rules.block.paragraph.exec(src); if (cap) { return { @@ -940,7 +937,7 @@ var Tokenizer_1 = class Tokenizer { } } - text(lexer, src, tokens, top) { + text(src) { const cap = this.rules.block.text.exec(src); if (cap) { return { @@ -951,7 +948,7 @@ var Tokenizer_1 = class Tokenizer { } } - escape(lexer, src, tokens) { + escape(src) { const cap = this.rules.inline.escape.exec(src); if (cap) { return { @@ -962,18 +959,18 @@ var Tokenizer_1 = class Tokenizer { } } - tag(lexer, src, tokens) { + tag(src, inLink, inRawBlock) { const cap = this.rules.inline.tag.exec(src); if (cap) { - if (!this.inLink && /^/i.test(cap[0])) { - this.inLink = false; + if (!inLink && /^/i.test(cap[0])) { + inLink = false; } - if (!this.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { - this.inRawBlock = true; - } else if (this.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { - this.inRawBlock = false; + if (!inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { + inRawBlock = true; + } else if (inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { + inRawBlock = false; } return { @@ -981,6 +978,8 @@ var Tokenizer_1 = class Tokenizer { ? 'text' : 'html', raw: cap[0], + inLink, + inRawBlock, text: this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) @@ -990,7 +989,7 @@ var Tokenizer_1 = class Tokenizer { } } - link(lexer, src, tokens) { + link(src) { const cap = this.rules.inline.link.exec(src); if (cap) { const lastParenIndex = findClosingBracket$1(cap[2], '()'); @@ -1001,7 +1000,6 @@ var Tokenizer_1 = class Tokenizer { cap[0] = cap[0].substring(0, linkLen).trim(); cap[3] = ''; } - this.inLink = true; let href = cap[2]; let title = ''; if (this.options.pedantic) { @@ -1020,18 +1018,17 @@ var Tokenizer_1 = class Tokenizer { const token = outputLink(cap, { href: href ? href.replace(this.rules.inline._escapes, '$1') : href, title: title ? title.replace(this.rules.inline._escapes, '$1') : title - }, tokens, cap[0], lexer); - this.inLink = false; + }, cap[0]); return token; } } - reflink(lexer, src, tokens) { + reflink(src, links) { let cap; if ((cap = this.rules.inline.reflink.exec(src)) || (cap = this.rules.inline.nolink.exec(src))) { let link = (cap[2] || cap[1]).replace(/\s+/g, ' '); - link = lexer.tokens.links[link.toLowerCase()]; + link = links[link.toLowerCase()]; if (!link || !link.href) { const text = cap[0].charAt(0); return { @@ -1040,36 +1037,34 @@ var Tokenizer_1 = class Tokenizer { text }; } - this.inLink = true; - const token = outputLink(cap, link, tokens, cap[0], lexer); - this.inLink = false; + const token = outputLink(cap, link, cap[0]); return token; } } - strong(lexer, src, tokens) { + strong(src) { const cap = this.rules.inline.strong.exec(src); if (cap) { return { type: 'strong', raw: cap[0], - tokens: lexer.inlineTokens(cap[4] || cap[3] || cap[2] || cap[1]) + text: cap[4] || cap[3] || cap[2] || cap[1] }; } } - em(lexer, src, tokens) { + em(src) { const cap = this.rules.inline.em.exec(src); if (cap) { return { type: 'em', raw: cap[0], - tokens: lexer.inlineTokens(cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1]) + text: cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1] }; } } - codespan(lexer, src, tokens) { + codespan(src) { const cap = this.rules.inline.code.exec(src); if (cap) { return { @@ -1080,7 +1075,7 @@ var Tokenizer_1 = class Tokenizer { } } - br(lexer, src, tokens) { + br(src) { const cap = this.rules.inline.br.exec(src); if (cap) { return { @@ -1090,18 +1085,18 @@ var Tokenizer_1 = class Tokenizer { } } - del(lexer, src, tokens) { + del(src) { const cap = this.rules.inline.del.exec(src); if (cap) { return { type: 'del', raw: cap[0], - tokens: lexer.inlineTokens(cap[1]) + text: cap[1] }; } } - autolink(lexer, src, tokens) { + autolink(src) { const cap = this.rules.inline.autolink.exec(src); if (cap) { let text, href; @@ -1129,9 +1124,9 @@ var Tokenizer_1 = class Tokenizer { } } - url(lexer, src, tokens) { + url(src) { let cap; - if (!this.inLink && (cap = this.rules.inline.url.exec(src))) { + if (cap = this.rules.inline.url.exec(src)) { let text, href; if (cap[2] === '@') { text = escape$1(this.options.mangle ? this.mangle(cap[0]) : cap[0]); @@ -1166,11 +1161,11 @@ var Tokenizer_1 = class Tokenizer { } } - inlineText(lexer, src, tokens) { + inlineText(src, inRawBlock) { const cap = this.rules.inline.text.exec(src); if (cap) { let text; - if (this.inRawBlock) { + if (inRawBlock) { text = this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape$1(cap[0])) : cap[0]; } else { text = escape$1(this.options.smartypants ? this.smartypants(cap[0]) : cap[0]); @@ -1276,11 +1271,11 @@ var Lexer_1 = class Lexer { */ blockTokens(src, tokens = [], top = true) { src = src.replace(/^ +$/gm, ''); - let token; + let token, i, l; while (src) { // newline - if (token = this.tokenizer.space(this, src, tokens, top)) { + if (token = this.tokenizer.space(src)) { src = src.substring(token.raw.length); if (token.type) { tokens.push(token); @@ -1289,63 +1284,68 @@ var Lexer_1 = class Lexer { } // code - if (token = this.tokenizer.code(this, src, tokens, top)) { + if (token = this.tokenizer.code(src, tokens)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // fences - if (token = this.tokenizer.fences(this, src, tokens, top)) { + if (token = this.tokenizer.fences(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // heading - if (token = this.tokenizer.heading(this, src, tokens, top)) { + if (token = this.tokenizer.heading(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // table no leading pipe (gfm) - if (token = this.tokenizer.nptable(this, src, tokens, top)) { + if (token = this.tokenizer.nptable(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // hr - if (token = this.tokenizer.hr(this, src, tokens, top)) { + if (token = this.tokenizer.hr(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // blockquote - if (token = this.tokenizer.blockquote(this, src, tokens, top)) { + if (token = this.tokenizer.blockquote(src)) { src = src.substring(token.raw.length); + token.tokens = this.blockTokens(token.text, [], top); tokens.push(token); continue; } // list - if (token = this.tokenizer.list(this, src, tokens, top)) { + if (token = this.tokenizer.list(src)) { src = src.substring(token.raw.length); + l = token.items.length; + for (i = 0; i < l; i++) { + token.items[i].tokens = this.blockTokens(token.items[i].text, [], false); + } tokens.push(token); continue; } // html - if (token = this.tokenizer.html(this, src, tokens, top)) { + if (token = this.tokenizer.html(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // def - if (top && (token = this.tokenizer.def(this, src, tokens, top))) { + if (top && (token = this.tokenizer.def(src))) { src = src.substring(token.raw.length); if (!this.tokens.links[token.tag]) { this.tokens.links[token.tag] = { @@ -1357,28 +1357,28 @@ var Lexer_1 = class Lexer { } // table (gfm) - if (token = this.tokenizer.table(this, src, tokens, top)) { + if (token = this.tokenizer.table(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // lheading - if (token = this.tokenizer.lheading(this, src, tokens, top)) { + if (token = this.tokenizer.lheading(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // top-level paragraph - if (top && (token = this.tokenizer.paragraph(this, src, tokens, top))) { + if (top && (token = this.tokenizer.paragraph(src))) { src = src.substring(token.raw.length); tokens.push(token); continue; } // text - if (token = this.tokenizer.text(this, src, tokens, top)) { + if (token = this.tokenizer.text(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; @@ -1463,89 +1463,100 @@ var Lexer_1 = class Lexer { /** * Lexing/Compiling */ - inlineTokens(src, tokens = []) { + inlineTokens(src, tokens = [], inLink = false, inRawBlock = false) { let token; while (src) { // escape - if (token = this.tokenizer.escape(this, src, tokens)) { + if (token = this.tokenizer.escape(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // tag - if (token = this.tokenizer.tag(this, src, tokens)) { + if (token = this.tokenizer.tag(src, inLink, inRawBlock)) { src = src.substring(token.raw.length); + inLink = token.inLink; + inRawBlock = token.inRawBlock; tokens.push(token); continue; } // link - if (token = this.tokenizer.link(this, src, tokens)) { + if (token = this.tokenizer.link(src)) { src = src.substring(token.raw.length); + if (token.type === 'link') { + token.tokens = this.inlineTokens(token.text, [], true, inRawBlock); + } tokens.push(token); continue; } // reflink, nolink - if (token = this.tokenizer.reflink(this, src, tokens)) { + if (token = this.tokenizer.reflink(src, this.tokens.links)) { src = src.substring(token.raw.length); + if (token.type === 'link') { + token.tokens = this.inlineTokens(token.text, [], true, inRawBlock); + } tokens.push(token); continue; } // strong - if (token = this.tokenizer.strong(this, src, tokens)) { + if (token = this.tokenizer.strong(src)) { src = src.substring(token.raw.length); + token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock); tokens.push(token); continue; } // em - if (token = this.tokenizer.em(this, src, tokens)) { + if (token = this.tokenizer.em(src)) { src = src.substring(token.raw.length); + token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock); tokens.push(token); continue; } // code - if (token = this.tokenizer.codespan(this, src, tokens)) { + if (token = this.tokenizer.codespan(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // br - if (token = this.tokenizer.br(this, src, tokens)) { + if (token = this.tokenizer.br(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // del (gfm) - if (token = this.tokenizer.del(this, src, tokens)) { + if (token = this.tokenizer.del(src)) { src = src.substring(token.raw.length); + token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock); tokens.push(token); continue; } // autolink - if (token = this.tokenizer.autolink(this, src, tokens)) { + if (token = this.tokenizer.autolink(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // url (gfm) - if (token = this.tokenizer.url(this, src, tokens)) { + if (!inLink && (token = this.tokenizer.url(src))) { src = src.substring(token.raw.length); tokens.push(token); continue; } // text - if (token = this.tokenizer.inlineText(this, src, tokens)) { + if (token = this.tokenizer.inlineText(src, inRawBlock)) { src = src.substring(token.raw.length); tokens.push(token); continue; diff --git a/lib/marked.js b/lib/marked.js index c5939a0053..41c91b498a 100644 --- a/lib/marked.js +++ b/lib/marked.js @@ -518,7 +518,7 @@ var block$1 = rules.block, inline$1 = rules.inline; - function outputLink(cap, link, tokens, raw, lexer) { + function outputLink(cap, link, raw) { var href = link.href; var title = link.title ? _escape(link.title) : null; @@ -528,7 +528,7 @@ raw: raw, href: href, title: title, - tokens: lexer.inlineTokens(cap[1]) + text: cap[1] }; } else { return { @@ -554,8 +554,6 @@ var _proto = Tokenizer.prototype; _proto.initialize = function initialize() { - this.inLink = false; - this.inRawBlock = false; this.rules = { block: block$1.normal, inline: inline$1.normal @@ -579,7 +577,7 @@ */ ; - _proto.space = function space(lexer, src, tokens, top) { + _proto.space = function space(src) { var cap = this.rules.block.newline.exec(src); if (cap) { @@ -596,7 +594,7 @@ } }; - _proto.code = function code(lexer, src, tokens, top) { + _proto.code = function code(src, tokens) { var cap = this.rules.block.code.exec(src); if (cap) { @@ -619,7 +617,7 @@ } }; - _proto.fences = function fences(lexer, src, tokens, top) { + _proto.fences = function fences(src) { var cap = this.rules.block.fences.exec(src); if (cap) { @@ -632,7 +630,7 @@ } }; - _proto.heading = function heading(lexer, src, tokens, top) { + _proto.heading = function heading(src) { var cap = this.rules.block.heading.exec(src); if (cap) { @@ -645,7 +643,7 @@ } }; - _proto.nptable = function nptable(lexer, src, tokens, top) { + _proto.nptable = function nptable(src) { var cap = this.rules.block.nptable.exec(src); if (cap) { @@ -684,7 +682,7 @@ } }; - _proto.hr = function hr(lexer, src, tokens, top) { + _proto.hr = function hr(src) { var cap = this.rules.block.hr.exec(src); if (cap) { @@ -695,7 +693,7 @@ } }; - _proto.blockquote = function blockquote(lexer, src, tokens, top) { + _proto.blockquote = function blockquote(src) { var cap = this.rules.block.blockquote.exec(src); if (cap) { @@ -703,12 +701,12 @@ return { type: 'blockquote', raw: cap[0], - tokens: lexer.blockTokens(text, [], top) + text: text }; } }; - _proto.list = function list(lexer, src, tokens, top) { + _proto.list = function list(src) { var cap = this.rules.block.list.exec(src); if (cap) { @@ -789,7 +787,7 @@ task: istask, checked: ischecked, loose: loose, - tokens: lexer.blockTokens(item, [], false) + text: item }); } @@ -797,7 +795,7 @@ } }; - _proto.html = function html(lexer, src, tokens, top) { + _proto.html = function html(src) { var cap = this.rules.block.html.exec(src); if (cap) { @@ -810,7 +808,7 @@ } }; - _proto.def = function def(lexer, src, tokens, top) { + _proto.def = function def(src) { var cap = this.rules.block.def.exec(src); if (cap) { @@ -825,7 +823,7 @@ } }; - _proto.table = function table(lexer, src, tokens, top) { + _proto.table = function table(src) { var cap = this.rules.block.table.exec(src); if (cap) { @@ -864,7 +862,7 @@ } }; - _proto.lheading = function lheading(lexer, src, tokens, top) { + _proto.lheading = function lheading(src) { var cap = this.rules.block.lheading.exec(src); if (cap) { @@ -877,7 +875,7 @@ } }; - _proto.paragraph = function paragraph(lexer, src, tokens, top) { + _proto.paragraph = function paragraph(src) { var cap = this.rules.block.paragraph.exec(src); if (cap) { @@ -889,7 +887,7 @@ } }; - _proto.text = function text(lexer, src, tokens, top) { + _proto.text = function text(src) { var cap = this.rules.block.text.exec(src); if (cap) { @@ -901,7 +899,7 @@ } }; - _proto.escape = function escape(lexer, src, tokens) { + _proto.escape = function escape(src) { var cap = this.rules.inline.escape.exec(src); if (cap) { @@ -913,31 +911,33 @@ } }; - _proto.tag = function tag(lexer, src, tokens) { + _proto.tag = function tag(src, inLink, inRawBlock) { var cap = this.rules.inline.tag.exec(src); if (cap) { - if (!this.inLink && /^/i.test(cap[0])) { - this.inLink = false; + if (!inLink && /^/i.test(cap[0])) { + inLink = false; } - if (!this.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { - this.inRawBlock = true; - } else if (this.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { - this.inRawBlock = false; + if (!inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { + inRawBlock = true; + } else if (inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { + inRawBlock = false; } return { type: this.options.sanitize ? 'text' : 'html', raw: cap[0], + inLink: inLink, + inRawBlock: inRawBlock, text: this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0] }; } }; - _proto.link = function link(lexer, src, tokens) { + _proto.link = function link(src) { var cap = this.rules.inline.link.exec(src); if (cap) { @@ -951,7 +951,6 @@ cap[3] = ''; } - this.inLink = true; var href = cap[2]; var title = ''; @@ -972,18 +971,17 @@ var token = outputLink(cap, { href: href ? href.replace(this.rules.inline._escapes, '$1') : href, title: title ? title.replace(this.rules.inline._escapes, '$1') : title - }, tokens, cap[0], lexer); - this.inLink = false; + }, cap[0]); return token; } }; - _proto.reflink = function reflink(lexer, src, tokens) { + _proto.reflink = function reflink(src, links) { var cap; if ((cap = this.rules.inline.reflink.exec(src)) || (cap = this.rules.inline.nolink.exec(src))) { var link = (cap[2] || cap[1]).replace(/\s+/g, ' '); - link = lexer.tokens.links[link.toLowerCase()]; + link = links[link.toLowerCase()]; if (!link || !link.href) { var text = cap[0].charAt(0); @@ -994,38 +992,36 @@ }; } - this.inLink = true; - var token = outputLink(cap, link, tokens, cap[0], lexer); - this.inLink = false; + var token = outputLink(cap, link, cap[0]); return token; } }; - _proto.strong = function strong(lexer, src, tokens) { + _proto.strong = function strong(src) { var cap = this.rules.inline.strong.exec(src); if (cap) { return { type: 'strong', raw: cap[0], - tokens: lexer.inlineTokens(cap[4] || cap[3] || cap[2] || cap[1]) + text: cap[4] || cap[3] || cap[2] || cap[1] }; } }; - _proto.em = function em(lexer, src, tokens) { + _proto.em = function em(src) { var cap = this.rules.inline.em.exec(src); if (cap) { return { type: 'em', raw: cap[0], - tokens: lexer.inlineTokens(cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1]) + text: cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1] }; } }; - _proto.codespan = function codespan(lexer, src, tokens) { + _proto.codespan = function codespan(src) { var cap = this.rules.inline.code.exec(src); if (cap) { @@ -1037,7 +1033,7 @@ } }; - _proto.br = function br(lexer, src, tokens) { + _proto.br = function br(src) { var cap = this.rules.inline.br.exec(src); if (cap) { @@ -1048,19 +1044,19 @@ } }; - _proto.del = function del(lexer, src, tokens) { + _proto.del = function del(src) { var cap = this.rules.inline.del.exec(src); if (cap) { return { type: 'del', raw: cap[0], - tokens: lexer.inlineTokens(cap[1]) + text: cap[1] }; } }; - _proto.autolink = function autolink(lexer, src, tokens) { + _proto.autolink = function autolink(src) { var cap = this.rules.inline.autolink.exec(src); if (cap) { @@ -1088,10 +1084,10 @@ } }; - _proto.url = function url(lexer, src, tokens) { + _proto.url = function url(src) { var cap; - if (!this.inLink && (cap = this.rules.inline.url.exec(src))) { + if (cap = this.rules.inline.url.exec(src)) { var text, href; if (cap[2] === '@') { @@ -1129,13 +1125,13 @@ } }; - _proto.inlineText = function inlineText(lexer, src, tokens) { + _proto.inlineText = function inlineText(src, inRawBlock) { var cap = this.rules.inline.text.exec(src); if (cap) { var text; - if (this.inRawBlock) { + if (inRawBlock) { text = this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0]; } else { text = _escape(this.options.smartypants ? this.smartypants(cap[0]) : cap[0]); @@ -1255,11 +1251,11 @@ } src = src.replace(/^ +$/gm, ''); - var token; + var token, i, l; while (src) { // newline - if (token = this.tokenizer.space(this, src, tokens, top)) { + if (token = this.tokenizer.space(src)) { src = src.substring(token.raw.length); if (token.type) { @@ -1270,63 +1266,70 @@ } // code - if (token = this.tokenizer.code(this, src, tokens, top)) { + if (token = this.tokenizer.code(src, tokens)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // fences - if (token = this.tokenizer.fences(this, src, tokens, top)) { + if (token = this.tokenizer.fences(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // heading - if (token = this.tokenizer.heading(this, src, tokens, top)) { + if (token = this.tokenizer.heading(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // table no leading pipe (gfm) - if (token = this.tokenizer.nptable(this, src, tokens, top)) { + if (token = this.tokenizer.nptable(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // hr - if (token = this.tokenizer.hr(this, src, tokens, top)) { + if (token = this.tokenizer.hr(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // blockquote - if (token = this.tokenizer.blockquote(this, src, tokens, top)) { + if (token = this.tokenizer.blockquote(src)) { src = src.substring(token.raw.length); + token.tokens = this.blockTokens(token.text, [], top); tokens.push(token); continue; } // list - if (token = this.tokenizer.list(this, src, tokens, top)) { + if (token = this.tokenizer.list(src)) { src = src.substring(token.raw.length); + l = token.items.length; + + for (i = 0; i < l; i++) { + token.items[i].tokens = this.blockTokens(token.items[i].text, [], false); + } + tokens.push(token); continue; } // html - if (token = this.tokenizer.html(this, src, tokens, top)) { + if (token = this.tokenizer.html(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // def - if (top && (token = this.tokenizer.def(this, src, tokens, top))) { + if (top && (token = this.tokenizer.def(src))) { src = src.substring(token.raw.length); if (!this.tokens.links[token.tag]) { @@ -1340,28 +1343,28 @@ } // table (gfm) - if (token = this.tokenizer.table(this, src, tokens, top)) { + if (token = this.tokenizer.table(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // lheading - if (token = this.tokenizer.lheading(this, src, tokens, top)) { + if (token = this.tokenizer.lheading(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // top-level paragraph - if (top && (token = this.tokenizer.paragraph(this, src, tokens, top))) { + if (top && (token = this.tokenizer.paragraph(src))) { src = src.substring(token.raw.length); tokens.push(token); continue; } // text - if (token = this.tokenizer.text(this, src, tokens, top)) { + if (token = this.tokenizer.text(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; @@ -1455,93 +1458,116 @@ */ ; - _proto.inlineTokens = function inlineTokens(src, tokens) { + _proto.inlineTokens = function inlineTokens(src, tokens, inLink, inRawBlock) { if (tokens === void 0) { tokens = []; } + if (inLink === void 0) { + inLink = false; + } + + if (inRawBlock === void 0) { + inRawBlock = false; + } + var token; while (src) { // escape - if (token = this.tokenizer.escape(this, src, tokens)) { + if (token = this.tokenizer.escape(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // tag - if (token = this.tokenizer.tag(this, src, tokens)) { + if (token = this.tokenizer.tag(src, inLink, inRawBlock)) { src = src.substring(token.raw.length); + inLink = token.inLink; + inRawBlock = token.inRawBlock; tokens.push(token); continue; } // link - if (token = this.tokenizer.link(this, src, tokens)) { + if (token = this.tokenizer.link(src)) { src = src.substring(token.raw.length); + + if (token.type === 'link') { + token.tokens = this.inlineTokens(token.text, [], true, inRawBlock); + } + tokens.push(token); continue; } // reflink, nolink - if (token = this.tokenizer.reflink(this, src, tokens)) { + if (token = this.tokenizer.reflink(src, this.tokens.links)) { src = src.substring(token.raw.length); + + if (token.type === 'link') { + token.tokens = this.inlineTokens(token.text, [], true, inRawBlock); + } + tokens.push(token); continue; } // strong - if (token = this.tokenizer.strong(this, src, tokens)) { + if (token = this.tokenizer.strong(src)) { src = src.substring(token.raw.length); + token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock); tokens.push(token); continue; } // em - if (token = this.tokenizer.em(this, src, tokens)) { + if (token = this.tokenizer.em(src)) { src = src.substring(token.raw.length); + token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock); tokens.push(token); continue; } // code - if (token = this.tokenizer.codespan(this, src, tokens)) { + if (token = this.tokenizer.codespan(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // br - if (token = this.tokenizer.br(this, src, tokens)) { + if (token = this.tokenizer.br(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // del (gfm) - if (token = this.tokenizer.del(this, src, tokens)) { + if (token = this.tokenizer.del(src)) { src = src.substring(token.raw.length); + token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock); tokens.push(token); continue; } // autolink - if (token = this.tokenizer.autolink(this, src, tokens)) { + if (token = this.tokenizer.autolink(src)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // url (gfm) - if (token = this.tokenizer.url(this, src, tokens)) { + if (!inLink && (token = this.tokenizer.url(src))) { src = src.substring(token.raw.length); tokens.push(token); continue; } // text - if (token = this.tokenizer.inlineText(this, src, tokens)) { + if (token = this.tokenizer.inlineText(src, inRawBlock)) { src = src.substring(token.raw.length); tokens.push(token); continue; diff --git a/marked.min.js b/marked.min.js index 492228f3c3..1f7a69f009 100644 --- a/marked.min.js +++ b/marked.min.js @@ -3,4 +3,4 @@ * Copyright (c) 2011-2020, Christopher Jeffrey. (MIT Licensed) * https://github.com/markedjs/marked */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).marked=t()}(this,function(){"use strict";function r(e,t){for(var n=0;n"']/),l=/[&<>"']/g,a=/[<>"']|&(?!#?\w+;)/,o=/[<>"']|&(?!#?\w+;)/g,h={"&":"&","<":"<",">":">",'"':""","'":"'"};var c=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;function u(e){return e.replace(c,function(e,t){return"colon"===(t=t.toLowerCase())?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""})}var p=/(^|[^\[])\^/g;var g=/[^\w:]/g,f=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;var d={},k=/^[^:]+:\/*[^/]*$/,b=/^([^:]+:)[\s\S]*$/,m=/^([^:]+:\/*[^/]*)[\s\S]*$/;function x(e,t){d[" "+e]||(k.test(e)?d[" "+e]=e+"/":d[" "+e]=w(e,"/",!0));var n=-1===(e=d[" "+e]).indexOf(":");return"//"===t.substring(0,2)?n?t:e.replace(b,"$1")+t:"/"===t.charAt(0)?n?t:e.replace(m,"$1")+t:e+t}function w(e,t,n){var r=e.length;if(0===r)return"";for(var i=0;it)n.splice(t);else for(;n.length ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:"^ {0,3}(?:<(script|pre|style)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?\\?>\\n*|\\n*|\\n*|)[\\s\\S]*?(?:\\n{2,}|$)|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$))",def:/^ {0,3}\[(label)\]: *\n? *]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,nptable:Z,table:Z,lheading:/^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,_paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html)[^\n]+)*)/,text:/^[^\n]+/,_label:/(?!\s*\])(?:\\[\[\]]|[^\[\]])+/,_title:/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/};T.def=q(T.def).replace("label",T._label).replace("title",T._title).getRegex(),T.bullet=/(?:[*+-]|\d{1,9}\.)/,T.item=/^( *)(bull) ?[^\n]*(?:\n(?!\1bull ?)[^\n]*)*/,T.item=q(T.item,"gm").replace(/bull/g,T.bullet).getRegex(),T.list=q(T.list).replace(/bull/g,T.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+T.def.source+")").getRegex(),T._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",T._comment=//,T.html=q(T.html,"i").replace("comment",T._comment).replace("tag",T._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),T.paragraph=q(T._paragraph).replace("hr",T.hr).replace("heading"," {0,3}#{1,6} ").replace("|lheading","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",T._tag).getRegex(),T.blockquote=q(T.blockquote).replace("paragraph",T.paragraph).getRegex(),T.normal=I({},T),T.gfm=I({},T.normal,{nptable:"^ *([^|\\n ].*\\|.*)\\n *([-:]+ *\\|[-| :]*)(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)",table:"^ *\\|(.+)\\n *\\|?( *[-:]+[-| :]*)(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)"}),T.gfm.nptable=q(T.gfm.nptable).replace("hr",T.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",T._tag).getRegex(),T.gfm.table=q(T.gfm.table).replace("hr",T.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",T._tag).getRegex(),T.pedantic=I({},T.normal,{html:q("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",T._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,fences:Z,paragraph:q(T.normal._paragraph).replace("hr",T.hr).replace("heading"," *#{1,6} *[^\n]").replace("lheading",T.lheading).replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").getRegex()});var L={escape:/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:Z,tag:"^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^",link:/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,strong:/^__([^\s_])__(?!_)|^\*\*([^\s*])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/,em:/^_([^\s_])_(?!_)|^\*([^\s*<\[])\*(?!\*)|^_([^\s<][\s\S]*?[^\s_])_(?!_|[^\spunctuation])|^_([^\s_<][\s\S]*?[^\s])_(?!_|[^\spunctuation])|^\*([^\s<"][\s\S]*?[^\s\*])\*(?!\*|[^\spunctuation])|^\*([^\s*"<\[][\s\S]*?[^\s])\*(?!\*)/,code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:Z,text:/^(`+|[^`])(?:[\s\S]*?(?:(?=[\\?@\\[^_{|}~"};L.em=q(L.em).replace(/punctuation/g,L._punctuation).getRegex(),L._escapes=/\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g,L._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,L._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])?)+(?![-_])/,L.autolink=q(L.autolink).replace("scheme",L._scheme).replace("email",L._email).getRegex(),L._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,L.tag=q(L.tag).replace("comment",T._comment).replace("attribute",L._attribute).getRegex(),L._label=/(?:\[[^\[\]]*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,L._href=/<(?:\\[<>]?|[^\s<>\\])*>|[^\s\x00-\x1f]*/,L._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,L.link=q(L.link).replace("label",L._label).replace("href",L._href).replace("title",L._title).getRegex(),L.reflink=q(L.reflink).replace("label",L._label).getRegex(),L.normal=I({},L),L.pedantic=I({},L.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,link:q(/^!?\[(label)\]\((.*?)\)/).replace("label",L._label).getRegex(),reflink:q(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",L._label).getRegex()}),L.gfm=I({},L.normal,{escape:q(L.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^~+(?=\S)([\s\S]*?\S)~+/,text:/^(`+|[^`])(?:[\s\S]*?(?:(?=[\\ ?/gm,"");return{type:"blockquote",raw:i[0],tokens:e.blockTokens(s,[],r)}}},t.list=function(e,t,n,r){var i=this.rules.block.list.exec(t);if(i){for(var s,l,a,o,h,c,u,p=i[0],g=i[2],f=1/i.test(n[0])&&(this.inLink=!1),!this.inRawBlock&&/^<(pre|code|kbd|script)(\s|>)/i.test(n[0])?this.inRawBlock=!0:this.inRawBlock&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(n[0])&&(this.inRawBlock=!1),{type:this.options.sanitize?"text":"html",raw:n[0],text:this.options.sanitize?this.options.sanitizer?this.options.sanitizer(n[0]):j(n[0]):n[0]}},t.link=function(e,t,n){var r=this.rules.inline.link.exec(t);if(r){var i=P(r[2],"()");if(-1$/,"$1"))?l.replace(this.rules.inline._escapes,"$1"):l,title:a?a.replace(this.rules.inline._escapes,"$1"):a},0,r[0],e);return this.inLink=!1,h}},t.reflink=function(e,t){var n;if((n=this.rules.inline.reflink.exec(t))||(n=this.rules.inline.nolink.exec(t))){var r=(n[2]||n[1]).replace(/\s+/g," ");if(!(r=e.tokens.links[r.toLowerCase()])||!r.href){var i=n[0].charAt(0);return{type:"text",raw:i,text:i}}this.inLink=!0;var s=F(n,r,0,n[0],e);return this.inLink=!1,s}},t.strong=function(e,t){var n=this.rules.inline.strong.exec(t);if(n)return{type:"strong",raw:n[0],tokens:e.inlineTokens(n[4]||n[3]||n[2]||n[1])}},t.em=function(e,t){var n=this.rules.inline.em.exec(t);if(n)return{type:"em",raw:n[0],tokens:e.inlineTokens(n[6]||n[5]||n[4]||n[3]||n[2]||n[1])}},t.codespan=function(e,t){var n=this.rules.inline.code.exec(t);if(n)return{type:"codespan",raw:n[0],text:j(n[2].trim(),!0)}},t.br=function(e,t){var n=this.rules.inline.br.exec(t);if(n)return{type:"br",raw:n[0]}},t.del=function(e,t){var n=this.rules.inline.del.exec(t);if(n)return{type:"del",raw:n[0],tokens:e.inlineTokens(n[1])}},t.autolink=function(e,t){var n,r,i=this.rules.inline.autolink.exec(t);if(i)return r="@"===i[2]?"mailto:"+(n=j(this.options.mangle?this.mangle(i[1]):i[1])):n=j(i[1]),{type:"link",raw:i[0],text:n,href:r,tokens:[{type:"text",raw:n,text:n}]}},t.url=function(e,t){var n;if(!this.inLink&&(n=this.rules.inline.url.exec(t))){var r,i;if("@"===n[2])i="mailto:"+(r=j(this.options.mangle?this.mangle(n[0]):n[0]));else{for(var s;s=n[0],n[0]=this.rules.inline._backpedal.exec(n[0])[0],s!==n[0];);r=j(n[0]),i="www."===n[1]?"http://"+r:r}return{type:"link",raw:n[0],text:r,href:i,tokens:[{type:"text",raw:r,text:r}]}}},t.inlineText=function(e,t){var n,r=this.rules.inline.text.exec(t);if(r)return n=this.inRawBlock?this.options.sanitize?this.options.sanitizer?this.options.sanitizer(r[0]):j(r[0]):r[0]:j(this.options.smartypants?this.smartypants(r[0]):r[0]),{type:"text",raw:r[0],text:n}},t.smartypants=function(e){return e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")},t.mangle=function(e){var t,n,r="",i=e.length;for(t=0;t'+(n?e:H(e,!0))+"\n":"
    "+(n?e:H(e,!0))+"
    "},t.blockquote=function(e){return"
    \n"+e+"
    \n"},t.html=function(e){return e},t.heading=function(e,t,n,r){return this.options.headerIds?"'+e+"\n":""+e+"\n"},t.hr=function(){return this.options.xhtml?"
    \n":"
    \n"},t.list=function(e,t,n){var r=t?"ol":"ul";return"<"+r+(t&&1!==n?' start="'+n+'"':"")+">\n"+e+"\n"},t.listitem=function(e){return"
  • "+e+"
  • \n"},t.checkbox=function(e){return" "},t.paragraph=function(e){return"

    "+e+"

    \n"},t.table=function(e,t){return"\n\n"+e+"\n"+(t=t&&""+t+"")+"
    \n"},t.tablerow=function(e){return"\n"+e+"\n"},t.tablecell=function(e,t){var n=t.header?"th":"td";return(t.align?"<"+n+' align="'+t.align+'">':"<"+n+">")+e+"\n"},t.strong=function(e){return""+e+""},t.em=function(e){return""+e+""},t.codespan=function(e){return""+e+""},t.br=function(){return this.options.xhtml?"
    ":"
    "},t.del=function(e){return""+e+""},t.link=function(e,t,n){if(null===(e=V(this.options.sanitize,this.options.baseUrl,e)))return n;var r='
    "},t.image=function(e,t,n){if(null===(e=V(this.options.sanitize,this.options.baseUrl,e)))return n;var r=''+n+'":">"},t.text=function(e){return e},e}(),K=function(){function e(){}var t=e.prototype;return t.strong=function(e){return e},t.em=function(e){return e},t.codespan=function(e){return e},t.del=function(e){return e},t.html=function(e){return e},t.text=function(e){return e},t.link=function(e,t,n){return""+n},t.image=function(e,t,n){return""+n},t.br=function(){return""},e}(),Q=function(){function e(){this.seen={}}return e.prototype.slug=function(e){var t=e.toLowerCase().trim().replace(/<[!\/a-z].*?>/gi,"").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g,"").replace(/\s/g,"-");if(this.seen.hasOwnProperty(t))for(var n=t;this.seen[n]++,t=n+"-"+this.seen[n],this.seen.hasOwnProperty(t););return this.seen[t]=0,t},e}(),W=t.defaults,Y=_,ee=function(){function n(e){this.options=e||W,this.options.renderer=this.options.renderer||new J,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new K,this.slugger=new Q}n.parse=function(e,t){return new n(t).parse(e)};var e=n.prototype;return e.parse=function(e,t){void 0===t&&(t=!0);var n,r,i,s,l,a,o,h,c,u,p,g,f,d,k,b,m,x,w="",v=e.length;for(n=0;nAn error occurred:

    "+re(e.message+"",!0)+"
    ";throw e}}return ae.options=ae.setOptions=function(e){return te(ae.defaults,e),se(ae.defaults),ae},ae.getDefaults=ie,ae.defaults=le,ae.Parser=ee,ae.parser=ee.parse,ae.Renderer=J,ae.TextRenderer=K,ae.Lexer=G,ae.lexer=G.lex,ae.Tokenizer=N,ae.Slugger=Q,ae.parse=ae}); +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).marked=t()}(this,function(){"use strict";function r(e,t){for(var n=0;n"']/),l=/[&<>"']/g,a=/[<>"']|&(?!#?\w+;)/,o=/[<>"']|&(?!#?\w+;)/g,c={"&":"&","<":"<",">":">",'"':""","'":"'"};var h=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;function u(e){return e.replace(h,function(e,t){return"colon"===(t=t.toLowerCase())?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""})}var p=/(^|[^\[])\^/g;var g=/[^\w:]/g,f=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;var d={},k=/^[^:]+:\/*[^/]*$/,b=/^([^:]+:)[\s\S]*$/,m=/^([^:]+:\/*[^/]*)[\s\S]*$/;function x(e,t){d[" "+e]||(k.test(e)?d[" "+e]=e+"/":d[" "+e]=w(e,"/",!0));var n=-1===(e=d[" "+e]).indexOf(":");return"//"===t.substring(0,2)?n?t:e.replace(b,"$1")+t:"/"===t.charAt(0)?n?t:e.replace(m,"$1")+t:e+t}function w(e,t,n){var r=e.length;if(0===r)return"";for(var i=0;it)n.splice(t);else for(;n.length ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:"^ {0,3}(?:<(script|pre|style)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?\\?>\\n*|\\n*|\\n*|)[\\s\\S]*?(?:\\n{2,}|$)|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$))",def:/^ {0,3}\[(label)\]: *\n? *]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,nptable:Z,table:Z,lheading:/^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,_paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html)[^\n]+)*)/,text:/^[^\n]+/,_label:/(?!\s*\])(?:\\[\[\]]|[^\[\]])+/,_title:/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/};I.def=q(I.def).replace("label",I._label).replace("title",I._title).getRegex(),I.bullet=/(?:[*+-]|\d{1,9}\.)/,I.item=/^( *)(bull) ?[^\n]*(?:\n(?!\1bull ?)[^\n]*)*/,I.item=q(I.item,"gm").replace(/bull/g,I.bullet).getRegex(),I.list=q(I.list).replace(/bull/g,I.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+I.def.source+")").getRegex(),I._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",I._comment=//,I.html=q(I.html,"i").replace("comment",I._comment).replace("tag",I._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),I.paragraph=q(I._paragraph).replace("hr",I.hr).replace("heading"," {0,3}#{1,6} ").replace("|lheading","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",I._tag).getRegex(),I.blockquote=q(I.blockquote).replace("paragraph",I.paragraph).getRegex(),I.normal=T({},I),I.gfm=T({},I.normal,{nptable:"^ *([^|\\n ].*\\|.*)\\n *([-:]+ *\\|[-| :]*)(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)",table:"^ *\\|(.+)\\n *\\|?( *[-:]+[-| :]*)(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)"}),I.gfm.nptable=q(I.gfm.nptable).replace("hr",I.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",I._tag).getRegex(),I.gfm.table=q(I.gfm.table).replace("hr",I.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",I._tag).getRegex(),I.pedantic=T({},I.normal,{html:q("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",I._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,fences:Z,paragraph:q(I.normal._paragraph).replace("hr",I.hr).replace("heading"," *#{1,6} *[^\n]").replace("lheading",I.lheading).replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").getRegex()});var C={escape:/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:Z,tag:"^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^",link:/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,strong:/^__([^\s_])__(?!_)|^\*\*([^\s*])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/,em:/^_([^\s_])_(?!_)|^_([^\s_<][\s\S]*?[^\s_])_(?!_|[^\spunctuation])|^_([^\s_<][\s\S]*?[^\s])_(?!_|[^\spunctuation])|^\*([^\s*<\[])\*(?!\*)|^\*([^\s<"][\s\S]*?[^\s\[\*])\*(?![\]`punctuation])|^\*([^\s*"<\[][\s\S]*[^\s])\*(?!\*)/,code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:Z,text:/^(`+|[^`])(?:[\s\S]*?(?:(?=[\\?@\\[^_{|}~"};C.em=q(C.em).replace(/punctuation/g,C._punctuation).getRegex(),C._escapes=/\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g,C._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,C._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])?)+(?![-_])/,C.autolink=q(C.autolink).replace("scheme",C._scheme).replace("email",C._email).getRegex(),C._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,C.tag=q(C.tag).replace("comment",I._comment).replace("attribute",C._attribute).getRegex(),C._label=/(?:\[[^\[\]]*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,C._href=/<(?:\\[<>]?|[^\s<>\\])*>|[^\s\x00-\x1f]*/,C._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,C.link=q(C.link).replace("label",C._label).replace("href",C._href).replace("title",C._title).getRegex(),C.reflink=q(C.reflink).replace("label",C._label).getRegex(),C.normal=T({},C),C.pedantic=T({},C.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,link:q(/^!?\[(label)\]\((.*?)\)/).replace("label",C._label).getRegex(),reflink:q(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",C._label).getRegex()}),C.gfm=T({},C.normal,{escape:q(C.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^~+(?=\S)([\s\S]*?\S)~+/,text:/^(`+|[^`])(?:[\s\S]*?(?:(?=[\\ ?/gm,"");return{type:"blockquote",raw:t[0],text:n}}},t.list=function(e){var t=this.rules.block.list.exec(e);if(t){for(var n,r,i,s,l,a,o,c=t[0],h=t[2],u=1/i.test(r[0])&&(t=!1),!n&&/^<(pre|code|kbd|script)(\s|>)/i.test(r[0])?n=!0:n&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(r[0])&&(n=!1),{type:this.options.sanitize?"text":"html",raw:r[0],inLink:t,inRawBlock:n,text:this.options.sanitize?this.options.sanitizer?this.options.sanitizer(r[0]):L(r[0]):r[0]}},t.link=function(e){var t=this.rules.inline.link.exec(e);if(t){var n=P(t[2],"()");if(-1$/,"$1"))?i.replace(this.rules.inline._escapes,"$1"):i,title:s?s.replace(this.rules.inline._escapes,"$1"):s},t[0])}},t.reflink=function(e,t){var n;if((n=this.rules.inline.reflink.exec(e))||(n=this.rules.inline.nolink.exec(e))){var r=(n[2]||n[1]).replace(/\s+/g," ");if((r=t[r.toLowerCase()])&&r.href)return F(n,r,n[0]);var i=n[0].charAt(0);return{type:"text",raw:i,text:i}}},t.strong=function(e){var t=this.rules.inline.strong.exec(e);if(t)return{type:"strong",raw:t[0],text:t[4]||t[3]||t[2]||t[1]}},t.em=function(e){var t=this.rules.inline.em.exec(e);if(t)return{type:"em",raw:t[0],text:t[6]||t[5]||t[4]||t[3]||t[2]||t[1]}},t.codespan=function(e){var t=this.rules.inline.code.exec(e);if(t)return{type:"codespan",raw:t[0],text:L(t[2].trim(),!0)}},t.br=function(e){var t=this.rules.inline.br.exec(e);if(t)return{type:"br",raw:t[0]}},t.del=function(e){var t=this.rules.inline.del.exec(e);if(t)return{type:"del",raw:t[0],text:t[1]}},t.autolink=function(e){var t,n,r=this.rules.inline.autolink.exec(e);if(r)return n="@"===r[2]?"mailto:"+(t=L(this.options.mangle?this.mangle(r[1]):r[1])):t=L(r[1]),{type:"link",raw:r[0],text:t,href:n,tokens:[{type:"text",raw:t,text:t}]}},t.url=function(e){var t;if(t=this.rules.inline.url.exec(e)){var n,r;if("@"===t[2])r="mailto:"+(n=L(this.options.mangle?this.mangle(t[0]):t[0]));else{for(var i;i=t[0],t[0]=this.rules.inline._backpedal.exec(t[0])[0],i!==t[0];);n=L(t[0]),r="www."===t[1]?"http://"+n:n}return{type:"link",raw:t[0],text:n,href:r,tokens:[{type:"text",raw:n,text:n}]}}},t.inlineText=function(e,t){var n,r=this.rules.inline.text.exec(e);if(r)return n=t?this.options.sanitize?this.options.sanitizer?this.options.sanitizer(r[0]):L(r[0]):r[0]:L(this.options.smartypants?this.smartypants(r[0]):r[0]),{type:"text",raw:r[0],text:n}},t.smartypants=function(e){return e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")},t.mangle=function(e){var t,n,r="",i=e.length;for(t=0;t'+(n?e:H(e,!0))+"\n":"
    "+(n?e:H(e,!0))+"
    "},t.blockquote=function(e){return"
    \n"+e+"
    \n"},t.html=function(e){return e},t.heading=function(e,t,n,r){return this.options.headerIds?"'+e+"\n":""+e+"\n"},t.hr=function(){return this.options.xhtml?"
    \n":"
    \n"},t.list=function(e,t,n){var r=t?"ol":"ul";return"<"+r+(t&&1!==n?' start="'+n+'"':"")+">\n"+e+"\n"},t.listitem=function(e){return"
  • "+e+"
  • \n"},t.checkbox=function(e){return" "},t.paragraph=function(e){return"

    "+e+"

    \n"},t.table=function(e,t){return"\n\n"+e+"\n"+(t=t&&""+t+"")+"
    \n"},t.tablerow=function(e){return"\n"+e+"\n"},t.tablecell=function(e,t){var n=t.header?"th":"td";return(t.align?"<"+n+' align="'+t.align+'">':"<"+n+">")+e+"\n"},t.strong=function(e){return""+e+""},t.em=function(e){return""+e+""},t.codespan=function(e){return""+e+""},t.br=function(){return this.options.xhtml?"
    ":"
    "},t.del=function(e){return""+e+""},t.link=function(e,t,n){if(null===(e=V(this.options.sanitize,this.options.baseUrl,e)))return n;var r='
    "},t.image=function(e,t,n){if(null===(e=V(this.options.sanitize,this.options.baseUrl,e)))return n;var r=''+n+'":">"},t.text=function(e){return e},e}(),K=function(){function e(){}var t=e.prototype;return t.strong=function(e){return e},t.em=function(e){return e},t.codespan=function(e){return e},t.del=function(e){return e},t.html=function(e){return e},t.text=function(e){return e},t.link=function(e,t,n){return""+n},t.image=function(e,t,n){return""+n},t.br=function(){return""},e}(),Q=function(){function e(){this.seen={}}return e.prototype.slug=function(e){var t=e.toLowerCase().trim().replace(/<[!\/a-z].*?>/gi,"").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g,"").replace(/\s/g,"-");if(this.seen.hasOwnProperty(t))for(var n=t;this.seen[n]++,t=n+"-"+this.seen[n],this.seen.hasOwnProperty(t););return this.seen[t]=0,t},e}(),W=t.defaults,Y=_,ee=function(){function n(e){this.options=e||W,this.options.renderer=this.options.renderer||new J,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new K,this.slugger=new Q}n.parse=function(e,t){return new n(t).parse(e)};var e=n.prototype;return e.parse=function(e,t){void 0===t&&(t=!0);var n,r,i,s,l,a,o,c,h,u,p,g,f,d,k,b,m,x,w="",v=e.length;for(n=0;nAn error occurred:

    "+re(e.message+"",!0)+"
    ";throw e}}return ae.options=ae.setOptions=function(e){return te(ae.defaults,e),se(ae.defaults),ae},ae.getDefaults=ie,ae.defaults=le,ae.Parser=ee,ae.parser=ee.parse,ae.Renderer=J,ae.TextRenderer=K,ae.Lexer=G,ae.lexer=G.lex,ae.Tokenizer=N,ae.Slugger=Q,ae.parse=ae}); \ No newline at end of file From 4117ba271f7adb4d70e5be95ce048deaababddd9 Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Tue, 14 Apr 2020 16:40:06 -0500 Subject: [PATCH 07/13] move smartypants, mangle, and rules to lexer --- docs/USING_PRO.md | 11 ++----- src/Lexer.js | 74 +++++++++++++++++++++++++++++++++++++---- src/Tokenizer.js | 84 ++++------------------------------------------- 3 files changed, 77 insertions(+), 92 deletions(-) diff --git a/docs/USING_PRO.md b/docs/USING_PRO.md index 9d92e8ef97..5e80f547c4 100644 --- a/docs/USING_PRO.md +++ b/docs/USING_PRO.md @@ -153,14 +153,9 @@ console.log(marked('$ latext code $', { tokenizer })); - codespan(*string* src) - br(*string* src) - del(*string* src) -- autolink(*string* src) -- url(*string* src) -- inlineText(*string* src, *bool* inRawBlock) - -### Other tokenizer methods - -- smartypants(*string* text) -- mangle(*string* text) +- autolink(*string* src, *function* mangle) +- url(*string* src, *function* mangle) +- inlineText(*string* src, *bool* inRawBlock, *function* smartypants)

    The lexer

    diff --git a/src/Lexer.js b/src/Lexer.js index 6c5e06a705..577f40f966 100644 --- a/src/Lexer.js +++ b/src/Lexer.js @@ -1,5 +1,47 @@ const Tokenizer = require('./Tokenizer.js'); const { defaults } = require('./defaults.js'); +const { block, inline } = require('./rules.js'); + +/** + * smartypants text replacement + */ +function smartypants(text) { + return text + // em-dashes + .replace(/---/g, '\u2014') + // en-dashes + .replace(/--/g, '\u2013') + // opening singles + .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018') + // closing singles & apostrophes + .replace(/'/g, '\u2019') + // opening doubles + .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c') + // closing doubles + .replace(/"/g, '\u201d') + // ellipses + .replace(/\.{3}/g, '\u2026'); +} + +/** + * mangle email addresses + */ +function mangle(text) { + let out = '', + i, + ch; + + const l = text.length; + for (i = 0; i < l; i++) { + ch = text.charCodeAt(i); + if (Math.random() > 0.5) { + ch = 'x' + ch.toString(16); + } + out += '&#' + ch + ';'; + } + + return out; +} /** * Block Lexer @@ -12,14 +54,34 @@ module.exports = class Lexer { this.options.tokenizer = this.options.tokenizer || new Tokenizer(); this.tokenizer = this.options.tokenizer; this.tokenizer.options = this.options; - this.tokenizer.initialize(); + + const rules = { + block: block.normal, + inline: inline.normal + }; + + if (this.options.pedantic) { + rules.block = block.pedantic; + rules.inline = inline.pedantic; + } else if (this.options.gfm) { + rules.block = block.gfm; + if (this.options.breaks) { + rules.inline = inline.breaks; + } else { + rules.inline = inline.gfm; + } + } + this.tokenizer.rules = rules; } /** - * Expose Block Rules + * Expose Rules */ static get rules() { - return Tokenizer.rules; + return { + block, + inline + }; } /** @@ -324,21 +386,21 @@ module.exports = class Lexer { } // autolink - if (token = this.tokenizer.autolink(src)) { + if (token = this.tokenizer.autolink(src, mangle)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // url (gfm) - if (!inLink && (token = this.tokenizer.url(src))) { + if (!inLink && (token = this.tokenizer.url(src, mangle))) { src = src.substring(token.raw.length); tokens.push(token); continue; } // text - if (token = this.tokenizer.inlineText(src, inRawBlock)) { + if (token = this.tokenizer.inlineText(src, inRawBlock, smartypants)) { src = src.substring(token.raw.length); tokens.push(token); continue; diff --git a/src/Tokenizer.js b/src/Tokenizer.js index 9432b8f60a..56656f52f9 100644 --- a/src/Tokenizer.js +++ b/src/Tokenizer.js @@ -5,7 +5,6 @@ const { escape, findClosingBracket } = require('./helpers.js'); -const { block, inline } = require('./rules.js'); function outputLink(cap, link, raw) { const href = link.href; @@ -36,36 +35,6 @@ function outputLink(cap, link, raw) { module.exports = class Tokenizer { constructor(options) { this.options = options || defaults; - this.initialize(); - } - - initialize() { - this.rules = { - block: block.normal, - inline: inline.normal - }; - - if (this.options.pedantic) { - this.rules.block = block.pedantic; - this.rules.inline = inline.pedantic; - } else if (this.options.gfm) { - this.rules.block = block.gfm; - if (this.options.breaks) { - this.rules.inline = inline.breaks; - } else { - this.rules.inline = inline.gfm; - } - } - } - - /** - * Expose Block Rules - */ - static get rules() { - return { - block, - inline - }; } space(src) { @@ -533,12 +502,12 @@ module.exports = class Tokenizer { } } - autolink(src) { + autolink(src, mangle) { const cap = this.rules.inline.autolink.exec(src); if (cap) { let text, href; if (cap[2] === '@') { - text = escape(this.options.mangle ? this.mangle(cap[1]) : cap[1]); + text = escape(this.options.mangle ? mangle(cap[1]) : cap[1]); href = 'mailto:' + text; } else { text = escape(cap[1]); @@ -561,12 +530,12 @@ module.exports = class Tokenizer { } } - url(src) { + url(src, mangle) { let cap; if (cap = this.rules.inline.url.exec(src)) { let text, href; if (cap[2] === '@') { - text = escape(this.options.mangle ? this.mangle(cap[0]) : cap[0]); + text = escape(this.options.mangle ? mangle(cap[0]) : cap[0]); href = 'mailto:' + text; } else { // do extended autolink path validation @@ -598,14 +567,14 @@ module.exports = class Tokenizer { } } - inlineText(src, inRawBlock) { + inlineText(src, inRawBlock, smartypants) { const cap = this.rules.inline.text.exec(src); if (cap) { let text; if (inRawBlock) { text = this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape(cap[0])) : cap[0]; } else { - text = escape(this.options.smartypants ? this.smartypants(cap[0]) : cap[0]); + text = escape(this.options.smartypants ? smartypants(cap[0]) : cap[0]); } return { type: 'text', @@ -614,45 +583,4 @@ module.exports = class Tokenizer { }; } } - - /** - * Smartypants Transformations - */ - smartypants(text) { - return text - // em-dashes - .replace(/---/g, '\u2014') - // en-dashes - .replace(/--/g, '\u2013') - // opening singles - .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018') - // closing singles & apostrophes - .replace(/'/g, '\u2019') - // opening doubles - .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c') - // closing doubles - .replace(/"/g, '\u201d') - // ellipses - .replace(/\.{3}/g, '\u2026'); - } - - /** - * Mangle Links - */ - mangle(text) { - let out = '', - i, - ch; - - const l = text.length; - for (i = 0; i < l; i++) { - ch = text.charCodeAt(i); - if (Math.random() > 0.5) { - ch = 'x' + ch.toString(16); - } - out += '&#' + ch + ';'; - } - - return out; - } }; From 1f5a621dab249b1b3f7906455e9333fc90b07451 Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Tue, 14 Apr 2020 16:40:39 -0500 Subject: [PATCH 08/13] spelling --- docs/USING_PRO.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/USING_PRO.md b/docs/USING_PRO.md index 5e80f547c4..50d98d9b3d 100644 --- a/docs/USING_PRO.md +++ b/docs/USING_PRO.md @@ -116,7 +116,7 @@ tokenizer.codespan = function(lexer, src) { }; // Run marked -console.log(marked('$ latext code $', { tokenizer })); +console.log(marked('$ latex code $', { tokenizer })); ``` **Output:** From ad5dace5a4c48abdd12e015a66f51e06d03f44d4 Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Tue, 14 Apr 2020 16:41:10 -0500 Subject: [PATCH 09/13] build --- lib/marked.esm.js | 1576 ++++++++++++++++++++++----------------------- lib/marked.js | 486 +++++++------- marked.min.js | 2 +- 3 files changed, 1020 insertions(+), 1044 deletions(-) diff --git a/lib/marked.esm.js b/lib/marked.esm.js index 4bf96ca4cd..7a89a4629a 100644 --- a/lib/marked.esm.js +++ b/lib/marked.esm.js @@ -294,933 +294,903 @@ var helpers = { checkSanitizeDeprecation }; +const { defaults: defaults$1 } = defaults; const { - noopTest: noopTest$1, - edit: edit$1, - merge: merge$1 + rtrim: rtrim$1, + splitCells: splitCells$1, + escape: escape$1, + findClosingBracket: findClosingBracket$1 } = helpers; +function outputLink(cap, link, raw) { + const href = link.href; + const title = link.title ? escape$1(link.title) : null; + + if (cap[0].charAt(0) !== '!') { + return { + type: 'link', + raw, + href, + title, + text: cap[1] + }; + } else { + return { + type: 'image', + raw, + text: escape$1(cap[1]), + href, + title + }; + } +} + /** - * Block-Level Grammar + * Tokenizer */ -const block = { - newline: /^\n+/, - code: /^( {4}[^\n]+\n*)+/, - fences: /^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/, - hr: /^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/, - heading: /^ {0,3}(#{1,6}) +([^\n]*?)(?: +#+)? *(?:\n+|$)/, - blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/, - list: /^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/, - html: '^ {0,3}(?:' // optional indentation - + '<(script|pre|style)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)' // (1) - + '|comment[^\\n]*(\\n+|$)' // (2) - + '|<\\?[\\s\\S]*?\\?>\\n*' // (3) - + '|\\n*' // (4) - + '|\\n*' // (5) - + '|)[\\s\\S]*?(?:\\n{2,}|$)' // (6) - + '|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) open tag - + '|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) closing tag - + ')', - def: /^ {0,3}\[(label)\]: *\n? *]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/, - nptable: noopTest$1, - table: noopTest$1, - lheading: /^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/, - // regex template, placeholders will be replaced according to different paragraph - // interruption rules of commonmark and the original markdown spec: - _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html)[^\n]+)*)/, - text: /^[^\n]+/ -}; +var Tokenizer_1 = class Tokenizer { + constructor(options) { + this.options = options || defaults$1; + } -block._label = /(?!\s*\])(?:\\[\[\]]|[^\[\]])+/; -block._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/; -block.def = edit$1(block.def) - .replace('label', block._label) - .replace('title', block._title) - .getRegex(); + space(src) { + const cap = this.rules.block.newline.exec(src); + if (cap) { + if (cap[0].length > 1) { + return { + type: 'space', + raw: cap[0] + }; + } + return { raw: '\n' }; + } + } -block.bullet = /(?:[*+-]|\d{1,9}\.)/; -block.item = /^( *)(bull) ?[^\n]*(?:\n(?!\1bull ?)[^\n]*)*/; -block.item = edit$1(block.item, 'gm') - .replace(/bull/g, block.bullet) - .getRegex(); + code(src, tokens) { + const cap = this.rules.block.code.exec(src); + if (cap) { + const lastToken = tokens[tokens.length - 1]; + // An indented code block cannot interrupt a paragraph. + if (lastToken && lastToken.type === 'paragraph') { + tokens.pop(); + lastToken.text += '\n' + cap[0].trimRight(); + lastToken.raw += '\n' + cap[0]; + return lastToken; + } else { + const text = cap[0].replace(/^ {4}/gm, ''); + return { + type: 'code', + raw: cap[0], + codeBlockStyle: 'indented', + text: !this.options.pedantic + ? rtrim$1(text, '\n') + : text + }; + } + } + } -block.list = edit$1(block.list) - .replace(/bull/g, block.bullet) - .replace('hr', '\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))') - .replace('def', '\\n+(?=' + block.def.source + ')') - .getRegex(); + fences(src) { + const cap = this.rules.block.fences.exec(src); + if (cap) { + return { + type: 'code', + raw: cap[0], + lang: cap[2] ? cap[2].trim() : cap[2], + text: cap[3] || '' + }; + } + } -block._tag = 'address|article|aside|base|basefont|blockquote|body|caption' - + '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption' - + '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe' - + '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option' - + '|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr' - + '|track|ul'; -block._comment = //; -block.html = edit$1(block.html, 'i') - .replace('comment', block._comment) - .replace('tag', block._tag) - .replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/) - .getRegex(); + heading(src) { + const cap = this.rules.block.heading.exec(src); + if (cap) { + return { + type: 'heading', + raw: cap[0], + depth: cap[1].length, + text: cap[2] + }; + } + } -block.paragraph = edit$1(block._paragraph) - .replace('hr', block.hr) - .replace('heading', ' {0,3}#{1,6} ') - .replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs - .replace('blockquote', ' {0,3}>') - .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n') - .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt - .replace('html', ')|<(?:script|pre|style|!--)') - .replace('tag', block._tag) // pars can be interrupted by type (6) html blocks - .getRegex(); + nptable(src) { + const cap = this.rules.block.nptable.exec(src); + if (cap) { + const item = { + type: 'table', + header: splitCells$1(cap[1].replace(/^ *| *\| *$/g, '')), + align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), + cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [], + raw: cap[0] + }; -block.blockquote = edit$1(block.blockquote) - .replace('paragraph', block.paragraph) - .getRegex(); + if (item.header.length === item.align.length) { + let l = item.align.length; + let i; + for (i = 0; i < l; i++) { + if (/^ *-+: *$/.test(item.align[i])) { + item.align[i] = 'right'; + } else if (/^ *:-+: *$/.test(item.align[i])) { + item.align[i] = 'center'; + } else if (/^ *:-+ *$/.test(item.align[i])) { + item.align[i] = 'left'; + } else { + item.align[i] = null; + } + } -/** - * Normal Block Grammar - */ + l = item.cells.length; + for (i = 0; i < l; i++) { + item.cells[i] = splitCells$1(item.cells[i], item.header.length); + } -block.normal = merge$1({}, block); + return item; + } + } + } -/** - * GFM Block Grammar - */ + hr(src) { + const cap = this.rules.block.hr.exec(src); + if (cap) { + return { + type: 'hr', + raw: cap[0] + }; + } + } -block.gfm = merge$1({}, block.normal, { - nptable: '^ *([^|\\n ].*\\|.*)\\n' // Header - + ' *([-:]+ *\\|[-| :]*)' // Align - + '(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)', // Cells - table: '^ *\\|(.+)\\n' // Header - + ' *\\|?( *[-:]+[-| :]*)' // Align - + '(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)' // Cells -}); + blockquote(src) { + const cap = this.rules.block.blockquote.exec(src); + if (cap) { + const text = cap[0].replace(/^ *> ?/gm, ''); -block.gfm.nptable = edit$1(block.gfm.nptable) - .replace('hr', block.hr) - .replace('heading', ' {0,3}#{1,6} ') - .replace('blockquote', ' {0,3}>') - .replace('code', ' {4}[^\\n]') - .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n') - .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt - .replace('html', ')|<(?:script|pre|style|!--)') - .replace('tag', block._tag) // tables can be interrupted by type (6) html blocks - .getRegex(); + return { + type: 'blockquote', + raw: cap[0], + text + }; + } + } -block.gfm.table = edit$1(block.gfm.table) - .replace('hr', block.hr) - .replace('heading', ' {0,3}#{1,6} ') - .replace('blockquote', ' {0,3}>') - .replace('code', ' {4}[^\\n]') - .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n') - .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt - .replace('html', ')|<(?:script|pre|style|!--)') - .replace('tag', block._tag) // tables can be interrupted by type (6) html blocks - .getRegex(); + list(src) { + const cap = this.rules.block.list.exec(src); + if (cap) { + let raw = cap[0]; + const bull = cap[2]; + const isordered = bull.length > 1; -/** - * Pedantic grammar (original John Gruber's loose markdown specification) - */ + const list = { + type: 'list', + raw, + ordered: isordered, + start: isordered ? +bull : '', + loose: false, + items: [] + }; -block.pedantic = merge$1({}, block.normal, { - html: edit$1( - '^ *(?:comment *(?:\\n|\\s*$)' - + '|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)' // closed tag - + '|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))') - .replace('comment', block._comment) - .replace(/tag/g, '(?!(?:' - + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub' - + '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)' - + '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b') - .getRegex(), - def: /^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/, - heading: /^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/, - fences: noopTest$1, // fences not supported - paragraph: edit$1(block.normal._paragraph) - .replace('hr', block.hr) - .replace('heading', ' *#{1,6} *[^\n]') - .replace('lheading', block.lheading) - .replace('blockquote', ' {0,3}>') - .replace('|fences', '') - .replace('|list', '') - .replace('|html', '') - .getRegex() -}); + // Get each top-level item. + const itemMatch = cap[0].match(this.rules.block.item); -/** - * Inline-Level Grammar - */ -const inline = { - escape: /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/, - autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/, - url: noopTest$1, - tag: '^comment' - + '|^' // self-closing tag - + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag - + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. - + '|^' // declaration, e.g. - + '|^', // CDATA section - link: /^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/, - reflink: /^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/, - nolink: /^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/, - strong: /^__([^\s_])__(?!_)|^\*\*([^\s*])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/, - em: /^_([^\s_])_(?!_)|^_([^\s_<][\s\S]*?[^\s_])_(?!_|[^\spunctuation])|^_([^\s_<][\s\S]*?[^\s])_(?!_|[^\spunctuation])|^\*([^\s*<\[])\*(?!\*)|^\*([^\s<"][\s\S]*?[^\s\[\*])\*(?![\]`punctuation])|^\*([^\s*"<\[][\s\S]*[^\s])\*(?!\*)/, - code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/, - br: /^( {2,}|\\)\n(?!\s*$)/, - del: noopTest$1, - text: /^(`+|[^`])(?:[\s\S]*?(?:(?=[\\?@\\[^_{|}~'; -inline.em = edit$1(inline.em).replace(/punctuation/g, inline._punctuation).getRegex(); + const l = itemMatch.length; + for (let i = 0; i < l; i++) { + item = itemMatch[i]; + raw = item; -inline._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g; + // Remove the list item's bullet + // so it is seen as the next token. + space = item.length; + item = item.replace(/^ *([*+-]|\d+\.) */, ''); -inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/; -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])?)+(?![-_])/; -inline.autolink = edit$1(inline.autolink) - .replace('scheme', inline._scheme) - .replace('email', inline._email) - .getRegex(); + // Outdent whatever the + // list item contains. Hacky. + if (~item.indexOf('\n ')) { + space -= item.length; + item = !this.options.pedantic + ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') + : item.replace(/^ {1,4}/gm, ''); + } -inline._attribute = /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/; + // Determine whether the next list item belongs here. + // Backpedal if it does not belong in this list. + if (i !== l - 1) { + b = this.rules.block.bullet.exec(itemMatch[i + 1])[0]; + if (bull.length > 1 ? b.length === 1 + : (b.length > 1 || (this.options.smartLists && b !== bull))) { + addBack = itemMatch.slice(i + 1).join('\n'); + list.raw = list.raw.substring(0, list.raw.length - addBack.length); + i = l - 1; + } + } -inline.tag = edit$1(inline.tag) - .replace('comment', block._comment) - .replace('attribute', inline._attribute) - .getRegex(); + // Determine whether item is loose or not. + // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/ + // for discount behavior. + loose = next || /\n\n(?!\s*$)/.test(item); + if (i !== l - 1) { + next = item.charAt(item.length - 1) === '\n'; + if (!loose) loose = next; + } -inline._label = /(?:\[[^\[\]]*\]|\\.|`[^`]*`|[^\[\]\\`])*?/; -inline._href = /<(?:\\[<>]?|[^\s<>\\])*>|[^\s\x00-\x1f]*/; -inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/; + if (loose) { + list.loose = true; + } -inline.link = edit$1(inline.link) - .replace('label', inline._label) - .replace('href', inline._href) - .replace('title', inline._title) - .getRegex(); + // Check for task list items + istask = /^\[[ xX]\] /.test(item); + ischecked = undefined; + if (istask) { + ischecked = item[1] !== ' '; + item = item.replace(/^\[[ xX]\] +/, ''); + } -inline.reflink = edit$1(inline.reflink) - .replace('label', inline._label) - .getRegex(); + list.items.push({ + raw, + task: istask, + checked: ischecked, + loose: loose, + text: item + }); + } -/** - * Normal Inline Grammar - */ + return list; + } + } -inline.normal = merge$1({}, inline); + html(src) { + const cap = this.rules.block.html.exec(src); + if (cap) { + return { + type: this.options.sanitize + ? 'paragraph' + : 'html', + raw: cap[0], + pre: !this.options.sanitizer + && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'), + text: this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape$1(cap[0])) : cap[0] + }; + } + } -/** - * Pedantic Inline Grammar - */ + def(src) { + const cap = this.rules.block.def.exec(src); + if (cap) { + if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1); + const tag = cap[1].toLowerCase().replace(/\s+/g, ' '); + return { + tag, + raw: cap[0], + href: cap[2], + title: cap[3] + }; + } + } -inline.pedantic = merge$1({}, inline.normal, { - strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/, - em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/, - link: edit$1(/^!?\[(label)\]\((.*?)\)/) - .replace('label', inline._label) - .getRegex(), - reflink: edit$1(/^!?\[(label)\]\s*\[([^\]]*)\]/) - .replace('label', inline._label) - .getRegex() -}); + table(src) { + const cap = this.rules.block.table.exec(src); + if (cap) { + const item = { + type: 'table', + header: splitCells$1(cap[1].replace(/^ *| *\| *$/g, '')), + align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), + cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [] + }; -/** - * GFM Inline Grammar - */ + if (item.header.length === item.align.length) { + item.raw = cap[0]; -inline.gfm = merge$1({}, inline.normal, { - escape: edit$1(inline.escape).replace('])', '~|])').getRegex(), - _extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/, - url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/, - _backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/, - del: /^~+(?=\S)([\s\S]*?\S)~+/, - text: /^(`+|[^`])(?:[\s\S]*?(?:(?=[\\ 1) { - return { - type: 'space', - raw: cap[0] - }; + if (!inLink && /^
    /i.test(cap[0])) { + inLink = false; } - return { raw: '\n' }; + if (!inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { + inRawBlock = true; + } else if (inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { + inRawBlock = false; + } + + return { + type: this.options.sanitize + ? 'text' + : 'html', + raw: cap[0], + inLink, + inRawBlock, + text: this.options.sanitize + ? (this.options.sanitizer + ? this.options.sanitizer(cap[0]) + : escape$1(cap[0])) + : cap[0] + }; } } - code(src, tokens) { - const cap = this.rules.block.code.exec(src); + link(src) { + const cap = this.rules.inline.link.exec(src); if (cap) { - const lastToken = tokens[tokens.length - 1]; - // An indented code block cannot interrupt a paragraph. - if (lastToken && lastToken.type === 'paragraph') { - tokens.pop(); - lastToken.text += '\n' + cap[0].trimRight(); - lastToken.raw += '\n' + cap[0]; - return lastToken; + const lastParenIndex = findClosingBracket$1(cap[2], '()'); + if (lastParenIndex > -1) { + const start = cap[0].indexOf('!') === 0 ? 5 : 4; + const linkLen = start + cap[1].length + lastParenIndex; + cap[2] = cap[2].substring(0, lastParenIndex); + cap[0] = cap[0].substring(0, linkLen).trim(); + cap[3] = ''; + } + let href = cap[2]; + let title = ''; + if (this.options.pedantic) { + const link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href); + + if (link) { + href = link[1]; + title = link[3]; + } else { + title = ''; + } } else { - const text = cap[0].replace(/^ {4}/gm, ''); + title = cap[3] ? cap[3].slice(1, -1) : ''; + } + href = href.trim().replace(/^<([\s\S]*)>$/, '$1'); + const token = outputLink(cap, { + href: href ? href.replace(this.rules.inline._escapes, '$1') : href, + title: title ? title.replace(this.rules.inline._escapes, '$1') : title + }, cap[0]); + return token; + } + } + + reflink(src, links) { + let cap; + if ((cap = this.rules.inline.reflink.exec(src)) + || (cap = this.rules.inline.nolink.exec(src))) { + let link = (cap[2] || cap[1]).replace(/\s+/g, ' '); + link = links[link.toLowerCase()]; + if (!link || !link.href) { + const text = cap[0].charAt(0); return { - type: 'code', - raw: cap[0], - codeBlockStyle: 'indented', - text: !this.options.pedantic - ? rtrim$1(text, '\n') - : text + type: 'text', + raw: text, + text }; } + const token = outputLink(cap, link, cap[0]); + return token; } } - fences(src) { - const cap = this.rules.block.fences.exec(src); + strong(src) { + const cap = this.rules.inline.strong.exec(src); if (cap) { return { - type: 'code', + type: 'strong', raw: cap[0], - lang: cap[2] ? cap[2].trim() : cap[2], - text: cap[3] || '' + text: cap[4] || cap[3] || cap[2] || cap[1] }; } } - heading(src) { - const cap = this.rules.block.heading.exec(src); + em(src) { + const cap = this.rules.inline.em.exec(src); if (cap) { return { - type: 'heading', + type: 'em', raw: cap[0], - depth: cap[1].length, - text: cap[2] + text: cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1] }; } } - nptable(src) { - const cap = this.rules.block.nptable.exec(src); + codespan(src) { + const cap = this.rules.inline.code.exec(src); if (cap) { - const item = { - type: 'table', - header: splitCells$1(cap[1].replace(/^ *| *\| *$/g, '')), - align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), - cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [], - raw: cap[0] + return { + type: 'codespan', + raw: cap[0], + text: escape$1(cap[2].trim(), true) }; - - if (item.header.length === item.align.length) { - let l = item.align.length; - let i; - for (i = 0; i < l; i++) { - if (/^ *-+: *$/.test(item.align[i])) { - item.align[i] = 'right'; - } else if (/^ *:-+: *$/.test(item.align[i])) { - item.align[i] = 'center'; - } else if (/^ *:-+ *$/.test(item.align[i])) { - item.align[i] = 'left'; - } else { - item.align[i] = null; - } - } - - l = item.cells.length; - for (i = 0; i < l; i++) { - item.cells[i] = splitCells$1(item.cells[i], item.header.length); - } - - return item; - } } } - hr(src) { - const cap = this.rules.block.hr.exec(src); + br(src) { + const cap = this.rules.inline.br.exec(src); if (cap) { return { - type: 'hr', + type: 'br', raw: cap[0] }; } } - blockquote(src) { - const cap = this.rules.block.blockquote.exec(src); + del(src) { + const cap = this.rules.inline.del.exec(src); if (cap) { - const text = cap[0].replace(/^ *> ?/gm, ''); - return { - type: 'blockquote', + type: 'del', raw: cap[0], - text + text: cap[1] }; } } - list(src) { - const cap = this.rules.block.list.exec(src); + autolink(src, mangle) { + const cap = this.rules.inline.autolink.exec(src); if (cap) { - let raw = cap[0]; - const bull = cap[2]; - const isordered = bull.length > 1; - - const list = { - type: 'list', - raw, - ordered: isordered, - start: isordered ? +bull : '', - loose: false, - items: [] - }; - - // Get each top-level item. - const itemMatch = cap[0].match(this.rules.block.item); - - let next = false, - item, - space, - b, - addBack, - loose, - istask, - ischecked; - - const l = itemMatch.length; - for (let i = 0; i < l; i++) { - item = itemMatch[i]; - raw = item; - - // Remove the list item's bullet - // so it is seen as the next token. - space = item.length; - item = item.replace(/^ *([*+-]|\d+\.) */, ''); - - // Outdent whatever the - // list item contains. Hacky. - if (~item.indexOf('\n ')) { - space -= item.length; - item = !this.options.pedantic - ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') - : item.replace(/^ {1,4}/gm, ''); - } - - // Determine whether the next list item belongs here. - // Backpedal if it does not belong in this list. - if (i !== l - 1) { - b = this.rules.block.bullet.exec(itemMatch[i + 1])[0]; - if (bull.length > 1 ? b.length === 1 - : (b.length > 1 || (this.options.smartLists && b !== bull))) { - addBack = itemMatch.slice(i + 1).join('\n'); - list.raw = list.raw.substring(0, list.raw.length - addBack.length); - i = l - 1; - } - } - - // Determine whether item is loose or not. - // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/ - // for discount behavior. - loose = next || /\n\n(?!\s*$)/.test(item); - if (i !== l - 1) { - next = item.charAt(item.length - 1) === '\n'; - if (!loose) loose = next; - } - - if (loose) { - list.loose = true; - } - - // Check for task list items - istask = /^\[[ xX]\] /.test(item); - ischecked = undefined; - if (istask) { - ischecked = item[1] !== ' '; - item = item.replace(/^\[[ xX]\] +/, ''); - } - - list.items.push({ - raw, - task: istask, - checked: ischecked, - loose: loose, - text: item - }); + let text, href; + if (cap[2] === '@') { + text = escape$1(this.options.mangle ? mangle(cap[1]) : cap[1]); + href = 'mailto:' + text; + } else { + text = escape$1(cap[1]); + href = text; } - return list; + return { + type: 'link', + raw: cap[0], + text, + href, + tokens: [ + { + type: 'text', + raw: text, + text + } + ] + }; } } - html(src) { - const cap = this.rules.block.html.exec(src); - if (cap) { + url(src, mangle) { + let cap; + if (cap = this.rules.inline.url.exec(src)) { + let text, href; + if (cap[2] === '@') { + text = escape$1(this.options.mangle ? mangle(cap[0]) : cap[0]); + href = 'mailto:' + text; + } else { + // do extended autolink path validation + let prevCapZero; + do { + prevCapZero = cap[0]; + cap[0] = this.rules.inline._backpedal.exec(cap[0])[0]; + } while (prevCapZero !== cap[0]); + text = escape$1(cap[0]); + if (cap[1] === 'www.') { + href = 'http://' + text; + } else { + href = text; + } + } return { - type: this.options.sanitize - ? 'paragraph' - : 'html', + type: 'link', raw: cap[0], - pre: !this.options.sanitizer - && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'), - text: this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape$1(cap[0])) : cap[0] + text, + href, + tokens: [ + { + type: 'text', + raw: text, + text + } + ] }; } } - def(src) { - const cap = this.rules.block.def.exec(src); + inlineText(src, inRawBlock, smartypants) { + const cap = this.rules.inline.text.exec(src); if (cap) { - if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1); - const tag = cap[1].toLowerCase().replace(/\s+/g, ' '); + let text; + if (inRawBlock) { + text = this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape$1(cap[0])) : cap[0]; + } else { + text = escape$1(this.options.smartypants ? smartypants(cap[0]) : cap[0]); + } return { - tag, + type: 'text', raw: cap[0], - href: cap[2], - title: cap[3] + text }; } } +}; - table(src) { - const cap = this.rules.block.table.exec(src); - if (cap) { - const item = { - type: 'table', - header: splitCells$1(cap[1].replace(/^ *| *\| *$/g, '')), - align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), - cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [] - }; +const { + noopTest: noopTest$1, + edit: edit$1, + merge: merge$1 +} = helpers; - if (item.header.length === item.align.length) { - item.raw = cap[0]; +/** + * Block-Level Grammar + */ +const block = { + newline: /^\n+/, + code: /^( {4}[^\n]+\n*)+/, + fences: /^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/, + hr: /^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/, + heading: /^ {0,3}(#{1,6}) +([^\n]*?)(?: +#+)? *(?:\n+|$)/, + blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/, + list: /^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/, + html: '^ {0,3}(?:' // optional indentation + + '<(script|pre|style)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)' // (1) + + '|comment[^\\n]*(\\n+|$)' // (2) + + '|<\\?[\\s\\S]*?\\?>\\n*' // (3) + + '|\\n*' // (4) + + '|\\n*' // (5) + + '|)[\\s\\S]*?(?:\\n{2,}|$)' // (6) + + '|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) open tag + + '|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) closing tag + + ')', + def: /^ {0,3}\[(label)\]: *\n? *]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/, + nptable: noopTest$1, + table: noopTest$1, + lheading: /^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/, + // regex template, placeholders will be replaced according to different paragraph + // interruption rules of commonmark and the original markdown spec: + _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html)[^\n]+)*)/, + text: /^[^\n]+/ +}; - let l = item.align.length; - let i; - for (i = 0; i < l; i++) { - if (/^ *-+: *$/.test(item.align[i])) { - item.align[i] = 'right'; - } else if (/^ *:-+: *$/.test(item.align[i])) { - item.align[i] = 'center'; - } else if (/^ *:-+ *$/.test(item.align[i])) { - item.align[i] = 'left'; - } else { - item.align[i] = null; - } - } +block._label = /(?!\s*\])(?:\\[\[\]]|[^\[\]])+/; +block._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/; +block.def = edit$1(block.def) + .replace('label', block._label) + .replace('title', block._title) + .getRegex(); - l = item.cells.length; - for (i = 0; i < l; i++) { - item.cells[i] = splitCells$1( - item.cells[i].replace(/^ *\| *| *\| *$/g, ''), - item.header.length); - } +block.bullet = /(?:[*+-]|\d{1,9}\.)/; +block.item = /^( *)(bull) ?[^\n]*(?:\n(?!\1bull ?)[^\n]*)*/; +block.item = edit$1(block.item, 'gm') + .replace(/bull/g, block.bullet) + .getRegex(); - return item; - } - } - } +block.list = edit$1(block.list) + .replace(/bull/g, block.bullet) + .replace('hr', '\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))') + .replace('def', '\\n+(?=' + block.def.source + ')') + .getRegex(); - lheading(src) { - const cap = this.rules.block.lheading.exec(src); - if (cap) { - return { - type: 'heading', - raw: cap[0], - depth: cap[2].charAt(0) === '=' ? 1 : 2, - text: cap[1] - }; - } - } +block._tag = 'address|article|aside|base|basefont|blockquote|body|caption' + + '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption' + + '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe' + + '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option' + + '|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr' + + '|track|ul'; +block._comment = //; +block.html = edit$1(block.html, 'i') + .replace('comment', block._comment) + .replace('tag', block._tag) + .replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/) + .getRegex(); - paragraph(src) { - const cap = this.rules.block.paragraph.exec(src); - if (cap) { - return { - type: 'paragraph', - raw: cap[0], - text: cap[1].charAt(cap[1].length - 1) === '\n' - ? cap[1].slice(0, -1) - : cap[1] - }; - } - } +block.paragraph = edit$1(block._paragraph) + .replace('hr', block.hr) + .replace('heading', ' {0,3}#{1,6} ') + .replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs + .replace('blockquote', ' {0,3}>') + .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n') + .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt + .replace('html', ')|<(?:script|pre|style|!--)') + .replace('tag', block._tag) // pars can be interrupted by type (6) html blocks + .getRegex(); - text(src) { - const cap = this.rules.block.text.exec(src); - if (cap) { - return { - type: 'text', - raw: cap[0], - text: cap[0] - }; - } - } +block.blockquote = edit$1(block.blockquote) + .replace('paragraph', block.paragraph) + .getRegex(); - escape(src) { - const cap = this.rules.inline.escape.exec(src); - if (cap) { - return { - type: 'escape', - raw: cap[0], - text: escape$1(cap[1]) - }; - } - } +/** + * Normal Block Grammar + */ - tag(src, inLink, inRawBlock) { - const cap = this.rules.inline.tag.exec(src); - if (cap) { - if (!inLink && /^/i.test(cap[0])) { - inLink = false; - } - if (!inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { - inRawBlock = true; - } else if (inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) { - inRawBlock = false; - } +block.normal = merge$1({}, block); - return { - type: this.options.sanitize - ? 'text' - : 'html', - raw: cap[0], - inLink, - inRawBlock, - text: this.options.sanitize - ? (this.options.sanitizer - ? this.options.sanitizer(cap[0]) - : escape$1(cap[0])) - : cap[0] - }; - } - } +/** + * GFM Block Grammar + */ - link(src) { - const cap = this.rules.inline.link.exec(src); - if (cap) { - const lastParenIndex = findClosingBracket$1(cap[2], '()'); - if (lastParenIndex > -1) { - const start = cap[0].indexOf('!') === 0 ? 5 : 4; - const linkLen = start + cap[1].length + lastParenIndex; - cap[2] = cap[2].substring(0, lastParenIndex); - cap[0] = cap[0].substring(0, linkLen).trim(); - cap[3] = ''; - } - let href = cap[2]; - let title = ''; - if (this.options.pedantic) { - const link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href); +block.gfm = merge$1({}, block.normal, { + nptable: '^ *([^|\\n ].*\\|.*)\\n' // Header + + ' *([-:]+ *\\|[-| :]*)' // Align + + '(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)', // Cells + table: '^ *\\|(.+)\\n' // Header + + ' *\\|?( *[-:]+[-| :]*)' // Align + + '(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)' // Cells +}); - if (link) { - href = link[1]; - title = link[3]; - } else { - title = ''; - } - } else { - title = cap[3] ? cap[3].slice(1, -1) : ''; - } - href = href.trim().replace(/^<([\s\S]*)>$/, '$1'); - const token = outputLink(cap, { - href: href ? href.replace(this.rules.inline._escapes, '$1') : href, - title: title ? title.replace(this.rules.inline._escapes, '$1') : title - }, cap[0]); - return token; - } - } +block.gfm.nptable = edit$1(block.gfm.nptable) + .replace('hr', block.hr) + .replace('heading', ' {0,3}#{1,6} ') + .replace('blockquote', ' {0,3}>') + .replace('code', ' {4}[^\\n]') + .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n') + .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt + .replace('html', ')|<(?:script|pre|style|!--)') + .replace('tag', block._tag) // tables can be interrupted by type (6) html blocks + .getRegex(); + +block.gfm.table = edit$1(block.gfm.table) + .replace('hr', block.hr) + .replace('heading', ' {0,3}#{1,6} ') + .replace('blockquote', ' {0,3}>') + .replace('code', ' {4}[^\\n]') + .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n') + .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt + .replace('html', ')|<(?:script|pre|style|!--)') + .replace('tag', block._tag) // tables can be interrupted by type (6) html blocks + .getRegex(); + +/** + * Pedantic grammar (original John Gruber's loose markdown specification) + */ + +block.pedantic = merge$1({}, block.normal, { + html: edit$1( + '^ *(?:comment *(?:\\n|\\s*$)' + + '|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)' // closed tag + + '|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))') + .replace('comment', block._comment) + .replace(/tag/g, '(?!(?:' + + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub' + + '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)' + + '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b') + .getRegex(), + def: /^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/, + heading: /^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/, + fences: noopTest$1, // fences not supported + paragraph: edit$1(block.normal._paragraph) + .replace('hr', block.hr) + .replace('heading', ' *#{1,6} *[^\n]') + .replace('lheading', block.lheading) + .replace('blockquote', ' {0,3}>') + .replace('|fences', '') + .replace('|list', '') + .replace('|html', '') + .getRegex() +}); + +/** + * Inline-Level Grammar + */ +const inline = { + escape: /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/, + autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/, + url: noopTest$1, + tag: '^comment' + + '|^' // self-closing tag + + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag + + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. + + '|^' // declaration, e.g. + + '|^', // CDATA section + link: /^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/, + reflink: /^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/, + nolink: /^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/, + strong: /^__([^\s_])__(?!_)|^\*\*([^\s*])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/, + em: /^_([^\s_])_(?!_)|^_([^\s_<][\s\S]*?[^\s_])_(?!_|[^\spunctuation])|^_([^\s_<][\s\S]*?[^\s])_(?!_|[^\spunctuation])|^\*([^\s*<\[])\*(?!\*)|^\*([^\s<"][\s\S]*?[^\s\[\*])\*(?![\]`punctuation])|^\*([^\s*"<\[][\s\S]*[^\s])\*(?!\*)/, + code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/, + br: /^( {2,}|\\)\n(?!\s*$)/, + del: noopTest$1, + text: /^(`+|[^`])(?:[\s\S]*?(?:(?=[\\?@\\[^_{|}~'; +inline.em = edit$1(inline.em).replace(/punctuation/g, inline._punctuation).getRegex(); - strong(src) { - const cap = this.rules.inline.strong.exec(src); - if (cap) { - return { - type: 'strong', - raw: cap[0], - text: cap[4] || cap[3] || cap[2] || cap[1] - }; - } - } +inline._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g; - em(src) { - const cap = this.rules.inline.em.exec(src); - if (cap) { - return { - type: 'em', - raw: cap[0], - text: cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1] - }; - } - } +inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/; +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])?)+(?![-_])/; +inline.autolink = edit$1(inline.autolink) + .replace('scheme', inline._scheme) + .replace('email', inline._email) + .getRegex(); - codespan(src) { - const cap = this.rules.inline.code.exec(src); - if (cap) { - return { - type: 'codespan', - raw: cap[0], - text: escape$1(cap[2].trim(), true) - }; - } - } +inline._attribute = /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/; - br(src) { - const cap = this.rules.inline.br.exec(src); - if (cap) { - return { - type: 'br', - raw: cap[0] - }; - } - } +inline.tag = edit$1(inline.tag) + .replace('comment', block._comment) + .replace('attribute', inline._attribute) + .getRegex(); - del(src) { - const cap = this.rules.inline.del.exec(src); - if (cap) { - return { - type: 'del', - raw: cap[0], - text: cap[1] - }; - } - } +inline._label = /(?:\[[^\[\]]*\]|\\.|`[^`]*`|[^\[\]\\`])*?/; +inline._href = /<(?:\\[<>]?|[^\s<>\\])*>|[^\s\x00-\x1f]*/; +inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/; - autolink(src) { - const cap = this.rules.inline.autolink.exec(src); - if (cap) { - let text, href; - if (cap[2] === '@') { - text = escape$1(this.options.mangle ? this.mangle(cap[1]) : cap[1]); - href = 'mailto:' + text; - } else { - text = escape$1(cap[1]); - href = text; - } +inline.link = edit$1(inline.link) + .replace('label', inline._label) + .replace('href', inline._href) + .replace('title', inline._title) + .getRegex(); - return { - type: 'link', - raw: cap[0], - text, - href, - tokens: [ - { - type: 'text', - raw: text, - text - } - ] - }; - } - } +inline.reflink = edit$1(inline.reflink) + .replace('label', inline._label) + .getRegex(); - url(src) { - let cap; - if (cap = this.rules.inline.url.exec(src)) { - let text, href; - if (cap[2] === '@') { - text = escape$1(this.options.mangle ? this.mangle(cap[0]) : cap[0]); - href = 'mailto:' + text; - } else { - // do extended autolink path validation - let prevCapZero; - do { - prevCapZero = cap[0]; - cap[0] = this.rules.inline._backpedal.exec(cap[0])[0]; - } while (prevCapZero !== cap[0]); - text = escape$1(cap[0]); - if (cap[1] === 'www.') { - href = 'http://' + text; - } else { - href = text; - } - } - return { - type: 'link', - raw: cap[0], - text, - href, - tokens: [ - { - type: 'text', - raw: text, - text - } - ] - }; - } - } +/** + * Normal Inline Grammar + */ - inlineText(src, inRawBlock) { - const cap = this.rules.inline.text.exec(src); - if (cap) { - let text; - if (inRawBlock) { - text = this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape$1(cap[0])) : cap[0]; - } else { - text = escape$1(this.options.smartypants ? this.smartypants(cap[0]) : cap[0]); - } - return { - type: 'text', - raw: cap[0], - text - }; - } - } +inline.normal = merge$1({}, inline); - /** - * Smartypants Transformations - */ - smartypants(text) { - return text - // em-dashes - .replace(/---/g, '\u2014') - // en-dashes - .replace(/--/g, '\u2013') - // opening singles - .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018') - // closing singles & apostrophes - .replace(/'/g, '\u2019') - // opening doubles - .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c') - // closing doubles - .replace(/"/g, '\u201d') - // ellipses - .replace(/\.{3}/g, '\u2026'); - } +/** + * Pedantic Inline Grammar + */ - /** - * Mangle Links - */ - mangle(text) { - let out = '', - i, - ch; +inline.pedantic = merge$1({}, inline.normal, { + strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/, + em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/, + link: edit$1(/^!?\[(label)\]\((.*?)\)/) + .replace('label', inline._label) + .getRegex(), + reflink: edit$1(/^!?\[(label)\]\s*\[([^\]]*)\]/) + .replace('label', inline._label) + .getRegex() +}); - const l = text.length; - for (i = 0; i < l; i++) { - ch = text.charCodeAt(i); - if (Math.random() > 0.5) { - ch = 'x' + ch.toString(16); - } - out += '&#' + ch + ';'; - } +/** + * GFM Inline Grammar + */ - return out; - } +inline.gfm = merge$1({}, inline.normal, { + escape: edit$1(inline.escape).replace('])', '~|])').getRegex(), + _extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/, + url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/, + _backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/, + del: /^~+(?=\S)([\s\S]*?\S)~+/, + text: /^(`+|[^`])(?:[\s\S]*?(?:(?=[\\ 0.5) { + ch = 'x' + ch.toString(16); + } + out += '&#' + ch + ';'; + } + + return out; +} /** * Block Lexer @@ -1233,14 +1203,34 @@ var Lexer_1 = class Lexer { this.options.tokenizer = this.options.tokenizer || new Tokenizer_1(); this.tokenizer = this.options.tokenizer; this.tokenizer.options = this.options; - this.tokenizer.initialize(); + + const rules = { + block: block$1.normal, + inline: inline$1.normal + }; + + if (this.options.pedantic) { + rules.block = block$1.pedantic; + rules.inline = inline$1.pedantic; + } else if (this.options.gfm) { + rules.block = block$1.gfm; + if (this.options.breaks) { + rules.inline = inline$1.breaks; + } else { + rules.inline = inline$1.gfm; + } + } + this.tokenizer.rules = rules; } /** - * Expose Block Rules + * Expose Rules */ static get rules() { - return Tokenizer_1.rules; + return { + block: block$1, + inline: inline$1 + }; } /** @@ -1542,21 +1532,21 @@ var Lexer_1 = class Lexer { } // autolink - if (token = this.tokenizer.autolink(src)) { + if (token = this.tokenizer.autolink(src, mangle)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // url (gfm) - if (!inLink && (token = this.tokenizer.url(src))) { + if (!inLink && (token = this.tokenizer.url(src, mangle))) { src = src.substring(token.raw.length); tokens.push(token); continue; } // text - if (token = this.tokenizer.inlineText(src, inRawBlock)) { + if (token = this.tokenizer.inlineText(src, inRawBlock, smartypants)) { src = src.substring(token.raw.length); tokens.push(token); continue; diff --git a/lib/marked.js b/lib/marked.js index 41c91b498a..b96962ff37 100644 --- a/lib/marked.js +++ b/lib/marked.js @@ -343,180 +343,11 @@ checkSanitizeDeprecation: checkSanitizeDeprecation }; - var noopTest$1 = helpers.noopTest, - edit$1 = helpers.edit, - merge$1 = helpers.merge; - /** - * Block-Level Grammar - */ - - var block = { - newline: /^\n+/, - code: /^( {4}[^\n]+\n*)+/, - fences: /^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/, - hr: /^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/, - heading: /^ {0,3}(#{1,6}) +([^\n]*?)(?: +#+)? *(?:\n+|$)/, - blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/, - list: /^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/, - html: '^ {0,3}(?:' // optional indentation - + '<(script|pre|style)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)' // (1) - + '|comment[^\\n]*(\\n+|$)' // (2) - + '|<\\?[\\s\\S]*?\\?>\\n*' // (3) - + '|\\n*' // (4) - + '|\\n*' // (5) - + '|)[\\s\\S]*?(?:\\n{2,}|$)' // (6) - + '|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) open tag - + '|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) closing tag - + ')', - def: /^ {0,3}\[(label)\]: *\n? *]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/, - nptable: noopTest$1, - table: noopTest$1, - lheading: /^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/, - // regex template, placeholders will be replaced according to different paragraph - // interruption rules of commonmark and the original markdown spec: - _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html)[^\n]+)*)/, - text: /^[^\n]+/ - }; - block._label = /(?!\s*\])(?:\\[\[\]]|[^\[\]])+/; - block._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/; - block.def = edit$1(block.def).replace('label', block._label).replace('title', block._title).getRegex(); - block.bullet = /(?:[*+-]|\d{1,9}\.)/; - block.item = /^( *)(bull) ?[^\n]*(?:\n(?!\1bull ?)[^\n]*)*/; - block.item = edit$1(block.item, 'gm').replace(/bull/g, block.bullet).getRegex(); - block.list = edit$1(block.list).replace(/bull/g, block.bullet).replace('hr', '\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))').replace('def', '\\n+(?=' + block.def.source + ')').getRegex(); - block._tag = 'address|article|aside|base|basefont|blockquote|body|caption' + '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption' + '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe' + '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option' + '|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr' + '|track|ul'; - block._comment = //; - block.html = edit$1(block.html, 'i').replace('comment', block._comment).replace('tag', block._tag).replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(); - block.paragraph = edit$1(block._paragraph).replace('hr', block.hr).replace('heading', ' {0,3}#{1,6} ').replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs - .replace('blockquote', ' {0,3}>').replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n').replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt - .replace('html', ')|<(?:script|pre|style|!--)').replace('tag', block._tag) // pars can be interrupted by type (6) html blocks - .getRegex(); - block.blockquote = edit$1(block.blockquote).replace('paragraph', block.paragraph).getRegex(); - /** - * Normal Block Grammar - */ - - block.normal = merge$1({}, block); - /** - * GFM Block Grammar - */ - - block.gfm = merge$1({}, block.normal, { - nptable: '^ *([^|\\n ].*\\|.*)\\n' // Header - + ' *([-:]+ *\\|[-| :]*)' // Align - + '(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)', - // Cells - table: '^ *\\|(.+)\\n' // Header - + ' *\\|?( *[-:]+[-| :]*)' // Align - + '(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)' // Cells - - }); - block.gfm.nptable = edit$1(block.gfm.nptable).replace('hr', block.hr).replace('heading', ' {0,3}#{1,6} ').replace('blockquote', ' {0,3}>').replace('code', ' {4}[^\\n]').replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n').replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt - .replace('html', ')|<(?:script|pre|style|!--)').replace('tag', block._tag) // tables can be interrupted by type (6) html blocks - .getRegex(); - block.gfm.table = edit$1(block.gfm.table).replace('hr', block.hr).replace('heading', ' {0,3}#{1,6} ').replace('blockquote', ' {0,3}>').replace('code', ' {4}[^\\n]').replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n').replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt - .replace('html', ')|<(?:script|pre|style|!--)').replace('tag', block._tag) // tables can be interrupted by type (6) html blocks - .getRegex(); - /** - * Pedantic grammar (original John Gruber's loose markdown specification) - */ - - block.pedantic = merge$1({}, block.normal, { - html: edit$1('^ *(?:comment *(?:\\n|\\s*$)' + '|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)' // closed tag - + '|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))').replace('comment', block._comment).replace(/tag/g, '(?!(?:' + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub' + '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)' + '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b').getRegex(), - def: /^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/, - heading: /^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/, - fences: noopTest$1, - // fences not supported - paragraph: edit$1(block.normal._paragraph).replace('hr', block.hr).replace('heading', ' *#{1,6} *[^\n]').replace('lheading', block.lheading).replace('blockquote', ' {0,3}>').replace('|fences', '').replace('|list', '').replace('|html', '').getRegex() - }); - /** - * Inline-Level Grammar - */ - - var inline = { - escape: /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/, - autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/, - url: noopTest$1, - tag: '^comment' + '|^' // self-closing tag - + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag - + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. - + '|^' // declaration, e.g. - + '|^', - // CDATA section - link: /^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/, - reflink: /^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/, - nolink: /^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/, - strong: /^__([^\s_])__(?!_)|^\*\*([^\s*])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/, - em: /^_([^\s_])_(?!_)|^_([^\s_<][\s\S]*?[^\s_])_(?!_|[^\spunctuation])|^_([^\s_<][\s\S]*?[^\s])_(?!_|[^\spunctuation])|^\*([^\s*<\[])\*(?!\*)|^\*([^\s<"][\s\S]*?[^\s\[\*])\*(?![\]`punctuation])|^\*([^\s*"<\[][\s\S]*[^\s])\*(?!\*)/, - code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/, - br: /^( {2,}|\\)\n(?!\s*$)/, - del: noopTest$1, - text: /^(`+|[^`])(?:[\s\S]*?(?:(?=[\\?@\\[^_{|}~'; - inline.em = edit$1(inline.em).replace(/punctuation/g, inline._punctuation).getRegex(); - inline._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g; - inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/; - 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])?)+(?![-_])/; - inline.autolink = edit$1(inline.autolink).replace('scheme', inline._scheme).replace('email', inline._email).getRegex(); - inline._attribute = /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/; - inline.tag = edit$1(inline.tag).replace('comment', block._comment).replace('attribute', inline._attribute).getRegex(); - inline._label = /(?:\[[^\[\]]*\]|\\.|`[^`]*`|[^\[\]\\`])*?/; - inline._href = /<(?:\\[<>]?|[^\s<>\\])*>|[^\s\x00-\x1f]*/; - inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/; - inline.link = edit$1(inline.link).replace('label', inline._label).replace('href', inline._href).replace('title', inline._title).getRegex(); - inline.reflink = edit$1(inline.reflink).replace('label', inline._label).getRegex(); - /** - * Normal Inline Grammar - */ - - inline.normal = merge$1({}, inline); - /** - * Pedantic Inline Grammar - */ - - inline.pedantic = merge$1({}, inline.normal, { - strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/, - em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/, - link: edit$1(/^!?\[(label)\]\((.*?)\)/).replace('label', inline._label).getRegex(), - reflink: edit$1(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace('label', inline._label).getRegex() - }); - /** - * GFM Inline Grammar - */ - - inline.gfm = merge$1({}, inline.normal, { - escape: edit$1(inline.escape).replace('])', '~|])').getRegex(), - _extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/, - url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/, - _backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/, - del: /^~+(?=\S)([\s\S]*?\S)~+/, - text: /^(`+|[^`])(?:[\s\S]*?(?:(?=[\\ ?(paragraph|[^\n]*)(?:\n|$))+/, + list: /^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/, + html: '^ {0,3}(?:' // optional indentation + + '<(script|pre|style)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)' // (1) + + '|comment[^\\n]*(\\n+|$)' // (2) + + '|<\\?[\\s\\S]*?\\?>\\n*' // (3) + + '|\\n*' // (4) + + '|\\n*' // (5) + + '|)[\\s\\S]*?(?:\\n{2,}|$)' // (6) + + '|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) open tag + + '|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) closing tag + + ')', + def: /^ {0,3}\[(label)\]: *\n? *]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/, + nptable: noopTest$1, + table: noopTest$1, + lheading: /^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/, + // regex template, placeholders will be replaced according to different paragraph + // interruption rules of commonmark and the original markdown spec: + _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html)[^\n]+)*)/, + text: /^[^\n]+/ + }; + block._label = /(?!\s*\])(?:\\[\[\]]|[^\[\]])+/; + block._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/; + block.def = edit$1(block.def).replace('label', block._label).replace('title', block._title).getRegex(); + block.bullet = /(?:[*+-]|\d{1,9}\.)/; + block.item = /^( *)(bull) ?[^\n]*(?:\n(?!\1bull ?)[^\n]*)*/; + block.item = edit$1(block.item, 'gm').replace(/bull/g, block.bullet).getRegex(); + block.list = edit$1(block.list).replace(/bull/g, block.bullet).replace('hr', '\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))').replace('def', '\\n+(?=' + block.def.source + ')').getRegex(); + block._tag = 'address|article|aside|base|basefont|blockquote|body|caption' + '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption' + '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe' + '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option' + '|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr' + '|track|ul'; + block._comment = //; + block.html = edit$1(block.html, 'i').replace('comment', block._comment).replace('tag', block._tag).replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(); + block.paragraph = edit$1(block._paragraph).replace('hr', block.hr).replace('heading', ' {0,3}#{1,6} ').replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs + .replace('blockquote', ' {0,3}>').replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n').replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt + .replace('html', ')|<(?:script|pre|style|!--)').replace('tag', block._tag) // pars can be interrupted by type (6) html blocks + .getRegex(); + block.blockquote = edit$1(block.blockquote).replace('paragraph', block.paragraph).getRegex(); + /** + * Normal Block Grammar + */ - if (Math.random() > 0.5) { - ch = 'x' + ch.toString(16); - } + block.normal = merge$1({}, block); + /** + * GFM Block Grammar + */ - out += '&#' + ch + ';'; - } + block.gfm = merge$1({}, block.normal, { + nptable: '^ *([^|\\n ].*\\|.*)\\n' // Header + + ' *([-:]+ *\\|[-| :]*)' // Align + + '(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)', + // Cells + table: '^ *\\|(.+)\\n' // Header + + ' *\\|?( *[-:]+[-| :]*)' // Align + + '(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)' // Cells - return out; - }; + }); + block.gfm.nptable = edit$1(block.gfm.nptable).replace('hr', block.hr).replace('heading', ' {0,3}#{1,6} ').replace('blockquote', ' {0,3}>').replace('code', ' {4}[^\\n]').replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n').replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt + .replace('html', ')|<(?:script|pre|style|!--)').replace('tag', block._tag) // tables can be interrupted by type (6) html blocks + .getRegex(); + block.gfm.table = edit$1(block.gfm.table).replace('hr', block.hr).replace('heading', ' {0,3}#{1,6} ').replace('blockquote', ' {0,3}>').replace('code', ' {4}[^\\n]').replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n').replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt + .replace('html', ')|<(?:script|pre|style|!--)').replace('tag', block._tag) // tables can be interrupted by type (6) html blocks + .getRegex(); + /** + * Pedantic grammar (original John Gruber's loose markdown specification) + */ - _createClass(Tokenizer, null, [{ - key: "rules", - get: function get() { - return { - block: block$1, - inline: inline$1 - }; - } - }]); + block.pedantic = merge$1({}, block.normal, { + html: edit$1('^ *(?:comment *(?:\\n|\\s*$)' + '|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)' // closed tag + + '|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))').replace('comment', block._comment).replace(/tag/g, '(?!(?:' + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub' + '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)' + '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b').getRegex(), + def: /^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/, + heading: /^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/, + fences: noopTest$1, + // fences not supported + paragraph: edit$1(block.normal._paragraph).replace('hr', block.hr).replace('heading', ' *#{1,6} *[^\n]').replace('lheading', block.lheading).replace('blockquote', ' {0,3}>').replace('|fences', '').replace('|list', '').replace('|html', '').getRegex() + }); + /** + * Inline-Level Grammar + */ - return Tokenizer; - }(); + var inline = { + escape: /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/, + autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/, + url: noopTest$1, + tag: '^comment' + '|^' // self-closing tag + + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag + + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. + + '|^' // declaration, e.g. + + '|^', + // CDATA section + link: /^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/, + reflink: /^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/, + nolink: /^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/, + strong: /^__([^\s_])__(?!_)|^\*\*([^\s*])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/, + em: /^_([^\s_])_(?!_)|^_([^\s_<][\s\S]*?[^\s_])_(?!_|[^\spunctuation])|^_([^\s_<][\s\S]*?[^\s])_(?!_|[^\spunctuation])|^\*([^\s*<\[])\*(?!\*)|^\*([^\s<"][\s\S]*?[^\s\[\*])\*(?![\]`punctuation])|^\*([^\s*"<\[][\s\S]*[^\s])\*(?!\*)/, + code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/, + br: /^( {2,}|\\)\n(?!\s*$)/, + del: noopTest$1, + text: /^(`+|[^`])(?:[\s\S]*?(?:(?=[\\?@\\[^_{|}~'; + inline.em = edit$1(inline.em).replace(/punctuation/g, inline._punctuation).getRegex(); + inline._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g; + inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/; + 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])?)+(?![-_])/; + inline.autolink = edit$1(inline.autolink).replace('scheme', inline._scheme).replace('email', inline._email).getRegex(); + inline._attribute = /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/; + inline.tag = edit$1(inline.tag).replace('comment', block._comment).replace('attribute', inline._attribute).getRegex(); + inline._label = /(?:\[[^\[\]]*\]|\\.|`[^`]*`|[^\[\]\\`])*?/; + inline._href = /<(?:\\[<>]?|[^\s<>\\])*>|[^\s\x00-\x1f]*/; + inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/; + inline.link = edit$1(inline.link).replace('label', inline._label).replace('href', inline._href).replace('title', inline._title).getRegex(); + inline.reflink = edit$1(inline.reflink).replace('label', inline._label).getRegex(); + /** + * Normal Inline Grammar + */ + + inline.normal = merge$1({}, inline); + /** + * Pedantic Inline Grammar + */ + + inline.pedantic = merge$1({}, inline.normal, { + strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/, + em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/, + link: edit$1(/^!?\[(label)\]\((.*?)\)/).replace('label', inline._label).getRegex(), + reflink: edit$1(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace('label', inline._label).getRegex() + }); + /** + * GFM Inline Grammar + */ + + inline.gfm = merge$1({}, inline.normal, { + escape: edit$1(inline.escape).replace('])', '~|])').getRegex(), + _extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/, + url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/, + _backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/, + del: /^~+(?=\S)([\s\S]*?\S)~+/, + text: /^(`+|[^`])(?:[\s\S]*?(?:(?=[\\ 0.5) { + ch = 'x' + ch.toString(16); + } + + out += '&#' + ch + ';'; + } + + return out; + } /** * Block Lexer */ + var Lexer_1 = /*#__PURE__*/function () { function Lexer(options) { this.tokens = []; @@ -1209,10 +1174,28 @@ this.options.tokenizer = this.options.tokenizer || new Tokenizer_1(); this.tokenizer = this.options.tokenizer; this.tokenizer.options = this.options; - this.tokenizer.initialize(); + var rules = { + block: block$1.normal, + inline: inline$1.normal + }; + + if (this.options.pedantic) { + rules.block = block$1.pedantic; + rules.inline = inline$1.pedantic; + } else if (this.options.gfm) { + rules.block = block$1.gfm; + + if (this.options.breaks) { + rules.inline = inline$1.breaks; + } else { + rules.inline = inline$1.gfm; + } + } + + this.tokenizer.rules = rules; } /** - * Expose Block Rules + * Expose Rules */ @@ -1553,21 +1536,21 @@ } // autolink - if (token = this.tokenizer.autolink(src)) { + if (token = this.tokenizer.autolink(src, mangle)) { src = src.substring(token.raw.length); tokens.push(token); continue; } // url (gfm) - if (!inLink && (token = this.tokenizer.url(src))) { + if (!inLink && (token = this.tokenizer.url(src, mangle))) { src = src.substring(token.raw.length); tokens.push(token); continue; } // text - if (token = this.tokenizer.inlineText(src, inRawBlock)) { + if (token = this.tokenizer.inlineText(src, inRawBlock, smartypants)) { src = src.substring(token.raw.length); tokens.push(token); continue; @@ -1591,7 +1574,10 @@ _createClass(Lexer, null, [{ key: "rules", get: function get() { - return Tokenizer_1.rules; + return { + block: block$1, + inline: inline$1 + }; } }]); diff --git a/marked.min.js b/marked.min.js index 1f7a69f009..8228059297 100644 --- a/marked.min.js +++ b/marked.min.js @@ -3,4 +3,4 @@ * Copyright (c) 2011-2020, Christopher Jeffrey. (MIT Licensed) * https://github.com/markedjs/marked */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).marked=t()}(this,function(){"use strict";function r(e,t){for(var n=0;n"']/),l=/[&<>"']/g,a=/[<>"']|&(?!#?\w+;)/,o=/[<>"']|&(?!#?\w+;)/g,c={"&":"&","<":"<",">":">",'"':""","'":"'"};var h=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;function u(e){return e.replace(h,function(e,t){return"colon"===(t=t.toLowerCase())?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""})}var p=/(^|[^\[])\^/g;var g=/[^\w:]/g,f=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;var d={},k=/^[^:]+:\/*[^/]*$/,b=/^([^:]+:)[\s\S]*$/,m=/^([^:]+:\/*[^/]*)[\s\S]*$/;function x(e,t){d[" "+e]||(k.test(e)?d[" "+e]=e+"/":d[" "+e]=w(e,"/",!0));var n=-1===(e=d[" "+e]).indexOf(":");return"//"===t.substring(0,2)?n?t:e.replace(b,"$1")+t:"/"===t.charAt(0)?n?t:e.replace(m,"$1")+t:e+t}function w(e,t,n){var r=e.length;if(0===r)return"";for(var i=0;it)n.splice(t);else for(;n.length ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:"^ {0,3}(?:<(script|pre|style)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?\\?>\\n*|\\n*|\\n*|)[\\s\\S]*?(?:\\n{2,}|$)|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$))",def:/^ {0,3}\[(label)\]: *\n? *]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,nptable:Z,table:Z,lheading:/^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,_paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html)[^\n]+)*)/,text:/^[^\n]+/,_label:/(?!\s*\])(?:\\[\[\]]|[^\[\]])+/,_title:/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/};I.def=q(I.def).replace("label",I._label).replace("title",I._title).getRegex(),I.bullet=/(?:[*+-]|\d{1,9}\.)/,I.item=/^( *)(bull) ?[^\n]*(?:\n(?!\1bull ?)[^\n]*)*/,I.item=q(I.item,"gm").replace(/bull/g,I.bullet).getRegex(),I.list=q(I.list).replace(/bull/g,I.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+I.def.source+")").getRegex(),I._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",I._comment=//,I.html=q(I.html,"i").replace("comment",I._comment).replace("tag",I._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),I.paragraph=q(I._paragraph).replace("hr",I.hr).replace("heading"," {0,3}#{1,6} ").replace("|lheading","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",I._tag).getRegex(),I.blockquote=q(I.blockquote).replace("paragraph",I.paragraph).getRegex(),I.normal=T({},I),I.gfm=T({},I.normal,{nptable:"^ *([^|\\n ].*\\|.*)\\n *([-:]+ *\\|[-| :]*)(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)",table:"^ *\\|(.+)\\n *\\|?( *[-:]+[-| :]*)(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)"}),I.gfm.nptable=q(I.gfm.nptable).replace("hr",I.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",I._tag).getRegex(),I.gfm.table=q(I.gfm.table).replace("hr",I.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",I._tag).getRegex(),I.pedantic=T({},I.normal,{html:q("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",I._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,fences:Z,paragraph:q(I.normal._paragraph).replace("hr",I.hr).replace("heading"," *#{1,6} *[^\n]").replace("lheading",I.lheading).replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").getRegex()});var C={escape:/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:Z,tag:"^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^",link:/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,strong:/^__([^\s_])__(?!_)|^\*\*([^\s*])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/,em:/^_([^\s_])_(?!_)|^_([^\s_<][\s\S]*?[^\s_])_(?!_|[^\spunctuation])|^_([^\s_<][\s\S]*?[^\s])_(?!_|[^\spunctuation])|^\*([^\s*<\[])\*(?!\*)|^\*([^\s<"][\s\S]*?[^\s\[\*])\*(?![\]`punctuation])|^\*([^\s*"<\[][\s\S]*[^\s])\*(?!\*)/,code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:Z,text:/^(`+|[^`])(?:[\s\S]*?(?:(?=[\\?@\\[^_{|}~"};C.em=q(C.em).replace(/punctuation/g,C._punctuation).getRegex(),C._escapes=/\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g,C._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,C._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])?)+(?![-_])/,C.autolink=q(C.autolink).replace("scheme",C._scheme).replace("email",C._email).getRegex(),C._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,C.tag=q(C.tag).replace("comment",I._comment).replace("attribute",C._attribute).getRegex(),C._label=/(?:\[[^\[\]]*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,C._href=/<(?:\\[<>]?|[^\s<>\\])*>|[^\s\x00-\x1f]*/,C._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,C.link=q(C.link).replace("label",C._label).replace("href",C._href).replace("title",C._title).getRegex(),C.reflink=q(C.reflink).replace("label",C._label).getRegex(),C.normal=T({},C),C.pedantic=T({},C.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,link:q(/^!?\[(label)\]\((.*?)\)/).replace("label",C._label).getRegex(),reflink:q(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",C._label).getRegex()}),C.gfm=T({},C.normal,{escape:q(C.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^~+(?=\S)([\s\S]*?\S)~+/,text:/^(`+|[^`])(?:[\s\S]*?(?:(?=[\\ ?/gm,"");return{type:"blockquote",raw:t[0],text:n}}},t.list=function(e){var t=this.rules.block.list.exec(e);if(t){for(var n,r,i,s,l,a,o,c=t[0],h=t[2],u=1/i.test(r[0])&&(t=!1),!n&&/^<(pre|code|kbd|script)(\s|>)/i.test(r[0])?n=!0:n&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(r[0])&&(n=!1),{type:this.options.sanitize?"text":"html",raw:r[0],inLink:t,inRawBlock:n,text:this.options.sanitize?this.options.sanitizer?this.options.sanitizer(r[0]):L(r[0]):r[0]}},t.link=function(e){var t=this.rules.inline.link.exec(e);if(t){var n=P(t[2],"()");if(-1$/,"$1"))?i.replace(this.rules.inline._escapes,"$1"):i,title:s?s.replace(this.rules.inline._escapes,"$1"):s},t[0])}},t.reflink=function(e,t){var n;if((n=this.rules.inline.reflink.exec(e))||(n=this.rules.inline.nolink.exec(e))){var r=(n[2]||n[1]).replace(/\s+/g," ");if((r=t[r.toLowerCase()])&&r.href)return F(n,r,n[0]);var i=n[0].charAt(0);return{type:"text",raw:i,text:i}}},t.strong=function(e){var t=this.rules.inline.strong.exec(e);if(t)return{type:"strong",raw:t[0],text:t[4]||t[3]||t[2]||t[1]}},t.em=function(e){var t=this.rules.inline.em.exec(e);if(t)return{type:"em",raw:t[0],text:t[6]||t[5]||t[4]||t[3]||t[2]||t[1]}},t.codespan=function(e){var t=this.rules.inline.code.exec(e);if(t)return{type:"codespan",raw:t[0],text:L(t[2].trim(),!0)}},t.br=function(e){var t=this.rules.inline.br.exec(e);if(t)return{type:"br",raw:t[0]}},t.del=function(e){var t=this.rules.inline.del.exec(e);if(t)return{type:"del",raw:t[0],text:t[1]}},t.autolink=function(e){var t,n,r=this.rules.inline.autolink.exec(e);if(r)return n="@"===r[2]?"mailto:"+(t=L(this.options.mangle?this.mangle(r[1]):r[1])):t=L(r[1]),{type:"link",raw:r[0],text:t,href:n,tokens:[{type:"text",raw:t,text:t}]}},t.url=function(e){var t;if(t=this.rules.inline.url.exec(e)){var n,r;if("@"===t[2])r="mailto:"+(n=L(this.options.mangle?this.mangle(t[0]):t[0]));else{for(var i;i=t[0],t[0]=this.rules.inline._backpedal.exec(t[0])[0],i!==t[0];);n=L(t[0]),r="www."===t[1]?"http://"+n:n}return{type:"link",raw:t[0],text:n,href:r,tokens:[{type:"text",raw:n,text:n}]}}},t.inlineText=function(e,t){var n,r=this.rules.inline.text.exec(e);if(r)return n=t?this.options.sanitize?this.options.sanitizer?this.options.sanitizer(r[0]):L(r[0]):r[0]:L(this.options.smartypants?this.smartypants(r[0]):r[0]),{type:"text",raw:r[0],text:n}},t.smartypants=function(e){return e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")},t.mangle=function(e){var t,n,r="",i=e.length;for(t=0;t'+(n?e:H(e,!0))+"\n":"
    "+(n?e:H(e,!0))+"
    "},t.blockquote=function(e){return"
    \n"+e+"
    \n"},t.html=function(e){return e},t.heading=function(e,t,n,r){return this.options.headerIds?"'+e+"\n":""+e+"\n"},t.hr=function(){return this.options.xhtml?"
    \n":"
    \n"},t.list=function(e,t,n){var r=t?"ol":"ul";return"<"+r+(t&&1!==n?' start="'+n+'"':"")+">\n"+e+"\n"},t.listitem=function(e){return"
  • "+e+"
  • \n"},t.checkbox=function(e){return" "},t.paragraph=function(e){return"

    "+e+"

    \n"},t.table=function(e,t){return"\n\n"+e+"\n"+(t=t&&""+t+"")+"
    \n"},t.tablerow=function(e){return"\n"+e+"\n"},t.tablecell=function(e,t){var n=t.header?"th":"td";return(t.align?"<"+n+' align="'+t.align+'">':"<"+n+">")+e+"\n"},t.strong=function(e){return""+e+""},t.em=function(e){return""+e+""},t.codespan=function(e){return""+e+""},t.br=function(){return this.options.xhtml?"
    ":"
    "},t.del=function(e){return""+e+""},t.link=function(e,t,n){if(null===(e=V(this.options.sanitize,this.options.baseUrl,e)))return n;var r='
    "},t.image=function(e,t,n){if(null===(e=V(this.options.sanitize,this.options.baseUrl,e)))return n;var r=''+n+'":">"},t.text=function(e){return e},e}(),K=function(){function e(){}var t=e.prototype;return t.strong=function(e){return e},t.em=function(e){return e},t.codespan=function(e){return e},t.del=function(e){return e},t.html=function(e){return e},t.text=function(e){return e},t.link=function(e,t,n){return""+n},t.image=function(e,t,n){return""+n},t.br=function(){return""},e}(),Q=function(){function e(){this.seen={}}return e.prototype.slug=function(e){var t=e.toLowerCase().trim().replace(/<[!\/a-z].*?>/gi,"").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g,"").replace(/\s/g,"-");if(this.seen.hasOwnProperty(t))for(var n=t;this.seen[n]++,t=n+"-"+this.seen[n],this.seen.hasOwnProperty(t););return this.seen[t]=0,t},e}(),W=t.defaults,Y=_,ee=function(){function n(e){this.options=e||W,this.options.renderer=this.options.renderer||new J,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new K,this.slugger=new Q}n.parse=function(e,t){return new n(t).parse(e)};var e=n.prototype;return e.parse=function(e,t){void 0===t&&(t=!0);var n,r,i,s,l,a,o,c,h,u,p,g,f,d,k,b,m,x,w="",v=e.length;for(n=0;nAn error occurred:

    "+re(e.message+"",!0)+"
    ";throw e}}return ae.options=ae.setOptions=function(e){return te(ae.defaults,e),se(ae.defaults),ae},ae.getDefaults=ie,ae.defaults=le,ae.Parser=ee,ae.parser=ee.parse,ae.Renderer=J,ae.TextRenderer=K,ae.Lexer=G,ae.lexer=G.lex,ae.Tokenizer=N,ae.Slugger=Q,ae.parse=ae}); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).marked=t()}(this,function(){"use strict";function s(e,t){for(var n=0;n"']/),i=/[&<>"']/g,l=/[<>"']|&(?!#?\w+;)/,a=/[<>"']|&(?!#?\w+;)/g,o={"&":"&","<":"<",">":">",'"':""","'":"'"};var c=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;function h(e){return e.replace(c,function(e,t){return"colon"===(t=t.toLowerCase())?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""})}var u=/(^|[^\[])\^/g;var p=/[^\w:]/g,g=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;var f={},d=/^[^:]+:\/*[^/]*$/,k=/^([^:]+:)[\s\S]*$/,b=/^([^:]+:\/*[^/]*)[\s\S]*$/;function m(e,t){f[" "+e]||(d.test(e)?f[" "+e]=e+"/":f[" "+e]=x(e,"/",!0));var n=-1===(e=f[" "+e]).indexOf(":");return"//"===t.substring(0,2)?n?t:e.replace(k,"$1")+t:"/"===t.charAt(0)?n?t:e.replace(b,"$1")+t:e+t}function x(e,t,n){var r=e.length;if(0===r)return"";for(var i=0;it)n.splice(t);else for(;n.length ?/gm,"");return{type:"blockquote",raw:t[0],text:n}}},t.list=function(e){var t=this.rules.block.list.exec(e);if(t){for(var n,r,i,s,l,a,o,c=t[0],h=t[2],u=1/i.test(r[0])&&(t=!1),!n&&/^<(pre|code|kbd|script)(\s|>)/i.test(r[0])?n=!0:n&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(r[0])&&(n=!1),{type:this.options.sanitize?"text":"html",raw:r[0],inLink:t,inRawBlock:n,text:this.options.sanitize?this.options.sanitizer?this.options.sanitizer(r[0]):C(r[0]):r[0]}},t.link=function(e){var t=this.rules.inline.link.exec(e);if(t){var n=O(t[2],"()");if(-1$/,"$1"))?i.replace(this.rules.inline._escapes,"$1"):i,title:s?s.replace(this.rules.inline._escapes,"$1"):s},t[0])}},t.reflink=function(e,t){var n;if((n=this.rules.inline.reflink.exec(e))||(n=this.rules.inline.nolink.exec(e))){var r=(n[2]||n[1]).replace(/\s+/g," ");if((r=t[r.toLowerCase()])&&r.href)return D(n,r,n[0]);var i=n[0].charAt(0);return{type:"text",raw:i,text:i}}},t.strong=function(e){var t=this.rules.inline.strong.exec(e);if(t)return{type:"strong",raw:t[0],text:t[4]||t[3]||t[2]||t[1]}},t.em=function(e){var t=this.rules.inline.em.exec(e);if(t)return{type:"em",raw:t[0],text:t[6]||t[5]||t[4]||t[3]||t[2]||t[1]}},t.codespan=function(e){var t=this.rules.inline.code.exec(e);if(t)return{type:"codespan",raw:t[0],text:C(t[2].trim(),!0)}},t.br=function(e){var t=this.rules.inline.br.exec(e);if(t)return{type:"br",raw:t[0]}},t.del=function(e){var t=this.rules.inline.del.exec(e);if(t)return{type:"del",raw:t[0],text:t[1]}},t.autolink=function(e,t){var n,r,i=this.rules.inline.autolink.exec(e);if(i)return r="@"===i[2]?"mailto:"+(n=C(this.options.mangle?t(i[1]):i[1])):n=C(i[1]),{type:"link",raw:i[0],text:n,href:r,tokens:[{type:"text",raw:n,text:n}]}},t.url=function(e,t){var n;if(n=this.rules.inline.url.exec(e)){var r,i;if("@"===n[2])i="mailto:"+(r=C(this.options.mangle?t(n[0]):n[0]));else{for(var s;s=n[0],n[0]=this.rules.inline._backpedal.exec(n[0])[0],s!==n[0];);r=C(n[0]),i="www."===n[1]?"http://"+r:r}return{type:"link",raw:n[0],text:r,href:i,tokens:[{type:"text",raw:r,text:r}]}}},t.inlineText=function(e,t,n){var r,i=this.rules.inline.text.exec(e);if(i)return r=t?this.options.sanitize?this.options.sanitizer?this.options.sanitizer(i[0]):C(i[0]):i[0]:C(this.options.smartypants?n(i[0]):i[0]),{type:"text",raw:i[0],text:r}},e}(),j=z,L=_,P=$,U={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:/^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,hr:/^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,heading:/^ {0,3}(#{1,6}) +([^\n]*?)(?: +#+)? *(?:\n+|$)/,blockquote:/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:"^ {0,3}(?:<(script|pre|style)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?\\?>\\n*|\\n*|\\n*|)[\\s\\S]*?(?:\\n{2,}|$)|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$))",def:/^ {0,3}\[(label)\]: *\n? *]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,nptable:j,table:j,lheading:/^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,_paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html)[^\n]+)*)/,text:/^[^\n]+/,_label:/(?!\s*\])(?:\\[\[\]]|[^\[\]])+/,_title:/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/};U.def=L(U.def).replace("label",U._label).replace("title",U._title).getRegex(),U.bullet=/(?:[*+-]|\d{1,9}\.)/,U.item=/^( *)(bull) ?[^\n]*(?:\n(?!\1bull ?)[^\n]*)*/,U.item=L(U.item,"gm").replace(/bull/g,U.bullet).getRegex(),U.list=L(U.list).replace(/bull/g,U.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+U.def.source+")").getRegex(),U._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",U._comment=//,U.html=L(U.html,"i").replace("comment",U._comment).replace("tag",U._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),U.paragraph=L(U._paragraph).replace("hr",U.hr).replace("heading"," {0,3}#{1,6} ").replace("|lheading","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",U._tag).getRegex(),U.blockquote=L(U.blockquote).replace("paragraph",U.paragraph).getRegex(),U.normal=P({},U),U.gfm=P({},U.normal,{nptable:"^ *([^|\\n ].*\\|.*)\\n *([-:]+ *\\|[-| :]*)(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)",table:"^ *\\|(.+)\\n *\\|?( *[-:]+[-| :]*)(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)"}),U.gfm.nptable=L(U.gfm.nptable).replace("hr",U.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",U._tag).getRegex(),U.gfm.table=L(U.gfm.table).replace("hr",U.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",U._tag).getRegex(),U.pedantic=P({},U.normal,{html:L("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",U._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,fences:j,paragraph:L(U.normal._paragraph).replace("hr",U.hr).replace("heading"," *#{1,6} *[^\n]").replace("lheading",U.lheading).replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").getRegex()});var B={escape:/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:j,tag:"^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^",link:/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,strong:/^__([^\s_])__(?!_)|^\*\*([^\s*])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/,em:/^_([^\s_])_(?!_)|^_([^\s_<][\s\S]*?[^\s_])_(?!_|[^\spunctuation])|^_([^\s_<][\s\S]*?[^\s])_(?!_|[^\spunctuation])|^\*([^\s*<\[])\*(?!\*)|^\*([^\s<"][\s\S]*?[^\s\[\*])\*(?![\]`punctuation])|^\*([^\s*"<\[][\s\S]*[^\s])\*(?!\*)/,code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:j,text:/^(`+|[^`])(?:[\s\S]*?(?:(?=[\\?@\\[^_{|}~"};B.em=L(B.em).replace(/punctuation/g,B._punctuation).getRegex(),B._escapes=/\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g,B._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,B._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])?)+(?![-_])/,B.autolink=L(B.autolink).replace("scheme",B._scheme).replace("email",B._email).getRegex(),B._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,B.tag=L(B.tag).replace("comment",U._comment).replace("attribute",B._attribute).getRegex(),B._label=/(?:\[[^\[\]]*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,B._href=/<(?:\\[<>]?|[^\s<>\\])*>|[^\s\x00-\x1f]*/,B._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,B.link=L(B.link).replace("label",B._label).replace("href",B._href).replace("title",B._title).getRegex(),B.reflink=L(B.reflink).replace("label",B._label).getRegex(),B.normal=P({},B),B.pedantic=P({},B.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,link:L(/^!?\[(label)\]\((.*?)\)/).replace("label",B._label).getRegex(),reflink:L(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",B._label).getRegex()}),B.gfm=P({},B.normal,{escape:L(B.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^~+(?=\S)([\s\S]*?\S)~+/,text:/^(`+|[^`])(?:[\s\S]*?(?:(?=[\\'+(n?e:Q(e,!0))+"\n":"
    "+(n?e:Q(e,!0))+"
    "},t.blockquote=function(e){return"
    \n"+e+"
    \n"},t.html=function(e){return e},t.heading=function(e,t,n,r){return this.options.headerIds?"'+e+"\n":""+e+"\n"},t.hr=function(){return this.options.xhtml?"
    \n":"
    \n"},t.list=function(e,t,n){var r=t?"ol":"ul";return"<"+r+(t&&1!==n?' start="'+n+'"':"")+">\n"+e+"\n"},t.listitem=function(e){return"
  • "+e+"
  • \n"},t.checkbox=function(e){return" "},t.paragraph=function(e){return"

    "+e+"

    \n"},t.table=function(e,t){return"\n\n"+e+"\n"+(t=t&&""+t+"")+"
    \n"},t.tablerow=function(e){return"\n"+e+"\n"},t.tablecell=function(e,t){var n=t.header?"th":"td";return(t.align?"<"+n+' align="'+t.align+'">':"<"+n+">")+e+"\n"},t.strong=function(e){return""+e+""},t.em=function(e){return""+e+""},t.codespan=function(e){return""+e+""},t.br=function(){return this.options.xhtml?"
    ":"
    "},t.del=function(e){return""+e+""},t.link=function(e,t,n){if(null===(e=K(this.options.sanitize,this.options.baseUrl,e)))return n;var r='
    "},t.image=function(e,t,n){if(null===(e=K(this.options.sanitize,this.options.baseUrl,e)))return n;var r=''+n+'":">"},t.text=function(e){return e},e}(),Y=function(){function e(){}var t=e.prototype;return t.strong=function(e){return e},t.em=function(e){return e},t.codespan=function(e){return e},t.del=function(e){return e},t.html=function(e){return e},t.text=function(e){return e},t.link=function(e,t,n){return""+n},t.image=function(e,t,n){return""+n},t.br=function(){return""},e}(),ee=function(){function e(){this.seen={}}return e.prototype.slug=function(e){var t=e.toLowerCase().trim().replace(/<[!\/a-z].*?>/gi,"").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g,"").replace(/\s/g,"-");if(this.seen.hasOwnProperty(t))for(var n=t;this.seen[n]++,t=n+"-"+this.seen[n],this.seen.hasOwnProperty(t););return this.seen[t]=0,t},e}(),te=t.defaults,ne=v,re=function(){function n(e){this.options=e||te,this.options.renderer=this.options.renderer||new W,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new Y,this.slugger=new ee}n.parse=function(e,t){return new n(t).parse(e)};var e=n.prototype;return e.parse=function(e,t){void 0===t&&(t=!0);var n,r,i,s,l,a,o,c,h,u,p,g,f,d,k,b,m,x,w="",v=e.length;for(n=0;nAn error occurred:

    "+le(e.message+"",!0)+"
    ";throw e}}return he.options=he.setOptions=function(e){return ie(he.defaults,e),oe(he.defaults),he},he.getDefaults=ae,he.defaults=ce,he.Parser=re,he.parser=re.parse,he.Renderer=W,he.TextRenderer=Y,he.Lexer=H,he.lexer=H.lex,he.Tokenizer=E,he.Slugger=ee,he.parse=he}); \ No newline at end of file From 0f0586094be32b196370bd5fe72f160acd2d369b Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Tue, 14 Apr 2020 16:43:02 -0500 Subject: [PATCH 10/13] fix example --- docs/USING_PRO.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/USING_PRO.md b/docs/USING_PRO.md index 50d98d9b3d..638618e60c 100644 --- a/docs/USING_PRO.md +++ b/docs/USING_PRO.md @@ -103,7 +103,7 @@ const marked = require('marked'); const tokenizer = new marked.Tokenizer(); const originalCodespan = tokenizer.codespan; // Override function -tokenizer.codespan = function(lexer, src) { +tokenizer.codespan = function(src) { const match = src.match(/\$+([^\$\n]+?)\$+/); if (match) { return { From dd8e5490876486db7c8656775006598771c70c5d Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Tue, 14 Apr 2020 16:53:06 -0500 Subject: [PATCH 11/13] add mangle smartypants examples --- docs/USING_PRO.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/USING_PRO.md b/docs/USING_PRO.md index 638618e60c..212aebef19 100644 --- a/docs/USING_PRO.md +++ b/docs/USING_PRO.md @@ -157,6 +157,22 @@ console.log(marked('$ latex code $', { tokenizer })); - url(*string* src, *function* mangle) - inlineText(*string* src, *bool* inRawBlock, *function* smartypants) +`mangle` is a method that changes text to HTML character references: + +```js +mangle('test@example.com') +// "test@example.com" +``` + +`smartypants` is a method that translates plain ASCII punctuation characters into “smart” typographic punctuation HTML entities: + +https://daringfireball.net/projects/smartypants/ + +```js +smartypants('"this ... string"') +// "“this … string”" +``` +

    The lexer

    The lexer takes a markdown string and calls the tokenizer functions. From 4aecab365ecbe7427ae484aef12453615924bd6c Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Tue, 14 Apr 2020 19:52:44 -0500 Subject: [PATCH 12/13] Update docs/USING_PRO.md Co-Authored-By: Steven --- docs/USING_PRO.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/USING_PRO.md b/docs/USING_PRO.md index 212aebef19..3b2109c55e 100644 --- a/docs/USING_PRO.md +++ b/docs/USING_PRO.md @@ -93,7 +93,7 @@ slugger.slug('foo-1') // foo-1-2 The tokenizer defines how to turn markdown text into tokens. -**Example:** Overriding default `codespan` tokenizer to include latex. +**Example:** Overriding default `codespan` tokenizer to include LaTeX. ```js // Create reference instance From dfbb0161f87a122e8433e4b86db974ed0abbd83e Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Wed, 15 Apr 2020 00:02:18 -0500 Subject: [PATCH 13/13] fix docs --- docs/USING_PRO.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/USING_PRO.md b/docs/USING_PRO.md index 212aebef19..ff8ca0958d 100644 --- a/docs/USING_PRO.md +++ b/docs/USING_PRO.md @@ -196,8 +196,10 @@ console.log(marked.parser(tokens, options)); const lexer = new marked.Lexer(options); const tokens = lexer.lex(markdown); console.log(tokens); -console.log(lexer.rules.block); // block level rules -console.log(lexer.rules.inline); // inline level rules +console.log(lexer.tokenizer.rules.block); // block level rules used +console.log(lexer.tokenizer.rules.inline); // inline level rules used +console.log(marked.Lexer.rules.block); // all block level rules +console.log(marked.Lexer.rules.inline); // all inline level rules ``` ``` bash