Socket
Socket
Sign inDemoInstall

markdown-to-jsx

Package Overview
Dependencies
Maintainers
1
Versions
110
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

markdown-to-jsx - npm Package Compare versions

Comparing version 6.7.4 to 6.8.0

dist/cjs.js

2209

index.js

@@ -12,46 +12,55 @@ /* @jsx h */

const ATTRIBUTE_TO_JSX_PROP_MAP = {
accesskey: 'accessKey',
allowfullscreen: 'allowFullScreen',
allowtransparency: 'allowTransparency',
autocomplete: 'autoComplete',
autofocus: 'autoFocus',
autoplay: 'autoPlay',
cellpadding: 'cellPadding',
cellspacing: 'cellSpacing',
charset: 'charSet',
class: 'className',
classid: 'classId',
colspan: 'colSpan',
contenteditable: 'contentEditable',
contextmenu: 'contextMenu',
crossorigin: 'crossOrigin',
enctype: 'encType',
for: 'htmlFor',
formaction: 'formAction',
formenctype: 'formEncType',
formmethod: 'formMethod',
formnovalidate: 'formNoValidate',
formtarget: 'formTarget',
frameborder: 'frameBorder',
hreflang: 'hrefLang',
inputmode: 'inputMode',
keyparams: 'keyParams',
keytype: 'keyType',
marginheight: 'marginHeight',
marginwidth: 'marginWidth',
maxlength: 'maxLength',
mediagroup: 'mediaGroup',
minlength: 'minLength',
novalidate: 'noValidate',
radiogroup: 'radioGroup',
readonly: 'readOnly',
rowspan: 'rowSpan',
spellcheck: 'spellCheck',
srcdoc: 'srcDoc',
srclang: 'srcLang',
srcset: 'srcSet',
tabindex: 'tabIndex',
usemap: 'useMap',
accesskey: 'accessKey',
allowfullscreen: 'allowFullScreen',
allowtransparency: 'allowTransparency',
autocomplete: 'autoComplete',
autofocus: 'autoFocus',
autoplay: 'autoPlay',
cellpadding: 'cellPadding',
cellspacing: 'cellSpacing',
charset: 'charSet',
class: 'className',
classid: 'classId',
colspan: 'colSpan',
contenteditable: 'contentEditable',
contextmenu: 'contextMenu',
crossorigin: 'crossOrigin',
enctype: 'encType',
for: 'htmlFor',
formaction: 'formAction',
formenctype: 'formEncType',
formmethod: 'formMethod',
formnovalidate: 'formNoValidate',
formtarget: 'formTarget',
frameborder: 'frameBorder',
hreflang: 'hrefLang',
inputmode: 'inputMode',
keyparams: 'keyParams',
keytype: 'keyType',
marginheight: 'marginHeight',
marginwidth: 'marginWidth',
maxlength: 'maxLength',
mediagroup: 'mediaGroup',
minlength: 'minLength',
novalidate: 'noValidate',
radiogroup: 'radioGroup',
readonly: 'readOnly',
rowspan: 'rowSpan',
spellcheck: 'spellCheck',
srcdoc: 'srcDoc',
srclang: 'srcLang',
srcset: 'srcSet',
tabindex: 'tabIndex',
usemap: 'useMap',
};
const namedCodesToUnicode = {
amp: '\u0026',
apos: '\u0027',
gt: '\u003e',
lt: '\u003c',
nbsp: '\u00a0',
quot: '\u201c',
};
const DO_NOT_PROCESS_HTML_ELEMENTS = ['style', 'script'];

@@ -137,2 +146,4 @@

const HTML_CHAR_CODE_R = /&([a-z]+);/g;
const HTML_COMMENT_R = /^<!--.*?-->/;

@@ -188,11 +199,11 @@

