@readme/markdown 13.1.3 → 13.1.4

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/dist/main.js CHANGED
@@ -70954,13 +70954,15 @@ const scanForClosingTag = (parent, startIndex, tag) => {
70954
70954
  if (isClosingTag(siblingValue, tag)) {
70955
70955
  return { closingIndex: i, extraClosingChildren: [] };
70956
70956
  }
70957
- // Embedded closing tag (closing tag at end of HTML block content)
70957
+ // Embedded closing tag (closing tag within HTML block content)
70958
70958
  if (siblingValue.includes(closingTagStr)) {
70959
- const contentBeforeClose = siblingValue.substring(0, siblingValue.lastIndexOf(closingTagStr)).trim();
70959
+ const closeTagPos = siblingValue.indexOf(closingTagStr);
70960
+ const contentBeforeClose = siblingValue.substring(0, closeTagPos).trim();
70961
+ const contentAfterClose = siblingValue.substring(closeTagPos + closingTagStr.length).trim();
70960
70962
  const extraChildren = contentBeforeClose
70961
70963
  ? parseMdChildren(contentBeforeClose)
70962
70964
  : [];
70963
- return { closingIndex: i, extraClosingChildren: extraChildren };
70965
+ return { closingIndex: i, extraClosingChildren: extraChildren, contentAfterClose: contentAfterClose || undefined };
70964
70966
  }
70965
70967
  }
70966
70968
  // Check paragraph siblings
