markdown-to-jsx 6.10.0 → 6.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -167,11 +167,12 @@ const REFERENCE_LINK_R = /^\[([^\]]*)\] ?\[([^\]]*)\]/;
167
167
  const SQUARE_BRACKETS_R = /(\[|\])/g;
168
168
  const SHOULD_RENDER_AS_BLOCK_R = /(\n|^[-*]\s|^#|^ {2,}|^-{2,}|^>\s)/;
169
169
  const TAB_R = /\t/g;
170
+ const TABLE_SEPARATOR_R = /^ *\| */;
170
171
  const TABLE_TRIM_PIPES = /(^ *\||\| *$)/g;
172
+ const TABLE_CELL_END_TRIM = / *$/;
171
173
  const TABLE_CENTER_ALIGN = /^ *:-+: *$/;
172
174
  const TABLE_LEFT_ALIGN = /^ *:-+ *$/;
173
175
  const TABLE_RIGHT_ALIGN = /^ *-+: *$/;
174
- const TABLE_ROW_SPLIT = / *\| */;
175
176
 
176
177
  const TEXT_BOLD_R = /^([*_])\1((?:\[.*?\][([].*?[)\]]|<.*?>(?:.*?<.*?>)?|`.*?`|~+.*?~+|.)*?)\1\1(?!\1)/;
177
178
  const TEXT_EMPHASIZED_R = /^([*_])((?:\[.*?\][([].*?[)\]]|<.*?>(?:.*?<.*?>)?|`.*?`|~+.*?~+|.)*?)\1(?!\1)/;
@@ -179,7 +180,7 @@ const TEXT_STRIKETHROUGHED_R = /^~~((?:\[.*?\]|<.*?>(?:.*?<.*?>)?|`.*?`|.)*?)~~/
179
180
 
180
181
  const TEXT_ESCAPED_R = /^\\([^0-9A-Za-z\s])/;
181
182
  const TEXT_PLAIN_R = /^[\s\S]+?(?=[^0-9A-Z\s\u00c0-\uffff&;.()'"]|\d+\.|\n\n| {2,}\n|\w+:\S|$)/i;
182
- const TRIM_NEWLINES_AND_TRAILING_WHITESPACE_R = /(^\n+|(\n|\s)+$)/g;
183
+ const TRIM_NEWLINES_AND_TRAILING_WHITESPACE_R = /(^\n+|\n+$|\s+$)/g;
183
184
 
184
185
  const HTML_LEFT_TRIM_AMOUNT_R = /^([ \t]*)/;
185
186
 
@@ -287,46 +288,56 @@ function parseTableAlignCapture(alignCapture) {
287
288
  return null;
288
289
  }
289
290
 
290
- function parseTableHeader(capture, parse, state) {
291
- const headerText = capture[1]
292
- .replace(TABLE_TRIM_PIPES, '')
293
- .trim()
294
- .split(TABLE_ROW_SPLIT);
295
-
296
- return headerText.map(function(text) {
297
- return parse(text, state);
291
+ function parseTableRow(source, parse, state) {
292
+ const prevInTable = state.inTable;
293
+ state.inTable = true;
294
+ const tableRow = parse(source.trim(), state);
295
+ state.inTable = prevInTable;
296
+
297
+ let cells = [[]];
298
+ tableRow.forEach(function(node, i) {
299
+ if (node.type === 'tableSeparator') {
300
+ // Filter out empty table separators at the start/end:
301
+ if (i !== 0 && i !== tableRow.length - 1) {
302
+ // Split the current row:
303
+ cells.push([]);
304
+ }
305
+ } else {
306
+ if (node.type === 'text' && (
307
+ tableRow[i + 1] == null ||
308
+ tableRow[i + 1].type === 'tableSeparator'
309
+ )) {
310
+ node.content = node.content.replace(TABLE_CELL_END_TRIM, "");
311
+ }
312
+ cells[cells.length - 1].push(node);
313
+ }
298
314
  });
315
+ return cells;
299
316
  }
300
317
 
301
- function parseTableAlign(capture /*, parse, state*/) {
302
- const alignText = capture[2]
318
+ function parseTableAlign(source /*, parse, state*/) {
319
+ const alignText = source
303
320
  .replace(TABLE_TRIM_PIPES, '')
304
- .trim()
305
- .split(TABLE_ROW_SPLIT);
321
+ .split('|');
306
322
 
307
323
  return alignText.map(parseTableAlignCapture);
308
324
  }
309
325
 
310
- function parseTableCells(capture, parse, state) {
311
- const rowsText = capture[3]
326
+ function parseTableCells(source, parse, state) {
327
+ const rowsText = source
312
328
  .trim()
313
329
  .split('\n');
314
330
 
315
331
  return rowsText.map(function(rowText) {
316
- return rowText
317
- .replace(TABLE_TRIM_PIPES, '')
318
- .split(TABLE_ROW_SPLIT)
319
- .map(function(text) {
320
- return parse(text.trim(), state);
321
- });
332
+ return parseTableRow(rowText, parse, state);
322
333
  });
323
334
  }
324
335
 
325
336
  function parseTable(capture, parse, state) {
326
337
  state.inline = true;
327
- const header = parseTableHeader(capture, parse, state);
328
- const align = parseTableAlign(capture, parse, state);
329
- const cells = parseTableCells(capture, parse, state);
338
+ const header = parseTableRow(capture[1], parse, state);
339
+ const align = parseTableAlign(capture[2], parse, state);
340
+ const cells = parseTableCells(capture[3], parse, state);
330
341
  state.inline = false;
331
342
 
332
343
  return {
@@ -374,6 +385,8 @@ function attributeValueToJSXPropValue(key, value) {
374
385
 
375
386
  return styles;
376
387
  }, {});
388
+ } else if (key === 'href') {
389
+ return sanitizeUrl(value)
377
390
  } else if (value.match(INTERPOLATION_R)) {
378
391
  // return as a string and let the consumer decide what to do with it
379
392
  value = value.slice(1, value.length - 1);
@@ -716,6 +729,9 @@ export function compiler(markdown, options) {
716
729
  options = options || {};
717
730
  options.overrides = options.overrides || {};
718
731
  options.slugify = options.slugify || slugify;
732
+ options.namedCodesToUnicode = options.namedCodesToUnicode
733
+ ? {...namedCodesToUnicode, ...options.namedCodesToUnicode}
734
+ : namedCodesToUnicode;
719
735
 
720
736
  const createElementFn = options.createElement || React.createElement;
721
737
 
@@ -811,6 +827,10 @@ export function compiler(markdown, options) {
811
827
  : undefined;
812
828
  }
813
829
 
830
+ function stripHtmlComments(html) {
831
+ return html.replace(/<!--[\s\S]*?(?:-->)/g, '')
832
+ }
833
+
814
834
  /* istanbul ignore next */
815
835
  if (process.env.NODE_ENV !== 'production') {
816
836
  if (typeof markdown !== 'string') {
@@ -1010,47 +1030,6 @@ export function compiler(markdown, options) {
1010
1030
  },
1011
1031
  },
1012
1032
 
1013
- htmlBlock: {
1014
- /**
1015
- * find the first matching end tag and process the interior
1016
- */
1017
- match: anyScopeRegex(HTML_BLOCK_ELEMENT_R),
1018
- order: PARSE_PRIORITY_HIGH,
1019
- parse(capture, parse, state) {
1020
- const [, whitespace] = capture[3].match(HTML_LEFT_TRIM_AMOUNT_R);
1021
- const trimmer = new RegExp(`^${whitespace}`, 'gm');
1022
- const trimmed = capture[3].replace(trimmer, '');
1023
-
1024
- const parseFunc = containsBlockSyntax(trimmed)
1025
- ? parseBlock
1026
- : parseInline;
1027
-
1028
- const tagName = capture[1].toLowerCase();
1029
- const noInnerParse =
1030
- DO_NOT_PROCESS_HTML_ELEMENTS.indexOf(tagName) !== -1;
1031
-
1032
- return {
1033
- attrs: attrStringToMap(capture[2]),
1034
- /**
1035
- * if another html block is detected within, parse as block,
1036
- * otherwise parse as inline to pick up any further markdown
1037
- */
1038
- content: noInnerParse ? capture[3] : parseFunc(parse, trimmed, state),
1039
-
1040
- noInnerParse,
1041
-
1042
- tag: noInnerParse ? tagName : capture[1]
1043
- };
1044
- },
1045
- react(node, output, state) {
1046
- return (
1047
- <node.tag key={state.key} {...node.attrs}>
1048
- {node.noInnerParse ? node.content : output(node.content, state)}
1049
- </node.tag>
1050
- );
1051
- },
1052
- },
1053
-
1054
1033
  htmlComment: {
1055
1034
  match: anyScopeRegex(HTML_COMMENT_R),
1056
1035
  order: PARSE_PRIORITY_HIGH,
@@ -1060,23 +1039,6 @@ export function compiler(markdown, options) {
1060
1039
  react: renderNothing,
1061
1040
  },
1062
1041
 
1063
- htmlSelfClosing: {
1064
- /**
1065
- * find the first matching end tag and process the interior
1066
- */
1067
- match: anyScopeRegex(HTML_SELF_CLOSING_ELEMENT_R),
1068
- order: PARSE_PRIORITY_HIGH,
1069
- parse(capture /*, parse, state*/) {
1070
- return {
1071
- attrs: attrStringToMap(capture[2] || ''),
1072
- tag: capture[1],
1073
- };
1074
- },
1075
- react(node, output, state) {
1076
- return <node.tag {...node.attrs} key={state.key} />;
1077
- },
1078
- },
1079
-
1080
1042
  image: {
1081
1043
  match: simpleInlineRegex(IMAGE_R),
1082
1044
  order: PARSE_PRIORITY_HIGH,
@@ -1408,6 +1370,21 @@ export function compiler(markdown, options) {
1408
1370
  },
1409
1371
  },
1410
1372
 
1373
+ tableSeparator: {
1374
+ match: function(source, state) {
1375
+ if (!state.inTable) {
1376
+ return null;
1377
+ }
1378
+ return TABLE_SEPARATOR_R.exec(source);
1379
+ },
1380
+ order: PARSE_PRIORITY_HIGH,
1381
+ parse: function() {
1382
+ return { type: 'tableSeparator' };
1383
+ },
1384
+ // These shouldn't be reached, but in case they are, be reasonable:
1385
+ react() { return ' | '; }
1386
+ },
1387
+
1411
1388
  text: {
1412
1389
  // Here we look for anything followed by non-symbols,
1413
1390
  // double newlines, or double-space-newlines
@@ -1420,8 +1397,8 @@ export function compiler(markdown, options) {
1420
1397
  content: capture[0]
1421
1398
  // nbsp -> unicode equivalent for named chars
1422
1399
  .replace(HTML_CHAR_CODE_R, (full, inner) => {
1423
- return namedCodesToUnicode[inner]
1424
- ? namedCodesToUnicode[inner]
1400
+ return options.namedCodesToUnicode[inner]
1401
+ ? options.namedCodesToUnicode[inner]
1425
1402
  : full;
1426
1403
  }),
1427
1404
  };
@@ -1518,10 +1495,70 @@ export function compiler(markdown, options) {
1518
1495
  // };
1519
1496
  // });
1520
1497
 
1498
+ if (options.disableParsingRawHTML !== true) {
1499
+ rules.htmlBlock = {
1500
+ /**
1501
+ * find the first matching end tag and process the interior
1502
+ */
1503
+ match: anyScopeRegex(HTML_BLOCK_ELEMENT_R),
1504
+ order: PARSE_PRIORITY_HIGH,
1505
+ parse(capture, parse, state) {
1506
+ const [, whitespace] = capture[3].match(HTML_LEFT_TRIM_AMOUNT_R);
1507
+ const trimmer = new RegExp(`^${whitespace}`, 'gm');
1508
+ const trimmed = capture[3].replace(trimmer, '');
1509
+
1510
+ const parseFunc = containsBlockSyntax(trimmed)
1511
+ ? parseBlock
1512
+ : parseInline;
1513
+
1514
+ const tagName = capture[1].toLowerCase();
1515
+ const noInnerParse =
1516
+ DO_NOT_PROCESS_HTML_ELEMENTS.indexOf(tagName) !== -1;
1517
+
1518
+ return {
1519
+ attrs: attrStringToMap(capture[2]),
1520
+ /**
1521
+ * if another html block is detected within, parse as block,
1522
+ * otherwise parse as inline to pick up any further markdown
1523
+ */
1524
+ content: noInnerParse ? capture[3] : parseFunc(parse, trimmed, state),
1525
+
1526
+ noInnerParse,
1527
+
1528
+ tag: noInnerParse ? tagName : capture[1]
1529
+ };
1530
+ },
1531
+ react(node, output, state) {
1532
+ return (
1533
+ <node.tag key={state.key} {...node.attrs}>
1534
+ {node.noInnerParse ? node.content : output(node.content, state)}
1535
+ </node.tag>
1536
+ );
1537
+ },
1538
+ }
1539
+
1540
+ rules.htmlSelfClosing = {
1541
+ /**
1542
+ * find the first matching end tag and process the interior
1543
+ */
1544
+ match: anyScopeRegex(HTML_SELF_CLOSING_ELEMENT_R),
1545
+ order: PARSE_PRIORITY_HIGH,
1546
+ parse(capture /*, parse, state*/) {
1547
+ return {
1548
+ attrs: attrStringToMap(capture[2] || ''),
1549
+ tag: capture[1],
1550
+ };
1551
+ },
1552
+ react(node, output, state) {
1553
+ return <node.tag {...node.attrs} key={state.key} />;
1554
+ },
1555
+ };
1556
+ }
1557
+
1521
1558
  const parser = parserFor(rules);
1522
1559
  const emitter = reactFor(ruleOutput(rules));
1523
1560
 
1524
- const jsx = compile(markdown);
1561
+ const jsx = compile(stripHtmlComments(markdown));
1525
1562
 
1526
1563
  if (footnotes.length) {
1527
1564
  jsx.props.children.push(
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Convert markdown to JSX with ease for React and React-like projects. Super lightweight and highly configurable.",
4
4
  "homepage": "https://probablyup.github.io/markdown-to-jsx",
5
5
  "license": "MIT",
6
- "version": "6.10.0",
6
+ "version": "6.11.0",
7
7
  "engines": {
8
8
  "node": ">= 4"
9
9
  },
@@ -90,7 +90,7 @@
90
90
  "size-limit": [
91
91
  {
92
92
  "path": "dist/cjs.js",
93
- "limit": "5.15 kB"
93
+ "limit": "5.28 kB"
94
94
  }
95
95
  ],
96
96
  "jest": {