*/
const TEXT_BOLD_R = /^([*_])\1((?:[^`~()\[\]<>]*?|(?:.*?([`~]).*?\3.*?)*|(?:.*?\([^)]*?\).*?)*|(?:.*?\[[^\]]*?\].*?)*|(?:.*?<.*?>.*?)*|[^\1]*?)\1?)\1{2}/;
const TEXT_EMPHASIZED_R = /^([*_])((?:[^`~()\[\]<>]*?|(?:.*?([`~]).*?\3.*?)*|(?:.*?\([^)]*?\).*?)*|(?:.*?\[[^\]]*?\].*?)*|(?:.*?<.*?>.*?)*|[^\1]*?))\1/;
const TEXT_BOLD_R = /^([*_])\1((?:[^`~()[\]<>]*?|(?:.*?([`~]).*?\3.*?)*|(?:.*?\([^)]*?\).*?)*|(?:.*?\[[^\]]*?\].*?)*|(?:.*?<.*?>.*?)*|[^\1]*?)\1?)\1{2}/;
const TEXT_EMPHASIZED_R = /^([*_])((?:[^`~()[\]<>]*?|(?:.*?([`~]).*?\3.*?)*|(?:.*?\([^)]*?\).*?)*|(?:.*?\[[^\]]*?\].*?)*|(?:.*?<.*?>.*?)*|[^\1]*?))\1/;
const TEXT_STRIKETHROUGHED_R = /^~~((?:.*?([`~]).*?\2.*?)*|(?:.*?<.*?>.*?)*|.+?)~~/;
const TEXT_ESCAPED_R = /^\\([^0-9A-Za-z\s])/;
const TEXT_PLAIN_R = /^[\s\S]+?(?=[^0-9A-Z\s\u00c0-\uffff]|\d+\.|\n\n| {2,}\n|\w+:\S|$)/i;
const TEXT_PLAIN_R = /^[\s\S]+?(?=[^0-9A-Z\s\u00c0-\uffff&;.]|\d+\.|\n\n| {2,}\n|\w+:\S|$)/i;
const TRIM_NEWLINES_AND_TRAILING_WHITESPACE_R = /(^\n+|(\n|\s)+$)/g;
const HTML_LEFT_TRIM_AMOUNT_R = /^([ \t]*)/
const HTML_LEFT_TRIM_AMOUNT_R = /^([ \t]*)/;

@@ -217,8 +228,8 @@ const UNESCAPE_URL_R = /\\([^0-9A-Z\s])/gi;

const LIST_ITEM_R = new RegExp(
LIST_ITEM_PREFIX +
'[^\\n]*(?:\\n' +
'(?!\\1' +
LIST_BULLET +
' )[^\\n]*)*(\\n|$)',
'gm'
LIST_ITEM_PREFIX +
'[^\\n]*(?:\\n' +
'(?!\\1' +
LIST_BULLET +
' )[^\\n]*)*(\\n|$)',
'gm'
);

@@ -229,12 +240,14 @@

const LIST_R = new RegExp(
'^( *)(' +
LIST_BULLET +
') ' +
'[\\s\\S]+?(?:\\n{2,}(?! )' +
'(?!\\1' +
LIST_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*$)'
'^( *)(' +
LIST_BULLET +
') ' +
'[\\s\\S]+?(?:\\n{2,}(?! )' +
'(?!\\1' +
LIST_BULLET +
' (?!' +
LIST_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*$)'
);

@@ -244,118 +257,122 @@

const LINK_HREF_AND_TITLE =
'\\s*<?((?:[^\\s\\\\]|\\\\.)*?)>?(?:\\s+[\'"]([\\s\\S]*?)[\'"])?\\s*';
'\\s*<?((?:[^\\s\\\\]|\\\\.)*?)>?(?:\\s+[\'"]([\\s\\S]*?)[\'"])?\\s*';
const LINK_R = new RegExp(
'^\\[(' + LINK_INSIDE + ')\\]\\(' + LINK_HREF_AND_TITLE + '\\)'
'^\\[(' + LINK_INSIDE + ')\\]\\(' + LINK_HREF_AND_TITLE + '\\)'
);
const IMAGE_R = new RegExp(
'^!\\[(' + LINK_INSIDE + ')\\]\\(' + LINK_HREF_AND_TITLE + '\\)'
'^!\\[(' + LINK_INSIDE + ')\\]\\(' + LINK_HREF_AND_TITLE + '\\)'
);
const BLOCK_SYNTAXES = [
BLOCKQUOTE_R,
CODE_BLOCK_R,
CODE_BLOCK_FENCED_R,
HEADING_R,
HEADING_SETEXT_R,
HTML_BLOCK_ELEMENT_R,
HTML_COMMENT_R,
HTML_SELF_CLOSING_ELEMENT_R,
LIST_ITEM_R,
LIST_R,
NP_TABLE_R,
PARAGRAPH_R
BLOCKQUOTE_R,
CODE_BLOCK_R,
CODE_BLOCK_FENCED_R,
HEADING_R,
HEADING_SETEXT_R,
HTML_BLOCK_ELEMENT_R,
HTML_COMMENT_R,
HTML_SELF_CLOSING_ELEMENT_R,
LIST_ITEM_R,
LIST_R,
NP_TABLE_R,
PARAGRAPH_R,
];
function containsBlockSyntax (input) {
return BLOCK_SYNTAXES.some(r => r.test(input))
function isPlainObject(input) {
return typeof input === 'object' && input.constructor === Object;
}
function containsBlockSyntax(input) {
return BLOCK_SYNTAXES.some(r => r.test(input));
}
// 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();
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';
}
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;
return null;
}
function parseTableHeader(capture, parse, state) {
const headerText = capture[1]
.replace(TABLE_TRIM_PIPES, '')
.trim()
.split(TABLE_ROW_SPLIT);
const headerText = capture[1]
.replace(TABLE_TRIM_PIPES, '')
.trim()
.split(TABLE_ROW_SPLIT);
return headerText.map(function(text) {
return parse(text, state);
});
return headerText.map(function(text) {
return parse(text, state);
});
}
function parseTableAlign(capture /*, parse, state*/) {
const alignText = capture[2]
.replace(TABLE_TRIM_PIPES, '')
.trim()
.split(TABLE_ROW_SPLIT);
const alignText = capture[2]
.replace(TABLE_TRIM_PIPES, '')
.trim()
.split(TABLE_ROW_SPLIT);
return alignText.map(parseTableAlignCapture);
return alignText.map(parseTableAlignCapture);
}
function parseTableCells(capture, parse, state) {
const rowsText = capture[3]
.replace(TABLE_TRIM_PIPES, '')
.trim()
.split('\n');
const rowsText = capture[3]
.replace(TABLE_TRIM_PIPES, '')
.trim()
.split('\n');
return rowsText.map(function(rowText) {
return rowText
.replace(TABLE_TRIM_PIPES, '')
.split(TABLE_ROW_SPLIT)
.map(function(text) {
return parse(text.trim(), state);
});
});
return rowsText.map(function(rowText) {
return rowText
.replace(TABLE_TRIM_PIPES, '')
.split(TABLE_ROW_SPLIT)
.map(function(text) {
return parse(text.trim(), state);
});
});
}
function parseTable(capture, parse, state) {
state.inline = true;
const header = parseTableHeader(capture, parse, state);
const align = parseTableAlign(capture, parse, state);
const cells = parseTableCells(capture, parse, state);
state.inline = false;
state.inline = true;
const header = parseTableHeader(capture, parse, state);
const align = parseTableAlign(capture, parse, state);
const cells = parseTableCells(capture, parse, state);
state.inline = false;
return {
align: align,
cells: cells,
header: header,
type: 'table',
};
return {
align: align,
cells: cells,
header: header,
type: 'table',
};
}
function getTableStyle(node, colIndex) {
return node.align[colIndex] == null
? {}
: {
textAlign: node.align[colIndex],
};
return node.align[colIndex] == null
? {}
: {
textAlign: node.align[colIndex],
};
}

@@ -365,54 +382,52 @@

function normalizeAttributeKey(key) {
const hyphenIndex = key.indexOf('-');
const 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();
});
}
if (hyphenIndex !== -1 && key.match(HTML_CUSTOM_ATTR_R) === null) {
key = key.replace(CAPTURE_LETTER_AFTER_HYPHEN, function(_, letter) {
return letter.toUpperCase();
});
}
return key;
return key;
}
function isInterpolation(value) {
return INTERPOLATION_R.test(value);
return INTERPOLATION_R.test(value);
}
function attributeValueToJSXPropValue(key, value) {
if (key === 'style') {
return value.split(/;\s?/).reduce(function(styles, kvPair) {
const key = kvPair.slice(0, kvPair.indexOf(':'));
if (key === 'style') {
return value.split(/;\s?/).reduce(function(styles, kvPair) {
const key = kvPair.slice(0, kvPair.indexOf(':'));
// snake-case to camelCase
// also handles PascalCasing vendor prefixes
const camelCasedKey = key.replace(/(-[a-z])/g, function toUpper(
substr
) {
return substr[1].toUpperCase();
});
// snake-case to camelCase
// also handles PascalCasing vendor prefixes
const camelCasedKey = key.replace(/(-[a-z])/g, function toUpper(substr) {
return substr[1].toUpperCase();
});
// key.length + 1 to skip over the colon
styles[camelCasedKey] = kvPair.slice(key.length + 1).trim();
// key.length + 1 to skip over the colon
styles[camelCasedKey] = kvPair.slice(key.length + 1).trim();
return styles;
}, {});
} else if (isInterpolation(value)) {
// return as a string and let the consumer decide what to do with it
value = value.slice(1, value.length - 1);
}
return styles;
}, {});
} else if (isInterpolation(value)) {
// return as a string and let the consumer decide what to do with it
value = value.slice(1, value.length - 1);
}
if (value === 'true') {
return true;
} else if (value === 'false') {
return false;
}
if (value === 'true') {
return true;
} else if (value === 'false') {
return false;
}
return value;
return value;
}
function normalizeWhitespace(source) {
return source
.replace(CR_NEWLINE_R, '\n')
.replace(FORMFEED_R, '')
.replace(TAB_R, ' ');
return source
.replace(CR_NEWLINE_R, '\n')
.replace(FORMFEED_R, '')
.replace(TAB_R, ' ');
}

@@ -440,85 +455,82 @@

function parserFor(rules) {
// Sorts rules in order of increasing order, then
// ascending rule name in case of ties.
let ruleList = Object.keys(rules);
// Sorts rules in order of increasing order, then
// ascending rule name in case of ties.
let ruleList = Object.keys(rules);
/* istanbul ignore next */
if (process.env.NODE_ENV !== 'production') {
ruleList.forEach(function(type) {
let order = rules[type].order;
if (
process.env.NODE_ENV !== 'production' &&
(typeof order !== 'number' || !isFinite(order)) &&
typeof console !== 'undefined'
) {
console.warn(
'markdown-to-jsx: Invalid order for rule `' +
type +
'`: ' +
order
);
}
});
}
/* istanbul ignore next */
if (process.env.NODE_ENV !== 'production') {
ruleList.forEach(function(type) {
let order = rules[type].order;
if (
process.env.NODE_ENV !== 'production' &&
(typeof order !== 'number' || !isFinite(order)) &&
typeof console !== 'undefined'
) {
console.warn(
'markdown-to-jsx: Invalid order for rule `' + type + '`: ' + order
);
}
});
}
ruleList.sort(function(typeA, typeB) {
let orderA = rules[typeA].order;
let orderB = rules[typeB].order;
ruleList.sort(function(typeA, typeB) {
let orderA = rules[typeA].order;
let orderB = rules[typeB].order;
// First sort based on increasing order
if (orderA !== orderB) {
return orderA - orderB;
// First sort based on increasing order
if (orderA !== orderB) {
return orderA - orderB;
// Then based on increasing unicode lexicographic ordering
} else if (typeA < typeB) {
return -1;
}
// Then based on increasing unicode lexicographic ordering
} else if (typeA < typeB) {
return -1;
}
return 1;
});
return 1;
});
function nestedParse(source, state) {
let result = [];
function nestedParse(source, state) {
let result = [];
// We store the previous capture so that match functions can
// use some limited amount of lookbehind. Lists use this to
// ensure they don't match arbitrary '- ' or '* ' in inline
// text (see the list rule for more information).
let prevCapture = '';
while (source) {
let i = 0;
while (i < ruleList.length) {
const ruleType = ruleList[i];
const rule = rules[ruleType];
const capture = rule.match(source, state, prevCapture);
// We store the previous capture so that match functions can
// use some limited amount of lookbehind. Lists use this to
// ensure they don't match arbitrary '- ' or '* ' in inline
// text (see the list rule for more information).
let prevCapture = '';
while (source) {
let i = 0;
while (i < ruleList.length) {
const ruleType = ruleList[i];
const rule = rules[ruleType];
const capture = rule.match(source, state, prevCapture);
if (capture) {
const currCaptureString = capture[0];
source = source.substring(currCaptureString.length);
const parsed = rule.parse(capture, nestedParse, state);
if (capture) {
const currCaptureString = capture[0];
source = source.substring(currCaptureString.length);
const parsed = rule.parse(capture, nestedParse, state);
// We also let rules override the default type of
// their parsed node if they would like to, so that
// there can be a single output function for all links,
// even if there are several rules to parse them.
if (parsed.type == null) {
parsed.type = ruleType;
}
// We also let rules override the default type of
// their parsed node if they would like to, so that
// there can be a single output function for all links,
// even if there are several rules to parse them.
if (parsed.type == null) {
parsed.type = ruleType;
}
result.push(parsed);
result.push(parsed);
prevCapture = currCaptureString;
break;
}
i++;
}
prevCapture = currCaptureString;
break;
}
return result;
i++;
}
}
return function outerParse(source, state) {
return nestedParse(normalizeWhitespace(source), state);
};
return result;
}
return function outerParse(source, state) {
return nestedParse(normalizeWhitespace(source), state);
};
}

@@ -528,9 +540,9 @@

function inlineRegex(regex) {
return function match(source, state) {
if (state.inline) {
return regex.exec(source);
} else {
return null;
}
};
return function match(source, state) {
if (state.inline) {
return regex.exec(source);
} else {
return null;
}
};
}

@@ -540,9 +552,9 @@

function simpleInlineRegex(regex) {
return function match(source, state) {
if (state.inline || state.simple) {
return regex.exec(source);
} else {
return null;
}
};
return function match(source, state) {
if (state.inline || state.simple) {
return regex.exec(source);
} else {
return null;
}
};
}

@@ -552,9 +564,9 @@

function blockRegex(regex) {
return function match(source, state) {
if (state.inline || state.simple) {
return null;
} else {
return regex.exec(source);
}
};
return function match(source, state) {
if (state.inline || state.simple) {
return null;
} else {
return regex.exec(source);
}
};
}

@@ -564,63 +576,63 @@

function anyScopeRegex(regex) {
return function match(source /*, state*/) {
return regex.exec(source);
};
return function match(source /*, state*/) {
return regex.exec(source);
};
}
function reactFor(outputFunc) {
return function nestedReactOutput(ast, state) {
state = state || {};
if (Array.isArray(ast)) {
const oldKey = state.key;
const result = [];
return function nestedReactOutput(ast, state) {
state = state || {};
if (Array.isArray(ast)) {
const oldKey = state.key;
const result = [];
// map nestedOutput over the ast, except group any text
// nodes together into a single string output.
let lastWasString = false;
// map nestedOutput over the ast, except group any text
// nodes together into a single string output.
let lastWasString = false;
for (let i = 0; i < ast.length; i++) {
state.key = i;
for (let i = 0; i < ast.length; i++) {
state.key = i;
const nodeOut = nestedReactOutput(ast[i], state);
const isString = typeof nodeOut === 'string';
const nodeOut = nestedReactOutput(ast[i], state);
const isString = typeof nodeOut === 'string';
if (isString && lastWasString) {
result[result.length - 1] += nodeOut;
} else {
result.push(nodeOut);
}
if (isString && lastWasString) {
result[result.length - 1] += nodeOut;
} else {
result.push(nodeOut);
}
lastWasString = isString;
}
lastWasString = isString;
}
state.key = oldKey;
state.key = oldKey;
return result;
}
return result;
}
return outputFunc(ast, nestedReactOutput, state);
};
return outputFunc(ast, nestedReactOutput, state);
};
}
function sanitizeUrl(url) {
try {
const prot = decodeURIComponent(url)
.replace(/[^A-Z0-9/:]/gi, '')
.toLowerCase();
try {
const prot = decodeURIComponent(url)
.replace(/[^A-Z0-9/:]/gi, '')
.toLowerCase();
if (prot.indexOf('javascript:') === 0) {
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;
if (prot.indexOf('javascript:') === 0) {
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 url;
return url;
}
function unescapeUrl(rawUrlString) {
return rawUrlString.replace(UNESCAPE_URL_R, '$1');
return rawUrlString.replace(UNESCAPE_URL_R, '$1');
}

@@ -632,10 +644,10 @@

function parseInline(parse, content, state) {
const isCurrentlyInline = state.inline || false;
const isCurrentlySimple = state.simple || false;
state.inline = true;
state.simple = true;
const result = parse(content, state);
state.inline = isCurrentlyInline;
state.simple = isCurrentlySimple;
return result;
const isCurrentlyInline = state.inline || false;
const isCurrentlySimple = state.simple || false;
state.inline = true;
state.simple = true;
const result = parse(content, state);
state.inline = isCurrentlyInline;
state.simple = isCurrentlySimple;
return result;
}

@@ -647,62 +659,65 @@

function parseSimpleInline(parse, content, state) {
const isCurrentlyInline = state.inline || false;
const isCurrentlySimple = state.simple || false;
state.inline = false;
state.simple = true;
const result = parse(content, state);
state.inline = isCurrentlyInline;
state.simple = isCurrentlySimple;
return result;
const isCurrentlyInline = state.inline || false;
const isCurrentlySimple = state.simple || false;
state.inline = false;
state.simple = true;
const result = parse(content, state);
state.inline = isCurrentlyInline;
state.simple = isCurrentlySimple;
return result;
}
function parseBlock(parse, content, state) {
state.inline = false;
return parse(content + '\n\n', state);
state.inline = false;
return parse(content + '\n\n', state);
}
function parseCaptureInline(capture, parse, state) {
return {
content: parseInline(parse, capture[1], state),
};
return {
content: parseInline(parse, capture[1], state),
};
}
function captureNothing() {
return {};
return {};
}
function renderNothing() {
return null;
return null;
}
function ruleOutput(rules) {
return function nestedRuleOutput(ast, outputFunc, state) {
return rules[ast.type].react(ast, outputFunc, state);
};
return function nestedRuleOutput(ast, outputFunc, state) {
return rules[ast.type].react(ast, outputFunc, state);
};
}
function cx() {
return Array.prototype.slice
.call(arguments)
.filter(Boolean)
.join(' ');
return Array.prototype.slice
.call(arguments)
.filter(Boolean)
.join(' ');
}
function get(src, path, fb) {
let ptr = src;
const frags = path.split('.');
let ptr = src;
const frags = path.split('.');
while (frags.length) {
ptr = ptr[frags[0]];
while (frags.length) {
ptr = ptr[frags[0]];
if (ptr === undefined) break;
else frags.shift();
}
if (ptr === undefined) break;
else frags.shift();
}
return ptr || fb;
return ptr || fb;
}
function getTag(tag, overrides) {
const override = get(overrides, tag);
return typeof override === 'function'
? override
: get(overrides, `${tag}.component`, tag);
const override = get(overrides, tag);
if (!override) return tag;
return isPlainObject(override)
? get(overrides, `${tag}.component`, tag)
: override;
}

@@ -736,116 +751,111 @@

export function compiler(markdown, options) {
options = options || {};
options.overrides = options.overrides || {};
options.slugify = options.slugify || slugify;
options = options || {};
options.overrides = options.overrides || {};
options.slugify = options.slugify || slugify;
const createElementFn = options.createElement || React.createElement;
const createElementFn = options.createElement || React.createElement;
// eslint-disable-next-line no-unused-vars
function h(tag, props, ...children) {
const overrideProps = get(options.overrides, `${tag}.props`, {});
// eslint-disable-next-line no-unused-vars
function h(tag, props, ...children) {
const overrideProps = get(options.overrides, `${tag}.props`, {});
return createElementFn(
getTag(tag, options.overrides),
{
...overrideProps,
...props,
className:
cx(props && props.className, overrideProps.className) ||
undefined,
},
...children
);
}
return createElementFn(
getTag(tag, options.overrides),
{
...overrideProps,
...props,
className:
cx(props && props.className, overrideProps.className) || undefined,
},
...children
);
}
function compile(input) {
let inline = false;
function compile(input) {
let 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;
}
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;
}
const arr = emitter(
parser(
inline
? input
: `${input.replace(
TRIM_NEWLINES_AND_TRAILING_WHITESPACE_R,
''
)}\n\n`,
{ inline }
)
);
const arr = emitter(
parser(
inline
? input
: `${input.replace(TRIM_NEWLINES_AND_TRAILING_WHITESPACE_R, '')}\n\n`,
{ inline }
)
);
let jsx;
if (arr.length > 1) {
jsx = inline ? <span>{arr}</span> : <div>{arr}</div>;
} else if (arr.length === 1) {
jsx = arr[0];
let jsx;
if (arr.length > 1) {
jsx = inline ? <span>{arr}</span> : <div>{arr}</div>;
} else if (arr.length === 1) {
jsx = arr[0];
// TODO: remove this for React 16
if (typeof jsx === 'string') {
jsx = <span>{jsx}</span>;
}
} else {
// TODO: return null for React 16
jsx = <span />;
}
return jsx;
// TODO: remove this for React 16
if (typeof jsx === 'string') {
jsx = <span>{jsx}</span>;
}
} else {
// TODO: return null for React 16
jsx = <span />;
}
function attrStringToMap(str) {
const attributes = str.match(ATTR_EXTRACTOR_R);
return jsx;
}
return attributes
? attributes.reduce(function(map, raw, index) {
const delimiterIdx = raw.indexOf('=');
function attrStringToMap(str) {
const attributes = str.match(ATTR_EXTRACTOR_R);
if (delimiterIdx !== -1) {
const key = normalizeAttributeKey(
raw.slice(0, delimiterIdx)
).trim();
const value = unquote(raw.slice(delimiterIdx + 1).trim());
return attributes
? attributes.reduce(function(map, raw, index) {
const delimiterIdx = raw.indexOf('=');
const mappedKey = ATTRIBUTE_TO_JSX_PROP_MAP[key] || key;
const normalizedValue = (map[
mappedKey
] = attributeValueToJSXPropValue(key, value));
if (delimiterIdx !== -1) {
const key = normalizeAttributeKey(
raw.slice(0, delimiterIdx)
).trim();
const value = unquote(raw.slice(delimiterIdx + 1).trim());
if (
HTML_BLOCK_ELEMENT_R.test(normalizedValue) ||
HTML_SELF_CLOSING_ELEMENT_R.test(normalizedValue)
) {
map[mappedKey] = React.cloneElement(
compile(normalizedValue.trim()),
{ key: index }
);
}
} else {
map[ATTRIBUTE_TO_JSX_PROP_MAP[raw] || raw] = true;
}
const mappedKey = ATTRIBUTE_TO_JSX_PROP_MAP[key] || key;
const normalizedValue = (map[
mappedKey
] = attributeValueToJSXPropValue(key, value));
return map;
}, {})
: undefined;
}
if (
HTML_BLOCK_ELEMENT_R.test(normalizedValue) ||
HTML_SELF_CLOSING_ELEMENT_R.test(normalizedValue)
) {
map[mappedKey] = React.cloneElement(
compile(normalizedValue.trim()),
{ key: index }
);
}
} else {
map[ATTRIBUTE_TO_JSX_PROP_MAP[raw] || raw] = true;
}
/* istanbul ignore next */
if (process.env.NODE_ENV !== 'production') {
if (typeof markdown !== 'string') {
throw new Error(`markdown-to-jsx: the first argument must be
return map;
}, {})
: undefined;
}
/* istanbul ignore next */
if (process.env.NODE_ENV !== 'production') {
if (typeof markdown !== 'string') {
throw new Error(`markdown-to-jsx: the first argument must be
a string`);
}
}
if (
Object.prototype.toString.call(options.overrides) !==
'[object Object]'
) {
throw new Error(`markdown-to-jsx: options.overrides (second argument property) must be
if (
Object.prototype.toString.call(options.overrides) !== '[object Object]'
) {
throw new Error(`markdown-to-jsx: options.overrides (second argument property) must be
undefined or an object literal with shape:

@@ -858,742 +868,709 @@ {

}`);
}
}
}
const footnotes = [];
const refs = {};
const footnotes = [];
const refs = {};
/**
* each rule's react() output function goes through our custom h() JSX pragma;
* this allows the override functionality to be automatically applied
*/
const rules = {
blockQuote: {
match: blockRegex(BLOCKQUOTE_R),
order: PARSE_PRIORITY_HIGH,
parse(capture, parse, state) {
return {
content: parse(
capture[0].replace(
BLOCKQUOTE_TRIM_LEFT_MULTILINE_R,
''
),
state
),
};
},
react(node, output, state) {
return (
<blockquote key={state.key}>
{output(node.content, state)}
</blockquote>
);
},
},
/**
* each rule's react() output function goes through our custom h() JSX pragma;
* this allows the override functionality to be automatically applied
*/
const rules = {
blockQuote: {
match: blockRegex(BLOCKQUOTE_R),
order: PARSE_PRIORITY_HIGH,
parse(capture, parse, state) {
return {
content: parse(
capture[0].replace(BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, ''),
state
),
};
},
react(node, output, state) {
return (
<blockquote key={state.key}>{output(node.content, state)}</blockquote>
);
},
},
breakLine: {
match: anyScopeRegex(BREAK_LINE_R),
order: PARSE_PRIORITY_HIGH,
parse: captureNothing,
react(_, __, state) {
return <br key={state.key} />;
},
},
breakLine: {
match: anyScopeRegex(BREAK_LINE_R),
order: PARSE_PRIORITY_HIGH,
parse: captureNothing,
react(_, __, state) {
return <br key={state.key} />;
},
},
breakThematic: {
match: blockRegex(BREAK_THEMATIC_R),
order: PARSE_PRIORITY_HIGH,
parse: captureNothing,
react(_, __, state) {
return <hr key={state.key} />;
},
},
breakThematic: {
match: blockRegex(BREAK_THEMATIC_R),
order: PARSE_PRIORITY_HIGH,
parse: captureNothing,
react(_, __, state) {
return <hr key={state.key} />;
},
},
codeBlock: {
match: blockRegex(CODE_BLOCK_R),
order: PARSE_PRIORITY_MAX,
parse(capture /*, parse, state*/) {
let content = capture[0]
.replace(/^ {4}/gm, '')
.replace(/\n+$/, '');
return {
content: content,
lang: undefined,
};
},
codeBlock: {
match: blockRegex(CODE_BLOCK_R),
order: PARSE_PRIORITY_MAX,
parse(capture /*, parse, state*/) {
let content = capture[0].replace(/^ {4}/gm, '').replace(/\n+$/, '');
return {
content: content,
lang: undefined,
};
},
react(node, output, state) {
return (
<pre key={state.key}>
<code className={node.lang ? `lang-${node.lang}` : ''}>
{node.content}
</code>
</pre>
);
},
},
react(node, output, state) {
return (
<pre key={state.key}>
<code className={node.lang ? `lang-${node.lang}` : ''}>
{node.content}
</code>
</pre>
);
},
},
codeFenced: {
match: blockRegex(CODE_BLOCK_FENCED_R),
order: PARSE_PRIORITY_MAX,
parse(capture /*, parse, state*/) {
return {
content: capture[3],
lang: capture[2] || undefined,
type: 'codeBlock',
};
},
},
codeFenced: {
match: blockRegex(CODE_BLOCK_FENCED_R),
order: PARSE_PRIORITY_MAX,
parse(capture /*, parse, state*/) {
return {
content: capture[3],
lang: capture[2] || undefined,
type: 'codeBlock',
};
},
},
codeInline: {
match: simpleInlineRegex(CODE_INLINE_R),
order: PARSE_PRIORITY_LOW,
parse(capture /*, parse, state*/) {
return {
content: capture[2],
};
},
react(node, output, state) {
return <code key={state.key}>{node.content}</code>;
},
},
codeInline: {
match: simpleInlineRegex(CODE_INLINE_R),
order: PARSE_PRIORITY_LOW,
parse(capture /*, parse, state*/) {
return {
content: capture[2],
};
},
react(node, output, state) {
return <code key={state.key}>{node.content}</code>;
},
},
/**
* footnotes are emitted at the end of compilation in a special <footer> block
*/
footnote: {
match: blockRegex(FOOTNOTE_R),
order: PARSE_PRIORITY_MAX,
parse(capture /*, parse, state*/) {
footnotes.push({
footnote: capture[2],
identifier: capture[1],
});
/**
* footnotes are emitted at the end of compilation in a special <footer> block
*/
footnote: {
match: blockRegex(FOOTNOTE_R),
order: PARSE_PRIORITY_MAX,
parse(capture /*, parse, state*/) {
footnotes.push({
footnote: capture[2],
identifier: capture[1],
});
return {};
},
react: renderNothing,
},
return {};
},
react: renderNothing,
},
footnoteReference: {
match: inlineRegex(FOOTNOTE_REFERENCE_R),
order: PARSE_PRIORITY_HIGH,
parse(capture /*, parse*/) {
return {
content: capture[1],
target: `#${capture[1]}`,
};
},
react(node, output, state) {
return (
<a key={state.key} href={sanitizeUrl(node.target)}>
<sup key={state.key}>{node.content}</sup>
</a>
);
},
},
footnoteReference: {
match: inlineRegex(FOOTNOTE_REFERENCE_R),
order: PARSE_PRIORITY_HIGH,
parse(capture /*, parse*/) {
return {
content: capture[1],
target: `#${capture[1]}`,
};
},
react(node, output, state) {
return (
<a key={state.key} href={sanitizeUrl(node.target)}>
<sup key={state.key}>{node.content}</sup>
</a>
);
},
},
gfmTask: {
match: inlineRegex(GFM_TASK_R),
order: PARSE_PRIORITY_HIGH,
parse(capture /*, parse, state*/) {
return {
completed: capture[1].toLowerCase() === 'x',
};
},
react(node, output, state) {
return (
<input
checked={node.completed}
key={state.key}
readOnly
type="checkbox"
/>
);
},
},
gfmTask: {
match: inlineRegex(GFM_TASK_R),
order: PARSE_PRIORITY_HIGH,
parse(capture /*, parse, state*/) {
return {
completed: capture[1].toLowerCase() === 'x',
};
},
react(node, output, state) {
return (
<input
checked={node.completed}
key={state.key}
readOnly
type="checkbox"
/>
);
},
},
heading: {
match: blockRegex(HEADING_R),
order: PARSE_PRIORITY_HIGH,
parse(capture, parse, state) {
return {
content: parseInline(parse, capture[2], state),
id: options.slugify(capture[2]),
level: capture[1].length,
};
},
react(node, output, state) {
const Tag = `h${node.level}`;
return (
<Tag id={node.id} key={state.key}>
{output(node.content, state)}
</Tag>
);
},
},
heading: {
match: blockRegex(HEADING_R),
order: PARSE_PRIORITY_HIGH,
parse(capture, parse, state) {
return {
content: parseInline(parse, capture[2], state),
id: options.slugify(capture[2]),
level: capture[1].length,
};
},
react(node, output, state) {
const Tag = `h${node.level}`;
return (
<Tag id={node.id} key={state.key}>
{output(node.content, state)}
</Tag>
);
},
},
headingSetext: {
match: blockRegex(HEADING_SETEXT_R),
order: PARSE_PRIORITY_MAX,
parse(capture, parse, state) {
return {
content: parseInline(parse, capture[1], state),
level: capture[2] === '=' ? 1 : 2,
type: 'heading',
};
},
},
headingSetext: {
match: blockRegex(HEADING_SETEXT_R),
order: PARSE_PRIORITY_MAX,
parse(capture, parse, state) {
return {
content: parseInline(parse, capture[1], state),
level: capture[2] === '=' ? 1 : 2,
type: 'heading',
};
},
},
htmlBlock: {
/**
* find the first matching end tag and process the interior
*/
match: anyScopeRegex(HTML_BLOCK_ELEMENT_R),
order: PARSE_PRIORITY_HIGH,
parse(capture, parse, state) {
const [, whitespace] = capture[3].match(HTML_LEFT_TRIM_AMOUNT_R)
const trimmer = new RegExp(`^${whitespace}`, 'gm')
const trimmed = capture[3].replace(trimmer, '');
htmlBlock: {
/**
* find the first matching end tag and process the interior
*/
match: anyScopeRegex(HTML_BLOCK_ELEMENT_R),
order: PARSE_PRIORITY_HIGH,
parse(capture, parse, state) {
const [, whitespace] = capture[3].match(HTML_LEFT_TRIM_AMOUNT_R);
const trimmer = new RegExp(`^${whitespace}`, 'gm');
const trimmed = capture[3].replace(trimmer, '');
const parseFunc = containsBlockSyntax(trimmed)
? parseBlock
: parseInline;
const parseFunc = containsBlockSyntax(trimmed)
? parseBlock
: parseInline;
const noInnerParse =
DO_NOT_PROCESS_HTML_ELEMENTS.indexOf(capture[1]) !== -1;
const noInnerParse =
DO_NOT_PROCESS_HTML_ELEMENTS.indexOf(capture[1]) !== -1;
return {
attrs: attrStringToMap(capture[2]),
/**
* if another html block is detected within, parse as block,
* otherwise parse as inline to pick up any further markdown
*/
content: noInnerParse
? capture[3]
: parseFunc(parse, trimmed, state),
return {
attrs: attrStringToMap(capture[2]),
/**
* if another html block is detected within, parse as block,
* otherwise parse as inline to pick up any further markdown
*/
content: noInnerParse ? capture[3] : parseFunc(parse, trimmed, state),
noInnerParse,
noInnerParse,
tag: capture[1],
};
},
react(node, output, state) {
return (
<node.tag key={state.key} {...node.attrs}>
{node.noInnerParse
? node.content
: output(node.content, state)}
</node.tag>
);
},
},
tag: capture[1],
};
},
react(node, output, state) {
return (
<node.tag key={state.key} {...node.attrs}>
{node.noInnerParse ? node.content : output(node.content, state)}
</node.tag>
);
},
},
htmlComment: {
match: anyScopeRegex(HTML_COMMENT_R),
order: PARSE_PRIORITY_HIGH,
parse() {
return {};
},
react: renderNothing,
},
htmlComment: {
match: anyScopeRegex(HTML_COMMENT_R),
order: PARSE_PRIORITY_HIGH,
parse() {
return {};
},
react: renderNothing,
},
htmlSelfClosing: {
/**
* find the first matching end tag and process the interior
*/
match: anyScopeRegex(HTML_SELF_CLOSING_ELEMENT_R),
order: PARSE_PRIORITY_HIGH,
parse(capture /*, parse, state*/) {
return {
attrs: attrStringToMap(capture[2] || ''),
tag: capture[1],
};
},
react(node, output, state) {
return <node.tag {...node.attrs} key={state.key} />;
},
},
htmlSelfClosing: {
/**
* find the first matching end tag and process the interior
*/
match: anyScopeRegex(HTML_SELF_CLOSING_ELEMENT_R),
order: PARSE_PRIORITY_HIGH,
parse(capture /*, parse, state*/) {
return {
attrs: attrStringToMap(capture[2] || ''),
tag: capture[1],
};
},
react(node, output, state) {
return <node.tag {...node.attrs} key={state.key} />;
},
},
image: {
match: simpleInlineRegex(IMAGE_R),
order: PARSE_PRIORITY_HIGH,
parse(capture /*, parse, state*/) {
return {
alt: capture[1],
target: unescapeUrl(capture[2]),
title: capture[3],
};
},
react(node, output, state) {
return (
<img
key={state.key}
alt={node.alt || undefined}
title={node.title || undefined}
src={sanitizeUrl(node.target)}
/>
);
},
},
image: {
match: simpleInlineRegex(IMAGE_R),
order: PARSE_PRIORITY_HIGH,
parse(capture /*, parse, state*/) {
return {
alt: capture[1],
target: unescapeUrl(capture[2]),
title: capture[3],
};
},
react(node, output, state) {
return (
<img
key={state.key}
alt={node.alt || undefined}
title={node.title || undefined}
src={sanitizeUrl(node.target)}
/>
);
},
},
link: {
match: inlineRegex(LINK_R, false),
order: PARSE_PRIORITY_LOW,
parse(capture, parse, state) {
return {
content: parseSimpleInline(parse, capture[1], state),
target: unescapeUrl(capture[2]),
title: capture[3],
};
},
react(node, output, state) {
return (
<a
key={state.key}
href={sanitizeUrl(node.target)}
title={node.title}
>
{output(node.content, state)}
</a>
);
},
},
link: {
match: inlineRegex(LINK_R, false),
order: PARSE_PRIORITY_LOW,
parse(capture, parse, state) {
return {
content: parseSimpleInline(parse, capture[1], state),
target: unescapeUrl(capture[2]),
title: capture[3],
};
},
react(node, output, state) {
return (
<a key={state.key} href={sanitizeUrl(node.target)} title={node.title}>
{output(node.content, state)}
</a>
);
},
},
// https://daringfireball.net/projects/markdown/syntax#autolink
linkAngleBraceStyleDetector: {
match: inlineRegex(LINK_AUTOLINK_R),
order: PARSE_PRIORITY_MAX,
parse(capture /*, parse, state*/) {
return {
content: [
{
content: capture[1],
type: 'text',
},
],
target: capture[1],
type: 'link',
};
// https://daringfireball.net/projects/markdown/syntax#autolink
linkAngleBraceStyleDetector: {
match: inlineRegex(LINK_AUTOLINK_R),
order: PARSE_PRIORITY_MAX,
parse(capture /*, parse, state*/) {
return {
content: [
{
content: capture[1],
type: 'text',
},
},
],
target: capture[1],
type: 'link',
};
},
},
linkBareUrlDetector: {
match: inlineRegex(LINK_AUTOLINK_BARE_URL_R),
order: PARSE_PRIORITY_MAX,
parse(capture /*, parse, state*/) {
return {
content: [
{
content: capture[1],
type: 'text',
},
],
target: capture[1],
title: undefined,
type: 'link',
};
linkBareUrlDetector: {
match: inlineRegex(LINK_AUTOLINK_BARE_URL_R),
order: PARSE_PRIORITY_MAX,
parse(capture /*, parse, state*/) {
return {
content: [
{
content: capture[1],
type: 'text',
},
},
],
target: capture[1],
title: undefined,
type: 'link',
};
},
},
linkMailtoDetector: {
match: inlineRegex(LINK_AUTOLINK_MAILTO_R),
order: PARSE_PRIORITY_MAX,
parse(capture /*, parse, state*/) {
let address = capture[1];
let target = capture[1];
linkMailtoDetector: {
match: inlineRegex(LINK_AUTOLINK_MAILTO_R),
order: PARSE_PRIORITY_MAX,
parse(capture /*, parse, state*/) {
let address = capture[1];
let target = capture[1];
// Check for a `mailto:` already existing in the link:
if (!AUTOLINK_MAILTO_CHECK_R.test(target)) {
target = 'mailto:' + target;
}
// Check for a `mailto:` already existing in the link:
if (!AUTOLINK_MAILTO_CHECK_R.test(target)) {
target = 'mailto:' + target;
}
return {
content: [
{
content: address.replace('mailto:', ''),
type: 'text',
},
],
target: target,
type: 'link',
};
return {
content: [
{
content: address.replace('mailto:', ''),
type: 'text',
},
},
],
target: target,
type: 'link',
};
},
},
list: {
match(source, state, prevCapture) {
// 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.
const isStartOfLine = LIST_LOOKBEHIND_R.exec(prevCapture);
const isListBlock = state._list || !state.inline;
list: {
match(source, state, prevCapture) {
// 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.
const isStartOfLine = LIST_LOOKBEHIND_R.exec(prevCapture);
const isListBlock = state._list || !state.inline;
if (isStartOfLine && isListBlock) {
source = isStartOfLine[1] + source;
if (isStartOfLine && isListBlock) {
source = isStartOfLine[1] + source;
return LIST_R.exec(source);
} else {
return null;
}
},
order: PARSE_PRIORITY_HIGH,
parse(capture, parse, state) {
const bullet = capture[2];
const ordered = bullet.length > 1;
const start = ordered ? +bullet : undefined;
const 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);
return LIST_R.exec(source);
} else {
return null;
}
},
order: PARSE_PRIORITY_HIGH,
parse(capture, parse, state) {
const bullet = capture[2];
const ordered = bullet.length > 1;
const start = ordered ? +bullet : undefined;
const 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);
let lastItemWasAParagraph = false;
const itemContent = items.map(function(item, i) {
// We need to see how far indented the item is:
const space = LIST_ITEM_PREFIX_R.exec(item)[0].length;
let lastItemWasAParagraph = false;
const itemContent = items.map(function(item, i) {
// We need to see how far indented the item is:
const space = LIST_ITEM_PREFIX_R.exec(item)[0].length;
// And then we construct a regex to "unindent" the subsequent
// lines of the items by that amount:
const spaceRegex = new RegExp('^ {1,' + space + '}', 'gm');
// And then we construct a regex to "unindent" the subsequent
// lines of the items by that amount:
const spaceRegex = new RegExp('^ {1,' + space + '}', 'gm');
// Before processing the item, we need a couple things
const content = item
// remove indents on trailing lines:
.replace(spaceRegex, '')
// remove the bullet:
.replace(LIST_ITEM_PREFIX_R, '');
// Before processing the item, we need a couple things
const 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
const isLastItem = i === items.length - 1;
const containsBlocks = content.indexOf('\n\n') !== -1;
// Handling "loose" lists, like:
//
// * this is wrapped in a paragraph
//
// * as is this
//
// * as is this
const isLastItem = i === items.length - 1;
const containsBlocks = content.indexOf('\n\n') !== -1;
// 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).
const thisItemIsAParagraph =
containsBlocks || (isLastItem && lastItemWasAParagraph);
lastItemWasAParagraph = thisItemIsAParagraph;
// 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).
const thisItemIsAParagraph =
containsBlocks || (isLastItem && lastItemWasAParagraph);
lastItemWasAParagraph = thisItemIsAParagraph;
// backup our state for restoration afterwards. We're going to
// want to set state._list to true, and state.inline depending
// on our list's looseness.
const oldStateInline = state.inline;
const oldStateList = state._list;
state._list = true;
// backup our state for restoration afterwards. We're going to
// want to set state._list to true, and state.inline depending
// on our list's looseness.
const oldStateInline = state.inline;
const oldStateList = state._list;
state._list = true;
// Parse inline if we're in a tight list, or block if we're in
// a loose list.
let adjustedContent;
if (thisItemIsAParagraph) {
state.inline = false;
adjustedContent = content.replace(
LIST_ITEM_END_R,
'\n\n'
);
} else {
state.inline = true;
adjustedContent = content.replace(LIST_ITEM_END_R, '');
}
// Parse inline if we're in a tight list, or block if we're in
// a loose list.
let adjustedContent;
if (thisItemIsAParagraph) {
state.inline = false;
adjustedContent = content.replace(LIST_ITEM_END_R, '\n\n');
} else {
state.inline = true;
adjustedContent = content.replace(LIST_ITEM_END_R, '');
}
const result = parse(adjustedContent, state);
const result = parse(adjustedContent, state);
// Restore our state before returning
state.inline = oldStateInline;
state._list = oldStateList;
// Restore our state before returning
state.inline = oldStateInline;
state._list = oldStateList;
return result;
});
return result;
});
return {
items: itemContent,
ordered: ordered,
start: start,
};
},
react(node, output, state) {
const Tag = node.ordered ? 'ol' : 'ul';
return {
items: itemContent,
ordered: ordered,
start: start,
};
},
react(node, output, state) {
const Tag = node.ordered ? 'ol' : 'ul';
return (
<Tag key={state.key} start={node.start}>
{node.items.map(function generateListItem(item, i) {
return <li key={i}>{output(item, state)}</li>;
})}
</Tag>
);
},
},
return (
<Tag key={state.key} start={node.start}>
{node.items.map(function generateListItem(item, i) {
return <li key={i}>{output(item, state)}</li>;
})}
</Tag>
);
},
},
newlineCoalescer: {
match: blockRegex(CONSECUTIVE_NEWLINE_R),
order: PARSE_PRIORITY_LOW,
parse: captureNothing,
react(/*node, output, state*/) {
return '\n';
},
},
newlineCoalescer: {
match: blockRegex(CONSECUTIVE_NEWLINE_R),
order: PARSE_PRIORITY_LOW,
parse: captureNothing,
react(/*node, output, state*/) {
return '\n';
},
},
paragraph: {
match: blockRegex(PARAGRAPH_R),
order: PARSE_PRIORITY_LOW,
parse: parseCaptureInline,
react(node, output, state) {
return <p key={state.key}>{output(node.content, state)}</p>;
},
},
paragraph: {
match: blockRegex(PARAGRAPH_R),
order: PARSE_PRIORITY_LOW,
parse: parseCaptureInline,
react(node, output, state) {
return <p key={state.key}>{output(node.content, state)}</p>;
},
},
ref: {
match: inlineRegex(REFERENCE_IMAGE_OR_LINK),
order: PARSE_PRIORITY_MAX,
parse(capture /*, parse*/) {
refs[capture[1]] = {
target: capture[2],
title: capture[4],
};
ref: {
match: inlineRegex(REFERENCE_IMAGE_OR_LINK),
order: PARSE_PRIORITY_MAX,
parse(capture /*, parse*/) {
refs[capture[1]] = {
target: capture[2],
title: capture[4],
};
return {};
},
react: renderNothing,
},
return {};
},
react: renderNothing,
},
refImage: {
match: simpleInlineRegex(REFERENCE_IMAGE_R),
order: PARSE_PRIORITY_MAX,
parse(capture) {
return {
alt: capture[1] || undefined,
ref: capture[2],
};
},
react(node, output, state) {
return (
<img
key={state.key}
alt={node.alt}
src={sanitizeUrl(refs[node.ref].target)}
title={refs[node.ref].title}
/>
);
},
},
refImage: {
match: simpleInlineRegex(REFERENCE_IMAGE_R),
order: PARSE_PRIORITY_MAX,
parse(capture) {
return {
alt: capture[1] || undefined,
ref: capture[2],
};
},
react(node, output, state) {
return (
<img
key={state.key}
alt={node.alt}
src={sanitizeUrl(refs[node.ref].target)}
title={refs[node.ref].title}
/>
);
},
},
refLink: {
match: inlineRegex(REFERENCE_LINK_R),
order: PARSE_PRIORITY_MAX,
parse(capture, parse, state) {
return {
content: parse(capture[1], state),
ref: capture[2],
};
},
react(node, output, state) {
return (
<a
key={state.key}
href={sanitizeUrl(refs[node.ref].target)}
title={refs[node.ref].title}
>
{output(node.content, state)}
</a>
);
},
},
refLink: {
match: inlineRegex(REFERENCE_LINK_R),
order: PARSE_PRIORITY_MAX,
parse(capture, parse, state) {
return {
content: parse(capture[1], state),
ref: capture[2],
};
},
react(node, output, state) {
return (
<a
key={state.key}
href={sanitizeUrl(refs[node.ref].target)}
title={refs[node.ref].title}
>
{output(node.content, state)}
</a>
);
},
},
table: {
match: blockRegex(NP_TABLE_R),
order: PARSE_PRIORITY_HIGH,
parse: parseTable,
react(node, output, state) {
table: {
match: blockRegex(NP_TABLE_R),
order: PARSE_PRIORITY_HIGH,
parse: parseTable,
react(node, output, state) {
return (
<table key={state.key}>
<thead>
<tr>
{node.header.map(function generateHeaderCell(content, i) {
return (
<th key={i} style={getTableStyle(node, i)} scope="col">
{output(content, state)}
</th>
);
})}
</tr>
</thead>
<tbody>
{node.cells.map(function generateTableRow(row, i) {
return (
<table key={state.key}>
<thead>
<tr>
{node.header.map(function generateHeaderCell(
content,
i
) {
return (
<th
key={i}
style={getTableStyle(node, i)}
scope="col"
>
{output(content, state)}
</th>
);
})}
</tr>
</thead>
<tbody>
{node.cells.map(function generateTableRow(row, i) {
return (
<tr key={i}>
{row.map(function generateTableCell(
content,
c
) {
return (
<td
key={c}
style={getTableStyle(
node,
c
)}
>
{output(content, state)}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
<tr key={i}>
{row.map(function generateTableCell(content, c) {
return (
<td key={c} style={getTableStyle(node, c)}>
{output(content, state)}
</td>
);
})}
</tr>
);
},
},
})}
</tbody>
</table>
);
},
},
text: {
// Here we look for anything followed by non-symbols,
// double newlines, or double-space-newlines
// We break on any symbol characters so that this grammar
// is easy to extend without needing to modify this regex
match: anyScopeRegex(TEXT_PLAIN_R),
order: PARSE_PRIORITY_MIN,
parse(capture /*, parse, state*/) {
return {
content: capture[0],
};
},
react(node /*, output, state*/) {
return node.content;
},
},
text: {
// Here we look for anything followed by non-symbols,
// double newlines, or double-space-newlines
// We break on any symbol characters so that this grammar
// is easy to extend without needing to modify this regex
match: anyScopeRegex(TEXT_PLAIN_R),
order: PARSE_PRIORITY_MIN,
parse(capture /*, parse, state*/) {
return {
// nbsp -> unicode equivalent for named chars
content: capture[0].replace(HTML_CHAR_CODE_R, (full, inner) => {
return namedCodesToUnicode[inner]
? namedCodesToUnicode[inner]
: full;
}),
};
},
react(node /*, output, state*/) {
return node.content;
},
},
textBolded: {
match: simpleInlineRegex(TEXT_BOLD_R),
order: PARSE_PRIORITY_MED,
parse(capture, parse, state) {
return {
// capture[1] -> the syntax control character
// capture[2] -> inner content
content: parse(capture[2], state),
};
},
react(node, output, state) {
return (
<strong key={state.key}>
{output(node.content, state)}
</strong>
);
},
},
textBolded: {
match: simpleInlineRegex(TEXT_BOLD_R),
order: PARSE_PRIORITY_MED,
parse(capture, parse, state) {
return {
// capture[1] -> the syntax control character
// capture[2] -> inner content
content: parse(capture[2], state),
};
},
react(node, output, state) {
return <strong key={state.key}>{output(node.content, state)}</strong>;
},
},
textEmphasized: {
match: simpleInlineRegex(TEXT_EMPHASIZED_R),
order: PARSE_PRIORITY_LOW,
parse(capture, parse, state) {
return {
// capture[1] -> opening * or _
// capture[2] -> inner content
content: parse(capture[2], state),
};
},
react(node, output, state) {
return <em key={state.key}>{output(node.content, state)}</em>;
},
},
textEmphasized: {
match: simpleInlineRegex(TEXT_EMPHASIZED_R),
order: PARSE_PRIORITY_LOW,
parse(capture, parse, state) {
return {
// capture[1] -> opening * or _
// capture[2] -> inner content
content: parse(capture[2], state),
};
},
react(node, output, state) {
return <em key={state.key}>{output(node.content, state)}</em>;
},
},
textEscaped: {
// We don't allow escaping numbers, letters, or spaces here so that
// backslashes used in plain text still get rendered. But allowing
// escaping anything else provides a very flexible escape mechanism,
// regardless of how this grammar is extended.
match: simpleInlineRegex(TEXT_ESCAPED_R),
order: PARSE_PRIORITY_HIGH,
parse(capture /*, parse, state*/) {
return {
content: capture[1],
type: 'text',
};
},
},
textEscaped: {
// We don't allow escaping numbers, letters, or spaces here so that
// backslashes used in plain text still get rendered. But allowing
// escaping anything else provides a very flexible escape mechanism,
// regardless of how this grammar is extended.
match: simpleInlineRegex(TEXT_ESCAPED_R),
order: PARSE_PRIORITY_HIGH,
parse(capture /*, parse, state*/) {
return {
content: capture[1],
type: 'text',
};
},
},
textStrikethroughed: {
match: simpleInlineRegex(TEXT_STRIKETHROUGHED_R),
order: PARSE_PRIORITY_LOW,
parse: parseCaptureInline,
react(node, output, state) {
return <del key={state.key}>{output(node.content, state)}</del>;
},
},
};
textStrikethroughed: {
match: simpleInlineRegex(TEXT_STRIKETHROUGHED_R),
order: PARSE_PRIORITY_LOW,
parse: parseCaptureInline,
react(node, output, state) {
return <del key={state.key}>{output(node.content, state)}</del>;
},
},
};
// Object.keys(rules).forEach(key => {
// let { match, parse } = rules[key];
// Object.keys(rules).forEach(key => {
// let { match, parse } = rules[key];
// rules[key].match = (...args) => {
// const start = performance.now();
// const result = match(...args);
// const delta = performance.now() - start;
// rules[key].match = (...args) => {
// const start = performance.now();
// const result = match(...args);
// const delta = performance.now() - start;
// if (delta > 5)
// console.warn(
// `Slow match for ${key}: ${delta.toFixed(3)}ms, input: ${
// args[0]
// }`
// );
// if (delta > 5)
// console.warn(
// `Slow match for ${key}: ${delta.toFixed(3)}ms, input: ${
// args[0]
// }`
// );
// return result;
// };
// return result;
// };
// rules[key].parse = (...args) => {
// const start = performance.now();
// const result = parse(...args);
// const delta = performance.now() - start;
// rules[key].parse = (...args) => {
// const start = performance.now();
// const result = parse(...args);
// const delta = performance.now() - start;
// if (delta > 5)
// console.warn(`Slow parse for ${key}: ${delta.toFixed(3)}ms`);
// if (delta > 5)
// console.warn(`Slow parse for ${key}: ${delta.toFixed(3)}ms`);
// console.log(`${key}:parse`, `${delta.toFixed(3)}ms`, args[0]);
// console.log(`${key}:parse`, `${delta.toFixed(3)}ms`, args[0]);
// return result;
// };
// });
// return result;
// };
// });
const parser = parserFor(rules);
const emitter = reactFor(ruleOutput(rules));
const parser = parserFor(rules);
const emitter = reactFor(ruleOutput(rules));
const jsx = compile(markdown);
const jsx = compile(markdown);
if (footnotes.length) {
jsx.props.children.push(
<footer>
{footnotes.map(function createFootnote(def) {
return (
<div id={def.identifier} key={def.identifier}>
{def.identifier}
{emitter(parser(def.footnote, { inline: true }))}
</div>
);
})}
</footer>
);
}
if (footnotes.length) {
jsx.props.children.push(
<footer>
{footnotes.map(function createFootnote(def) {
return (
<div id={def.identifier} key={def.identifier}>
{def.identifier}
{emitter(parser(def.footnote, { inline: true }))}
</div>
);
})}
</footer>
);
}
return jsx;
return jsx;
}

@@ -1612,12 +1589,12 @@

export default function Markdown({ children, options, ...props }) {
return React.cloneElement(compiler(children, options), props);
return React.cloneElement(compiler(children, options), props);
}
if (process.env.NODE_ENV !== 'production') {
const PropTypes = require('prop-types');
const PropTypes = require('prop-types');
Markdown.propTypes = {
children: PropTypes.string.isRequired,
options: PropTypes.object,
};
Markdown.propTypes = {
children: PropTypes.string.isRequired,
options: PropTypes.object,
};
}

@@ -6,3 +6,3 @@ {

"license": "MIT",
"version": "6.7.4",
"version": "6.8.0",
"engines": {

@@ -24,45 +24,46 @@ "node": ">= 4"

"index.js",
"index.cjs.js",
"index.js.js.map",
"index.esm.js",
"index.esm.js.map",
"dist",
"LICENSE",
"README.md"
],
"main": "index.cjs.js",
"jsnext:main": "index.esm.js",
"module": "index.esm.js",
"main": "dist/cjs.js",
"jsnext:main": "dist/esm.js",
"module": "dist/esm.js",
"devDependencies": {
"babel-cli": "^6.14.0",
"babel-core": "^6.26.0",
"babel-eslint": "^8.2.2",
"babel-jest": "^22.4.3",
"babel-eslint": "^10.0.1",
"babel-jest": "^23.6.0",
"babel-loader": "^7.1.4",
"babel-plugin-emotion": "^9.1.2",
"babel-plugin-transform-react-remove-prop-types": "^0.4.13",
"babel-plugin-emotion": "^9.2.11",
"babel-plugin-transform-react-remove-prop-types": "^0.4.19",
"babel-preset-env": "^1.7.0",
"babel-preset-minify": "^0.5.0",
"babel-preset-react": "^6.11.1",
"babel-preset-stage-2": "^6.13.0",
"codecov": "^3.0.1",
"emotion": "^9.1.2",
"eslint": "^4.12.1",
"eslint-config-prettier": "^2.9.0",
"eslint-plugin-react": "^7.5.1",
"codecov": "^3.1.0",
"emotion": "^9.2.12",
"eslint": "^5.7.0",
"eslint-config-prettier": "^3.1.0",
"eslint-plugin-react": "^7.11.1",
"in-publish": "^2.0.0",
"jest": "^22.4.3",
"jest": "^23.6.0",
"jest-serializer-html": "^5.0.0",
"mkdirp": "^0.5.1",
"polished": "^1.3.0",
"preact": "^8.2.1",
"preact-compat": "^3.16.0",
"preact-emotion": "^9.1.2",
"preact": "^8.3.1",
"preact-compat": "^3.18.4",
"preact-emotion": "^9.2.12",
"prettier": "^1.14.3",
"react": "^15.6.1",
"react-dom": "^15.6.1",
"size-limit": "^0.17.0",
"uglify-js": "^3.3.15",
"webpack": "^4.1.1",
"webpack-cli": "^2.0.12",
"webpack-dev-server": "^3.1.1"
"rimraf": "^2.6.2",
"size-limit": "^0.20.1",
"uglify-js": "^3.4.9",
"webpack": "^4.21.0",
"webpack-cli": "^3.1.2",
"webpack-dev-server": "^3.1.9"
},
"dependencies": {
"prop-types": "^15.5.10",
"prop-types": "^15.6.2",
"unquote": "^1.1.0"

@@ -75,4 +76,5 @@ },

"prepublish": "in-publish && npm run build && npm run release || not-in-publish",
"lint": "eslint index.js index.spec.js site.js",
"build": "babel index.js --out-file index.cjs.js --source-maps && BABEL_ENV=esm babel index.js --out-file index.esm.js --source-maps",
"lint": "eslint .",
"prebuild": "rimraf dist && mkdirp dist",
"build": "NODE_ENV=production babel index.js --out-file dist/cjs.js --source-maps && NODE_ENV=production BABEL_ENV=esm babel index.js --out-file dist/esm.js --source-maps",
"release": "webpack --config ./webpack.config.prod.babel.js -p --display-optimization-bailout",

@@ -86,3 +88,3 @@ "release:debug": "webpack --config ./webpack.config.babel.js --display-optimization-bailout",

{
"path": "index.cjs.js",
"path": "dist/cjs.js",
"limit": "5 kB"

@@ -89,0 +91,0 @@ }

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc