@readme/markdown 11.14.1 → 12.0.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/dist/index.d.ts +1 -1
- package/dist/lib/index.d.ts +0 -1
- package/dist/main.js +459 -187
- package/dist/main.node.js +459 -187
- package/dist/main.node.js.map +1 -1
- package/dist/processor/transform/extract-text.d.ts +14 -0
- package/dist/processor/transform/mdxish/normalize-table-separator.d.ts +23 -0
- package/dist/processor/transform/mdxish/preprocess-jsx-expressions.d.ts +1 -0
- package/package.json +2 -2
- package/dist/lib/utils/isPlainText.d.ts +0 -9
package/dist/main.js
CHANGED
|
@@ -11362,7 +11362,6 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
11362
11362
|
exports: () => (/* reexport */ lib_exports),
|
|
11363
11363
|
gemojiRegex: () => (/* reexport */ gemoji_regex),
|
|
11364
11364
|
hast: () => (/* reexport */ lib_hast),
|
|
11365
|
-
isPlainText: () => (/* reexport */ isPlainText),
|
|
11366
11365
|
mdast: () => (/* reexport */ lib_mdast),
|
|
11367
11366
|
mdastV6: () => (/* reexport */ lib_mdastV6),
|
|
11368
11367
|
mdx: () => (/* reexport */ lib_mdx),
|
|
@@ -52944,12 +52943,40 @@ const plain = (node, opts = {}) => {
|
|
|
52944
52943
|
};
|
|
52945
52944
|
/* harmony default export */ const lib_plain = (plain);
|
|
52946
52945
|
|
|
52946
|
+
;// ./processor/transform/extract-text.ts
|
|
52947
|
+
/**
|
|
52948
|
+
* Extracts text content from a single AST node recursively.
|
|
52949
|
+
* Works with both MDAST and HAST-like node structures.
|
|
52950
|
+
*
|
|
52951
|
+
* Placed this outside of the utils.ts file to avoid circular dependencies.
|
|
52952
|
+
*
|
|
52953
|
+
* @param node - The node to extract text from (can be MDAST Node or HAST-like structure)
|
|
52954
|
+
* @returns The concatenated text content
|
|
52955
|
+
*/
|
|
52956
|
+
const extractText = (node) => {
|
|
52957
|
+
if (node.type === 'text' && typeof node.value === 'string') {
|
|
52958
|
+
return node.value;
|
|
52959
|
+
}
|
|
52960
|
+
if (node.children && Array.isArray(node.children)) {
|
|
52961
|
+
return node.children
|
|
52962
|
+
.map(child => {
|
|
52963
|
+
if (child && typeof child === 'object' && 'type' in child) {
|
|
52964
|
+
return extractText(child);
|
|
52965
|
+
}
|
|
52966
|
+
return '';
|
|
52967
|
+
})
|
|
52968
|
+
.join('');
|
|
52969
|
+
}
|
|
52970
|
+
return '';
|
|
52971
|
+
};
|
|
52972
|
+
|
|
52947
52973
|
;// ./processor/transform/callouts.ts
|
|
52948
52974
|
|
|
52949
52975
|
|
|
52950
52976
|
|
|
52951
52977
|
|
|
52952
52978
|
|
|
52979
|
+
|
|
52953
52980
|
const callouts_regex = `^(${emoji_regex().source}|⚠)(\\s+|$)`;
|
|
52954
52981
|
const findFirst = (node) => {
|
|
52955
52982
|
if ('children' in node)
|
|
@@ -52970,42 +52997,76 @@ const wrapHeading = (node) => {
|
|
|
52970
52997
|
},
|
|
52971
52998
|
};
|
|
52972
52999
|
};
|
|
53000
|
+
/**
|
|
53001
|
+
* Checks if a blockquote matches the expected callout structure:
|
|
53002
|
+
* blockquote > paragraph > text node
|
|
53003
|
+
*/
|
|
53004
|
+
const isCalloutStructure = (node) => {
|
|
53005
|
+
const firstChild = node.children?.[0];
|
|
53006
|
+
if (!firstChild || firstChild.type !== 'paragraph')
|
|
53007
|
+
return false;
|
|
53008
|
+
if (!('children' in firstChild))
|
|
53009
|
+
return false;
|
|
53010
|
+
const firstTextChild = firstChild.children?.[0];
|
|
53011
|
+
return firstTextChild?.type === 'text';
|
|
53012
|
+
};
|
|
53013
|
+
const processBlockquote = (node, index, parent) => {
|
|
53014
|
+
if (!isCalloutStructure(node)) {
|
|
53015
|
+
// Only stringify empty blockquotes (no extractable text content)
|
|
53016
|
+
// Preserve blockquotes with actual content (e.g., headings, lists, etc.)
|
|
53017
|
+
const content = extractText(node);
|
|
53018
|
+
const isEmpty = !content || content.trim() === '';
|
|
53019
|
+
if (isEmpty && index !== undefined && parent) {
|
|
53020
|
+
const textNode = {
|
|
53021
|
+
type: 'text',
|
|
53022
|
+
value: '>',
|
|
53023
|
+
};
|
|
53024
|
+
const paragraphNode = {
|
|
53025
|
+
type: 'paragraph',
|
|
53026
|
+
children: [textNode],
|
|
53027
|
+
position: node.position,
|
|
53028
|
+
};
|
|
53029
|
+
parent.children.splice(index, 1, paragraphNode);
|
|
53030
|
+
}
|
|
53031
|
+
return;
|
|
53032
|
+
}
|
|
53033
|
+
// isCalloutStructure ensures node.children[0] is a Paragraph with children
|
|
53034
|
+
const firstParagraph = node.children[0];
|
|
53035
|
+
const startText = lib_plain(firstParagraph).toString();
|
|
53036
|
+
const [match, icon] = startText.match(callouts_regex) || [];
|
|
53037
|
+
if (icon && match) {
|
|
53038
|
+
const heading = startText.slice(match.length);
|
|
53039
|
+
const empty = !heading.length && firstParagraph.children.length === 1;
|
|
53040
|
+
const theme = themes[icon] || 'default';
|
|
53041
|
+
const firstChild = findFirst(node.children[0]);
|
|
53042
|
+
if (firstChild && 'value' in firstChild && typeof firstChild.value === 'string') {
|
|
53043
|
+
firstChild.value = firstChild.value.slice(match.length);
|
|
53044
|
+
}
|
|
53045
|
+
if (heading) {
|
|
53046
|
+
node.children[0] = wrapHeading(node);
|
|
53047
|
+
// @note: We add to the offset/column the length of the unicode
|
|
53048
|
+
// character that was stripped off, so that the start position of the
|
|
53049
|
+
// heading/text matches where it actually starts.
|
|
53050
|
+
node.children[0].position.start.offset += match.length;
|
|
53051
|
+
node.children[0].position.start.column += match.length;
|
|
53052
|
+
}
|
|
53053
|
+
Object.assign(node, {
|
|
53054
|
+
type: NodeTypes.callout,
|
|
53055
|
+
data: {
|
|
53056
|
+
hName: 'Callout',
|
|
53057
|
+
hProperties: {
|
|
53058
|
+
icon,
|
|
53059
|
+
...(empty && { empty }),
|
|
53060
|
+
theme,
|
|
53061
|
+
},
|
|
53062
|
+
},
|
|
53063
|
+
});
|
|
53064
|
+
}
|
|
53065
|
+
};
|
|
52973
53066
|
const calloutTransformer = () => {
|
|
52974
53067
|
return (tree) => {
|
|
52975
|
-
visit(tree, 'blockquote', (node) => {
|
|
52976
|
-
|
|
52977
|
-
return;
|
|
52978
|
-
// @ts-expect-error -- @todo: update plain to accept mdast
|
|
52979
|
-
const startText = lib_plain(node.children[0]).toString();
|
|
52980
|
-
const [match, icon] = startText.match(callouts_regex) || [];
|
|
52981
|
-
if (icon && match) {
|
|
52982
|
-
const heading = startText.slice(match.length);
|
|
52983
|
-
const empty = !heading.length && node.children[0].children.length === 1;
|
|
52984
|
-
const theme = themes[icon] || 'default';
|
|
52985
|
-
const firstChild = findFirst(node.children[0]);
|
|
52986
|
-
if (firstChild && 'value' in firstChild && typeof firstChild.value === 'string') {
|
|
52987
|
-
firstChild.value = firstChild.value.slice(match.length);
|
|
52988
|
-
}
|
|
52989
|
-
if (heading) {
|
|
52990
|
-
node.children[0] = wrapHeading(node);
|
|
52991
|
-
// @note: We add to the offset/column the length of the unicode
|
|
52992
|
-
// character that was stripped off, so that the start position of the
|
|
52993
|
-
// heading/text matches where it actually starts.
|
|
52994
|
-
node.children[0].position.start.offset += match.length;
|
|
52995
|
-
node.children[0].position.start.column += match.length;
|
|
52996
|
-
}
|
|
52997
|
-
Object.assign(node, {
|
|
52998
|
-
type: NodeTypes.callout,
|
|
52999
|
-
data: {
|
|
53000
|
-
hName: 'Callout',
|
|
53001
|
-
hProperties: {
|
|
53002
|
-
icon,
|
|
53003
|
-
...(empty && { empty }),
|
|
53004
|
-
theme,
|
|
53005
|
-
},
|
|
53006
|
-
},
|
|
53007
|
-
});
|
|
53008
|
-
}
|
|
53068
|
+
visit(tree, 'blockquote', (node, index, parent) => {
|
|
53069
|
+
processBlockquote(node, index, parent);
|
|
53009
53070
|
});
|
|
53010
53071
|
};
|
|
53011
53072
|
};
|
|
@@ -70621,10 +70682,13 @@ const tagAttributePattern = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*("[^"]*"|'[^'
|
|
|
70621
70682
|
const MAX_LOOKAHEAD = 30;
|
|
70622
70683
|
/**
|
|
70623
70684
|
* Tags that have dedicated transformers and should NOT be handled by this plugin.
|
|
70624
|
-
* These components have special parsing requirements that the generic component
|
|
70625
|
-
* block transformer cannot handle correctly
|
|
70685
|
+
* These components either have special parsing requirements that the generic component
|
|
70686
|
+
* block transformer cannot handle correctly, or are inline components that we don't
|
|
70687
|
+
* want to convert to mdxJsxFlowElement which is a block level element.
|
|
70688
|
+
*
|
|
70689
|
+
* Glossary and Anchor are inline components.
|
|
70626
70690
|
*/
|
|
70627
|
-
const EXCLUDED_TAGS = new Set(['HTMLBlock', 'Table']);
|
|
70691
|
+
const EXCLUDED_TAGS = new Set(['HTMLBlock', 'Table', 'Glossary', 'Anchor']);
|
|
70628
70692
|
const inlineMdProcessor = unified().use(remarkParse);
|
|
70629
70693
|
const isClosingTag = (value, tag) => value.trim() === `</${tag}>`;
|
|
70630
70694
|
/**
|
|
@@ -70668,6 +70732,17 @@ const parseTag = (value) => {
|
|
|
70668
70732
|
contentAfterTag,
|
|
70669
70733
|
};
|
|
70670
70734
|
};
|
|
70735
|
+
/**
|
|
70736
|
+
* Parse substring content of a node and update the parent's children to include the new nodes.
|
|
70737
|
+
*/
|
|
70738
|
+
const parseSibling = (stack, parent, index, sibling) => {
|
|
70739
|
+
const siblingNodes = parseMdChildren(sibling);
|
|
70740
|
+
// The new sibling nodes might contain new components to be processed
|
|
70741
|
+
if (siblingNodes.length > 0) {
|
|
70742
|
+
parent.children.splice(index + 1, 0, ...siblingNodes);
|
|
70743
|
+
stack.push(parent);
|
|
70744
|
+
}
|
|
70745
|
+
};
|
|
70671
70746
|
/**
|
|
70672
70747
|
* Create an MdxJsxFlowElement node from component data.
|
|
70673
70748
|
*/
|
|
@@ -70810,11 +70885,12 @@ const mdxishComponentBlocks = () => tree => {
|
|
|
70810
70885
|
if ('children' in node && Array.isArray(node.children)) {
|
|
70811
70886
|
stack.push(node);
|
|
70812
70887
|
}
|
|
70813
|
-
// Only visit HTML nodes with an actual html tag
|
|
70888
|
+
// Only visit HTML nodes with an actual html tag,
|
|
70889
|
+
// which means a potential unparsed MDX component
|
|
70814
70890
|
const value = node.value;
|
|
70815
70891
|
if (node.type !== 'html' || typeof value !== 'string')
|
|
70816
70892
|
return;
|
|
70817
|
-
const parsed = parseTag(value);
|
|
70893
|
+
const parsed = parseTag(value.trim());
|
|
70818
70894
|
if (!parsed)
|
|
70819
70895
|
return;
|
|
70820
70896
|
const { tag, attributes, selfClosing, contentAfterTag = '' } = parsed;
|
|
@@ -70831,11 +70907,19 @@ const mdxishComponentBlocks = () => tree => {
|
|
|
70831
70907
|
startPosition: node.position,
|
|
70832
70908
|
});
|
|
70833
70909
|
substituteNodeWithMdxNode(parent, index, componentNode);
|
|
70910
|
+
// Check and parse if there's relevant content after the current closing tag
|
|
70911
|
+
const remainingContent = contentAfterTag.trim();
|
|
70912
|
+
if (remainingContent) {
|
|
70913
|
+
parseSibling(stack, parent, index, remainingContent);
|
|
70914
|
+
}
|
|
70834
70915
|
return;
|
|
70835
70916
|
}
|
|
70836
70917
|
// Case 2: Self-contained block (closing tag in content)
|
|
70837
70918
|
if (contentAfterTag.includes(closingTagStr)) {
|
|
70838
|
-
|
|
70919
|
+
// Find the first closing tag
|
|
70920
|
+
const closingTagIndex = contentAfterTag.indexOf(closingTagStr);
|
|
70921
|
+
const componentInnerContent = contentAfterTag.substring(0, closingTagIndex).trim();
|
|
70922
|
+
const contentAfterClose = contentAfterTag.substring(closingTagIndex + closingTagStr.length).trim();
|
|
70839
70923
|
const componentNode = createComponentNode({
|
|
70840
70924
|
tag,
|
|
70841
70925
|
attributes,
|
|
@@ -70843,6 +70927,14 @@ const mdxishComponentBlocks = () => tree => {
|
|
|
70843
70927
|
startPosition: node.position,
|
|
70844
70928
|
});
|
|
70845
70929
|
substituteNodeWithMdxNode(parent, index, componentNode);
|
|
70930
|
+
// After the closing tag, there might be more content to be processed
|
|
70931
|
+
if (contentAfterClose) {
|
|
70932
|
+
parseSibling(stack, parent, index, contentAfterClose);
|
|
70933
|
+
}
|
|
70934
|
+
else if (componentNode.children.length > 0) {
|
|
70935
|
+
// The content inside the component block might contain new components to be processed
|
|
70936
|
+
stack.push(componentNode);
|
|
70937
|
+
}
|
|
70846
70938
|
return;
|
|
70847
70939
|
}
|
|
70848
70940
|
// Case 3: Multi-sibling component (closing tag in a following sibling)
|
|
@@ -70868,8 +70960,13 @@ const mdxishComponentBlocks = () => tree => {
|
|
|
70868
70960
|
});
|
|
70869
70961
|
// Remove all nodes from opening tag to closing tag (inclusive) and replace with component node
|
|
70870
70962
|
parent.children.splice(index, closingIndex - index + 1, componentNode);
|
|
70963
|
+
// Since we might be merging sibling nodes together and combining content,
|
|
70964
|
+
// there might be new components to process
|
|
70965
|
+
if (componentNode.children.length > 0) {
|
|
70966
|
+
stack.push(componentNode);
|
|
70967
|
+
}
|
|
70871
70968
|
};
|
|
70872
|
-
//
|
|
70969
|
+
// Process the nodes with the components depth-first to maintain the correct order of the nodes
|
|
70873
70970
|
while (stack.length) {
|
|
70874
70971
|
const parent = stack.pop();
|
|
70875
70972
|
if (parent?.children) {
|
|
@@ -70890,6 +70987,7 @@ const mdxishComponentBlocks = () => tree => {
|
|
|
70890
70987
|
|
|
70891
70988
|
|
|
70892
70989
|
|
|
70990
|
+
|
|
70893
70991
|
const isTableCell = (node) => isMDXElement(node) && ['th', 'td'].includes(node.name);
|
|
70894
70992
|
const tableTypes = {
|
|
70895
70993
|
tr: 'tableRow',
|
|
@@ -70914,18 +71012,13 @@ const isTextOnly = (children) => {
|
|
|
70914
71012
|
});
|
|
70915
71013
|
};
|
|
70916
71014
|
/**
|
|
70917
|
-
*
|
|
71015
|
+
* Convenience wrapper that extracts text content from an array of children nodes.
|
|
70918
71016
|
*/
|
|
70919
|
-
const
|
|
71017
|
+
const extractTextFromChildren = (children) => {
|
|
70920
71018
|
return children
|
|
70921
71019
|
.map(child => {
|
|
70922
71020
|
if (child && typeof child === 'object' && 'type' in child) {
|
|
70923
|
-
|
|
70924
|
-
return child.value;
|
|
70925
|
-
}
|
|
70926
|
-
if (child.type === 'mdxJsxTextElement' && 'children' in child && Array.isArray(child.children)) {
|
|
70927
|
-
return extractText(child.children);
|
|
70928
|
-
}
|
|
71021
|
+
return extractText(child);
|
|
70929
71022
|
}
|
|
70930
71023
|
return '';
|
|
70931
71024
|
})
|
|
@@ -70956,7 +71049,7 @@ const processTableNode = (node, index, parent) => {
|
|
|
70956
71049
|
let parsedChildren = cellChildren;
|
|
70957
71050
|
// If cell contains only text nodes, try to re-parse as markdown
|
|
70958
71051
|
if (isTextOnly(cellChildren)) {
|
|
70959
|
-
const textContent =
|
|
71052
|
+
const textContent = extractTextFromChildren(cellChildren);
|
|
70960
71053
|
if (textContent.trim()) {
|
|
70961
71054
|
try {
|
|
70962
71055
|
const parsed = parseMarkdown(textContent);
|
|
@@ -86371,7 +86464,7 @@ const CUSTOM_PROP_BOUNDARIES = [
|
|
|
86371
86464
|
/**
|
|
86372
86465
|
* Tags that should be passed through and handled at runtime (not by the mdxish plugin)
|
|
86373
86466
|
*/
|
|
86374
|
-
const RUNTIME_COMPONENT_TAGS = new Set(['Variable', 'variable']);
|
|
86467
|
+
const RUNTIME_COMPONENT_TAGS = new Set(['Variable', 'variable', 'rdme-pin']);
|
|
86375
86468
|
/**
|
|
86376
86469
|
* Standard HTML tags that should never be treated as custom components.
|
|
86377
86470
|
* Uses the html-tags package, converted to a Set<string> for efficient lookups.
|
|
@@ -93002,6 +93095,33 @@ const INLINE_COMPONENT_TAGS = new Set(['anchor', 'glossary']);
|
|
|
93002
93095
|
function isElementContentNode(node) {
|
|
93003
93096
|
return node.type === 'element' || node.type === 'text' || node.type === 'comment';
|
|
93004
93097
|
}
|
|
93098
|
+
/**
|
|
93099
|
+
* Components are assumed to be block-level, so whitespace between them can be removed
|
|
93100
|
+
* We want to remove them because it can be treated as actual children of the component
|
|
93101
|
+
* when it doesn't need to.
|
|
93102
|
+
*
|
|
93103
|
+
* It can be a problem because it can be passed as args to the components, like the ones
|
|
93104
|
+
* defined in /components, which can break the type assumptions of the components and cause
|
|
93105
|
+
* type errors, accessing properties that don't exist.
|
|
93106
|
+
*/
|
|
93107
|
+
function areAllChildrenComponents(children) {
|
|
93108
|
+
return children.every(child => {
|
|
93109
|
+
// Whitespace-only text nodes don't affect the check
|
|
93110
|
+
if (child.type === 'text' && !child.value.trim())
|
|
93111
|
+
return true;
|
|
93112
|
+
// Text with actual content means we have mixed content
|
|
93113
|
+
if (child.type === 'text')
|
|
93114
|
+
return false;
|
|
93115
|
+
// Comments don't affect the check
|
|
93116
|
+
if (child.type === 'comment')
|
|
93117
|
+
return true;
|
|
93118
|
+
// Standard HTML tags are not considered components
|
|
93119
|
+
if (child.type === 'element' && 'tagName' in child) {
|
|
93120
|
+
return !STANDARD_HTML_TAGS.has(child.tagName.toLowerCase());
|
|
93121
|
+
}
|
|
93122
|
+
return false;
|
|
93123
|
+
});
|
|
93124
|
+
}
|
|
93005
93125
|
/** Check if nodes represent a single paragraph with only text (no markdown formatting) */
|
|
93006
93126
|
function isSingleParagraphTextNode(nodes) {
|
|
93007
93127
|
return (nodes.length === 1 &&
|
|
@@ -93046,6 +93166,7 @@ function isActualHtmlTag(tagName, originalExcerpt) {
|
|
|
93046
93166
|
function parseTextChildren(node, processMarkdown) {
|
|
93047
93167
|
if (!node.children?.length)
|
|
93048
93168
|
return;
|
|
93169
|
+
// First pass: Recursively process text children as they may contain stringified markdown / mdx content
|
|
93049
93170
|
node.children = node.children.flatMap(child => {
|
|
93050
93171
|
if (child.type !== 'text' || !child.value.trim())
|
|
93051
93172
|
return [child];
|
|
@@ -93057,6 +93178,15 @@ function parseTextChildren(node, processMarkdown) {
|
|
|
93057
93178
|
}
|
|
93058
93179
|
return children;
|
|
93059
93180
|
});
|
|
93181
|
+
// Post-processing: remove whitespace-only text nodes if all siblings are components
|
|
93182
|
+
// This prevents whitespace between component children from being counted as extra children
|
|
93183
|
+
if (areAllChildrenComponents(node.children)) {
|
|
93184
|
+
node.children = node.children.filter(child => {
|
|
93185
|
+
if (child.type === 'text' && !child.value.trim())
|
|
93186
|
+
return false;
|
|
93187
|
+
return true;
|
|
93188
|
+
});
|
|
93189
|
+
}
|
|
93060
93190
|
}
|
|
93061
93191
|
/** Convert node properties from kebab-case/lowercase to camelCase */
|
|
93062
93192
|
function normalizeProperties(node) {
|
|
@@ -93119,6 +93249,15 @@ const mdxExpressionHandler = (_state, node) => ({
|
|
|
93119
93249
|
type: 'text',
|
|
93120
93250
|
value: node.value || '',
|
|
93121
93251
|
});
|
|
93252
|
+
// Since we serialize component / html tag attributes
|
|
93253
|
+
function decodeHtmlEntities(value) {
|
|
93254
|
+
return value
|
|
93255
|
+
.replace(/"/g, '"')
|
|
93256
|
+
.replace(/</g, '<')
|
|
93257
|
+
.replace(/>/g, '>')
|
|
93258
|
+
.replace(/ /g, '\n')
|
|
93259
|
+
.replace(/&/g, '&');
|
|
93260
|
+
}
|
|
93122
93261
|
// Convert MDX JSX elements to HAST elements, preserving attributes and children
|
|
93123
93262
|
const mdxJsxElementHandler = (state, node) => {
|
|
93124
93263
|
const { attributes = [], name } = node;
|
|
@@ -93130,7 +93269,7 @@ const mdxJsxElementHandler = (state, node) => {
|
|
|
93130
93269
|
properties[attribute.name] = true;
|
|
93131
93270
|
}
|
|
93132
93271
|
else if (typeof attribute.value === 'string') {
|
|
93133
|
-
properties[attribute.name] = attribute.value;
|
|
93272
|
+
properties[attribute.name] = decodeHtmlEntities(attribute.value);
|
|
93134
93273
|
}
|
|
93135
93274
|
else {
|
|
93136
93275
|
properties[attribute.name] = attribute.value.value;
|
|
@@ -93192,6 +93331,17 @@ function base64Decode(str) {
|
|
|
93192
93331
|
}
|
|
93193
93332
|
return decodeURIComponent(escape(atob(str)));
|
|
93194
93333
|
}
|
|
93334
|
+
function escapeHtmlAttribute(value) {
|
|
93335
|
+
return value
|
|
93336
|
+
.replace(/&/g, '&')
|
|
93337
|
+
.replace(/"/g, '"')
|
|
93338
|
+
.replace(/</g, '<')
|
|
93339
|
+
.replace(/>/g, '>')
|
|
93340
|
+
.replace(/\n/g, ' ');
|
|
93341
|
+
}
|
|
93342
|
+
// Marker prefix for JSON-serialized complex values (arrays/objects)
|
|
93343
|
+
// Using a prefix that won't conflict with regular string values
|
|
93344
|
+
const JSON_VALUE_MARKER = '__MDXISH_JSON__';
|
|
93195
93345
|
// Markers for protected HTMLBlock content (HTML comments avoid markdown parsing issues)
|
|
93196
93346
|
const HTML_BLOCK_CONTENT_START = '<!--RDMX_HTMLBLOCK:';
|
|
93197
93347
|
const HTML_BLOCK_CONTENT_END = ':RDMX_HTMLBLOCK-->';
|
|
@@ -93321,6 +93471,16 @@ function extractBalancedBraces(content, start) {
|
|
|
93321
93471
|
return null;
|
|
93322
93472
|
return { content: content.slice(start, pos - 1), end: pos };
|
|
93323
93473
|
}
|
|
93474
|
+
function restoreInlineCode(content, protectedCode) {
|
|
93475
|
+
return content.replace(/___INLINE_CODE_(\d+)___/g, (_m, idx) => {
|
|
93476
|
+
return protectedCode.inlineCode[parseInt(idx, 10)];
|
|
93477
|
+
});
|
|
93478
|
+
}
|
|
93479
|
+
function restoreCodeBlocks(content, protectedCode) {
|
|
93480
|
+
return content.replace(/___CODE_BLOCK_(\d+)___/g, (_m, idx) => {
|
|
93481
|
+
return protectedCode.codeBlocks[parseInt(idx, 10)];
|
|
93482
|
+
});
|
|
93483
|
+
}
|
|
93324
93484
|
/**
|
|
93325
93485
|
* Converts JSX attribute expressions (attribute={expression}) to HTML attributes (attribute="value").
|
|
93326
93486
|
* Handles style objects (camelCase → kebab-case), className → class, and JSON stringifies objects.
|
|
@@ -93336,7 +93496,7 @@ function extractBalancedBraces(content, start) {
|
|
|
93336
93496
|
* // Returns: '<a href="https://example.com">Link</a>'
|
|
93337
93497
|
* ```
|
|
93338
93498
|
*/
|
|
93339
|
-
function evaluateAttributeExpressions(content, context) {
|
|
93499
|
+
function evaluateAttributeExpressions(content, context, protectedCode) {
|
|
93340
93500
|
const attrStartRegex = /(\w+)=\{/g;
|
|
93341
93501
|
let result = '';
|
|
93342
93502
|
let lastEnd = 0;
|
|
@@ -93346,7 +93506,14 @@ function evaluateAttributeExpressions(content, context) {
|
|
|
93346
93506
|
const braceStart = match.index + match[0].length;
|
|
93347
93507
|
const extracted = extractBalancedBraces(content, braceStart);
|
|
93348
93508
|
if (extracted) {
|
|
93349
|
-
|
|
93509
|
+
// The expression might contain template literals in MDX component tag props
|
|
93510
|
+
// E.g. <Component greeting={`Hello World!`} />
|
|
93511
|
+
// that is marked as inline code. So we need to restore the inline codes
|
|
93512
|
+
// in the expression to evaluate it
|
|
93513
|
+
let expression = extracted.content;
|
|
93514
|
+
if (protectedCode) {
|
|
93515
|
+
expression = restoreInlineCode(expression, protectedCode);
|
|
93516
|
+
}
|
|
93350
93517
|
const fullMatchEnd = extracted.end;
|
|
93351
93518
|
result += content.slice(lastEnd, match.index);
|
|
93352
93519
|
try {
|
|
@@ -93362,14 +93529,20 @@ function evaluateAttributeExpressions(content, context) {
|
|
|
93362
93529
|
result += `style="${cssString}"`;
|
|
93363
93530
|
}
|
|
93364
93531
|
else {
|
|
93365
|
-
|
|
93532
|
+
// These are arrays / objects attribute values
|
|
93533
|
+
// Mark JSON-serialized values with a prefix so they can be parsed back correctly
|
|
93534
|
+
const jsonValue = escapeHtmlAttribute(JSON_VALUE_MARKER + JSON.stringify(evalResult));
|
|
93535
|
+
// Use double quotes so that multi-paragraph values are not split into multiple attributes by the processors
|
|
93536
|
+
result += `${attributeName}="${jsonValue}"`;
|
|
93366
93537
|
}
|
|
93367
93538
|
}
|
|
93368
93539
|
else if (attributeName === 'className') {
|
|
93369
|
-
|
|
93540
|
+
// Escape special characters so that it doesn't break and split the attribute value to nodes
|
|
93541
|
+
// This will be restored later in the pipeline
|
|
93542
|
+
result += `class="${escapeHtmlAttribute(String(evalResult))}"`;
|
|
93370
93543
|
}
|
|
93371
93544
|
else {
|
|
93372
|
-
result += `${attributeName}="${evalResult}"`;
|
|
93545
|
+
result += `${attributeName}="${escapeHtmlAttribute(String(evalResult))}"`;
|
|
93373
93546
|
}
|
|
93374
93547
|
}
|
|
93375
93548
|
catch (_error) {
|
|
@@ -93400,13 +93573,9 @@ function evaluateAttributeExpressions(content, context) {
|
|
|
93400
93573
|
* // Returns: 'Text with `inline` and ```js\ncode\n```'
|
|
93401
93574
|
* ```
|
|
93402
93575
|
*/
|
|
93403
|
-
function
|
|
93404
|
-
let restored = content
|
|
93405
|
-
|
|
93406
|
-
});
|
|
93407
|
-
restored = restored.replace(/___INLINE_CODE_(\d+)___/g, (_match, index) => {
|
|
93408
|
-
return protectedCode.inlineCode[parseInt(index, 10)];
|
|
93409
|
-
});
|
|
93576
|
+
function restoreProtectedCodes(content, protectedCode) {
|
|
93577
|
+
let restored = restoreCodeBlocks(content, protectedCode);
|
|
93578
|
+
restored = restoreInlineCode(restored, protectedCode);
|
|
93410
93579
|
return restored;
|
|
93411
93580
|
}
|
|
93412
93581
|
/**
|
|
@@ -93427,9 +93596,9 @@ function preprocessJSXExpressions(content, context = {}) {
|
|
|
93427
93596
|
// Step 3: Evaluate attribute expressions (JSX attribute syntax: href={baseUrl})
|
|
93428
93597
|
// For inline expressions, we use a library to parse the expression & evaluate it later
|
|
93429
93598
|
// For attribute expressions, it was difficult to use a library to parse them, so do it manually
|
|
93430
|
-
processed = evaluateAttributeExpressions(processed, context);
|
|
93599
|
+
processed = evaluateAttributeExpressions(processed, context, protectedCode);
|
|
93431
93600
|
// Step 4: Restore protected code blocks
|
|
93432
|
-
processed =
|
|
93601
|
+
processed = restoreProtectedCodes(processed, protectedCode);
|
|
93433
93602
|
return processed;
|
|
93434
93603
|
}
|
|
93435
93604
|
|
|
@@ -93841,7 +94010,7 @@ const wrapPinnedBlocks = (node, json) => {
|
|
|
93841
94010
|
return node;
|
|
93842
94011
|
return {
|
|
93843
94012
|
children: [node],
|
|
93844
|
-
data: {
|
|
94013
|
+
data: { hName: 'rdme-pin', hProperties: { className: 'pin' } },
|
|
93845
94014
|
type: 'rdme-pin',
|
|
93846
94015
|
};
|
|
93847
94016
|
};
|
|
@@ -93929,15 +94098,16 @@ function parseMagicBlock(raw, options = {}) {
|
|
|
93929
94098
|
type: 'code',
|
|
93930
94099
|
value: obj.code.trim(),
|
|
93931
94100
|
}));
|
|
93932
|
-
// Single code block without a tab name renders as a plain code block
|
|
94101
|
+
// Single code block without a tab name (meta or language) renders as a plain code block
|
|
94102
|
+
// Otherwise, we want to render it as a code tabs block
|
|
93933
94103
|
if (children.length === 1) {
|
|
93934
94104
|
if (!children[0].value)
|
|
93935
94105
|
return [];
|
|
93936
|
-
if (children[0].meta)
|
|
94106
|
+
if (!(children[0].meta || children[0].lang))
|
|
93937
94107
|
return [wrapPinnedBlocks(children[0], json)];
|
|
93938
94108
|
}
|
|
93939
|
-
// Multiple code blocks
|
|
93940
|
-
return [wrapPinnedBlocks({ children, className: 'tabs', data: { hName: '
|
|
94109
|
+
// Multiple code blocks or a single code block with a tab name (meta or language) renders as a code tabs block
|
|
94110
|
+
return [wrapPinnedBlocks({ children, className: 'tabs', data: { hName: 'CodeTabs' }, type: 'code-tabs' }, json)];
|
|
93941
94111
|
}
|
|
93942
94112
|
// API header: renders as a heading element (h1-h6)
|
|
93943
94113
|
case 'api-header': {
|
|
@@ -94138,11 +94308,31 @@ function parseMagicBlock(raw, options = {}) {
|
|
|
94138
94308
|
}
|
|
94139
94309
|
}
|
|
94140
94310
|
/**
|
|
94141
|
-
*
|
|
94311
|
+
* Block-level node types that cannot be nested inside paragraphs.
|
|
94142
94312
|
*/
|
|
94143
|
-
const
|
|
94144
|
-
|
|
94145
|
-
|
|
94313
|
+
const blockTypes = [
|
|
94314
|
+
'heading',
|
|
94315
|
+
'code',
|
|
94316
|
+
'code-tabs',
|
|
94317
|
+
'paragraph',
|
|
94318
|
+
'blockquote',
|
|
94319
|
+
'list',
|
|
94320
|
+
'table',
|
|
94321
|
+
'thematicBreak',
|
|
94322
|
+
'html',
|
|
94323
|
+
'yaml',
|
|
94324
|
+
'toml',
|
|
94325
|
+
'rdme-pin',
|
|
94326
|
+
'rdme-callout',
|
|
94327
|
+
'html-block',
|
|
94328
|
+
'embed',
|
|
94329
|
+
'figure',
|
|
94330
|
+
'mdxJsxFlowElement',
|
|
94331
|
+
];
|
|
94332
|
+
/**
|
|
94333
|
+
* Check if a node is a block-level node (cannot be inside a paragraph)
|
|
94334
|
+
*/
|
|
94335
|
+
const isBlockNode = (node) => blockTypes.includes(node.type);
|
|
94146
94336
|
/**
|
|
94147
94337
|
* Unified plugin that restores magic blocks from placeholder tokens.
|
|
94148
94338
|
*
|
|
@@ -94155,8 +94345,9 @@ const magicBlockRestorer = ({ blocks }) => tree => {
|
|
|
94155
94345
|
return;
|
|
94156
94346
|
// Map: key → original raw magic block content
|
|
94157
94347
|
const magicBlockKeys = new Map(blocks.map(({ key, raw }) => [key, raw]));
|
|
94158
|
-
//
|
|
94159
|
-
const
|
|
94348
|
+
// Collect replacements to apply (we need to visit in reverse to maintain indices)
|
|
94349
|
+
const replacements = [];
|
|
94350
|
+
// First pass: collect all replacements
|
|
94160
94351
|
visit(tree, 'inlineCode', (node, index, parent) => {
|
|
94161
94352
|
if (!parent || index == null)
|
|
94162
94353
|
return undefined;
|
|
@@ -94166,31 +94357,73 @@ const magicBlockRestorer = ({ blocks }) => tree => {
|
|
|
94166
94357
|
const children = parseMagicBlock(raw);
|
|
94167
94358
|
if (!children.length)
|
|
94168
94359
|
return undefined;
|
|
94169
|
-
|
|
94170
|
-
|
|
94171
|
-
|
|
94172
|
-
|
|
94173
|
-
|
|
94174
|
-
|
|
94175
|
-
|
|
94360
|
+
// If parent is a paragraph and we're inserting block nodes (which must not be in paragraphs), lift them out
|
|
94361
|
+
if (parent.type === 'paragraph' && children.some(child => isBlockNode(child))) {
|
|
94362
|
+
const blockNodes = [];
|
|
94363
|
+
const inlineNodes = [];
|
|
94364
|
+
// Separate block and inline nodes
|
|
94365
|
+
children.forEach(child => {
|
|
94366
|
+
if (isBlockNode(child)) {
|
|
94367
|
+
blockNodes.push(child);
|
|
94176
94368
|
}
|
|
94177
|
-
|
|
94178
|
-
|
|
94179
|
-
if (paragraphParent) {
|
|
94180
|
-
const paragraphIndex = paragraphParent.children.indexOf(parent);
|
|
94181
|
-
if (paragraphIndex !== -1) {
|
|
94182
|
-
modifications.push({ children, index: paragraphIndex, parent: paragraphParent });
|
|
94369
|
+
else {
|
|
94370
|
+
inlineNodes.push(child);
|
|
94183
94371
|
}
|
|
94184
|
-
}
|
|
94185
|
-
|
|
94372
|
+
});
|
|
94373
|
+
const before = parent.children.slice(0, index);
|
|
94374
|
+
const after = parent.children.slice(index + 1);
|
|
94375
|
+
replacements.push({
|
|
94376
|
+
parent,
|
|
94377
|
+
blockNodes,
|
|
94378
|
+
inlineNodes,
|
|
94379
|
+
before,
|
|
94380
|
+
after,
|
|
94381
|
+
});
|
|
94186
94382
|
}
|
|
94187
|
-
|
|
94188
|
-
|
|
94189
|
-
|
|
94190
|
-
|
|
94191
|
-
|
|
94192
|
-
parent.children.splice(index, 1, ...children);
|
|
94383
|
+
else {
|
|
94384
|
+
// Normal case: just replace the inlineCode with the children
|
|
94385
|
+
parent.children.splice(index, 1, ...children);
|
|
94386
|
+
}
|
|
94387
|
+
return undefined;
|
|
94193
94388
|
});
|
|
94389
|
+
// Second pass: apply replacements that require lifting block nodes out of paragraphs
|
|
94390
|
+
// Process in reverse order to maintain correct indices
|
|
94391
|
+
for (let i = replacements.length - 1; i >= 0; i -= 1) {
|
|
94392
|
+
const { after, before, blockNodes, inlineNodes, parent } = replacements[i];
|
|
94393
|
+
// Find the paragraph's position in the root
|
|
94394
|
+
const rootChildren = tree.children;
|
|
94395
|
+
const paraIndex = rootChildren.findIndex(child => child === parent);
|
|
94396
|
+
if (paraIndex === -1) {
|
|
94397
|
+
// Paragraph not found in root - fall back to normal replacement
|
|
94398
|
+
// This shouldn't happen normally, but handle it gracefully
|
|
94399
|
+
// Reconstruct the original index from before.length
|
|
94400
|
+
const originalIndex = before.length;
|
|
94401
|
+
parent.children.splice(originalIndex, 1, ...blockNodes, ...inlineNodes);
|
|
94402
|
+
// eslint-disable-next-line no-continue
|
|
94403
|
+
continue;
|
|
94404
|
+
}
|
|
94405
|
+
// Update or remove the paragraph
|
|
94406
|
+
if (inlineNodes.length > 0) {
|
|
94407
|
+
// Keep paragraph with inline nodes
|
|
94408
|
+
parent.children = [...before, ...inlineNodes, ...after];
|
|
94409
|
+
// Insert block nodes after the paragraph
|
|
94410
|
+
if (blockNodes.length > 0) {
|
|
94411
|
+
rootChildren.splice(paraIndex + 1, 0, ...blockNodes);
|
|
94412
|
+
}
|
|
94413
|
+
}
|
|
94414
|
+
else if (before.length === 0 && after.length === 0) {
|
|
94415
|
+
// Remove empty paragraph and replace with block nodes
|
|
94416
|
+
rootChildren.splice(paraIndex, 1, ...blockNodes);
|
|
94417
|
+
}
|
|
94418
|
+
else {
|
|
94419
|
+
// Keep paragraph with remaining content
|
|
94420
|
+
parent.children = [...before, ...after];
|
|
94421
|
+
// Insert block nodes after the paragraph
|
|
94422
|
+
if (blockNodes.length > 0) {
|
|
94423
|
+
rootChildren.splice(paraIndex + 1, 0, ...blockNodes);
|
|
94424
|
+
}
|
|
94425
|
+
}
|
|
94426
|
+
}
|
|
94194
94427
|
};
|
|
94195
94428
|
/* harmony default export */ const mdxish_magic_blocks = (magicBlockRestorer);
|
|
94196
94429
|
|
|
@@ -94414,6 +94647,92 @@ const normalizeEmphasisAST = () => (tree) => {
|
|
|
94414
94647
|
};
|
|
94415
94648
|
/* harmony default export */ const normalize_malformed_md_syntax = (normalizeEmphasisAST);
|
|
94416
94649
|
|
|
94650
|
+
;// ./processor/transform/mdxish/normalize-table-separator.ts
|
|
94651
|
+
/**
|
|
94652
|
+
* Preprocessor to normalize malformed GFM table separator syntax.
|
|
94653
|
+
*
|
|
94654
|
+
* Fixes the common mistake where the alignment colon is placed after the pipe
|
|
94655
|
+
* instead of before the dashes:
|
|
94656
|
+
*
|
|
94657
|
+
* Invalid: `|: ---` or `|:---` (colon after pipe)
|
|
94658
|
+
* Valid: `| :---` (colon before dashes)
|
|
94659
|
+
*
|
|
94660
|
+
* Also handles right alignment:
|
|
94661
|
+
* Invalid: `| ---:| ` with space before pipe
|
|
94662
|
+
* Valid: `| ---:|` (no space before closing pipe)
|
|
94663
|
+
*
|
|
94664
|
+
* This runs before remark-parse to ensure the table is recognized as a valid GFM table.
|
|
94665
|
+
*/
|
|
94666
|
+
/**
|
|
94667
|
+
* Pattern to match a table separator row.
|
|
94668
|
+
* A separator row consists of cells that contain only dashes, colons (for alignment), and spaces.
|
|
94669
|
+
*
|
|
94670
|
+
* Valid GFM separator formats:
|
|
94671
|
+
* - `---` or `----` (no alignment, defaults to left)
|
|
94672
|
+
* - `:---` (left aligned)
|
|
94673
|
+
* - `---:` (right aligned)
|
|
94674
|
+
* - `:---:` (center aligned)
|
|
94675
|
+
*
|
|
94676
|
+
* Invalid formats this fixes:
|
|
94677
|
+
* - `|: ---` → `| :---` (colon wrongly placed after pipe)
|
|
94678
|
+
* - `|:---` → `| :---` (colon directly after pipe, missing space)
|
|
94679
|
+
* - `|::---` or `| ::---` → `| :---` (double colon typo)
|
|
94680
|
+
*/
|
|
94681
|
+
// Match a line that looks like a table separator row
|
|
94682
|
+
// This regex captures the whole line if it contains only pipe-separated cells with dashes/colons
|
|
94683
|
+
const TABLE_SEPARATOR_LINE_REGEX = /^(\|[:\s-]+)+\|?\s*$/;
|
|
94684
|
+
// Match malformed left-alignment: `|: ` or `|:` followed by dashes
|
|
94685
|
+
// Captures: group 1 = pipe, group 2 = spaces after colon, group 3 = dashes
|
|
94686
|
+
const MALFORMED_LEFT_ALIGN_REGEX = /\|:(\s*)(-+)/g;
|
|
94687
|
+
// Match malformed double colon: `|::---` or `| ::---` → `| :---`
|
|
94688
|
+
const MALFORMED_DOUBLE_COLON_REGEX = /\|\s*::(\s*)(-+)/g;
|
|
94689
|
+
// Match malformed patterns with spaces before closing colons: `| --- : |` → `| ---: |`
|
|
94690
|
+
const MALFORMED_RIGHT_ALIGN_SPACE_REGEX = /(-+)\s+:(\s*\|)/g;
|
|
94691
|
+
// Match malformed center alignment with spaces: `| : --- : |` → `| :---: |`
|
|
94692
|
+
const MALFORMED_CENTER_ALIGN_REGEX = /\|:(\s+)(-+)(\s+):/g;
|
|
94693
|
+
/**
|
|
94694
|
+
* Normalizes a single table separator line.
|
|
94695
|
+
*/
|
|
94696
|
+
function normalizeTableSeparatorLine(line) {
|
|
94697
|
+
// Check if this line looks like a table separator
|
|
94698
|
+
if (!TABLE_SEPARATOR_LINE_REGEX.test(line)) {
|
|
94699
|
+
return line;
|
|
94700
|
+
}
|
|
94701
|
+
let normalized = line;
|
|
94702
|
+
// Fix `|::---` → `| :---` (double colon typo)
|
|
94703
|
+
// Must run before single colon fix to avoid partial replacement
|
|
94704
|
+
normalized = normalized.replace(MALFORMED_DOUBLE_COLON_REGEX, '| :$2');
|
|
94705
|
+
// Fix `|: ---` or `|:---` → `| :---`
|
|
94706
|
+
// The colon should be adjacent to the dashes, not the pipe
|
|
94707
|
+
normalized = normalized.replace(MALFORMED_LEFT_ALIGN_REGEX, '| :$2');
|
|
94708
|
+
// Fix `| --- : |` → `| ---: |`
|
|
94709
|
+
// Remove space before right-alignment colon
|
|
94710
|
+
normalized = normalized.replace(MALFORMED_RIGHT_ALIGN_SPACE_REGEX, '$1:$2');
|
|
94711
|
+
// Fix `| : --- : |` → `| :---: |`
|
|
94712
|
+
// Remove spaces around center-aligned dashes
|
|
94713
|
+
normalized = normalized.replace(MALFORMED_CENTER_ALIGN_REGEX, '| :$2:');
|
|
94714
|
+
return normalized;
|
|
94715
|
+
}
|
|
94716
|
+
/**
|
|
94717
|
+
* Preprocesses markdown content to normalize malformed table separator syntax.
|
|
94718
|
+
*
|
|
94719
|
+
* @param content - The raw markdown content
|
|
94720
|
+
* @returns The content with normalized table separators
|
|
94721
|
+
*/
|
|
94722
|
+
function normalizeTableSeparator(content) {
|
|
94723
|
+
const lines = content.split('\n');
|
|
94724
|
+
const normalizedLines = lines.map((line, index) => {
|
|
94725
|
+
const prevLine = index > 0 ? lines[index - 1] : '';
|
|
94726
|
+
const isPrevLineTableRow = prevLine.trim().startsWith('|');
|
|
94727
|
+
if (isPrevLineTableRow) {
|
|
94728
|
+
return normalizeTableSeparatorLine(line);
|
|
94729
|
+
}
|
|
94730
|
+
return line;
|
|
94731
|
+
});
|
|
94732
|
+
return normalizedLines.join('\n');
|
|
94733
|
+
}
|
|
94734
|
+
/* harmony default export */ const normalize_table_separator = ((/* unused pure expression or super */ null && (normalizeTableSeparator)));
|
|
94735
|
+
|
|
94417
94736
|
;// ./processor/transform/mdxish/restore-snake-case-component-name.ts
|
|
94418
94737
|
|
|
94419
94738
|
|
|
@@ -94677,6 +94996,7 @@ function loadComponents() {
|
|
|
94677
94996
|
|
|
94678
94997
|
|
|
94679
94998
|
|
|
94999
|
+
|
|
94680
95000
|
|
|
94681
95001
|
|
|
94682
95002
|
const defaultTransformers = [callouts, code_tabs, gemoji_, transform_embeds];
|
|
@@ -94689,9 +95009,11 @@ function mdxishAstProcessor(mdContent, opts = {}) {
|
|
|
94689
95009
|
// Preprocessing pipeline: Transform content to be parser-ready
|
|
94690
95010
|
// Step 1: Extract legacy magic blocks
|
|
94691
95011
|
const { replaced: contentAfterMagicBlocks, blocks } = extractMagicBlocks(mdContent);
|
|
94692
|
-
// Step 2:
|
|
94693
|
-
const
|
|
94694
|
-
// Step 3:
|
|
95012
|
+
// Step 2: Normalize malformed table separator syntax (e.g., `|: ---` → `| :---`)
|
|
95013
|
+
const contentAfterTableNormalization = normalizeTableSeparator(contentAfterMagicBlocks);
|
|
95014
|
+
// Step 3: Evaluate JSX expressions in attributes
|
|
95015
|
+
const contentAfterJSXEvaluation = preprocessJSXExpressions(contentAfterTableNormalization, jsxContext);
|
|
95016
|
+
// Step 4: Replace snake_case component names with parser-safe placeholders
|
|
94695
95017
|
// (e.g., <Snake_case /> → <MDXishSnakeCase0 /> which will be restored after parsing)
|
|
94696
95018
|
const { content: parserReadyContent, mapping: snakeCaseMapping } = processSnakeCaseComponent(contentAfterJSXEvaluation);
|
|
94697
95019
|
// Create string map for tailwind transformer
|
|
@@ -94955,6 +95277,40 @@ const makeUseMDXComponents = (more = {}) => {
|
|
|
94955
95277
|
|
|
94956
95278
|
|
|
94957
95279
|
|
|
95280
|
+
|
|
95281
|
+
/**
|
|
95282
|
+
* Parse JSON-marked string values in props back to their original types.
|
|
95283
|
+
* This handles arrays and objects that were serialized during JSX preprocessing.
|
|
95284
|
+
*/
|
|
95285
|
+
function parseJsonProps(props) {
|
|
95286
|
+
if (!props)
|
|
95287
|
+
return props;
|
|
95288
|
+
const parsed = {};
|
|
95289
|
+
Object.entries(props).forEach(([key, value]) => {
|
|
95290
|
+
if (typeof value === 'string' && value.startsWith(JSON_VALUE_MARKER)) {
|
|
95291
|
+
try {
|
|
95292
|
+
parsed[key] = JSON.parse(value.slice(JSON_VALUE_MARKER.length));
|
|
95293
|
+
}
|
|
95294
|
+
catch {
|
|
95295
|
+
// If parsing fails, use the value without the marker
|
|
95296
|
+
parsed[key] = value.slice(JSON_VALUE_MARKER.length);
|
|
95297
|
+
}
|
|
95298
|
+
}
|
|
95299
|
+
else {
|
|
95300
|
+
parsed[key] = value;
|
|
95301
|
+
}
|
|
95302
|
+
});
|
|
95303
|
+
return parsed;
|
|
95304
|
+
}
|
|
95305
|
+
/**
|
|
95306
|
+
* Custom createElement wrapper that parses JSON-marked string props.
|
|
95307
|
+
* This is needed because rehype-react converts HAST to React, but complex
|
|
95308
|
+
* types (arrays/objects) get serialized to strings during markdown parsing.
|
|
95309
|
+
*/
|
|
95310
|
+
function createElementWithJsonProps(type, props, ...children) {
|
|
95311
|
+
const parsedProps = parseJsonProps(props);
|
|
95312
|
+
return external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement(type, parsedProps, ...children);
|
|
95313
|
+
}
|
|
94958
95314
|
/** Flatten CustomComponents into a component map for rehype-react */
|
|
94959
95315
|
function exportComponentsForRehype(components) {
|
|
94960
95316
|
const exported = Object.entries(components).reduce((memo, [tag, mod]) => {
|
|
@@ -94986,7 +95342,7 @@ function exportComponentsForRehype(components) {
|
|
|
94986
95342
|
function createRehypeReactProcessor(components) {
|
|
94987
95343
|
// @ts-expect-error - rehype-react types are incompatible with React.Fragment return type
|
|
94988
95344
|
return unified().use((rehype_react_default()), {
|
|
94989
|
-
createElement:
|
|
95345
|
+
createElement: createElementWithJsonProps,
|
|
94990
95346
|
Fragment: (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default()).Fragment,
|
|
94991
95347
|
components,
|
|
94992
95348
|
});
|
|
@@ -95295,89 +95651,6 @@ async function stripComments(doc, { mdx } = {}) {
|
|
|
95295
95651
|
}
|
|
95296
95652
|
/* harmony default export */ const lib_stripComments = (stripComments);
|
|
95297
95653
|
|
|
95298
|
-
;// ./lib/utils/isPlainText.ts
|
|
95299
|
-
|
|
95300
|
-
/**
|
|
95301
|
-
* Detects if content contains HTML, magic blocks, or MDX syntax.
|
|
95302
|
-
*
|
|
95303
|
-
* We can use this in some pipelines to determine if we should have to parse content through
|
|
95304
|
-
* `.plain() or if it is already plain text and it should be able to detect everything that would
|
|
95305
|
-
* be stripped or sanitized by `.plain()`.
|
|
95306
|
-
*
|
|
95307
|
-
*/
|
|
95308
|
-
function isPlainText(content) {
|
|
95309
|
-
if (!content || typeof content !== 'string') {
|
|
95310
|
-
return true;
|
|
95311
|
-
}
|
|
95312
|
-
// Exclude markdown code blocks and inline code to avoid false positives
|
|
95313
|
-
// Match code blocks with optional language identifier: ```lang\n...\n```
|
|
95314
|
-
const codeBlockRegex = /```[^\n]*\n[\s\S]*?```/g;
|
|
95315
|
-
// Match inline code: `code` (but not escaped backticks)
|
|
95316
|
-
const inlineCodeRegex = /`[^`\n]+`/g;
|
|
95317
|
-
// Remove code blocks and inline code to avoid false positives
|
|
95318
|
-
let contentWithoutCode = structuredClone(content);
|
|
95319
|
-
contentWithoutCode = contentWithoutCode.replace(codeBlockRegex, '');
|
|
95320
|
-
contentWithoutCode = contentWithoutCode.replace(inlineCodeRegex, '');
|
|
95321
|
-
// Check for magic blocks: `[block:TYPE]...[/block]`
|
|
95322
|
-
// Only check after removing code blocks to avoid detecting magic blocks in code
|
|
95323
|
-
if (contentWithoutCode.match(MAGIC_BLOCK_REGEX) !== null) {
|
|
95324
|
-
return false;
|
|
95325
|
-
}
|
|
95326
|
-
// Check for markdown links: [text](url) or [text][reference]
|
|
95327
|
-
// Pattern matches inline links and reference-style links
|
|
95328
|
-
// Exclude images which start with ! before the bracket
|
|
95329
|
-
// Only check after removing code blocks
|
|
95330
|
-
const markdownLinkPattern = /(?<!!)\[([^\]]+)\]\(([^)]+)\)|(?<!!)\[([^\]]+)\]\[([^\]]*)\]/;
|
|
95331
|
-
if (markdownLinkPattern.test(contentWithoutCode)) {
|
|
95332
|
-
return false;
|
|
95333
|
-
}
|
|
95334
|
-
// Check for JSX elements (PascalCase components) in the original content
|
|
95335
|
-
// This includes code blocks since JSX code examples should be detected
|
|
95336
|
-
// Pattern matches:
|
|
95337
|
-
// - Self-closing: <Component /> or <Component/>
|
|
95338
|
-
// - With attributes: <Component prop="value" />
|
|
95339
|
-
// - With children: <Component>...</Component>
|
|
95340
|
-
// Use simpler, safer patterns to avoid ReDoS from backtracking
|
|
95341
|
-
// Match self-closing tags with bounded attribute length to prevent excessive backtracking
|
|
95342
|
-
const jsxSelfClosingPattern = /<[A-Z][a-zA-Z0-9]*(?:\s[^>]{0,50})?\/>/;
|
|
95343
|
-
if (jsxSelfClosingPattern.test(content)) {
|
|
95344
|
-
return false;
|
|
95345
|
-
}
|
|
95346
|
-
// For components with children, use a safer pattern that limits backtracking
|
|
95347
|
-
// Match opening tag with bounded attributes, then look for closing tag with same name
|
|
95348
|
-
const jsxWithChildrenPattern = /<([A-Z][a-zA-Z0-9]*)(?:\s[^>]{0,50})?>[\s\S]{0,50}<\/\1>/;
|
|
95349
|
-
if (jsxWithChildrenPattern.test(content)) {
|
|
95350
|
-
return false;
|
|
95351
|
-
}
|
|
95352
|
-
// Check for MDX expressions and HTML tags in the original content
|
|
95353
|
-
// HTML/JSX/MDX in code blocks should be detected (as per test requirements)
|
|
95354
|
-
// But exclude inline code that contains magic block patterns to avoid false positives
|
|
95355
|
-
let contentForHtmlMdx = content;
|
|
95356
|
-
// Find inline code blocks and check if they contain [block: pattern
|
|
95357
|
-
// Exclude these from HTML/MDX detection to avoid false positives
|
|
95358
|
-
const inlineCodePattern = /`[^`\n]+`/g;
|
|
95359
|
-
let inlineCodeMatch;
|
|
95360
|
-
inlineCodePattern.lastIndex = 0;
|
|
95361
|
-
while ((inlineCodeMatch = inlineCodePattern.exec(content)) !== null) {
|
|
95362
|
-
if (inlineCodeMatch[0].includes('[block:')) {
|
|
95363
|
-
contentForHtmlMdx = contentForHtmlMdx.replace(inlineCodeMatch[0], '');
|
|
95364
|
-
}
|
|
95365
|
-
}
|
|
95366
|
-
// Match simple MDX variable expressions like {variable}, {user.name}, {getValue()}, {}
|
|
95367
|
-
// Use bounded quantifier to prevent ReDoS - limit to reasonable variable name length
|
|
95368
|
-
// Allow empty braces {} to be detected as well
|
|
95369
|
-
const jsxExpressionPattern = /\{[^}"]{0,50}\}/;
|
|
95370
|
-
if (jsxExpressionPattern.test(contentForHtmlMdx)) {
|
|
95371
|
-
return false;
|
|
95372
|
-
}
|
|
95373
|
-
// Match HTML tags with bounded attribute length to prevent ReDoS
|
|
95374
|
-
const htmlTagPattern = /<[a-z][a-z0-9]*(?:\s[^>]{0,50})?(?:\/>|>)/i;
|
|
95375
|
-
if (htmlTagPattern.test(contentForHtmlMdx)) {
|
|
95376
|
-
return false;
|
|
95377
|
-
}
|
|
95378
|
-
return true;
|
|
95379
|
-
}
|
|
95380
|
-
|
|
95381
95654
|
;// ./lib/index.ts
|
|
95382
95655
|
|
|
95383
95656
|
|
|
@@ -95396,7 +95669,6 @@ function isPlainText(content) {
|
|
|
95396
95669
|
|
|
95397
95670
|
|
|
95398
95671
|
|
|
95399
|
-
|
|
95400
95672
|
;// ./index.tsx
|
|
95401
95673
|
|
|
95402
95674
|
|