@@ -71105,7 +71107,7 @@ const mdxishComponentBlocks = () => tree => {
71105
71107
  const scanResult = scanForClosingTag(parent, index, tag);
71106
71108
  if (!scanResult)
71107
71109
  return;
71108
- const { closingIndex, extraClosingChildren, strippedParagraph } = scanResult;
71110
+ const { closingIndex, extraClosingChildren, strippedParagraph, contentAfterClose: remainingAfterClose } = scanResult;
71109
71111
  const extraChildren = contentAfterTag ? parseMdChildren(contentAfterTag.trimStart()) : [];
71110
71112
  // Collect all intermediate siblings between opening tag and closing tag
71111
71113
  const intermediateChildren = parent.children.slice(index + 1, closingIndex);
@@ -71128,6 +71130,11 @@ const mdxishComponentBlocks = () => tree => {
71128
71130
  if (componentNode.children.length > 0) {
71129
71131
  stack.push(componentNode);
71130
71132
  }
71133
+ // If the closing tag sibling had content after it (e.g., another component opening tag),
71134
+ // re-insert it as a sibling so it can be processed in subsequent iterations
71135
+ if (remainingAfterClose) {
71136
+ parseSibling(stack, parent, index, remainingAfterClose);
71137
+ }
71131
71138
  };
71132
71139
  // Process the nodes with the components depth-first to maintain the correct order of the nodes
71133
71140
  while (stack.length) {
@@ -93444,7 +93451,7 @@ function isActualHtmlTag(tagName, originalExcerpt) {
93444
93451
  return false;
93445
93452
  }
93446
93453
  /** Parse and replace text children with processed markdown */
93447
- function parseTextChildren(node, processMarkdown) {
93454
+ function parseTextChildren(node, processMarkdown, components) {
93448
93455
  if (!node.children?.length)
93449
93456
  return;
93450
93457
  // First pass: Recursively process text children as they may contain stringified markdown / mdx content
@@ -93459,6 +93466,27 @@ function parseTextChildren(node, processMarkdown) {
93459
93466
  }
93460
93467
  return children;
93461
93468
  });
93469
+ // Unwrap <p> elements whose meaningful children are ALL components.
93470
+ // The markdown parser wraps inline content in <p> tags, but when that content
93471
+ // is actually component children (e.g., <Tab> inside <Tabs>), the wrapper
93472
+ // should be removed so components appear as direct children.
93473
+ // Only unwrap when every non-whitespace, non-br child is a known component
93474
+ // to avoid breaking paragraphs with mixed content (text + inline HTML like <code>).
93475
+ node.children = node.children.flatMap(child => {
93476
+ if (child.type !== 'element' || child.tagName !== 'p')
93477
+ return [child];
93478
+ const meaningfulChildren = child.children.filter(gc => {
93479
+ if (gc.type === 'text' && !gc.value.trim())
93480
+ return false;
93481
+ if (gc.type === 'element' && gc.tagName === 'br')
93482
+ return false;
93483
+ return true;
93484
+ });
93485
+ const allComponents = meaningfulChildren.length > 0 && meaningfulChildren.every(gc => gc.type === 'element' && getComponentName(gc.tagName, components));
93486
+ if (!allComponents)
93487
+ return [child];
93488
+ return meaningfulChildren;
93489
+ });
93462
93490
  // Post-processing: remove whitespace-only text nodes if all siblings are components
93463
93491
  // This prevents whitespace between component children from being counted as extra children
93464
93492
  if (areAllChildrenComponents(node.children)) {
@@ -93513,7 +93541,7 @@ const rehypeMdxishComponents = ({ components, processMarkdown }) => {
93513
93541
  }
93514
93542
  node.tagName = componentName;
93515
93543
  normalizeProperties(node);
93516
- parseTextChildren(node, processMarkdown);
93544
+ parseTextChildren(node, processMarkdown, components);
93517
93545
  });
93518
93546
  // Remove unknown components in reverse order to preserve indices
93519
93547
  for (let i = nodesToRemove.length - 1; i >= 0; i -= 1) {
@@ -93814,8 +93842,10 @@ function escapeUnbalancedBraces(content) {
93814
93842
  const unbalanced = new Set();
93815
93843
  let strDelim = null;
93816
93844
  let strEscaped = false;
93817
- for (let i = 0; i < content.length; i += 1) {
93818
- const ch = content[i];
93845
+ // Convert to array of Unicode code points to handle emojis and multi-byte characters correctly
93846
+ const chars = Array.from(content);
93847
+ for (let i = 0; i < chars.length; i += 1) {
93848
+ const ch = chars[i];
93819
93849
  // Track strings inside expressions to ignore braces within them
93820
93850
  if (opens.length > 0) {
93821
93851
  if (strDelim) {
@@ -93837,7 +93867,7 @@ function escapeUnbalancedBraces(content) {
93837
93867
  // Skip already-escaped braces (count preceding backslashes)
93838
93868
  if (ch === '{' || ch === '}') {
93839
93869
  let bs = 0;
93840
- for (let j = i - 1; j >= 0 && content[j] === '\\'; j -= 1)
93870
+ for (let j = i - 1; j >= 0 && chars[j] === '\\'; j -= 1)
93841
93871
  bs += 1;
93842
93872
  if (bs % 2 === 1) {
93843
93873
  // eslint-disable-next-line no-continue
@@ -93856,7 +93886,7 @@ function escapeUnbalancedBraces(content) {
93856
93886
  opens.forEach(pos => unbalanced.add(pos));
93857
93887
  if (unbalanced.size === 0)
93858
93888
  return content;
93859
- return Array.from(content)
93889
+ return chars
93860
93890
  .map((ch, i) => (unbalanced.has(i) ? `\\${ch}` : ch))
93861
93891
  .join('');
93862
93892
  }
package/dist/main.node.js CHANGED
@@ -91158,13 +91158,15 @@ const scanForClosingTag = (parent, startIndex, tag) => {
91158
91158
  if (isClosingTag(siblingValue, tag)) {
91159
91159
  return { closingIndex: i, extraClosingChildren: [] };
91160
91160
  }
91161
- // Embedded closing tag (closing tag at end of HTML block content)
91161
+ // Embedded closing tag (closing tag within HTML block content)
91162
91162
  if (siblingValue.includes(closingTagStr)) {
91163
- const contentBeforeClose = siblingValue.substring(0, siblingValue.lastIndexOf(closingTagStr)).trim();
91163
+ const closeTagPos = siblingValue.indexOf(closingTagStr);
91164
+ const contentBeforeClose = siblingValue.substring(0, closeTagPos).trim();
91165
+ const contentAfterClose = siblingValue.substring(closeTagPos + closingTagStr.length).trim();
91164
91166
  const extraChildren = contentBeforeClose
91165
91167
  ? parseMdChildren(contentBeforeClose)
91166
91168
  : [];
91167
- return { closingIndex: i, extraClosingChildren: extraChildren };
91169
+ return { closingIndex: i, extraClosingChildren: extraChildren, contentAfterClose: contentAfterClose || undefined };
91168
91170
  }
91169
91171
  }
91170
91172
  // Check paragraph siblings
@@ -91309,7 +91311,7 @@ const mdxishComponentBlocks = () => tree => {
91309
91311
  const scanResult = scanForClosingTag(parent, index, tag);
91310
91312
  if (!scanResult)
91311
91313
  return;
91312
- const { closingIndex, extraClosingChildren, strippedParagraph } = scanResult;
91314
+ const { closingIndex, extraClosingChildren, strippedParagraph, contentAfterClose: remainingAfterClose } = scanResult;
91313
91315
  const extraChildren = contentAfterTag ? parseMdChildren(contentAfterTag.trimStart()) : [];
91314
91316
  // Collect all intermediate siblings between opening tag and closing tag
91315
91317
  const intermediateChildren = parent.children.slice(index + 1, closingIndex);
@@ -91332,6 +91334,11 @@ const mdxishComponentBlocks = () => tree => {
91332
91334
  if (componentNode.children.length > 0) {
91333
91335
  stack.push(componentNode);
91334
91336
  }
91337
+ // If the closing tag sibling had content after it (e.g., another component opening tag),
91338
+ // re-insert it as a sibling so it can be processed in subsequent iterations
91339
+ if (remainingAfterClose) {
91340
+ parseSibling(stack, parent, index, remainingAfterClose);
91341
+ }
91335
91342
  };
91336
91343
  // Process the nodes with the components depth-first to maintain the correct order of the nodes
91337
91344
  while (stack.length) {
@@ -113648,7 +113655,7 @@ function isActualHtmlTag(tagName, originalExcerpt) {
113648
113655
  return false;
113649
113656
  }
113650
113657
  /** Parse and replace text children with processed markdown */
113651
- function parseTextChildren(node, processMarkdown) {
113658
+ function parseTextChildren(node, processMarkdown, components) {
113652
113659
  if (!node.children?.length)
113653
113660
  return;
113654
113661
  // First pass: Recursively process text children as they may contain stringified markdown / mdx content
@@ -113663,6 +113670,27 @@ function parseTextChildren(node, processMarkdown) {
113663
113670
  }
113664
113671
  return children;
113665
113672
  });
113673
+ // Unwrap <p> elements whose meaningful children are ALL components.
113674
+ // The markdown parser wraps inline content in <p> tags, but when that content
113675
+ // is actually component children (e.g., <Tab> inside <Tabs>), the wrapper
113676
+ // should be removed so components appear as direct children.
113677
+ // Only unwrap when every non-whitespace, non-br child is a known component
113678
+ // to avoid breaking paragraphs with mixed content (text + inline HTML like <code>).
113679
+ node.children = node.children.flatMap(child => {
113680
+ if (child.type !== 'element' || child.tagName !== 'p')
113681
+ return [child];
113682
+ const meaningfulChildren = child.children.filter(gc => {
113683
+ if (gc.type === 'text' && !gc.value.trim())
113684
+ return false;
113685
+ if (gc.type === 'element' && gc.tagName === 'br')
113686
+ return false;
113687
+ return true;
113688
+ });
113689
+ const allComponents = meaningfulChildren.length > 0 && meaningfulChildren.every(gc => gc.type === 'element' && getComponentName(gc.tagName, components));
113690
+ if (!allComponents)
113691
+ return [child];
113692
+ return meaningfulChildren;
113693
+ });
113666
113694
  // Post-processing: remove whitespace-only text nodes if all siblings are components
113667
113695
  // This prevents whitespace between component children from being counted as extra children
113668
113696
  if (areAllChildrenComponents(node.children)) {
@@ -113717,7 +113745,7 @@ const rehypeMdxishComponents = ({ components, processMarkdown }) => {
113717
113745
  }
113718
113746
  node.tagName = componentName;
113719
113747
  normalizeProperties(node);
113720
- parseTextChildren(node, processMarkdown);
113748
+ parseTextChildren(node, processMarkdown, components);
113721
113749
  });
113722
113750
  // Remove unknown components in reverse order to preserve indices
113723
113751
  for (let i = nodesToRemove.length - 1; i >= 0; i -= 1) {
@@ -114018,8 +114046,10 @@ function escapeUnbalancedBraces(content) {
114018
114046
  const unbalanced = new Set();
114019
114047
  let strDelim = null;
114020
114048
  let strEscaped = false;
114021
- for (let i = 0; i < content.length; i += 1) {
114022
- const ch = content[i];
114049
+ // Convert to array of Unicode code points to handle emojis and multi-byte characters correctly
114050
+ const chars = Array.from(content);
114051
+ for (let i = 0; i < chars.length; i += 1) {
114052
+ const ch = chars[i];
114023
114053
  // Track strings inside expressions to ignore braces within them
114024
114054
  if (opens.length > 0) {
114025
114055
  if (strDelim) {
@@ -114041,7 +114071,7 @@ function escapeUnbalancedBraces(content) {
114041
114071
  // Skip already-escaped braces (count preceding backslashes)
114042
114072
  if (ch === '{' || ch === '}') {
114043
114073
  let bs = 0;
114044
- for (let j = i - 1; j >= 0 && content[j] === '\\'; j -= 1)
114074
+ for (let j = i - 1; j >= 0 && chars[j] === '\\'; j -= 1)
114045
114075
  bs += 1;
114046
114076
  if (bs % 2 === 1) {
114047
114077
  // eslint-disable-next-line no-continue
@@ -114060,7 +114090,7 @@ function escapeUnbalancedBraces(content) {
114060
114090
  opens.forEach(pos => unbalanced.add(pos));
114061
114091
  if (unbalanced.size === 0)
114062
114092
  return content;
114063
- return Array.from(content)
114093
+ return chars
114064
114094
  .map((ch, i) => (unbalanced.has(i) ? `\\${ch}` : ch))
114065
114095
  .join('');
114066
114096
  }