@readme/markdown 11.15.0 → 12.0.1
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
|
@@ -52943,12 +52943,45 @@ const plain = (node, opts = {}) => {
|
|
|
52943
52943
|
};
|
|
52944
52944
|
/* harmony default export */ const lib_plain = (plain);
|
|
52945
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
|
+
// When a blockquote contains only an image (no text), treat it as having content
|
|
52961
|
+
// so the blockquote is no longer treated as empty and preserved correctly.
|
|
52962
|
+
if (node.type === 'image') {
|
|
52963
|
+
return typeof node.alt === 'string' && node.alt ? node.alt : '[image]';
|
|
52964
|
+
}
|
|
52965
|
+
if (node.children && Array.isArray(node.children)) {
|
|
52966
|
+
return node.children
|
|
52967
|
+
.map(child => {
|
|
52968
|
+
if (child && typeof child === 'object' && 'type' in child) {
|
|
52969
|
+
return extractText(child);
|
|
52970
|
+
}
|
|
52971
|
+
return '';
|
|
52972
|
+
})
|
|
52973
|
+
.join('');
|
|
52974
|
+
}
|
|
52975
|
+
return '';
|
|
52976
|
+
};
|
|
52977
|
+
|
|
52946
52978
|
;// ./processor/transform/callouts.ts
|
|
52947
52979
|
|
|
52948
52980
|
|
|
52949
52981
|
|
|
52950
52982
|
|
|
52951
52983
|
|
|
52984
|
+
|
|
52952
52985
|
const callouts_regex = `^(${emoji_regex().source}|⚠)(\\s+|$)`;
|
|
52953
52986
|
const findFirst = (node) => {
|
|
52954
52987
|
if ('children' in node)
|
|
@@ -52969,42 +53002,76 @@ const wrapHeading = (node) => {
|
|
|
52969
53002
|
},
|
|
52970
53003
|
};
|
|
52971
53004
|
};
|
|
53005
|
+
/**
|
|
53006
|
+
* Checks if a blockquote matches the expected callout structure:
|
|
53007
|
+
* blockquote > paragraph > text node
|
|
53008
|
+
*/
|
|
53009
|
+
const isCalloutStructure = (node) => {
|
|
53010
|
+
const firstChild = node.children?.[0];
|
|
53011
|
+
if (!firstChild || firstChild.type !== 'paragraph')
|
|
53012
|
+
return false;
|
|
53013
|
+
if (!('children' in firstChild))
|
|
53014
|
+
return false;
|
|
53015
|
+
const firstTextChild = firstChild.children?.[0];
|
|
53016
|
+
return firstTextChild?.type === 'text';
|
|
53017
|
+
};
|
|
53018
|
+
const processBlockquote = (node, index, parent) => {
|
|
53019
|
+
if (!isCalloutStructure(node)) {
|
|
53020
|
+
// Only stringify empty blockquotes (no extractable text content)
|
|
53021
|
+
// Preserve blockquotes with actual content (e.g., headings, lists, etc.)
|
|
53022
|
+
const content = extractText(node);
|
|
53023
|
+
const isEmpty = !content || content.trim() === '';
|
|
53024
|
+
if (isEmpty && index !== undefined && parent) {
|
|
53025
|
+
const textNode = {
|
|
53026
|
+
type: 'text',
|
|
53027
|
+
value: '>',
|
|
53028
|
+
};
|
|
53029
|
+
const paragraphNode = {
|
|
53030
|
+
type: 'paragraph',
|
|
53031
|
+
children: [textNode],
|
|
53032
|
+
position: node.position,
|
|
53033
|
+
};
|
|
53034
|
+
parent.children.splice(index, 1, paragraphNode);
|
|
53035
|
+
}
|
|
53036
|
+
return;
|
|
53037
|
+
}
|
|
53038
|
+
// isCalloutStructure ensures node.children[0] is a Paragraph with children
|
|
53039
|
+
const firstParagraph = node.children[0];
|
|
53040
|
+
const startText = lib_plain(firstParagraph).toString();
|
|
53041
|
+
const [match, icon] = startText.match(callouts_regex) || [];
|
|
53042
|
+
if (icon && match) {
|
|
53043
|
+
const heading = startText.slice(match.length);
|
|
53044
|
+
const empty = !heading.length && firstParagraph.children.length === 1;
|
|
53045
|
+
const theme = themes[icon] || 'default';
|
|
53046
|
+
const firstChild = findFirst(node.children[0]);
|
|
53047
|
+
if (firstChild && 'value' in firstChild && typeof firstChild.value === 'string') {
|
|
53048
|
+
firstChild.value = firstChild.value.slice(match.length);
|
|
53049
|
+
}
|
|
53050
|
+
if (heading) {
|
|
53051
|
+
node.children[0] = wrapHeading(node);
|
|
53052
|
+
// @note: We add to the offset/column the length of the unicode
|
|
53053
|
+
// character that was stripped off, so that the start position of the
|
|
53054
|
+
// heading/text matches where it actually starts.
|
|
53055
|
+
node.children[0].position.start.offset += match.length;
|
|
53056
|
+
node.children[0].position.start.column += match.length;
|
|
53057
|
+
}
|
|
53058
|
+
Object.assign(node, {
|
|
53059
|
+
type: NodeTypes.callout,
|
|
53060
|
+
data: {
|
|
53061
|
+
hName: 'Callout',
|
|
53062
|
+
hProperties: {
|
|
53063
|
+
icon,
|
|
53064
|
+
...(empty && { empty }),
|
|
53065
|
+
theme,
|
|
53066
|
+
},
|
|
53067
|
+
},
|
|
53068
|
+
});
|
|
53069
|
+
}
|
|
53070
|
+
};
|
|
52972
53071
|
const calloutTransformer = () => {
|
|
52973
53072
|
return (tree) => {
|
|
52974
|
-
visit(tree, 'blockquote', (node) => {
|
|
52975
|
-
|
|
52976
|
-
return;
|
|
52977
|
-
// @ts-expect-error -- @todo: update plain to accept mdast
|
|
52978
|
-
const startText = lib_plain(node.children[0]).toString();
|
|
52979
|
-
const [match, icon] = startText.match(callouts_regex) || [];
|
|
52980
|
-
if (icon && match) {
|
|
52981
|
-
const heading = startText.slice(match.length);
|
|
52982
|
-
const empty = !heading.length && node.children[0].children.length === 1;
|
|
52983
|
-
const theme = themes[icon] || 'default';
|
|
52984
|
-
const firstChild = findFirst(node.children[0]);
|
|
52985
|
-
if (firstChild && 'value' in firstChild && typeof firstChild.value === 'string') {
|
|
52986
|
-
firstChild.value = firstChild.value.slice(match.length);
|
|
52987
|
-
}
|
|
52988
|
-
if (heading) {
|
|
52989
|
-
node.children[0] = wrapHeading(node);
|
|
52990
|
-
// @note: We add to the offset/column the length of the unicode
|
|
52991
|
-
// character that was stripped off, so that the start position of the
|
|
52992
|
-
// heading/text matches where it actually starts.
|
|
52993
|
-
node.children[0].position.start.offset += match.length;
|
|
52994
|
-
node.children[0].position.start.column += match.length;
|
|
52995
|
-
}
|
|
52996
|
-
Object.assign(node, {
|
|
52997
|
-
type: NodeTypes.callout,
|
|
52998
|
-
data: {
|
|
52999
|
-
hName: 'Callout',
|
|
53000
|
-
hProperties: {
|
|
53001
|
-
icon,
|
|
53002
|
-
...(empty && { empty }),
|
|
53003
|
-
theme,
|
|
53004
|
-
},
|
|
53005
|
-
},
|
|
53006
|
-
});
|
|
53007
|
-
}
|
|
53073
|
+
visit(tree, 'blockquote', (node, index, parent) => {
|
|
53074
|
+
processBlockquote(node, index, parent);
|
|
53008
53075
|
});
|
|
53009
53076
|
};
|
|
53010
53077
|
};
|
|
@@ -70670,6 +70737,17 @@ const parseTag = (value) => {
|
|
|
70670
70737
|
contentAfterTag,
|
|
70671
70738
|
};
|
|
70672
70739
|
};
|
|
70740
|
+
/**
|
|
70741
|
+
* Parse substring content of a node and update the parent's children to include the new nodes.
|
|
70742
|
+
*/
|
|
70743
|
+
const parseSibling = (stack, parent, index, sibling) => {
|
|
70744
|
+
const siblingNodes = parseMdChildren(sibling);
|
|
70745
|
+
// The new sibling nodes might contain new components to be processed
|
|
70746
|
+
if (siblingNodes.length > 0) {
|
|
70747
|
+
parent.children.splice(index + 1, 0, ...siblingNodes);
|
|
70748
|
+
stack.push(parent);
|
|
70749
|
+
}
|
|
70750
|
+
};
|
|
70673
70751
|
/**
|
|
70674
70752
|
* Create an MdxJsxFlowElement node from component data.
|
|
70675
70753
|
*/
|
|
@@ -70812,11 +70890,12 @@ const mdxishComponentBlocks = () => tree => {
|
|
|
70812
70890
|
if ('children' in node && Array.isArray(node.children)) {
|
|
70813
70891
|
stack.push(node);
|
|
70814
70892
|
}
|
|
70815
|
-
// Only visit HTML nodes with an actual html tag
|
|
70893
|
+
// Only visit HTML nodes with an actual html tag,
|
|
70894
|
+
// which means a potential unparsed MDX component
|
|
70816
70895
|
const value = node.value;
|
|
70817
70896
|
if (node.type !== 'html' || typeof value !== 'string')
|
|
70818
70897
|
return;
|
|
70819
|
-
const parsed = parseTag(value);
|
|
70898
|
+
const parsed = parseTag(value.trim());
|
|
70820
70899
|
if (!parsed)
|
|
70821
70900
|
return;
|
|
70822
70901
|
const { tag, attributes, selfClosing, contentAfterTag = '' } = parsed;
|
|
@@ -70833,11 +70912,19 @@ const mdxishComponentBlocks = () => tree => {
|
|
|
70833
70912
|
startPosition: node.position,
|
|
70834
70913
|
});
|
|
70835
70914
|
substituteNodeWithMdxNode(parent, index, componentNode);
|
|
70915
|
+
// Check and parse if there's relevant content after the current closing tag
|
|
70916
|
+
const remainingContent = contentAfterTag.trim();
|
|
70917
|
+
if (remainingContent) {
|
|
70918
|
+
parseSibling(stack, parent, index, remainingContent);
|
|
70919
|
+
}
|
|
70836
70920
|
return;
|
|
70837
70921
|
}
|
|
70838
70922
|
// Case 2: Self-contained block (closing tag in content)
|
|
70839
70923
|
if (contentAfterTag.includes(closingTagStr)) {
|
|
70840
|
-
|
|
70924
|
+
// Find the first closing tag
|
|
70925
|
+
const closingTagIndex = contentAfterTag.indexOf(closingTagStr);
|
|
70926
|
+
const componentInnerContent = contentAfterTag.substring(0, closingTagIndex).trim();
|
|
70927
|
+
const contentAfterClose = contentAfterTag.substring(closingTagIndex + closingTagStr.length).trim();
|
|
70841
70928
|
const componentNode = createComponentNode({
|
|
70842
70929
|
tag,
|
|
70843
70930
|
attributes,
|
|
@@ -70845,6 +70932,14 @@ const mdxishComponentBlocks = () => tree => {
|
|
|
70845
70932
|
startPosition: node.position,
|
|
70846
70933
|
});
|
|
70847
70934
|
substituteNodeWithMdxNode(parent, index, componentNode);
|
|
70935
|
+
// After the closing tag, there might be more content to be processed
|
|
70936
|
+
if (contentAfterClose) {
|
|
70937
|
+
parseSibling(stack, parent, index, contentAfterClose);
|
|
70938
|
+
}
|
|
70939
|
+
else if (componentNode.children.length > 0) {
|
|
70940
|
+
// The content inside the component block might contain new components to be processed
|
|
70941
|
+
stack.push(componentNode);
|
|
70942
|
+
}
|
|
70848
70943
|
return;
|
|
70849
70944
|
}
|
|
70850
70945
|
// Case 3: Multi-sibling component (closing tag in a following sibling)
|
|
@@ -70870,8 +70965,13 @@ const mdxishComponentBlocks = () => tree => {
|
|
|
70870
70965
|
});
|
|
70871
70966
|
// Remove all nodes from opening tag to closing tag (inclusive) and replace with component node
|
|
70872
70967
|
parent.children.splice(index, closingIndex - index + 1, componentNode);
|
|
70968
|
+
// Since we might be merging sibling nodes together and combining content,
|
|
70969
|
+
// there might be new components to process
|
|
70970
|
+
if (componentNode.children.length > 0) {
|
|
70971
|
+
stack.push(componentNode);
|
|
70972
|
+
}
|
|
70873
70973
|
};
|
|
70874
|
-
//
|
|
70974
|
+
// Process the nodes with the components depth-first to maintain the correct order of the nodes
|
|
70875
70975
|
while (stack.length) {
|
|
70876
70976
|
const parent = stack.pop();
|
|
70877
70977
|
if (parent?.children) {
|
|
@@ -70892,6 +70992,7 @@ const mdxishComponentBlocks = () => tree => {
|
|
|
70892
70992
|
|
|
70893
70993
|
|
|
70894
70994
|
|
|
70995
|
+
|
|
70895
70996
|
const isTableCell = (node) => isMDXElement(node) && ['th', 'td'].includes(node.name);
|
|
70896
70997
|
const tableTypes = {
|
|
70897
70998
|
tr: 'tableRow',
|
|
@@ -70916,18 +71017,13 @@ const isTextOnly = (children) => {
|
|
|
70916
71017
|
});
|
|
70917
71018
|
};
|
|
70918
71019
|
/**
|
|
70919
|
-
*
|
|
71020
|
+
* Convenience wrapper that extracts text content from an array of children nodes.
|
|
70920
71021
|
*/
|
|
70921
|
-
const
|
|
71022
|
+
const extractTextFromChildren = (children) => {
|
|
70922
71023
|
return children
|
|
70923
71024
|
.map(child => {
|
|
70924
71025
|
if (child && typeof child === 'object' && 'type' in child) {
|
|
70925
|
-
|
|
70926
|
-
return child.value;
|
|
70927
|
-
}
|
|
70928
|
-
if (child.type === 'mdxJsxTextElement' && 'children' in child && Array.isArray(child.children)) {
|
|
70929
|
-
return extractText(child.children);
|
|
70930
|
-
}
|
|
71026
|
+
return extractText(child);
|
|
70931
71027
|
}
|
|
70932
71028
|
return '';
|
|
70933
71029
|
})
|
|
@@ -70958,7 +71054,7 @@ const processTableNode = (node, index, parent) => {
|
|
|
70958
71054
|
let parsedChildren = cellChildren;
|
|
70959
71055
|
// If cell contains only text nodes, try to re-parse as markdown
|
|
70960
71056
|
if (isTextOnly(cellChildren)) {
|
|
70961
|
-
const textContent =
|
|
71057
|
+
const textContent = extractTextFromChildren(cellChildren);
|
|
70962
71058
|
if (textContent.trim()) {
|
|
70963
71059
|
try {
|
|
70964
71060
|
const parsed = parseMarkdown(textContent);
|
|
@@ -86373,7 +86469,7 @@ const CUSTOM_PROP_BOUNDARIES = [
|
|
|
86373
86469
|
/**
|
|
86374
86470
|
* Tags that should be passed through and handled at runtime (not by the mdxish plugin)
|
|
86375
86471
|
*/
|
|
86376
|
-
const RUNTIME_COMPONENT_TAGS = new Set(['Variable', 'variable']);
|
|
86472
|
+
const RUNTIME_COMPONENT_TAGS = new Set(['Variable', 'variable', 'rdme-pin']);
|
|
86377
86473
|
/**
|
|
86378
86474
|
* Standard HTML tags that should never be treated as custom components.
|
|
86379
86475
|
* Uses the html-tags package, converted to a Set<string> for efficient lookups.
|
|
@@ -93004,6 +93100,33 @@ const INLINE_COMPONENT_TAGS = new Set(['anchor', 'glossary']);
|
|
|
93004
93100
|
function isElementContentNode(node) {
|
|
93005
93101
|
return node.type === 'element' || node.type === 'text' || node.type === 'comment';
|
|
93006
93102
|
}
|
|
93103
|
+
/**
|
|
93104
|
+
* Components are assumed to be block-level, so whitespace between them can be removed
|
|
93105
|
+
* We want to remove them because it can be treated as actual children of the component
|
|
93106
|
+
* when it doesn't need to.
|
|
93107
|
+
*
|
|
93108
|
+
* It can be a problem because it can be passed as args to the components, like the ones
|
|
93109
|
+
* defined in /components, which can break the type assumptions of the components and cause
|
|
93110
|
+
* type errors, accessing properties that don't exist.
|
|
93111
|
+
*/
|
|
93112
|
+
function areAllChildrenComponents(children) {
|
|
93113
|
+
return children.every(child => {
|
|
93114
|
+
// Whitespace-only text nodes don't affect the check
|
|
93115
|
+
if (child.type === 'text' && !child.value.trim())
|
|
93116
|
+
return true;
|
|
93117
|
+
// Text with actual content means we have mixed content
|
|
93118
|
+
if (child.type === 'text')
|
|
93119
|
+
return false;
|
|
93120
|
+
// Comments don't affect the check
|
|
93121
|
+
if (child.type === 'comment')
|
|
93122
|
+
return true;
|
|
93123
|
+
// Standard HTML tags are not considered components
|
|
93124
|
+
if (child.type === 'element' && 'tagName' in child) {
|
|
93125
|
+
return !STANDARD_HTML_TAGS.has(child.tagName.toLowerCase());
|
|
93126
|
+
}
|
|
93127
|
+
return false;
|
|
93128
|
+
});
|
|
93129
|
+
}
|
|
93007
93130
|
/** Check if nodes represent a single paragraph with only text (no markdown formatting) */
|
|
93008
93131
|
function isSingleParagraphTextNode(nodes) {
|
|
93009
93132
|
return (nodes.length === 1 &&
|
|
@@ -93048,6 +93171,7 @@ function isActualHtmlTag(tagName, originalExcerpt) {
|
|
|
93048
93171
|
function parseTextChildren(node, processMarkdown) {
|
|
93049
93172
|
if (!node.children?.length)
|
|
93050
93173
|
return;
|
|
93174
|
+
// First pass: Recursively process text children as they may contain stringified markdown / mdx content
|
|
93051
93175
|
node.children = node.children.flatMap(child => {
|
|
93052
93176
|
if (child.type !== 'text' || !child.value.trim())
|
|
93053
93177
|
return [child];
|
|
@@ -93059,6 +93183,15 @@ function parseTextChildren(node, processMarkdown) {
|
|
|
93059
93183
|
}
|
|
93060
93184
|
return children;
|
|
93061
93185
|
});
|
|
93186
|
+
// Post-processing: remove whitespace-only text nodes if all siblings are components
|
|
93187
|
+
// This prevents whitespace between component children from being counted as extra children
|
|
93188
|
+
if (areAllChildrenComponents(node.children)) {
|
|
93189
|
+
node.children = node.children.filter(child => {
|
|
93190
|
+
if (child.type === 'text' && !child.value.trim())
|
|
93191
|
+
return false;
|
|
93192
|
+
return true;
|
|
93193
|
+
});
|
|
93194
|
+
}
|
|
93062
93195
|
}
|
|
93063
93196
|
/** Convert node properties from kebab-case/lowercase to camelCase */
|
|
93064
93197
|
function normalizeProperties(node) {
|
|
@@ -93121,6 +93254,15 @@ const mdxExpressionHandler = (_state, node) => ({
|
|
|
93121
93254
|
type: 'text',
|
|
93122
93255
|
value: node.value || '',
|
|
93123
93256
|
});
|
|
93257
|
+
// Since we serialize component / html tag attributes
|
|
93258
|
+
function decodeHtmlEntities(value) {
|
|
93259
|
+
return value
|
|
93260
|
+
.replace(/"/g, '"')
|
|
93261
|
+
.replace(/</g, '<')
|
|
93262
|
+
.replace(/>/g, '>')
|
|
93263
|
+
.replace(/ /g, '\n')
|
|
93264
|
+
.replace(/&/g, '&');
|
|
93265
|
+
}
|
|
93124
93266
|
// Convert MDX JSX elements to HAST elements, preserving attributes and children
|
|
93125
93267
|
const mdxJsxElementHandler = (state, node) => {
|
|
93126
93268
|
const { attributes = [], name } = node;
|
|
@@ -93132,7 +93274,7 @@ const mdxJsxElementHandler = (state, node) => {
|
|
|
93132
93274
|
properties[attribute.name] = true;
|
|
93133
93275
|
}
|
|
93134
93276
|
else if (typeof attribute.value === 'string') {
|
|
93135
|
-
properties[attribute.name] = attribute.value;
|
|
93277
|
+
properties[attribute.name] = decodeHtmlEntities(attribute.value);
|
|
93136
93278
|
}
|
|
93137
93279
|
else {
|
|
93138
93280
|
properties[attribute.name] = attribute.value.value;
|
|
@@ -93194,6 +93336,17 @@ function base64Decode(str) {
|
|
|
93194
93336
|
}
|
|
93195
93337
|
return decodeURIComponent(escape(atob(str)));
|
|
93196
93338
|
}
|
|
93339
|
+
function escapeHtmlAttribute(value) {
|
|
93340
|
+
return value
|
|
93341
|
+
.replace(/&/g, '&')
|
|
93342
|
+
.replace(/"/g, '"')
|
|
93343
|
+
.replace(/</g, '<')
|
|
93344
|
+
.replace(/>/g, '>')
|
|
93345
|
+
.replace(/\n/g, ' ');
|
|
93346
|
+
}
|
|
93347
|
+
// Marker prefix for JSON-serialized complex values (arrays/objects)
|
|
93348
|
+
// Using a prefix that won't conflict with regular string values
|
|
93349
|
+
const JSON_VALUE_MARKER = '__MDXISH_JSON__';
|
|
93197
93350
|
// Markers for protected HTMLBlock content (HTML comments avoid markdown parsing issues)
|
|
93198
93351
|
const HTML_BLOCK_CONTENT_START = '<!--RDMX_HTMLBLOCK:';
|
|
93199
93352
|
const HTML_BLOCK_CONTENT_END = ':RDMX_HTMLBLOCK-->';
|
|
@@ -93323,6 +93476,16 @@ function extractBalancedBraces(content, start) {
|
|
|
93323
93476
|
return null;
|
|
93324
93477
|
return { content: content.slice(start, pos - 1), end: pos };
|
|
93325
93478
|
}
|
|
93479
|
+
function restoreInlineCode(content, protectedCode) {
|
|
93480
|
+
return content.replace(/___INLINE_CODE_(\d+)___/g, (_m, idx) => {
|
|
93481
|
+
return protectedCode.inlineCode[parseInt(idx, 10)];
|
|
93482
|
+
});
|
|
93483
|
+
}
|
|
93484
|
+
function restoreCodeBlocks(content, protectedCode) {
|
|
93485
|
+
return content.replace(/___CODE_BLOCK_(\d+)___/g, (_m, idx) => {
|
|
93486
|
+
return protectedCode.codeBlocks[parseInt(idx, 10)];
|
|
93487
|
+
});
|
|
93488
|
+
}
|
|
93326
93489
|
/**
|
|
93327
93490
|
* Converts JSX attribute expressions (attribute={expression}) to HTML attributes (attribute="value").
|
|
93328
93491
|
* Handles style objects (camelCase → kebab-case), className → class, and JSON stringifies objects.
|
|
@@ -93338,7 +93501,7 @@ function extractBalancedBraces(content, start) {
|
|
|
93338
93501
|
* // Returns: '<a href="https://example.com">Link</a>'
|
|
93339
93502
|
* ```
|
|
93340
93503
|
*/
|
|
93341
|
-
function evaluateAttributeExpressions(content, context) {
|
|
93504
|
+
function evaluateAttributeExpressions(content, context, protectedCode) {
|
|
93342
93505
|
const attrStartRegex = /(\w+)=\{/g;
|
|
93343
93506
|
let result = '';
|
|
93344
93507
|
let lastEnd = 0;
|
|
@@ -93348,7 +93511,14 @@ function evaluateAttributeExpressions(content, context) {
|
|
|
93348
93511
|
const braceStart = match.index + match[0].length;
|
|
93349
93512
|
const extracted = extractBalancedBraces(content, braceStart);
|
|
93350
93513
|
if (extracted) {
|
|
93351
|
-
|
|
93514
|
+
// The expression might contain template literals in MDX component tag props
|
|
93515
|
+
// E.g. <Component greeting={`Hello World!`} />
|
|
93516
|
+
// that is marked as inline code. So we need to restore the inline codes
|
|
93517
|
+
// in the expression to evaluate it
|
|
93518
|
+
let expression = extracted.content;
|
|
93519
|
+
if (protectedCode) {
|
|
93520
|
+
expression = restoreInlineCode(expression, protectedCode);
|
|
93521
|
+
}
|
|
93352
93522
|
const fullMatchEnd = extracted.end;
|
|
93353
93523
|
result += content.slice(lastEnd, match.index);
|
|
93354
93524
|
try {
|
|
@@ -93364,14 +93534,20 @@ function evaluateAttributeExpressions(content, context) {
|
|
|
93364
93534
|
result += `style="${cssString}"`;
|
|
93365
93535
|
}
|
|
93366
93536
|
else {
|
|
93367
|
-
|
|
93537
|
+
// These are arrays / objects attribute values
|
|
93538
|
+
// Mark JSON-serialized values with a prefix so they can be parsed back correctly
|
|
93539
|
+
const jsonValue = escapeHtmlAttribute(JSON_VALUE_MARKER + JSON.stringify(evalResult));
|
|
93540
|
+
// Use double quotes so that multi-paragraph values are not split into multiple attributes by the processors
|
|
93541
|
+
result += `${attributeName}="${jsonValue}"`;
|
|
93368
93542
|
}
|
|
93369
93543
|
}
|
|
93370
93544
|
else if (attributeName === 'className') {
|
|
93371
|
-
|
|
93545
|
+
// Escape special characters so that it doesn't break and split the attribute value to nodes
|
|
93546
|
+
// This will be restored later in the pipeline
|
|
93547
|
+
result += `class="${escapeHtmlAttribute(String(evalResult))}"`;
|
|
93372
93548
|
}
|
|
93373
93549
|
else {
|
|
93374
|
-
result += `${attributeName}="${evalResult}"`;
|
|
93550
|
+
result += `${attributeName}="${escapeHtmlAttribute(String(evalResult))}"`;
|
|
93375
93551
|
}
|
|
93376
93552
|
}
|
|
93377
93553
|
catch (_error) {
|
|
@@ -93402,13 +93578,9 @@ function evaluateAttributeExpressions(content, context) {
|
|
|
93402
93578
|
* // Returns: 'Text with `inline` and ```js\ncode\n```'
|
|
93403
93579
|
* ```
|
|
93404
93580
|
*/
|
|
93405
|
-
function
|
|
93406
|
-
let restored = content
|
|
93407
|
-
|
|
93408
|
-
});
|
|
93409
|
-
restored = restored.replace(/___INLINE_CODE_(\d+)___/g, (_match, index) => {
|
|
93410
|
-
return protectedCode.inlineCode[parseInt(index, 10)];
|
|
93411
|
-
});
|
|
93581
|
+
function restoreProtectedCodes(content, protectedCode) {
|
|
93582
|
+
let restored = restoreCodeBlocks(content, protectedCode);
|
|
93583
|
+
restored = restoreInlineCode(restored, protectedCode);
|
|
93412
93584
|
return restored;
|
|
93413
93585
|
}
|
|
93414
93586
|
/**
|
|
@@ -93429,9 +93601,9 @@ function preprocessJSXExpressions(content, context = {}) {
|
|
|
93429
93601
|
// Step 3: Evaluate attribute expressions (JSX attribute syntax: href={baseUrl})
|
|
93430
93602
|
// For inline expressions, we use a library to parse the expression & evaluate it later
|
|
93431
93603
|
// For attribute expressions, it was difficult to use a library to parse them, so do it manually
|
|
93432
|
-
processed = evaluateAttributeExpressions(processed, context);
|
|
93604
|
+
processed = evaluateAttributeExpressions(processed, context, protectedCode);
|
|
93433
93605
|
// Step 4: Restore protected code blocks
|
|
93434
|
-
processed =
|
|
93606
|
+
processed = restoreProtectedCodes(processed, protectedCode);
|
|
93435
93607
|
return processed;
|
|
93436
93608
|
}
|
|
93437
93609
|
|
|
@@ -93843,7 +94015,7 @@ const wrapPinnedBlocks = (node, json) => {
|
|
|
93843
94015
|
return node;
|
|
93844
94016
|
return {
|
|
93845
94017
|
children: [node],
|
|
93846
|
-
data: {
|
|
94018
|
+
data: { hName: 'rdme-pin', hProperties: { className: 'pin' } },
|
|
93847
94019
|
type: 'rdme-pin',
|
|
93848
94020
|
};
|
|
93849
94021
|
};
|
|
@@ -93931,15 +94103,16 @@ function parseMagicBlock(raw, options = {}) {
|
|
|
93931
94103
|
type: 'code',
|
|
93932
94104
|
value: obj.code.trim(),
|
|
93933
94105
|
}));
|
|
93934
|
-
// Single code block without a tab name renders as a plain code block
|
|
94106
|
+
// Single code block without a tab name (meta or language) renders as a plain code block
|
|
94107
|
+
// Otherwise, we want to render it as a code tabs block
|
|
93935
94108
|
if (children.length === 1) {
|
|
93936
94109
|
if (!children[0].value)
|
|
93937
94110
|
return [];
|
|
93938
|
-
if (children[0].meta)
|
|
94111
|
+
if (!(children[0].meta || children[0].lang))
|
|
93939
94112
|
return [wrapPinnedBlocks(children[0], json)];
|
|
93940
94113
|
}
|
|
93941
|
-
// Multiple code blocks
|
|
93942
|
-
return [wrapPinnedBlocks({ children, className: 'tabs', data: { hName: '
|
|
94114
|
+
// Multiple code blocks or a single code block with a tab name (meta or language) renders as a code tabs block
|
|
94115
|
+
return [wrapPinnedBlocks({ children, className: 'tabs', data: { hName: 'CodeTabs' }, type: 'code-tabs' }, json)];
|
|
93943
94116
|
}
|
|
93944
94117
|
// API header: renders as a heading element (h1-h6)
|
|
93945
94118
|
case 'api-header': {
|
|
@@ -94140,11 +94313,31 @@ function parseMagicBlock(raw, options = {}) {
|
|
|
94140
94313
|
}
|
|
94141
94314
|
}
|
|
94142
94315
|
/**
|
|
94143
|
-
*
|
|
94316
|
+
* Block-level node types that cannot be nested inside paragraphs.
|
|
94144
94317
|
*/
|
|
94145
|
-
const
|
|
94146
|
-
|
|
94147
|
-
|
|
94318
|
+
const blockTypes = [
|
|
94319
|
+
'heading',
|
|
94320
|
+
'code',
|
|
94321
|
+
'code-tabs',
|
|
94322
|
+
'paragraph',
|
|
94323
|
+
'blockquote',
|
|
94324
|
+
'list',
|
|
94325
|
+
'table',
|
|
94326
|
+
'thematicBreak',
|
|
94327
|
+
'html',
|
|
94328
|
+
'yaml',
|
|
94329
|
+
'toml',
|
|
94330
|
+
'rdme-pin',
|
|
94331
|
+
'rdme-callout',
|
|
94332
|
+
'html-block',
|
|
94333
|
+
'embed',
|
|
94334
|
+
'figure',
|
|
94335
|
+
'mdxJsxFlowElement',
|
|
94336
|
+
];
|
|
94337
|
+
/**
|
|
94338
|
+
* Check if a node is a block-level node (cannot be inside a paragraph)
|
|
94339
|
+
*/
|
|
94340
|
+
const isBlockNode = (node) => blockTypes.includes(node.type);
|
|
94148
94341
|
/**
|
|
94149
94342
|
* Unified plugin that restores magic blocks from placeholder tokens.
|
|
94150
94343
|
*
|
|
@@ -94157,8 +94350,9 @@ const magicBlockRestorer = ({ blocks }) => tree => {
|
|
|
94157
94350
|
return;
|
|
94158
94351
|
// Map: key → original raw magic block content
|
|
94159
94352
|
const magicBlockKeys = new Map(blocks.map(({ key, raw }) => [key, raw]));
|
|
94160
|
-
//
|
|
94161
|
-
const
|
|
94353
|
+
// Collect replacements to apply (we need to visit in reverse to maintain indices)
|
|
94354
|
+
const replacements = [];
|
|
94355
|
+
// First pass: collect all replacements
|
|
94162
94356
|
visit(tree, 'inlineCode', (node, index, parent) => {
|
|
94163
94357
|
if (!parent || index == null)
|
|
94164
94358
|
return undefined;
|
|
@@ -94168,31 +94362,73 @@ const magicBlockRestorer = ({ blocks }) => tree => {
|
|
|
94168
94362
|
const children = parseMagicBlock(raw);
|
|
94169
94363
|
if (!children.length)
|
|
94170
94364
|
return undefined;
|
|
94171
|
-
|
|
94172
|
-
|
|
94173
|
-
|
|
94174
|
-
|
|
94175
|
-
|
|
94176
|
-
|
|
94177
|
-
|
|
94365
|
+
// If parent is a paragraph and we're inserting block nodes (which must not be in paragraphs), lift them out
|
|
94366
|
+
if (parent.type === 'paragraph' && children.some(child => isBlockNode(child))) {
|
|
94367
|
+
const blockNodes = [];
|
|
94368
|
+
const inlineNodes = [];
|
|
94369
|
+
// Separate block and inline nodes
|
|
94370
|
+
children.forEach(child => {
|
|
94371
|
+
if (isBlockNode(child)) {
|
|
94372
|
+
blockNodes.push(child);
|
|
94178
94373
|
}
|
|
94179
|
-
|
|
94180
|
-
|
|
94181
|
-
if (paragraphParent) {
|
|
94182
|
-
const paragraphIndex = paragraphParent.children.indexOf(parent);
|
|
94183
|
-
if (paragraphIndex !== -1) {
|
|
94184
|
-
modifications.push({ children, index: paragraphIndex, parent: paragraphParent });
|
|
94374
|
+
else {
|
|
94375
|
+
inlineNodes.push(child);
|
|
94185
94376
|
}
|
|
94186
|
-
}
|
|
94187
|
-
|
|
94377
|
+
});
|
|
94378
|
+
const before = parent.children.slice(0, index);
|
|
94379
|
+
const after = parent.children.slice(index + 1);
|
|
94380
|
+
replacements.push({
|
|
94381
|
+
parent,
|
|
94382
|
+
blockNodes,
|
|
94383
|
+
inlineNodes,
|
|
94384
|
+
before,
|
|
94385
|
+
after,
|
|
94386
|
+
});
|
|
94188
94387
|
}
|
|
94189
|
-
|
|
94190
|
-
|
|
94191
|
-
|
|
94192
|
-
|
|
94193
|
-
|
|
94194
|
-
parent.children.splice(index, 1, ...children);
|
|
94388
|
+
else {
|
|
94389
|
+
// Normal case: just replace the inlineCode with the children
|
|
94390
|
+
parent.children.splice(index, 1, ...children);
|
|
94391
|
+
}
|
|
94392
|
+
return undefined;
|
|
94195
94393
|
});
|
|
94394
|
+
// Second pass: apply replacements that require lifting block nodes out of paragraphs
|
|
94395
|
+
// Process in reverse order to maintain correct indices
|
|
94396
|
+
for (let i = replacements.length - 1; i >= 0; i -= 1) {
|
|
94397
|
+
const { after, before, blockNodes, inlineNodes, parent } = replacements[i];
|
|
94398
|
+
// Find the paragraph's position in the root
|
|
94399
|
+
const rootChildren = tree.children;
|
|
94400
|
+
const paraIndex = rootChildren.findIndex(child => child === parent);
|
|
94401
|
+
if (paraIndex === -1) {
|
|
94402
|
+
// Paragraph not found in root - fall back to normal replacement
|
|
94403
|
+
// This shouldn't happen normally, but handle it gracefully
|
|
94404
|
+
// Reconstruct the original index from before.length
|
|
94405
|
+
const originalIndex = before.length;
|
|
94406
|
+
parent.children.splice(originalIndex, 1, ...blockNodes, ...inlineNodes);
|
|
94407
|
+
// eslint-disable-next-line no-continue
|
|
94408
|
+
continue;
|
|
94409
|
+
}
|
|
94410
|
+
// Update or remove the paragraph
|
|
94411
|
+
if (inlineNodes.length > 0) {
|
|
94412
|
+
// Keep paragraph with inline nodes
|
|
94413
|
+
parent.children = [...before, ...inlineNodes, ...after];
|
|
94414
|
+
// Insert block nodes after the paragraph
|
|
94415
|
+
if (blockNodes.length > 0) {
|
|
94416
|
+
rootChildren.splice(paraIndex + 1, 0, ...blockNodes);
|
|
94417
|
+
}
|
|
94418
|
+
}
|
|
94419
|
+
else if (before.length === 0 && after.length === 0) {
|
|
94420
|
+
// Remove empty paragraph and replace with block nodes
|
|
94421
|
+
rootChildren.splice(paraIndex, 1, ...blockNodes);
|
|
94422
|
+
}
|
|
94423
|
+
else {
|
|
94424
|
+
// Keep paragraph with remaining content
|
|
94425
|
+
parent.children = [...before, ...after];
|
|
94426
|
+
// Insert block nodes after the paragraph
|
|
94427
|
+
if (blockNodes.length > 0) {
|
|
94428
|
+
rootChildren.splice(paraIndex + 1, 0, ...blockNodes);
|
|
94429
|
+
}
|
|
94430
|
+
}
|
|
94431
|
+
}
|
|
94196
94432
|
};
|
|
94197
94433
|
/* harmony default export */ const mdxish_magic_blocks = (magicBlockRestorer);
|
|
94198
94434
|
|
|
@@ -95046,6 +95282,40 @@ const makeUseMDXComponents = (more = {}) => {
|
|
|
95046
95282
|
|
|
95047
95283
|
|
|
95048
95284
|
|
|
95285
|
+
|
|
95286
|
+
/**
|
|
95287
|
+
* Parse JSON-marked string values in props back to their original types.
|
|
95288
|
+
* This handles arrays and objects that were serialized during JSX preprocessing.
|
|
95289
|
+
*/
|
|
95290
|
+
function parseJsonProps(props) {
|
|
95291
|
+
if (!props)
|
|
95292
|
+
return props;
|
|
95293
|
+
const parsed = {};
|
|
95294
|
+
Object.entries(props).forEach(([key, value]) => {
|
|
95295
|
+
if (typeof value === 'string' && value.startsWith(JSON_VALUE_MARKER)) {
|
|
95296
|
+
try {
|
|
95297
|
+
parsed[key] = JSON.parse(value.slice(JSON_VALUE_MARKER.length));
|
|
95298
|
+
}
|
|
95299
|
+
catch {
|
|
95300
|
+
// If parsing fails, use the value without the marker
|
|
95301
|
+
parsed[key] = value.slice(JSON_VALUE_MARKER.length);
|
|
95302
|
+
}
|
|
95303
|
+
}
|
|
95304
|
+
else {
|
|
95305
|
+
parsed[key] = value;
|
|
95306
|
+
}
|
|
95307
|
+
});
|
|
95308
|
+
return parsed;
|
|
95309
|
+
}
|
|
95310
|
+
/**
|
|
95311
|
+
* Custom createElement wrapper that parses JSON-marked string props.
|
|
95312
|
+
* This is needed because rehype-react converts HAST to React, but complex
|
|
95313
|
+
* types (arrays/objects) get serialized to strings during markdown parsing.
|
|
95314
|
+
*/
|
|
95315
|
+
function createElementWithJsonProps(type, props, ...children) {
|
|
95316
|
+
const parsedProps = parseJsonProps(props);
|
|
95317
|
+
return external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement(type, parsedProps, ...children);
|
|
95318
|
+
}
|
|
95049
95319
|
/** Flatten CustomComponents into a component map for rehype-react */
|
|
95050
95320
|
function exportComponentsForRehype(components) {
|
|
95051
95321
|
const exported = Object.entries(components).reduce((memo, [tag, mod]) => {
|
|
@@ -95077,7 +95347,7 @@ function exportComponentsForRehype(components) {
|
|
|
95077
95347
|
function createRehypeReactProcessor(components) {
|
|
95078
95348
|
// @ts-expect-error - rehype-react types are incompatible with React.Fragment return type
|
|
95079
95349
|
return unified().use((rehype_react_default()), {
|
|
95080
|
-
createElement:
|
|
95350
|
+
createElement: createElementWithJsonProps,
|
|
95081
95351
|
Fragment: (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default()).Fragment,
|
|
95082
95352
|
components,
|
|
95083
95353
|
});
|