markdown-to-jsx
Version:
Convert markdown to JSX with ease for React and React-like projects. Super lightweight and highly configurable.
1,481 lines (1,477 loc) • 60.4 kB
JavaScript
import * as React from 'react';
function _extends() {
return _extends = Object.assign ? Object.assign.bind() : function (n) {
for (var e = 1; e < arguments.length; e++) {
var t = arguments[e];
for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
}
return n;
}, _extends.apply(null, arguments);
}
function _objectWithoutPropertiesLoose(r, e) {
if (null == r) return {};
var t = {};
for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
if (-1 !== e.indexOf(n)) continue;
t[n] = r[n];
}
return t;
}
/**
* Analogous to `node.type`. Please note that the values here may change at any time,
* so do not hard code against the value directly.
*/
var RuleType$1 = {
blockQuote: '0',
breakLine: '1',
breakThematic: '2',
codeBlock: '3',
codeFenced: '4',
codeInline: '5',
footnote: '6',
footnoteReference: '7',
gfmTask: '8',
heading: '9',
headingSetext: '10',
htmlBlock: '11',
htmlComment: '12',
htmlSelfClosing: '13',
image: '14',
link: '15',
linkAngleBraceStyleDetector: '16',
linkBareUrlDetector: '17',
linkMailtoDetector: '18',
newlineCoalescer: '19',
orderedList: '20',
paragraph: '21',
ref: '22',
refImage: '23',
refLink: '24',
table: '25',
tableSeparator: '26',
text: '27',
textEscaped: '28',
textFormatted: '34',
unorderedList: '30'
};
var T = ['strong', 'em', 'del', 'mark'];
var DELS = [['**', T[0]], ['__', T[0]], ['~~', T[2]], ['==', T[3]], ['*', T[1]], ['_', T[1]]];
function skipLinkOrImage(source, pos) {
var bracketDepth = 1;
var i = pos + 1;
while (i < source.length && bracketDepth > 0) {
if (source[i] === '\\') {
i += 2;
continue;
}
if (source[i] === '[') bracketDepth++;
if (source[i] === ']') bracketDepth--;
i++;
}
if (bracketDepth === 0 && i < source.length && (source[i] === '(' || source[i] === '[')) {
var closingChar = source[i] === '(' ? ')' : ']';
var parenDepth = 1;
i++;
while (i < source.length && parenDepth > 0) {
if (source[i] === '\\') {
i += 2;
continue;
}
if (source[i] === '(' && closingChar === ')') parenDepth++;
if (source[i] === closingChar) parenDepth--;
i++;
}
if (parenDepth === 0) return i;
}
return -1;
}
function matchInlineFormatting(source, state) {
if (!state || !state.inline && !state.simple) return null;
var c = source[0];
if (c !== '*' && c !== '_' && c !== '~' && c !== '=') return null;
var delimiter = '';
var startLength = 0;
var tag = '';
for (var i = 0; i < 6; i++) {
var d = DELS[i][0];
if (source.startsWith(d) && source.length >= d.length * 2) {
delimiter = d;
startLength = d.length;
tag = DELS[i][1];
break;
}
}
if (!delimiter) return null;
var pos = startLength;
var inCode = false;
var inHTMLTag = false;
var inHTMLQuote = '';
var htmlDepth = 0;
var content = '';
var lastWasEscape = false;
var lastChar = '';
while (pos < source.length) {
var _char = source[pos];
if (lastWasEscape) {
content += _char;
lastWasEscape = false;
lastChar = _char;
pos++;
continue;
}
if (_char === '\\') {
content += _char;
lastWasEscape = true;
lastChar = _char;
pos++;
continue;
}
if (_char === '`' && htmlDepth === 0) {
inCode = !inCode;
content += _char;
lastChar = _char;
pos++;
continue;
}
if (_char === '[' && !inCode && htmlDepth === 0) {
var linkEnd = skipLinkOrImage(source, pos);
if (linkEnd !== -1) {
content += source.slice(pos, linkEnd);
pos = linkEnd;
lastChar = source[linkEnd - 1];
continue;
}
}
if (inHTMLTag) {
content += _char;
if (inHTMLQuote) {
if (_char === inHTMLQuote) inHTMLQuote = '';
} else if (_char === '"' || _char === "'") {
inHTMLQuote = _char;
} else if (_char === '>') {
inHTMLTag = false;
}
lastChar = _char;
pos++;
continue;
}
if (_char === '<' && !inCode) {
var nextChar = source[pos + 1];
var tagEnd = source.indexOf('>', pos);
if (tagEnd !== -1) {
var tagContent = source.slice(pos, tagEnd + 1);
var isSelfClosing = tagContent.endsWith('/>');
if (nextChar === '/') {
htmlDepth = Math.max(0, htmlDepth - 1);
} else if (!isSelfClosing) {
htmlDepth++;
}
}
inHTMLTag = true;
content += _char;
lastChar = _char;
pos++;
continue;
}
if (_char === '\n' && lastChar === '\n' && !inCode && htmlDepth === 0) {
return null;
}
if (!inCode && htmlDepth === 0) {
var delimiterRunLength = 0;
while (pos + delimiterRunLength < source.length && source[pos + delimiterRunLength] === delimiter[0]) {
delimiterRunLength++;
}
if (delimiterRunLength >= startLength) {
if (startLength !== 1 || delimiter !== '*' && delimiter !== '_' || source[pos - 1] !== delimiter && source[pos + 1] !== delimiter) {
var result = [source.slice(0, pos + delimiterRunLength), tag, content + source.slice(pos + startLength, pos + delimiterRunLength)];
result.index = 0;
result.input = source;
return result;
}
}
}
content += _char;
lastChar = _char;
pos++;
}
return null;
}
var _excluded = ["children", "options"];
var RuleType = RuleType$1;
var Priority = {
/**
* anything that must scan the tree before everything else
*/
MAX: 0,
/**
* scans for block-level constructs
*/
HIGH: 1,
/**
* inline w/ more priority than other inline
*/
MED: 2,
/**
* inline elements
*/
LOW: 3,
/**
* bare text and stuff that is considered leftovers
*/
MIN: 4
};
/** TODO: Drop for React 16? */
var ATTRIBUTE_TO_JSX_PROP_MAP = ['allowFullScreen', 'allowTransparency', 'autoComplete', 'autoFocus', 'autoPlay', 'cellPadding', 'cellSpacing', 'charSet', 'classId', 'colSpan', 'contentEditable', 'contextMenu', 'crossOrigin', 'encType', 'formAction', 'formEncType', 'formMethod', 'formNoValidate', 'formTarget', 'frameBorder', 'hrefLang', 'inputMode', 'keyParams', 'keyType', 'marginHeight', 'marginWidth', 'maxLength', 'mediaGroup', 'minLength', 'noValidate', 'radioGroup', 'readOnly', 'rowSpan', 'spellCheck', 'srcDoc', 'srcLang', 'srcSet', 'tabIndex', 'useMap'].reduce(function (obj, x) {
obj[x.toLowerCase()] = x;
return obj;
}, {
"class": 'className',
"for": 'htmlFor'
});
var namedCodesToUnicode = {
amp: "&",
apos: "'",
gt: ">",
lt: "<",
nbsp: "\xA0",
quot: "\u201C"
};
var DO_NOT_PROCESS_HTML_ELEMENTS = ['style', 'script', 'pre'];
var ATTRIBUTES_TO_SANITIZE = ['src', 'href', 'data', 'formAction', 'srcDoc', 'action'];
/**
* the attribute extractor regex looks for a valid attribute name,
* followed by an equal sign (whitespace around the equal sign is allowed), followed
* by one of the following:
*
* 1. a single quote-bounded string, e.g. 'foo'
* 2. a double quote-bounded string, e.g. "bar"
* 3. an interpolation, e.g. {something}
*
* JSX can be be interpolated into itself and is passed through the compiler using
* the same options and setup as the current run.
*
* <Something children={<SomeOtherThing />} />
* ==================
* ↳ children: [<SomeOtherThing />]
*
* Otherwise, interpolations are handled as strings or simple booleans
* unless HTML syntax is detected.
*
* <Something color={green} disabled={true} />
* ===== ====
* ↓ ↳ disabled: true
* ↳ color: "green"
*
* Numbers are not parsed at this time due to complexities around int, float,
* and the upcoming bigint functionality that would make handling it unwieldy.
* Parse the string in your component as desired.
*
* <Something someBigNumber={123456789123456789} />
* ==================
* ↳ someBigNumber: "123456789123456789"
*/
var ATTR_EXTRACTOR_R = /([-A-Z0-9_:]+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|(?:\{((?:\\.|{[^}]*?}|[^}])*)\})))?/gi;
/** TODO: Write explainers for each of these */
var BLOCK_END_R = /\n{2,}$/;
var BLOCKQUOTE_R = /^(\s*>[\s\S]*?)(?=\n\n|$)/;
var BLOCKQUOTE_TRIM_LEFT_MULTILINE_R = /^ *> ?/gm;
var BLOCKQUOTE_ALERT_R = /^(?:\[!([^\]]*)\]\n)?([\s\S]*)/;
var BREAK_LINE_R = /^ {2,}\n/;
var BREAK_THEMATIC_R = /^(?:([-*_])( *\1){2,}) *(?:\n *)+\n/;
var CODE_BLOCK_FENCED_R = /^(?: {1,3})?(`{3,}|~{3,}) *(\S+)? *([^\n]*?)?\n([\s\S]*?)(?:\1\n?|$)/;
var CODE_BLOCK_R = /^(?: {4}[^\n]+\n*)+(?:\n *)+\n?/;
var CODE_INLINE_R = /^(`+)((?:\\`|(?!\1)`|[^`])+)\1/;
var CONSECUTIVE_NEWLINE_R = /^(?:\n *)*\n/;
var CR_NEWLINE_R = /\r\n?/g;
/**
* Matches footnotes on the format:
*
* [^key]: value
*
* Matches multiline footnotes
*
* [^key]: row
* row
* row
*
* And empty lines in indented multiline footnotes
*
* [^key]: indented with
* row
*
* row
*
* Explanation:
*
* 1. Look for the starting tag, eg: [^key]
* ^\[\^([^\]]+)]
*
* 2. The first line starts with a colon, and continues for the rest of the line
* :(.*)
*
* 3. Parse as many additional lines as possible. Matches new non-empty lines that doesn't begin with a new footnote definition.
* (\n(?!\[\^).+)
*
* 4. ...or allows for repeated newlines if the next line begins with at least four whitespaces.
* (\n+ {4,}.*)
*/
var FOOTNOTE_R = /^\[\^([^\]]+)](:(.*)((\n+ {4,}.*)|(\n(?!\[\^).+))*)/;
var FOOTNOTE_REFERENCE_R = /^\[\^([^\]]+)]/;
var FORMFEED_R = /\f/g;
var FRONT_MATTER_R = /^---[ \t]*\n(.|\n)*\n---[ \t]*\n/;
var GFM_TASK_R = /^\[(x|\s)\]/;
var HEADING_R = /^(#{1,6}) *([^\n]+?)(?: +#*)?(?:\n *)*(?:\n|$)/;
var HEADING_ATX_COMPLIANT_R = /^ *(#{1,6}) +([^\n]+?)(?: +#*)?(?:\n *)*(?:\n|$)/;
var HEADING_SETEXT_R = /^([^\n]+)\n *(=|-)\2{2,} *\n/;
var HTML_BLOCK_ELEMENT_START_R = /^<([a-z][^ >/]*) ?((?:[^>]*[^/])?)>/i;
function matchHTMLBlock(source) {
var m = HTML_BLOCK_ELEMENT_START_R.exec(source);
if (!m) return null;
var tagName = m[1];
var tagLower = tagName.toLowerCase();
var openTagLen = tagLower.length + 1;
var pos = m[0].length;
if (source[pos] === '\n') pos++;
var contentStart = pos;
var contentEnd = pos;
var depth = 1;
var sourceLen = source.length;
while (depth > 0) {
var idx = source.indexOf('<', pos);
if (idx === -1) return null;
var openIdx = -1;
var closeIdx = -1;
if (source[idx + 1] === '/') {
closeIdx = idx;
} else if (source[idx + 1] === tagLower[0] || source[idx + 1] === tagName[0]) {
var match = true;
for (var i = 0; i < tagLower.length; i++) {
var c = source[idx + 1 + i];
if (c !== tagLower[i] && c !== tagName[i]) {
match = false;
break;
}
}
if (match && (source[idx + openTagLen] === ' ' || source[idx + openTagLen] === '>')) {
openIdx = idx;
}
}
if (openIdx === -1 && closeIdx === -1) {
pos = idx + 1;
continue;
}
if (openIdx !== -1 && (closeIdx === -1 || openIdx < closeIdx)) {
pos = openIdx + openTagLen + 1;
depth++;
} else {
var p = closeIdx + 2;
while (p < sourceLen) {
var _c = source[p];
if (_c !== ' ' && _c !== '\t' && _c !== '\n' && _c !== '\r') break;
p++;
}
if (p + tagLower.length > sourceLen) return null;
var _match = true;
for (var _i = 0; _i < tagLower.length; _i++) {
var _c2 = source[p + _i];
if (_c2 !== tagLower[_i] && _c2 !== tagName[_i]) {
_match = false;
break;
}
}
if (!_match) {
pos = p;
continue;
}
p += tagLower.length;
while (p < sourceLen) {
var _c3 = source[p];
if (_c3 !== ' ' && _c3 !== '\t' && _c3 !== '\n' && _c3 !== '\r') break;
p++;
}
if (p >= sourceLen || source[p] !== '>') {
pos = p;
continue;
}
contentEnd = closeIdx;
pos = p + 1;
depth--;
}
}
var trailingNl = 0;
while (pos + trailingNl < sourceLen && source[pos + trailingNl] === '\n') trailingNl++;
return [source.slice(0, pos + trailingNl), tagName, m[2], source.slice(contentStart, contentEnd)];
}
var HTML_CHAR_CODE_R = /&([a-z0-9]+|#[0-9]{1,6}|#x[0-9a-fA-F]{1,6});/gi;
var HTML_COMMENT_R = /^<!--[\s\S]*?(?:-->)/;
/**
* borrowed from React 15(https://github.com/facebook/react/blob/894d20744cba99383ffd847dbd5b6e0800355a5c/src/renderers/dom/shared/HTMLDOMPropertyConfig.js)
*/
var HTML_CUSTOM_ATTR_R = /^(data|aria|x)-[a-z_][a-z\d_.-]*$/;
var HTML_SELF_CLOSING_ELEMENT_R = /^ *<([a-z][a-z0-9:]*)(?:\s+((?:<.*?>|[^>])*))?\/?>(?!<\/\1>)(\s*\n)?/i;
var INTERPOLATION_R = /^\{.*\}$/;
var LINK_AUTOLINK_BARE_URL_R = /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/;
var LINK_AUTOLINK_R = /^<([^ >]+[:@\/][^ >]+)>/;
var CAPTURE_LETTER_AFTER_HYPHEN = /-([a-z])?/gi;
var NP_TABLE_R = /^(\|.*)\n(?: *(\|? *[-:]+ *\|[-| :]*)\n((?:.*\|.*\n)*))?\n?/;
var PARAGRAPH_R = /^[^\n]+(?: \n|\n{2,})/;
var REFERENCE_IMAGE_OR_LINK = /^\[([^\]]*)\]:\s+<?([^\s>]+)>?\s*("([^"]*)")?/;
var REFERENCE_IMAGE_R = /^!\[([^\]]*)\] ?\[([^\]]*)\]/;
var REFERENCE_LINK_R = /^\[([^\]]*)\] ?\[([^\]]*)\]/;
var SHOULD_RENDER_AS_BLOCK_R = /(\n|^[-*]\s|^#|^ {2,}|^-{2,}|^>\s)/;
var TAB_R = /\t/g;
var TABLE_TRIM_PIPES = /(^ *\||\| *$)/g;
var TABLE_CENTER_ALIGN = /^ *:-+: *$/;
var TABLE_LEFT_ALIGN = /^ *:-+ *$/;
var TABLE_RIGHT_ALIGN = /^ *-+: *$/;
/**
* Special case for shortcodes like :big-smile: or :emoji:
*/
var SHORTCODE_R = /^(:[a-zA-Z0-9-_]+:)/;
var TEXT_ESCAPED_R = /^\\([^0-9A-Za-z\s])/;
var UNESCAPE_R = /\\([^0-9A-Za-z\s])/g;
/**
* Always take the first character, then eagerly take text until a double space
* (potential line break) or some markdown-like punctuation is reached.
*/
var TEXT_PLAIN_R = /^[\s\S](?:(?! \n|[0-9]\.|http)[^=*_~\-\n:<`\\\[!])*/;
var TRIM_STARTING_NEWLINES = /^\n+/;
var HTML_LEFT_TRIM_AMOUNT_R = /^([ \t]*)/;
var ORDERED = 1;
var UNORDERED = 2;
var LIST_LOOKBEHIND_R = /(?:^|\n)( *)$/;
// recognize a `*` `-`, `+`, `1.`, `2.`... list bullet
var ORDERED_LIST_BULLET = '(?:\\d+\\.)';
var UNORDERED_LIST_BULLET = '(?:[*+-])';
function generateListItemPrefix(type) {
return '( *)(' + (type === ORDERED ? ORDERED_LIST_BULLET : UNORDERED_LIST_BULLET) + ') +';
}
// recognize the start of a list item:
// leading space plus a bullet plus a space (` * `)
var ORDERED_LIST_ITEM_PREFIX = generateListItemPrefix(ORDERED);
var UNORDERED_LIST_ITEM_PREFIX = generateListItemPrefix(UNORDERED);
function generateListItemPrefixRegex(type) {
return new RegExp('^' + (type === ORDERED ? ORDERED_LIST_ITEM_PREFIX : UNORDERED_LIST_ITEM_PREFIX));
}
var ORDERED_LIST_ITEM_PREFIX_R = generateListItemPrefixRegex(ORDERED);
var UNORDERED_LIST_ITEM_PREFIX_R = generateListItemPrefixRegex(UNORDERED);
function generateListItemRegex(type) {
// recognize an individual list item:
// * hi
// this is part of the same item
//
// as is this, which is a new paragraph in the same item
//
// * but this is not part of the same item
return new RegExp('^' + (type === ORDERED ? ORDERED_LIST_ITEM_PREFIX : UNORDERED_LIST_ITEM_PREFIX) + '[^\\n]*(?:\\n' + '(?!\\1' + (type === ORDERED ? ORDERED_LIST_BULLET : UNORDERED_LIST_BULLET) + ' )[^\\n]*)*(\\n|$)', 'gm');
}
var ORDERED_LIST_ITEM_R = generateListItemRegex(ORDERED);
var UNORDERED_LIST_ITEM_R = generateListItemRegex(UNORDERED);
// check whether a list item has paragraphs: if it does,
// we leave the newlines at the end
function generateListRegex(type) {
var bullet = type === ORDERED ? ORDERED_LIST_BULLET : UNORDERED_LIST_BULLET;
return new RegExp('^( *)(' + bullet + ') ' + '[\\s\\S]+?(?:\\n{2,}(?! )' + '(?!\\1' + bullet + ' (?!' + bullet + ' ))\\n*' +
// the \\s*$ here is so that we can parse the inside of nested
// lists, where our content might end before we receive two `\n`s
'|\\s*\\n*$)');
}
var ORDERED_LIST_R = generateListRegex(ORDERED);
var UNORDERED_LIST_R = generateListRegex(UNORDERED);
function generateListRule(h, type) {
var ordered = type === ORDERED;
var LIST_R = ordered ? ORDERED_LIST_R : UNORDERED_LIST_R;
var LIST_ITEM_R = ordered ? ORDERED_LIST_ITEM_R : UNORDERED_LIST_ITEM_R;
var LIST_ITEM_PREFIX_R = ordered ? ORDERED_LIST_ITEM_PREFIX_R : UNORDERED_LIST_ITEM_PREFIX_R;
return {
_qualify: function _qualify(source) {
return LIST_ITEM_PREFIX_R.test(source);
},
_match: allowInline(function (source, state) {
// We only want to break into a list if we are at the start of a
// line. This is to avoid parsing "hi * there" with "* there"
// becoming a part of a list.
// You might wonder, "but that's inline, so of course it wouldn't
// start a list?". You would be correct! Except that some of our
// lists can be inline, because they might be inside another list,
// in which case we can parse with inline scope, but need to allow
// nested lists inside this inline scope.
var isStartOfLine = LIST_LOOKBEHIND_R.exec(state.prevCapture);
var isListAllowed = state.list || !state.inline && !state.simple;
if (isStartOfLine && isListAllowed) {
source = isStartOfLine[1] + source;
return LIST_R.exec(source);
} else {
return null;
}
}),
_order: Priority.HIGH,
_parse: function _parse(capture, parse, state) {
var bullet = capture[2];
var start = ordered ? +bullet : undefined;
var items = capture[0]
// recognize the end of a paragraph block inside a list item:
// two or more newlines at end end of the item
.replace(BLOCK_END_R, '\n').match(LIST_ITEM_R);
var firstPrefixMatch = LIST_ITEM_PREFIX_R.exec(items[0]);
var space = firstPrefixMatch ? firstPrefixMatch[0].length : 0;
var spaceRegex = new RegExp('^ {1,' + space + '}', 'gm');
var lastItemWasAParagraph = false;
var itemContent = items.map(function (item, i) {
// Before processing the item, we need a couple things
var content = item
// remove indents on trailing lines:
.replace(spaceRegex, '')
// remove the bullet:
.replace(LIST_ITEM_PREFIX_R, '');
// Handling "loose" lists, like:
//
// * this is wrapped in a paragraph
//
// * as is this
//
// * as is this
var isLastItem = i === items.length - 1;
var containsBlocks = includes(content, '\n\n');
// Any element in a list is a block if it contains multiple
// newlines. The last element in the list can also be a block
// if the previous item in the list was a block (this is
// because non-last items in the list can end with \n\n, but
// the last item can't, so we just "inherit" this property
// from our previous element).
var thisItemIsAParagraph = containsBlocks || isLastItem && lastItemWasAParagraph;
lastItemWasAParagraph = thisItemIsAParagraph;
// backup our state for delta afterwards. We're going to
// want to set state.list to true, and state.inline depending
// on our list's looseness.
var oldStateInline = state.inline;
var oldStateList = state.list;
state.list = true;
// Parse inline if we're in a tight list, or block if we're in
// a loose list.
var adjustedContent;
if (thisItemIsAParagraph) {
state.inline = false;
adjustedContent = trimEnd(content) + '\n\n';
} else {
state.inline = true;
adjustedContent = trimEnd(content);
}
var result = parse(adjustedContent, state);
// Restore our state before returning
state.inline = oldStateInline;
state.list = oldStateList;
return result;
});
return {
items: itemContent,
ordered: ordered,
start: start
};
}
};
}
var LINK_INSIDE = '(?:\\[[^\\[\\]]*(?:\\[[^\\[\\]]*\\][^\\[\\]]*)*\\]|[^\\[\\]])*';
var LINK_HREF_AND_TITLE = '\\s*<?((?:\\([^)]*\\)|[^\\s\\\\]|\\\\.)*?)>?(?:\\s+[\'"]([\\s\\S]*?)[\'"])?\\s*';
var LINK_R = new RegExp('^\\[(' + LINK_INSIDE + ')\\]\\(' + LINK_HREF_AND_TITLE + '\\)');
var IMAGE_R = /^!\[(.*?)\]\( *((?:\([^)]*\)|[^() ])*) *"?([^)"]*)?"?\)/;
function isString(value) {
return typeof value === 'string';
}
function trimEnd(str) {
var end = str.length;
while (end > 0 && str[end - 1] <= ' ') end--;
return str.slice(0, end);
}
function startsWith(str, prefix) {
return str.startsWith(prefix);
}
function includes(str, search) {
return str.indexOf(search) !== -1;
}
function qualifies(source, state, qualify) {
if (Array.isArray(qualify)) {
for (var i = 0; i < qualify.length; i++) {
if (startsWith(source, qualify[i])) return true;
}
return false;
}
return qualify(source, state);
}
/** Remove symmetrical leading and trailing quotes */
function unquote(str) {
var first = str[0];
if ((first === '"' || first === "'") && str.length >= 2 && str[str.length - 1] === first) {
return str.slice(1, -1);
}
return str;
}
// based on https://stackoverflow.com/a/18123682/1141611
// not complete, but probably good enough
function slugify(str) {
return str.replace(/[ÀÁÂÃÄÅàáâãä忯]/g, 'a').replace(/[çÇ]/g, 'c').replace(/[ðÐ]/g, 'd').replace(/[ÈÉÊËéèêë]/g, 'e').replace(/[ÏïÎîÍíÌì]/g, 'i').replace(/[Ññ]/g, 'n').replace(/[øØœŒÕõÔôÓóÒò]/g, 'o').replace(/[ÜüÛûÚúÙù]/g, 'u').replace(/[ŸÿÝý]/g, 'y').replace(/[^a-z0-9- ]/gi, '').replace(/ /gi, '-').toLowerCase();
}
function parseTableAlignCapture(alignCapture) {
if (TABLE_RIGHT_ALIGN.test(alignCapture)) {
return 'right';
} else if (TABLE_CENTER_ALIGN.test(alignCapture)) {
return 'center';
} else if (TABLE_LEFT_ALIGN.test(alignCapture)) {
return 'left';
}
return null;
}
function parseTableRow(source, parse, state, tableOutput) {
var prevInTable = state.inTable;
state.inTable = true;
var cells = [[]];
var acc = '';
function flush() {
if (!acc) return;
var cell = cells[cells.length - 1];
cell.push.apply(cell, parse(acc, state));
acc = '';
}
source.trim()
// isolate situations where a pipe should be ignored (inline code, escaped, etc)
.split(/(`[^`]*`|\\\||\|)/).filter(Boolean).forEach(function (fragment, i, arr) {
if (fragment.trim() === '|') {
flush();
if (tableOutput) {
if (i !== 0 && i !== arr.length - 1) {
// Split the current row
cells.push([]);
}
return;
}
}
acc += fragment;
});
flush();
state.inTable = prevInTable;
return cells;
}
function parseTableAlign(source /*, parse, state*/) {
var alignText = source.replace(TABLE_TRIM_PIPES, '').split('|');
return alignText.map(parseTableAlignCapture);
}
function parseTableCells(source, parse, state) {
var rowsText = source.trim().split('\n');
return rowsText.map(function (rowText) {
return parseTableRow(rowText, parse, state, true);
});
}
function parseTable(capture, parse, state) {
/**
* The table syntax makes some other parsing angry so as a bit of a hack even if alignment and/or cell rows are missing,
* we'll still run a detected first row through the parser and then just emit a paragraph.
*/
state.inline = true;
var align = capture[2] ? parseTableAlign(capture[2]) : [];
var cells = capture[3] ? parseTableCells(capture[3], parse, state) : [];
var header = parseTableRow(capture[1], parse, state, !!cells.length);
state.inline = false;
return cells.length ? {
align: align,
cells: cells,
header: header,
type: RuleType.table
} : {
children: header,
type: RuleType.paragraph
};
}
function getTableStyle(node, colIndex) {
return node.align[colIndex] == null ? {} : {
textAlign: node.align[colIndex]
};
}
/** TODO: remove for react 16 */
function normalizeAttributeKey(key) {
var hyphenIndex = key.indexOf('-');
if (hyphenIndex !== -1 && key.match(HTML_CUSTOM_ATTR_R) === null) {
key = key.replace(CAPTURE_LETTER_AFTER_HYPHEN, function (_, letter) {
return letter.toUpperCase();
});
}
return key;
}
function parseStyleAttribute(styleString) {
var styles = [];
if (!styleString) return styles;
var buffer = '';
var depth = 0;
var quoteChar = '';
for (var i = 0; i < styleString.length; i++) {
var _char = styleString[i];
if (_char === '"' || _char === "'") {
if (!quoteChar) {
quoteChar = _char;
depth++;
} else if (_char === quoteChar) {
quoteChar = '';
depth--;
}
} else if (_char === '(' && buffer.endsWith('url')) {
depth++;
} else if (_char === ')' && depth > 0) {
depth--;
} else if (_char === ';' && depth === 0) {
var _colonIndex = buffer.indexOf(':');
if (_colonIndex > 0) {
styles.push([buffer.slice(0, _colonIndex).trim(), buffer.slice(_colonIndex + 1).trim()]);
}
buffer = '';
continue;
}
buffer += _char;
}
var colonIndex = buffer.indexOf(':');
if (colonIndex > 0) {
styles.push([buffer.slice(0, colonIndex).trim(), buffer.slice(colonIndex + 1).trim()]);
}
return styles;
}
function attributeValueToJSXPropValue(tag, key, value, sanitizeUrlFn) {
if (key === 'style') {
return parseStyleAttribute(value).reduce(function (styles, _ref) {
var key = _ref[0],
value = _ref[1];
styles[key.replace(/(-[a-z])/g, function (substr) {
return substr[1].toUpperCase();
})] = sanitizeUrlFn(value, tag, key);
return styles;
}, {});
}
if (ATTRIBUTES_TO_SANITIZE.indexOf(key) !== -1) {
return sanitizeUrlFn(unescape(value), tag, key);
}
if (value.match(INTERPOLATION_R)) {
value = unescape(value.slice(1, value.length - 1));
}
return value === 'true' ? true : value === 'false' ? false : value;
}
function normalizeWhitespace(source) {
return source.replace(CR_NEWLINE_R, '\n').replace(FORMFEED_R, '').replace(TAB_R, ' ');
}
/**
* Creates a parser for a given set of rules, with the precedence
* specified as a list of rules.
*
* @rules: an object containing
* rule type -> {match, order, parse} objects
* (lower order is higher precedence)
* (Note: `order` is added to defaultRules after creation so that
* the `order` of defaultRules in the source matches the `order`
* of defaultRules in terms of `order` fields.)
*
* @returns The resulting parse function, with the following parameters:
* @source: the input source string to be parsed
* @state: an optional object to be threaded through parse
* calls. Allows clients to add stateful operations to
* parsing, such as keeping track of how many levels deep
* some nesting is. For an example use-case, see passage-ref
* parsing in src/widgets/passage/passage-markdown.jsx
*/
function parserFor(rules) {
var ruleList = Object.keys(rules);
// Sorts rules in order of increasing order, then
// ascending rule name in case of ties.
ruleList.sort(function (a, b) {
return rules[a]._order - rules[b]._order || (a < b ? -1 : 1);
});
function nestedParse(source, state) {
var result = [];
state.prevCapture = state.prevCapture || '';
if (source.trim()) {
while (source) {
var i = 0;
while (i < ruleList.length) {
var ruleType = ruleList[i];
var rule = rules[ruleType];
if (rule._qualify && !qualifies(source, state, rule._qualify)) {
i++;
continue;
}
var capture = rule._match(source, state);
if (capture && capture[0]) {
source = source.substring(capture[0].length);
var parsed = rule._parse(capture, nestedParse, state);
state.prevCapture += capture[0];
if (!parsed.type) parsed.type = ruleType;
result.push(parsed);
break;
}
i++;
}
}
}
// reset on exit
state.prevCapture = '';
return result;
}
return function (source, state) {
return nestedParse(normalizeWhitespace(source), state);
};
}
/**
* Marks a matcher function as eligible for being run inside an inline context;
* allows us to do a little less work in the nested parser.
*/
function allowInline(fn) {
fn.inline = 1;
return fn;
}
// Creates a match function for an inline scoped or simple element from a regex
function inlineRegex(regex) {
return allowInline(function match(source, state) {
if (state.inline) {
return regex.exec(source);
} else {
return null;
}
});
}
// basically any inline element except links
function simpleInlineRegex(regex) {
return allowInline(function match(source, state) {
if (state.inline || state.simple) {
return regex.exec(source);
} else {
return null;
}
});
}
// Creates a match function for a block scoped element from a regex
function blockRegex(regex) {
return function match(source, state) {
if (state.inline || state.simple) {
return null;
} else {
return regex.exec(source);
}
};
}
// Creates a match function from a regex, ignoring block/inline scope
function anyScopeRegex(regex) {
return allowInline(function match(source /*, state*/) {
return regex.exec(source);
});
}
var SANITIZE_R = /(javascript|vbscript|data(?!:image)):/i;
function sanitizer(input) {
try {
var decoded = decodeURIComponent(input).replace(/[^A-Za-z0-9/:]/g, '');
if (SANITIZE_R.test(decoded)) {
if ("production" !== 'production') ;
return null;
}
} catch (e) {
// decodeURIComponent sometimes throws a URIError
// See `decodeURIComponent('a%AFc');`
// http://stackoverflow.com/questions/9064536/javascript-decodeuricomponent-malformed-uri-exception
return null;
}
return input;
}
function unescape(rawString) {
return rawString ? rawString.replace(UNESCAPE_R, '$1') : rawString;
}
/**
* Everything inline, including links.
*/
function parseInline(parse, children, state) {
var isCurrentlyInline = state.inline || false;
var isCurrentlySimple = state.simple || false;
state.inline = true;
state.simple = true;
var result = parse(children, state);
state.inline = isCurrentlyInline;
state.simple = isCurrentlySimple;
return result;
}
/**
* Anything inline that isn't a link.
*/
function parseSimpleInline(parse, children, state) {
var isCurrentlyInline = state.inline || false;
var isCurrentlySimple = state.simple || false;
state.inline = false;
state.simple = true;
var result = parse(children, state);
state.inline = isCurrentlyInline;
state.simple = isCurrentlySimple;
return result;
}
function parseBlock(parse, children, state) {
var isCurrentlyInline = state.inline || false;
state.inline = false;
var result = parse(children, state);
state.inline = isCurrentlyInline;
return result;
}
var parseCaptureInline = function parseCaptureInline(capture, parse, state) {
return {
children: parseInline(parse, capture[2], state)
};
};
function captureNothing() {
return {};
}
function render(node, output, state, h, sanitize, slug, refs) {
switch (node.type) {
case RuleType.blockQuote:
{
var props = {
key: state.key
};
if (node.alert) {
props.className = 'markdown-alert-' + slug(node.alert.toLowerCase(), slugify);
node.children.unshift({
attrs: {},
children: [{
type: RuleType.text,
text: node.alert
}],
noInnerParse: true,
type: RuleType.htmlBlock,
tag: 'header'
});
}
return h('blockquote', props, output(node.children, state));
}
case RuleType.breakLine:
return h("br", {
key: state.key
});
case RuleType.breakThematic:
return h("hr", {
key: state.key
});
case RuleType.codeBlock:
return h("pre", {
key: state.key
}, h("code", _extends({}, node.attrs, {
className: node.lang ? "lang-" + node.lang : ''
}), node.text));
case RuleType.codeInline:
return h("code", {
key: state.key
}, node.text);
case RuleType.footnoteReference:
return h("a", {
key: state.key,
href: sanitize(node.target, 'a', 'href')
}, h("sup", {
key: state.key
}, node.text));
case RuleType.gfmTask:
return h("input", {
checked: node.completed,
key: state.key,
readOnly: true,
type: "checkbox"
});
case RuleType.heading:
return h("h" + node.level, {
id: node.id,
key: state.key
}, output(node.children, state));
case RuleType.htmlBlock:
return h(node.tag, _extends({
key: state.key
}, node.attrs), node.text || (node.children ? output(node.children, state) : ''));
case RuleType.htmlSelfClosing:
return h(node.tag, _extends({}, node.attrs, {
key: state.key
}));
case RuleType.image:
return h("img", {
key: state.key,
alt: node.alt || undefined,
title: node.title || undefined,
src: sanitize(node.target, 'img', 'src')
});
case RuleType.link:
return h("a", {
key: state.key,
href: sanitize(node.target, 'a', 'href'),
title: node.title
}, output(node.children, state));
case RuleType.refImage:
return refs[node.ref] ? h("img", {
key: state.key,
alt: node.alt,
src: sanitize(refs[node.ref].target, 'img', 'src'),
title: refs[node.ref].title
}) : null;
case RuleType.refLink:
return refs[node.ref] ? h("a", {
key: state.key,
href: sanitize(refs[node.ref].target, 'a', 'href'),
title: refs[node.ref].title
}, output(node.children, state)) : h("span", {
key: state.key
}, node.fallbackChildren);
case RuleType.table:
{
var table = node;
return h("table", {
key: state.key
}, h("thead", null, h("tr", null, table.header.map(function generateHeaderCell(content, i) {
return h("th", {
key: i,
style: getTableStyle(table, i)
}, output(content, state));
}))), h("tbody", null, table.cells.map(function generateTableRow(row, i) {
return h("tr", {
key: i
}, row.map(function generateTableCell(content, c) {
return h("td", {
key: c,
style: getTableStyle(table, c)
}, output(content, state));
}));
})));
}
case RuleType.text:
return node.text;
case RuleType.textFormatted:
return h(node.tag, {
key: state.key
}, output(node.children, state));
case RuleType.orderedList:
case RuleType.unorderedList:
{
var Tag = node.ordered ? 'ol' : 'ul';
return h(Tag, {
key: state.key,
start: node.type === RuleType.orderedList ? node.start : undefined
}, node.items.map(function generateListItem(item, i) {
return h("li", {
key: i
}, output(item, state));
}));
}
case RuleType.newlineCoalescer:
return '\n';
case RuleType.paragraph:
return h("p", {
key: state.key
}, output(node.children, state));
default:
return null;
}
}
function createRenderer(userRender, h, sanitize, slug, refs) {
function renderRule(ast, renderer, state) {
var nodeRender = function nodeRender() {
return render(ast, renderer, state, h, sanitize, slug, refs);
};
return userRender ? userRender(nodeRender, ast, renderer, state) : nodeRender();
}
// Return plain text as fallback to prevent stack overflow
function handleStackOverflow(ast) {
if (Array.isArray(ast)) {
return ast.map(function (node) {
return 'text' in node ? node.text : '';
});
}
return 'text' in ast ? ast.text : '';
}
return function patchedRender(ast, state) {
if (state === void 0) {
state = {};
}
// Track render depth to prevent stack overflow from extremely deep nesting
var currentDepth = (state.renderDepth || 0) + 1;
var MAX_RENDER_DEPTH = 2500;
if (currentDepth > MAX_RENDER_DEPTH) {
return handleStackOverflow(ast);
}
state.renderDepth = currentDepth;
try {
if (Array.isArray(ast)) {
var oldKey = state.key;
var _result = [];
// map nestedOutput over the ast, except group any text
// nodes together into a single string output.
var lastWasString = false;
for (var i = 0; i < ast.length; i++) {
state.key = i;
var nodeOut = patchedRender(ast[i], state);
var _isString = isString(nodeOut);
if (_isString && lastWasString) {
_result[_result.length - 1] += nodeOut;
} else if (nodeOut !== null) {
_result.push(nodeOut);
}
lastWasString = _isString;
}
state.key = oldKey;
state.renderDepth = currentDepth - 1;
return _result;
}
var result = renderRule(ast, patchedRender, state);
state.renderDepth = currentDepth - 1;
return result;
} catch (error) {
// Catch stack overflow or other unexpected errors
if (error instanceof RangeError && error.message.includes('Maximum call stack')) {
return handleStackOverflow(ast);
}
// Re-throw other errors
throw error;
}
};
}
function cx() {
return [].slice.call(arguments).filter(Boolean).join(' ');
}
function get(src, path, fb) {
var ptr = src;
var frags = path.split('.');
while (frags.length) {
ptr = ptr[frags[0]];
if (ptr === undefined) break;else frags.shift();
}
return ptr || fb;
}
function getTag(tag, overrides) {
var override = get(overrides, tag);
if (!override) return tag;
return typeof override === 'function' || typeof override === 'object' && 'render' in override ? override : get(overrides, tag + ".component", tag);
}
function attrStringToMap(tag, str, sanitize, compile) {
if (!str || !str.trim()) return null;
var attributes = str.match(ATTR_EXTRACTOR_R);
if (!attributes) return null;
return attributes.reduce(function (map, raw) {
var delimiterIdx = raw.indexOf('=');
if (delimiterIdx !== -1) {
var key = normalizeAttributeKey(raw.slice(0, delimiterIdx)).trim();
var mappedKey = ATTRIBUTE_TO_JSX_PROP_MAP[key] || key;
if (mappedKey === 'ref') return map;
var normalizedValue = map[mappedKey] = attributeValueToJSXPropValue(tag, key, unquote(raw.slice(delimiterIdx + 1).trim()), sanitize);
if (typeof normalizedValue === 'string' && (HTML_BLOCK_ELEMENT_START_R.test(normalizedValue) || HTML_SELF_CLOSING_ELEMENT_R.test(normalizedValue))) {
map[mappedKey] = compile(normalizedValue.trim());
}
} else if (raw !== 'style') {
map[ATTRIBUTE_TO_JSX_PROP_MAP[raw] || raw] = true;
}
return map;
}, {});
}
function some(regexes, input) {
for (var i = 0; i < regexes.length; i++) {
if (regexes[i].test(input)) {
return true;
}
}
return false;
}
function compiler(markdown, options) {
var _rules;
if (markdown === void 0) {
markdown = '';
}
if (options === void 0) {
options = {};
}
options.overrides = options.overrides || {};
options.namedCodesToUnicode = options.namedCodesToUnicode ? _extends({}, namedCodesToUnicode, options.namedCodesToUnicode) : namedCodesToUnicode;
var slug = options.slugify || slugify;
var sanitize = options.sanitizer || sanitizer;
var createElement = options.createElement || React.createElement;
var NON_PARAGRAPH_BLOCK_SYNTAXES = [BLOCKQUOTE_R, CODE_BLOCK_FENCED_R, CODE_BLOCK_R, options.enforceAtxHeadings ? HEADING_ATX_COMPLIANT_R : HEADING_R, HEADING_SETEXT_R, NP_TABLE_R, ORDERED_LIST_R, UNORDERED_LIST_R];
var BLOCK_SYNTAXES = [].concat(NON_PARAGRAPH_BLOCK_SYNTAXES, [PARAGRAPH_R, HTML_BLOCK_ELEMENT_START_R, HTML_COMMENT_R, HTML_SELF_CLOSING_ELEMENT_R]);
function matchParagraph(source, state) {
if (state.inline || state.simple || state.inHTML && !includes(source, '\n\n') && !includes(state.prevCapture, '\n\n')) return null;
var match = '';
var start = 0;
while (true) {
var nlIdx = source.indexOf('\n', start);
var line = source.slice(start, nlIdx === -1 ? undefined : nlIdx + 1);
var c = source[start];
if ((c === '>' || c === '#' || c === '|' || c === '`' || c === '~' || c === '*' || c === '-' || c === '_' || c === ' ') && some(NON_PARAGRAPH_BLOCK_SYNTAXES, line)) break;
match += line;
if (nlIdx === -1 || !line.trim()) break;
start = nlIdx + 1;
}
var captured = trimEnd(match);
if (captured === '') return null;
return [match,, captured];
}
// JSX custom pragma
// eslint-disable-next-line no-unused-vars
function h(
// locally we always will render a known string tag
tag, props) {
var overrideProps = get(options.overrides, tag + ".props", {});
return createElement.apply(void 0, [getTag(tag, options.overrides), _extends({}, props, overrideProps, {
className: cx(props == null ? void 0 : props.className, overrideProps.className) || undefined
})].concat([].slice.call(arguments, 2)));
}
function compile(input) {
input = input.replace(FRONT_MATTER_R, '');
var inline = false;
if (options.forceInline) {
inline = true;
} else if (!options.forceBlock) {
/**
* should not contain any block-level markdown like newlines, lists, headings,
* thematic breaks, blockquotes, tables, etc
*/
inline = SHOULD_RENDER_AS_BLOCK_R.test(input) === false;
}
var astNodes = parser(inline ? input : trimEnd(input).replace(TRIM_STARTING_NEWLINES, '') + "\n\n", {
inline: inline
});
if (options.ast) {
return astNodes;
}
var arr = emitter(astNodes);
while (isString(arr[arr.length - 1]) && !arr[arr.length - 1].trim()) {
arr.pop();
}
if (footnotes.length) {
arr.push(h("footer", {
key: "footer"
}, footnotes.map(function createFootnote(def) {
return h("div", {
id: slug(def.identifier, slugify),
key: def.identifier
}, def.identifier, emitter(parser(def.footnote, {
inline: true
})));
})));
}
if (options.wrapper === null) {
return arr;
}
var wrapper = options.wrapper || (inline ? 'span' : 'div');
var jsx;
if (arr.length > 1 || options.forceWrapper) {
jsx = arr;
} else if (arr.length === 1) {
jsx = arr[0];
// TODO: remove this for React 16
if (typeof jsx === 'string') {
return h("span", {
key: "outer"
}, jsx);
} else {
return jsx;
}
} else {
// TODO: return null for React 16
jsx = null;
}
return createElement(wrapper, _extends({
key: 'outer'
}, options.wrapperProps), jsx);
}
var footnotes = [];
var refs = {};
/**
* each rule's react() output function goes through our custom
* h() JSX pragma; this allows the override functionality to be
* automatically applied
*/
// @ts-ignore
var rules = (_rules = {}, _rules[RuleType.blockQuote] = {
_qualify: ['>'],
_match: blockRegex(BLOCKQUOTE_R),
_order: Priority.HIGH,
_parse: function _parse(capture, parse, state) {
var _capture$0$replace$ma = capture[0].replace(BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, '').match(BLOCKQUOTE_ALERT_R),
alert = _capture$0$replace$ma[1],
content = _capture$0$replace$ma[2];
return {
alert: alert,
children: parse(content, state)
};
}
}, _rules[RuleType.breakLine] = {
_qualify: [' '],
_match: inlineRegex(BREAK_LINE_R),
_order: Priority.HIGH,
_parse: captureNothing
}, _rules[RuleType.breakThematic] = {
_qualify: function _qualify(source, state) {
// Only attempt in block mode
if (state.inline || state.simple) return false;
var c = source[0];
return c === '-' || c === '*' || c === '_';
},
_match: blockRegex(BREAK_THEMATIC_R),
_order: Priority.HIGH,
_parse: captureNothing
}, _rules[RuleType.codeBlock] = {
_qualify: [' '],
_match: blockRegex(CODE_BLOCK_R),
_order: Priority.MAX,
_parse: function _parse(capture /*, parse, state*/) {
return {
lang: undefined,
text: unescape(trimEnd(capture[0].replace(/^ {4}/gm, '')))
};
}
}, _rules[RuleType.codeFenced] = {
_qualify: ['```', '~~~'],
_match: blockRegex(CODE_BLOCK_FENCED_R),
_order: Priority.MAX,
_parse: function _parse(capture /*, parse, state*/) {
return {
// if capture[3] it's additional metadata
attrs: attrStringToMap('code', capture[3] || '', sanitize, compile),
lang: capture[2] || undefined,
text: capture[4],
type: RuleType.codeBlock
};
}
}, _rules[RuleType.codeInline] = {
_qualify: ['`'],
_match: simpleInlineRegex(CODE_INLINE_R),
_order: Priority.LOW,
_parse: function _parse(capture /*, parse, state*/) {
return {
text: unescape(capture[2])
};
}
}, _rules[RuleType.footnote] = {
_qualify: ['[^'],
_match: blockRegex(FOOTNOTE_R),
_order: Priority.MAX,
_parse: function _parse(capture /*, parse, state*/) {
footnotes.push({
footnote: capture[2],
identifier: capture[1]
});
return {};
}
}, _rules[RuleType.footnoteReference] = {
_qualify: ['[^'],
_match: inlineRegex(FOOTNOTE_REFERENCE_R),
_order: Priority.HIGH,
_parse: function _parse(capture /*, parse*/) {
return {
target: "#" + slug(capture[1], slugify),
text: capture[1]
};
}
}, _rules[RuleType.gfmTask] = {
_qualify: ['[ ]', '[x]'],
_match: inlineRegex(GFM_TASK_R),
_order: Priority.HIGH,
_parse: function _parse(capture /*, parse, state*/) {
return {
completed: capture[1].toLowerCase() === 'x'
};
}
}, _rules[RuleType.heading] = {
_qualify: ['#'],
_match: blockRegex(options.enforceAtxHeadings ? HEADING_ATX_COMPLIANT_R : HEADING_R),
_order: Priority.HIGH,
_parse: function _parse(capture, parse, state) {
return {
children: parseInline(parse, capture[2], state),
id: slug(capture[2], slugify),
level: capture[1].length
};
}
}, _rules[RuleType.headingSetext] = {
_qualify: function _qualify(source) {
var nlIndex = source.indexOf('\n');
return nlIndex > 0 && nlIndex < source.length - 1 && (source[nlIndex + 1] === '=' || source[nlIndex + 1] === '-');
},
_match: blockRegex(HEADING_SETEXT_R),
_order: Priority.HIGH,
_parse: function _parse(capture, parse, state) {
return {
children: parseInline(parse, capture[1], state),
level: capture[2] === '=' ? 1 : 2,
type: RuleType.heading
};
}
}, _rules[RuleType.htmlBlock] = {
_qualify: ['<'],
/**
* find the first matching end tag and process the interior
*/
_match: allowInline(matchHTMLBlock),
_order: Priority.HIGH,
_parse: function _parse(capture, parse, state) {
var _capture$3$match = capture[3].match(HTML_LEFT_TRIM_AMOUNT_R),
whitespace = _capture$3$match[1];
var trimmer = new RegExp("^" + whitespace, 'gm');
var trimmed = capture[3].replace(trimmer, '');
var parseFunc = some(BLOCK_SYNTAXES, trimmed) ? parseBlock : parseInline;
var tagName = capture[1].toLowerCase();
var noInnerParse = DO_NOT_PROCESS_HTML_ELEMENTS.indexOf(tagName) !== -1;
var tag = (noInnerParse ? tagName : capture[1]).trim();
var ast = {
attrs: attrStringToMap(tag, capture[2], sanitize, compile),
noInnerParse: noInnerParse,
tag: tag
};
state.inAnchor = state.inAnchor || tagName === 'a';
if (noInnerParse) {
ast.text = capture[3];
} else {
var prevInHTML = state.inHTML;
state.inHTML = true;
ast.children = parseFunc(parse, trimmed, state);
state.inHTML = prevInHTML;
}
/**
* if another html block is detected within, parse as block,
* otherwise parse as inline to pick up any further markdown
*/
state.inAnchor = false;
return ast;
}
}, _rules[RuleType.htmlSelfClosing] = {
_qualify: ['<'],
/**
* find the first matching end tag and process the interior
*/
_match: anyScopeRegex(HTML_SELF_CLOSING_ELEMENT_R),
_order: Priority.HIGH,
_parse: function _parse(capture /*, parse, state*/) {
var tag = capture[1].trim();
return {
attrs: attrStringToMap(tag, capture[2] || '', sanitize, compile),
tag: tag
};
}
}, _rules[RuleType.htmlComment] = {
_qualify: ['<!--'],
_match: anyScopeRegex(HTML_COMMENT_R),
_order: Priority.HIGH,
_parse: function _parse() {
return {};
}
}, _rules[RuleType.image] = {
_qualify: ['!['],
_match: simpleInlineRegex(IMAGE_R),
_order: Priority.HIGH,
_parse: function _parse(capture /*, parse, state*/) {
return {
alt: unescape(capture[1]),
target: unescape(capture[2]),
title: unescape(capture[3])
};
}
}, _rules[RuleType.link] = {
_qualify: ['['],
_match: inlineRegex(LINK_R),
_order: Priority.LOW,
_parse: function _parse(capture, parse, state) {
return {
children: parseSimpleInline(parse, capture[1], state),
target: unescape(capture[2]),
title: unescape(capture[3])
};
}
}, _rules[RuleType.linkAngleBraceStyleDetector] = {