@readme/markdown 11.15.0 → 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/main.node.js
CHANGED
|
@@ -73147,12 +73147,40 @@ const plain = (node, opts = {}) => {
|
|
|
73147
73147
|
};
|
|
73148
73148
|
/* harmony default export */ const lib_plain = (plain);
|
|
73149
73149
|
|
|
73150
|
+
;// ./processor/transform/extract-text.ts
|
|
73151
|
+
/**
|
|
73152
|
+
* Extracts text content from a single AST node recursively.
|
|
73153
|
+
* Works with both MDAST and HAST-like node structures.
|
|
73154
|
+
*
|
|
73155
|
+
* Placed this outside of the utils.ts file to avoid circular dependencies.
|
|
73156
|
+
*
|
|
73157
|
+
* @param node - The node to extract text from (can be MDAST Node or HAST-like structure)
|
|
73158
|
+
* @returns The concatenated text content
|
|
73159
|
+
*/
|
|
73160
|
+
const extractText = (node) => {
|
|
73161
|
+
if (node.type === 'text' && typeof node.value === 'string') {
|
|
73162
|
+
return node.value;
|
|
73163
|
+
}
|
|
73164
|
+
if (node.children && Array.isArray(node.children)) {
|
|
73165
|
+
return node.children
|
|
73166
|
+
.map(child => {
|
|
73167
|
+
if (child && typeof child === 'object' && 'type' in child) {
|
|
73168
|
+
return extractText(child);
|
|
73169
|
+
}
|
|
73170
|
+
return '';
|
|
73171
|
+
})
|
|
73172
|
+
.join('');
|
|
73173
|
+
}
|
|
73174
|
+
return '';
|
|
73175
|
+
};
|
|
73176
|
+
|
|
73150
73177
|
;// ./processor/transform/callouts.ts
|
|
73151
73178
|
|
|
73152
73179
|
|
|
73153
73180
|
|
|
73154
73181
|
|
|
73155
73182
|
|
|
73183
|
+
|
|
73156
73184
|
const callouts_regex = `^(${emoji_regex().source}|⚠)(\\s+|$)`;
|
|
73157
73185
|
const findFirst = (node) => {
|
|
73158
73186
|
if ('children' in node)
|
|
@@ -73173,42 +73201,76 @@ const wrapHeading = (node) => {
|
|
|
73173
73201
|
},
|
|
73174
73202
|
};
|
|
73175
73203
|
};
|
|
73204
|
+
/**
|
|
73205
|
+
* Checks if a blockquote matches the expected callout structure:
|
|
73206
|
+
* blockquote > paragraph > text node
|
|
73207
|
+
*/
|
|
73208
|
+
const isCalloutStructure = (node) => {
|
|
73209
|
+
const firstChild = node.children?.[0];
|
|
73210
|
+
if (!firstChild || firstChild.type !== 'paragraph')
|
|
73211
|
+
return false;
|
|
73212
|
+
if (!('children' in firstChild))
|
|
73213
|
+
return false;
|
|
73214
|
+
const firstTextChild = firstChild.children?.[0];
|
|
73215
|
+
return firstTextChild?.type === 'text';
|
|
73216
|
+
};
|
|
73217
|
+
const processBlockquote = (node, index, parent) => {
|
|
73218
|
+
if (!isCalloutStructure(node)) {
|
|
73219
|
+
// Only stringify empty blockquotes (no extractable text content)
|
|
73220
|
+
// Preserve blockquotes with actual content (e.g., headings, lists, etc.)
|
|
73221
|
+
const content = extractText(node);
|
|
73222
|
+
const isEmpty = !content || content.trim() === '';
|
|
73223
|
+
if (isEmpty && index !== undefined && parent) {
|
|
73224
|
+
const textNode = {
|
|
73225
|
+
type: 'text',
|
|
73226
|
+
value: '>',
|
|
73227
|
+
};
|
|
73228
|
+
const paragraphNode = {
|
|
73229
|
+
type: 'paragraph',
|
|
73230
|
+
children: [textNode],
|
|
73231
|
+
position: node.position,
|
|
73232
|
+
};
|
|
73233
|
+
parent.children.splice(index, 1, paragraphNode);
|
|
73234
|
+
}
|
|
73235
|
+
return;
|
|
73236
|
+
}
|
|
73237
|
+
// isCalloutStructure ensures node.children[0] is a Paragraph with children
|
|
73238
|
+
const firstParagraph = node.children[0];
|
|
73239
|
+
const startText = lib_plain(firstParagraph).toString();
|
|
73240
|
+
const [match, icon] = startText.match(callouts_regex) || [];
|
|
73241
|
+
if (icon && match) {
|
|
73242
|
+
const heading = startText.slice(match.length);
|
|
73243
|
+
const empty = !heading.length && firstParagraph.children.length === 1;
|
|
73244
|
+
const theme = themes[icon] || 'default';
|
|
73245
|
+
const firstChild = findFirst(node.children[0]);
|
|
73246
|
+
if (firstChild && 'value' in firstChild && typeof firstChild.value === 'string') {
|
|
73247
|
+
firstChild.value = firstChild.value.slice(match.length);
|
|
73248
|
+
}
|
|
73249
|
+
if (heading) {
|
|
73250
|
+
node.children[0] = wrapHeading(node);
|
|
73251
|
+
// @note: We add to the offset/column the length of the unicode
|
|
73252
|
+
// character that was stripped off, so that the start position of the
|
|
73253
|
+
// heading/text matches where it actually starts.
|
|
73254
|
+
node.children[0].position.start.offset += match.length;
|
|
73255
|
+
node.children[0].position.start.column += match.length;
|
|
73256
|
+
}
|
|
73257
|
+
Object.assign(node, {
|
|
73258
|
+
type: NodeTypes.callout,
|
|
73259
|
+
data: {
|
|
73260
|
+
hName: 'Callout',
|
|
73261
|
+
hProperties: {
|
|
73262
|
+
icon,
|
|
73263
|
+
...(empty && { empty }),
|
|
73264
|
+
theme,
|
|
73265
|
+
},
|
|
73266
|
+
},
|
|
73267
|
+
});
|
|
73268
|
+
}
|
|
73269
|
+
};
|
|
73176
73270
|
const calloutTransformer = () => {
|
|
73177
73271
|
return (tree) => {
|
|
73178
|
-
visit(tree, 'blockquote', (node) => {
|
|
73179
|
-
|
|
73180
|
-
return;
|
|
73181
|
-
// @ts-expect-error -- @todo: update plain to accept mdast
|
|
73182
|
-
const startText = lib_plain(node.children[0]).toString();
|
|
73183
|
-
const [match, icon] = startText.match(callouts_regex) || [];
|
|
73184
|
-
if (icon && match) {
|
|
73185
|
-
const heading = startText.slice(match.length);
|
|
73186
|
-
const empty = !heading.length && node.children[0].children.length === 1;
|
|
73187
|
-
const theme = themes[icon] || 'default';
|
|
73188
|
-
const firstChild = findFirst(node.children[0]);
|
|
73189
|
-
if (firstChild && 'value' in firstChild && typeof firstChild.value === 'string') {
|
|
73190
|
-
firstChild.value = firstChild.value.slice(match.length);
|
|
73191
|
-
}
|
|
73192
|
-
if (heading) {
|
|
73193
|
-
node.children[0] = wrapHeading(node);
|
|
73194
|
-
// @note: We add to the offset/column the length of the unicode
|
|
73195
|
-
// character that was stripped off, so that the start position of the
|
|
73196
|
-
// heading/text matches where it actually starts.
|
|
73197
|
-
node.children[0].position.start.offset += match.length;
|
|
73198
|
-
node.children[0].position.start.column += match.length;
|
|
73199
|
-
}
|
|
73200
|
-
Object.assign(node, {
|
|
73201
|
-
type: NodeTypes.callout,
|
|
73202
|
-
data: {
|
|
73203
|
-
hName: 'Callout',
|
|
73204
|
-
hProperties: {
|
|
73205
|
-
icon,
|
|
73206
|
-
...(empty && { empty }),
|
|
73207
|
-
theme,
|
|
73208
|
-
},
|
|
73209
|
-
},
|
|
73210
|
-
});
|
|
73211
|
-
}
|
|
73272
|
+
visit(tree, 'blockquote', (node, index, parent) => {
|
|
73273
|
+
processBlockquote(node, index, parent);
|
|
73212
73274
|
});
|
|
73213
73275
|
};
|
|
73214
73276
|
};
|
|
@@ -90874,6 +90936,17 @@ const parseTag = (value) => {
|
|
|
90874
90936
|
contentAfterTag,
|
|
90875
90937
|
};
|
|
90876
90938
|
};
|
|
90939
|
+
/**
|
|
90940
|
+
* Parse substring content of a node and update the parent's children to include the new nodes.
|
|
90941
|
+
*/
|
|
90942
|
+
const parseSibling = (stack, parent, index, sibling) => {
|
|
90943
|
+
const siblingNodes = parseMdChildren(sibling);
|
|
90944
|
+
// The new sibling nodes might contain new components to be processed
|
|
90945
|
+
if (siblingNodes.length > 0) {
|
|
90946
|
+
parent.children.splice(index + 1, 0, ...siblingNodes);
|
|
90947
|
+
stack.push(parent);
|
|
90948
|
+
}
|
|
90949
|
+
};
|
|
90877
90950
|
/**
|
|
90878
90951
|
* Create an MdxJsxFlowElement node from component data.
|
|
90879
90952
|
*/
|
|
@@ -91016,11 +91089,12 @@ const mdxishComponentBlocks = () => tree => {
|
|
|
91016
91089
|
if ('children' in node && Array.isArray(node.children)) {
|
|
91017
91090
|
stack.push(node);
|
|
91018
91091
|
}
|
|
91019
|
-
// Only visit HTML nodes with an actual html tag
|
|
91092
|
+
// Only visit HTML nodes with an actual html tag,
|
|
91093
|
+
// which means a potential unparsed MDX component
|
|
91020
91094
|
const value = node.value;
|
|
91021
91095
|
if (node.type !== 'html' || typeof value !== 'string')
|
|
91022
91096
|
return;
|
|
91023
|
-
const parsed = parseTag(value);
|
|
91097
|
+
const parsed = parseTag(value.trim());
|
|
91024
91098
|
if (!parsed)
|
|
91025
91099
|
return;
|
|
91026
91100
|
const { tag, attributes, selfClosing, contentAfterTag = '' } = parsed;
|
|
@@ -91037,11 +91111,19 @@ const mdxishComponentBlocks = () => tree => {
|
|
|
91037
91111
|
startPosition: node.position,
|
|
91038
91112
|
});
|
|
91039
91113
|
substituteNodeWithMdxNode(parent, index, componentNode);
|
|
91114
|
+
// Check and parse if there's relevant content after the current closing tag
|
|
91115
|
+
const remainingContent = contentAfterTag.trim();
|
|
91116
|
+
if (remainingContent) {
|
|
91117
|
+
parseSibling(stack, parent, index, remainingContent);
|
|
91118
|
+
}
|
|
91040
91119
|
return;
|
|
91041
91120
|
}
|
|
91042
91121
|
// Case 2: Self-contained block (closing tag in content)
|
|
91043
91122
|
if (contentAfterTag.includes(closingTagStr)) {
|
|
91044
|
-
|
|
91123
|
+
// Find the first closing tag
|
|
91124
|
+
const closingTagIndex = contentAfterTag.indexOf(closingTagStr);
|
|
91125
|
+
const componentInnerContent = contentAfterTag.substring(0, closingTagIndex).trim();
|
|
91126
|
+
const contentAfterClose = contentAfterTag.substring(closingTagIndex + closingTagStr.length).trim();
|
|
91045
91127
|
const componentNode = createComponentNode({
|
|
91046
91128
|
tag,
|
|
91047
91129
|
attributes,
|
|
@@ -91049,6 +91131,14 @@ const mdxishComponentBlocks = () => tree => {
|
|
|
91049
91131
|
startPosition: node.position,
|
|
91050
91132
|
});
|
|
91051
91133
|
substituteNodeWithMdxNode(parent, index, componentNode);
|
|
91134
|
+
// After the closing tag, there might be more content to be processed
|
|
91135
|
+
if (contentAfterClose) {
|
|
91136
|
+
parseSibling(stack, parent, index, contentAfterClose);
|
|
91137
|
+
}
|
|
91138
|
+
else if (componentNode.children.length > 0) {
|
|
91139
|
+
// The content inside the component block might contain new components to be processed
|
|
91140
|
+
stack.push(componentNode);
|
|
91141
|
+
}
|
|
91052
91142
|
return;
|
|
91053
91143
|
}
|
|
91054
91144
|
// Case 3: Multi-sibling component (closing tag in a following sibling)
|
|
@@ -91074,8 +91164,13 @@ const mdxishComponentBlocks = () => tree => {
|
|
|
91074
91164
|
});
|
|
91075
91165
|
// Remove all nodes from opening tag to closing tag (inclusive) and replace with component node
|
|
91076
91166
|
parent.children.splice(index, closingIndex - index + 1, componentNode);
|
|
91167
|
+
// Since we might be merging sibling nodes together and combining content,
|
|
91168
|
+
// there might be new components to process
|
|
91169
|
+
if (componentNode.children.length > 0) {
|
|
91170
|
+
stack.push(componentNode);
|
|
91171
|
+
}
|
|
91077
91172
|
};
|
|
91078
|
-
//
|
|
91173
|
+
// Process the nodes with the components depth-first to maintain the correct order of the nodes
|
|
91079
91174
|
while (stack.length) {
|
|
91080
91175
|
const parent = stack.pop();
|
|
91081
91176
|
if (parent?.children) {
|
|
@@ -91096,6 +91191,7 @@ const mdxishComponentBlocks = () => tree => {
|
|
|
91096
91191
|
|
|
91097
91192
|
|
|
91098
91193
|
|
|
91194
|
+
|
|
91099
91195
|
const isTableCell = (node) => isMDXElement(node) && ['th', 'td'].includes(node.name);
|
|
91100
91196
|
const tableTypes = {
|
|
91101
91197
|
tr: 'tableRow',
|
|
@@ -91120,18 +91216,13 @@ const isTextOnly = (children) => {
|
|
|
91120
91216
|
});
|
|
91121
91217
|
};
|
|
91122
91218
|
/**
|
|
91123
|
-
*
|
|
91219
|
+
* Convenience wrapper that extracts text content from an array of children nodes.
|
|
91124
91220
|
*/
|
|
91125
|
-
const
|
|
91221
|
+
const extractTextFromChildren = (children) => {
|
|
91126
91222
|
return children
|
|
91127
91223
|
.map(child => {
|
|
91128
91224
|
if (child && typeof child === 'object' && 'type' in child) {
|
|
91129
|
-
|
|
91130
|
-
return child.value;
|
|
91131
|
-
}
|
|
91132
|
-
if (child.type === 'mdxJsxTextElement' && 'children' in child && Array.isArray(child.children)) {
|
|
91133
|
-
return extractText(child.children);
|
|
91134
|
-
}
|
|
91225
|
+
return extractText(child);
|
|
91135
91226
|
}
|
|
91136
91227
|
return '';
|
|
91137
91228
|
})
|
|
@@ -91162,7 +91253,7 @@ const processTableNode = (node, index, parent) => {
|
|
|
91162
91253
|
let parsedChildren = cellChildren;
|
|
91163
91254
|
// If cell contains only text nodes, try to re-parse as markdown
|
|
91164
91255
|
if (isTextOnly(cellChildren)) {
|
|
91165
|
-
const textContent =
|
|
91256
|
+
const textContent = extractTextFromChildren(cellChildren);
|
|
91166
91257
|
if (textContent.trim()) {
|
|
91167
91258
|
try {
|
|
91168
91259
|
const parsed = parseMarkdown(textContent);
|
|
@@ -106577,7 +106668,7 @@ const CUSTOM_PROP_BOUNDARIES = [
|
|
|
106577
106668
|
/**
|
|
106578
106669
|
* Tags that should be passed through and handled at runtime (not by the mdxish plugin)
|
|
106579
106670
|
*/
|
|
106580
|
-
const RUNTIME_COMPONENT_TAGS = new Set(['Variable', 'variable']);
|
|
106671
|
+
const RUNTIME_COMPONENT_TAGS = new Set(['Variable', 'variable', 'rdme-pin']);
|
|
106581
106672
|
/**
|
|
106582
106673
|
* Standard HTML tags that should never be treated as custom components.
|
|
106583
106674
|
* Uses the html-tags package, converted to a Set<string> for efficient lookups.
|
|
@@ -113208,6 +113299,33 @@ const INLINE_COMPONENT_TAGS = new Set(['anchor', 'glossary']);
|
|
|
113208
113299
|
function isElementContentNode(node) {
|
|
113209
113300
|
return node.type === 'element' || node.type === 'text' || node.type === 'comment';
|
|
113210
113301
|
}
|
|
113302
|
+
/**
|
|
113303
|
+
* Components are assumed to be block-level, so whitespace between them can be removed
|
|
113304
|
+
* We want to remove them because it can be treated as actual children of the component
|
|
113305
|
+
* when it doesn't need to.
|
|
113306
|
+
*
|
|
113307
|
+
* It can be a problem because it can be passed as args to the components, like the ones
|
|
113308
|
+
* defined in /components, which can break the type assumptions of the components and cause
|
|
113309
|
+
* type errors, accessing properties that don't exist.
|
|
113310
|
+
*/
|
|
113311
|
+
function areAllChildrenComponents(children) {
|
|
113312
|
+
return children.every(child => {
|
|
113313
|
+
// Whitespace-only text nodes don't affect the check
|
|
113314
|
+
if (child.type === 'text' && !child.value.trim())
|
|
113315
|
+
return true;
|
|
113316
|
+
// Text with actual content means we have mixed content
|
|
113317
|
+
if (child.type === 'text')
|
|
113318
|
+
return false;
|
|
113319
|
+
// Comments don't affect the check
|
|
113320
|
+
if (child.type === 'comment')
|
|
113321
|
+
return true;
|
|
113322
|
+
// Standard HTML tags are not considered components
|
|
113323
|
+
if (child.type === 'element' && 'tagName' in child) {
|
|
113324
|
+
return !STANDARD_HTML_TAGS.has(child.tagName.toLowerCase());
|
|
113325
|
+
}
|
|
113326
|
+
return false;
|
|
113327
|
+
});
|
|
113328
|
+
}
|
|
113211
113329
|
/** Check if nodes represent a single paragraph with only text (no markdown formatting) */
|
|
113212
113330
|
function isSingleParagraphTextNode(nodes) {
|
|
113213
113331
|
return (nodes.length === 1 &&
|
|
@@ -113252,6 +113370,7 @@ function isActualHtmlTag(tagName, originalExcerpt) {
|
|
|
113252
113370
|
function parseTextChildren(node, processMarkdown) {
|
|
113253
113371
|
if (!node.children?.length)
|
|
113254
113372
|
return;
|
|
113373
|
+
// First pass: Recursively process text children as they may contain stringified markdown / mdx content
|
|
113255
113374
|
node.children = node.children.flatMap(child => {
|
|
113256
113375
|
if (child.type !== 'text' || !child.value.trim())
|
|
113257
113376
|
return [child];
|
|
@@ -113263,6 +113382,15 @@ function parseTextChildren(node, processMarkdown) {
|
|
|
113263
113382
|
}
|
|
113264
113383
|
return children;
|
|
113265
113384
|
});
|
|
113385
|
+
// Post-processing: remove whitespace-only text nodes if all siblings are components
|
|
113386
|
+
// This prevents whitespace between component children from being counted as extra children
|
|
113387
|
+
if (areAllChildrenComponents(node.children)) {
|
|
113388
|
+
node.children = node.children.filter(child => {
|
|
113389
|
+
if (child.type === 'text' && !child.value.trim())
|
|
113390
|
+
return false;
|
|
113391
|
+
return true;
|
|
113392
|
+
});
|
|
113393
|
+
}
|
|
113266
113394
|
}
|
|
113267
113395
|
/** Convert node properties from kebab-case/lowercase to camelCase */
|
|
113268
113396
|
function normalizeProperties(node) {
|
|
@@ -113325,6 +113453,15 @@ const mdxExpressionHandler = (_state, node) => ({
|
|
|
113325
113453
|
type: 'text',
|
|
113326
113454
|
value: node.value || '',
|
|
113327
113455
|
});
|
|
113456
|
+
// Since we serialize component / html tag attributes
|
|
113457
|
+
function decodeHtmlEntities(value) {
|
|
113458
|
+
return value
|
|
113459
|
+
.replace(/"/g, '"')
|
|
113460
|
+
.replace(/</g, '<')
|
|
113461
|
+
.replace(/>/g, '>')
|
|
113462
|
+
.replace(/ /g, '\n')
|
|
113463
|
+
.replace(/&/g, '&');
|
|
113464
|
+
}
|
|
113328
113465
|
// Convert MDX JSX elements to HAST elements, preserving attributes and children
|
|
113329
113466
|
const mdxJsxElementHandler = (state, node) => {
|
|
113330
113467
|
const { attributes = [], name } = node;
|
|
@@ -113336,7 +113473,7 @@ const mdxJsxElementHandler = (state, node) => {
|
|
|
113336
113473
|
properties[attribute.name] = true;
|
|
113337
113474
|
}
|
|
113338
113475
|
else if (typeof attribute.value === 'string') {
|
|
113339
|
-
properties[attribute.name] = attribute.value;
|
|
113476
|
+
properties[attribute.name] = decodeHtmlEntities(attribute.value);
|
|
113340
113477
|
}
|
|
113341
113478
|
else {
|
|
113342
113479
|
properties[attribute.name] = attribute.value.value;
|
|
@@ -113398,6 +113535,17 @@ function base64Decode(str) {
|
|
|
113398
113535
|
}
|
|
113399
113536
|
return decodeURIComponent(escape(atob(str)));
|
|
113400
113537
|
}
|
|
113538
|
+
function escapeHtmlAttribute(value) {
|
|
113539
|
+
return value
|
|
113540
|
+
.replace(/&/g, '&')
|
|
113541
|
+
.replace(/"/g, '"')
|
|
113542
|
+
.replace(/</g, '<')
|
|
113543
|
+
.replace(/>/g, '>')
|
|
113544
|
+
.replace(/\n/g, ' ');
|
|
113545
|
+
}
|
|
113546
|
+
// Marker prefix for JSON-serialized complex values (arrays/objects)
|
|
113547
|
+
// Using a prefix that won't conflict with regular string values
|
|
113548
|
+
const JSON_VALUE_MARKER = '__MDXISH_JSON__';
|
|
113401
113549
|
// Markers for protected HTMLBlock content (HTML comments avoid markdown parsing issues)
|
|
113402
113550
|
const HTML_BLOCK_CONTENT_START = '<!--RDMX_HTMLBLOCK:';
|
|
113403
113551
|
const HTML_BLOCK_CONTENT_END = ':RDMX_HTMLBLOCK-->';
|
|
@@ -113527,6 +113675,16 @@ function extractBalancedBraces(content, start) {
|
|
|
113527
113675
|
return null;
|
|
113528
113676
|
return { content: content.slice(start, pos - 1), end: pos };
|
|
113529
113677
|
}
|
|
113678
|
+
function restoreInlineCode(content, protectedCode) {
|
|
113679
|
+
return content.replace(/___INLINE_CODE_(\d+)___/g, (_m, idx) => {
|
|
113680
|
+
return protectedCode.inlineCode[parseInt(idx, 10)];
|
|
113681
|
+
});
|
|
113682
|
+
}
|
|
113683
|
+
function restoreCodeBlocks(content, protectedCode) {
|
|
113684
|
+
return content.replace(/___CODE_BLOCK_(\d+)___/g, (_m, idx) => {
|
|
113685
|
+
return protectedCode.codeBlocks[parseInt(idx, 10)];
|
|
113686
|
+
});
|
|
113687
|
+
}
|
|
113530
113688
|
/**
|
|
113531
113689
|
* Converts JSX attribute expressions (attribute={expression}) to HTML attributes (attribute="value").
|
|
113532
113690
|
* Handles style objects (camelCase → kebab-case), className → class, and JSON stringifies objects.
|
|
@@ -113542,7 +113700,7 @@ function extractBalancedBraces(content, start) {
|
|
|
113542
113700
|
* // Returns: '<a href="https://example.com">Link</a>'
|
|
113543
113701
|
* ```
|
|
113544
113702
|
*/
|
|
113545
|
-
function evaluateAttributeExpressions(content, context) {
|
|
113703
|
+
function evaluateAttributeExpressions(content, context, protectedCode) {
|
|
113546
113704
|
const attrStartRegex = /(\w+)=\{/g;
|
|
113547
113705
|
let result = '';
|
|
113548
113706
|
let lastEnd = 0;
|
|
@@ -113552,7 +113710,14 @@ function evaluateAttributeExpressions(content, context) {
|
|
|
113552
113710
|
const braceStart = match.index + match[0].length;
|
|
113553
113711
|
const extracted = extractBalancedBraces(content, braceStart);
|
|
113554
113712
|
if (extracted) {
|
|
113555
|
-
|
|
113713
|
+
// The expression might contain template literals in MDX component tag props
|
|
113714
|
+
// E.g. <Component greeting={`Hello World!`} />
|
|
113715
|
+
// that is marked as inline code. So we need to restore the inline codes
|
|
113716
|
+
// in the expression to evaluate it
|
|
113717
|
+
let expression = extracted.content;
|
|
113718
|
+
if (protectedCode) {
|
|
113719
|
+
expression = restoreInlineCode(expression, protectedCode);
|
|
113720
|
+
}
|
|
113556
113721
|
const fullMatchEnd = extracted.end;
|
|
113557
113722
|
result += content.slice(lastEnd, match.index);
|
|
113558
113723
|
try {
|
|
@@ -113568,14 +113733,20 @@ function evaluateAttributeExpressions(content, context) {
|
|
|
113568
113733
|
result += `style="${cssString}"`;
|
|
113569
113734
|
}
|
|
113570
113735
|
else {
|
|
113571
|
-
|
|
113736
|
+
// These are arrays / objects attribute values
|
|
113737
|
+
// Mark JSON-serialized values with a prefix so they can be parsed back correctly
|
|
113738
|
+
const jsonValue = escapeHtmlAttribute(JSON_VALUE_MARKER + JSON.stringify(evalResult));
|
|
113739
|
+
// Use double quotes so that multi-paragraph values are not split into multiple attributes by the processors
|
|
113740
|
+
result += `${attributeName}="${jsonValue}"`;
|
|
113572
113741
|
}
|
|
113573
113742
|
}
|
|
113574
113743
|
else if (attributeName === 'className') {
|
|
113575
|
-
|
|
113744
|
+
// Escape special characters so that it doesn't break and split the attribute value to nodes
|
|
113745
|
+
// This will be restored later in the pipeline
|
|
113746
|
+
result += `class="${escapeHtmlAttribute(String(evalResult))}"`;
|
|
113576
113747
|
}
|
|
113577
113748
|
else {
|
|
113578
|
-
result += `${attributeName}="${evalResult}"`;
|
|
113749
|
+
result += `${attributeName}="${escapeHtmlAttribute(String(evalResult))}"`;
|
|
113579
113750
|
}
|
|
113580
113751
|
}
|
|
113581
113752
|
catch (_error) {
|
|
@@ -113606,13 +113777,9 @@ function evaluateAttributeExpressions(content, context) {
|
|
|
113606
113777
|
* // Returns: 'Text with `inline` and ```js\ncode\n```'
|
|
113607
113778
|
* ```
|
|
113608
113779
|
*/
|
|
113609
|
-
function
|
|
113610
|
-
let restored = content
|
|
113611
|
-
|
|
113612
|
-
});
|
|
113613
|
-
restored = restored.replace(/___INLINE_CODE_(\d+)___/g, (_match, index) => {
|
|
113614
|
-
return protectedCode.inlineCode[parseInt(index, 10)];
|
|
113615
|
-
});
|
|
113780
|
+
function restoreProtectedCodes(content, protectedCode) {
|
|
113781
|
+
let restored = restoreCodeBlocks(content, protectedCode);
|
|
113782
|
+
restored = restoreInlineCode(restored, protectedCode);
|
|
113616
113783
|
return restored;
|
|
113617
113784
|
}
|
|
113618
113785
|
/**
|
|
@@ -113633,9 +113800,9 @@ function preprocessJSXExpressions(content, context = {}) {
|
|
|
113633
113800
|
// Step 3: Evaluate attribute expressions (JSX attribute syntax: href={baseUrl})
|
|
113634
113801
|
// For inline expressions, we use a library to parse the expression & evaluate it later
|
|
113635
113802
|
// For attribute expressions, it was difficult to use a library to parse them, so do it manually
|
|
113636
|
-
processed = evaluateAttributeExpressions(processed, context);
|
|
113803
|
+
processed = evaluateAttributeExpressions(processed, context, protectedCode);
|
|
113637
113804
|
// Step 4: Restore protected code blocks
|
|
113638
|
-
processed =
|
|
113805
|
+
processed = restoreProtectedCodes(processed, protectedCode);
|
|
113639
113806
|
return processed;
|
|
113640
113807
|
}
|
|
113641
113808
|
|
|
@@ -114047,7 +114214,7 @@ const wrapPinnedBlocks = (node, json) => {
|
|
|
114047
114214
|
return node;
|
|
114048
114215
|
return {
|
|
114049
114216
|
children: [node],
|
|
114050
|
-
data: {
|
|
114217
|
+
data: { hName: 'rdme-pin', hProperties: { className: 'pin' } },
|
|
114051
114218
|
type: 'rdme-pin',
|
|
114052
114219
|
};
|
|
114053
114220
|
};
|
|
@@ -114135,15 +114302,16 @@ function parseMagicBlock(raw, options = {}) {
|
|
|
114135
114302
|
type: 'code',
|
|
114136
114303
|
value: obj.code.trim(),
|
|
114137
114304
|
}));
|
|
114138
|
-
// Single code block without a tab name renders as a plain code block
|
|
114305
|
+
// Single code block without a tab name (meta or language) renders as a plain code block
|
|
114306
|
+
// Otherwise, we want to render it as a code tabs block
|
|
114139
114307
|
if (children.length === 1) {
|
|
114140
114308
|
if (!children[0].value)
|
|
114141
114309
|
return [];
|
|
114142
|
-
if (children[0].meta)
|
|
114310
|
+
if (!(children[0].meta || children[0].lang))
|
|
114143
114311
|
return [wrapPinnedBlocks(children[0], json)];
|
|
114144
114312
|
}
|
|
114145
|
-
// Multiple code blocks
|
|
114146
|
-
return [wrapPinnedBlocks({ children, className: 'tabs', data: { hName: '
|
|
114313
|
+
// Multiple code blocks or a single code block with a tab name (meta or language) renders as a code tabs block
|
|
114314
|
+
return [wrapPinnedBlocks({ children, className: 'tabs', data: { hName: 'CodeTabs' }, type: 'code-tabs' }, json)];
|
|
114147
114315
|
}
|
|
114148
114316
|
// API header: renders as a heading element (h1-h6)
|
|
114149
114317
|
case 'api-header': {
|
|
@@ -114344,11 +114512,31 @@ function parseMagicBlock(raw, options = {}) {
|
|
|
114344
114512
|
}
|
|
114345
114513
|
}
|
|
114346
114514
|
/**
|
|
114347
|
-
*
|
|
114515
|
+
* Block-level node types that cannot be nested inside paragraphs.
|
|
114348
114516
|
*/
|
|
114349
|
-
const
|
|
114350
|
-
|
|
114351
|
-
|
|
114517
|
+
const blockTypes = [
|
|
114518
|
+
'heading',
|
|
114519
|
+
'code',
|
|
114520
|
+
'code-tabs',
|
|
114521
|
+
'paragraph',
|
|
114522
|
+
'blockquote',
|
|
114523
|
+
'list',
|
|
114524
|
+
'table',
|
|
114525
|
+
'thematicBreak',
|
|
114526
|
+
'html',
|
|
114527
|
+
'yaml',
|
|
114528
|
+
'toml',
|
|
114529
|
+
'rdme-pin',
|
|
114530
|
+
'rdme-callout',
|
|
114531
|
+
'html-block',
|
|
114532
|
+
'embed',
|
|
114533
|
+
'figure',
|
|
114534
|
+
'mdxJsxFlowElement',
|
|
114535
|
+
];
|
|
114536
|
+
/**
|
|
114537
|
+
* Check if a node is a block-level node (cannot be inside a paragraph)
|
|
114538
|
+
*/
|
|
114539
|
+
const isBlockNode = (node) => blockTypes.includes(node.type);
|
|
114352
114540
|
/**
|
|
114353
114541
|
* Unified plugin that restores magic blocks from placeholder tokens.
|
|
114354
114542
|
*
|
|
@@ -114361,8 +114549,9 @@ const magicBlockRestorer = ({ blocks }) => tree => {
|
|
|
114361
114549
|
return;
|
|
114362
114550
|
// Map: key → original raw magic block content
|
|
114363
114551
|
const magicBlockKeys = new Map(blocks.map(({ key, raw }) => [key, raw]));
|
|
114364
|
-
//
|
|
114365
|
-
const
|
|
114552
|
+
// Collect replacements to apply (we need to visit in reverse to maintain indices)
|
|
114553
|
+
const replacements = [];
|
|
114554
|
+
// First pass: collect all replacements
|
|
114366
114555
|
visit(tree, 'inlineCode', (node, index, parent) => {
|
|
114367
114556
|
if (!parent || index == null)
|
|
114368
114557
|
return undefined;
|
|
@@ -114372,31 +114561,73 @@ const magicBlockRestorer = ({ blocks }) => tree => {
|
|
|
114372
114561
|
const children = parseMagicBlock(raw);
|
|
114373
114562
|
if (!children.length)
|
|
114374
114563
|
return undefined;
|
|
114375
|
-
|
|
114376
|
-
|
|
114377
|
-
|
|
114378
|
-
|
|
114379
|
-
|
|
114380
|
-
|
|
114381
|
-
|
|
114564
|
+
// If parent is a paragraph and we're inserting block nodes (which must not be in paragraphs), lift them out
|
|
114565
|
+
if (parent.type === 'paragraph' && children.some(child => isBlockNode(child))) {
|
|
114566
|
+
const blockNodes = [];
|
|
114567
|
+
const inlineNodes = [];
|
|
114568
|
+
// Separate block and inline nodes
|
|
114569
|
+
children.forEach(child => {
|
|
114570
|
+
if (isBlockNode(child)) {
|
|
114571
|
+
blockNodes.push(child);
|
|
114382
114572
|
}
|
|
114383
|
-
|
|
114384
|
-
|
|
114385
|
-
if (paragraphParent) {
|
|
114386
|
-
const paragraphIndex = paragraphParent.children.indexOf(parent);
|
|
114387
|
-
if (paragraphIndex !== -1) {
|
|
114388
|
-
modifications.push({ children, index: paragraphIndex, parent: paragraphParent });
|
|
114573
|
+
else {
|
|
114574
|
+
inlineNodes.push(child);
|
|
114389
114575
|
}
|
|
114390
|
-
}
|
|
114391
|
-
|
|
114576
|
+
});
|
|
114577
|
+
const before = parent.children.slice(0, index);
|
|
114578
|
+
const after = parent.children.slice(index + 1);
|
|
114579
|
+
replacements.push({
|
|
114580
|
+
parent,
|
|
114581
|
+
blockNodes,
|
|
114582
|
+
inlineNodes,
|
|
114583
|
+
before,
|
|
114584
|
+
after,
|
|
114585
|
+
});
|
|
114392
114586
|
}
|
|
114393
|
-
|
|
114394
|
-
|
|
114395
|
-
|
|
114396
|
-
|
|
114397
|
-
|
|
114398
|
-
parent.children.splice(index, 1, ...children);
|
|
114587
|
+
else {
|
|
114588
|
+
// Normal case: just replace the inlineCode with the children
|
|
114589
|
+
parent.children.splice(index, 1, ...children);
|
|
114590
|
+
}
|
|
114591
|
+
return undefined;
|
|
114399
114592
|
});
|
|
114593
|
+
// Second pass: apply replacements that require lifting block nodes out of paragraphs
|
|
114594
|
+
// Process in reverse order to maintain correct indices
|
|
114595
|
+
for (let i = replacements.length - 1; i >= 0; i -= 1) {
|
|
114596
|
+
const { after, before, blockNodes, inlineNodes, parent } = replacements[i];
|
|
114597
|
+
// Find the paragraph's position in the root
|
|
114598
|
+
const rootChildren = tree.children;
|
|
114599
|
+
const paraIndex = rootChildren.findIndex(child => child === parent);
|
|
114600
|
+
if (paraIndex === -1) {
|
|
114601
|
+
// Paragraph not found in root - fall back to normal replacement
|
|
114602
|
+
// This shouldn't happen normally, but handle it gracefully
|
|
114603
|
+
// Reconstruct the original index from before.length
|
|
114604
|
+
const originalIndex = before.length;
|
|
114605
|
+
parent.children.splice(originalIndex, 1, ...blockNodes, ...inlineNodes);
|
|
114606
|
+
// eslint-disable-next-line no-continue
|
|
114607
|
+
continue;
|
|
114608
|
+
}
|
|
114609
|
+
// Update or remove the paragraph
|
|
114610
|
+
if (inlineNodes.length > 0) {
|
|
114611
|
+
// Keep paragraph with inline nodes
|
|
114612
|
+
parent.children = [...before, ...inlineNodes, ...after];
|
|
114613
|
+
// Insert block nodes after the paragraph
|
|
114614
|
+
if (blockNodes.length > 0) {
|
|
114615
|
+
rootChildren.splice(paraIndex + 1, 0, ...blockNodes);
|
|
114616
|
+
}
|
|
114617
|
+
}
|
|
114618
|
+
else if (before.length === 0 && after.length === 0) {
|
|
114619
|
+
// Remove empty paragraph and replace with block nodes
|
|
114620
|
+
rootChildren.splice(paraIndex, 1, ...blockNodes);
|
|
114621
|
+
}
|
|
114622
|
+
else {
|
|
114623
|
+
// Keep paragraph with remaining content
|
|
114624
|
+
parent.children = [...before, ...after];
|
|
114625
|
+
// Insert block nodes after the paragraph
|
|
114626
|
+
if (blockNodes.length > 0) {
|
|
114627
|
+
rootChildren.splice(paraIndex + 1, 0, ...blockNodes);
|
|
114628
|
+
}
|
|
114629
|
+
}
|
|
114630
|
+
}
|
|
114400
114631
|
};
|
|
114401
114632
|
/* harmony default export */ const mdxish_magic_blocks = (magicBlockRestorer);
|
|
114402
114633
|
|
|
@@ -115250,6 +115481,40 @@ const makeUseMDXComponents = (more = {}) => {
|
|
|
115250
115481
|
|
|
115251
115482
|
|
|
115252
115483
|
|
|
115484
|
+
|
|
115485
|
+
/**
|
|
115486
|
+
* Parse JSON-marked string values in props back to their original types.
|
|
115487
|
+
* This handles arrays and objects that were serialized during JSX preprocessing.
|
|
115488
|
+
*/
|
|
115489
|
+
function parseJsonProps(props) {
|
|
115490
|
+
if (!props)
|
|
115491
|
+
return props;
|
|
115492
|
+
const parsed = {};
|
|
115493
|
+
Object.entries(props).forEach(([key, value]) => {
|
|
115494
|
+
if (typeof value === 'string' && value.startsWith(JSON_VALUE_MARKER)) {
|
|
115495
|
+
try {
|
|
115496
|
+
parsed[key] = JSON.parse(value.slice(JSON_VALUE_MARKER.length));
|
|
115497
|
+
}
|
|
115498
|
+
catch {
|
|
115499
|
+
// If parsing fails, use the value without the marker
|
|
115500
|
+
parsed[key] = value.slice(JSON_VALUE_MARKER.length);
|
|
115501
|
+
}
|
|
115502
|
+
}
|
|
115503
|
+
else {
|
|
115504
|
+
parsed[key] = value;
|
|
115505
|
+
}
|
|
115506
|
+
});
|
|
115507
|
+
return parsed;
|
|
115508
|
+
}
|
|
115509
|
+
/**
|
|
115510
|
+
* Custom createElement wrapper that parses JSON-marked string props.
|
|
115511
|
+
* This is needed because rehype-react converts HAST to React, but complex
|
|
115512
|
+
* types (arrays/objects) get serialized to strings during markdown parsing.
|
|
115513
|
+
*/
|
|
115514
|
+
function createElementWithJsonProps(type, props, ...children) {
|
|
115515
|
+
const parsedProps = parseJsonProps(props);
|
|
115516
|
+
return external_react_default().createElement(type, parsedProps, ...children);
|
|
115517
|
+
}
|
|
115253
115518
|
/** Flatten CustomComponents into a component map for rehype-react */
|
|
115254
115519
|
function exportComponentsForRehype(components) {
|
|
115255
115520
|
const exported = Object.entries(components).reduce((memo, [tag, mod]) => {
|
|
@@ -115281,7 +115546,7 @@ function exportComponentsForRehype(components) {
|
|
|
115281
115546
|
function createRehypeReactProcessor(components) {
|
|
115282
115547
|
// @ts-expect-error - rehype-react types are incompatible with React.Fragment return type
|
|
115283
115548
|
return unified().use((rehype_react_default()), {
|
|
115284
|
-
createElement:
|
|
115549
|
+
createElement: createElementWithJsonProps,
|
|
115285
115550
|
Fragment: (external_react_default()).Fragment,
|
|
115286
115551
|
components,
|
|
115287
115552
|
});
|