@readme/markdown 14.1.1 → 14.1.3
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 +168 -109
- package/dist/main.node.js +168 -109
- package/dist/main.node.js.map +1 -1
- package/dist/processor/transform/mdxish/components/utils.d.ts +7 -5
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -87611,7 +87611,12 @@ const tocHastToMdx = (toc, components, variables) => {
|
|
|
87611
87611
|
|
|
87612
87612
|
|
|
87613
87613
|
const sanitizeSchema = cjs_default()(defaultSchema, {
|
|
87614
|
-
|
|
87614
|
+
attributes: {
|
|
87615
|
+
a: ['target'],
|
|
87616
|
+
},
|
|
87617
|
+
protocols: {
|
|
87618
|
+
href: ['doc', 'ref', 'blog', 'changelog', 'page'],
|
|
87619
|
+
},
|
|
87615
87620
|
});
|
|
87616
87621
|
const compile_compile = (text, { components = {}, missingComponents, copyButtons, useTailwind, ...opts } = {}) => {
|
|
87617
87622
|
// Destructure at runtime to avoid circular dependency issues
|
|
@@ -97202,17 +97207,46 @@ function mdxComponent() {
|
|
|
97202
97207
|
|
|
97203
97208
|
|
|
97204
97209
|
|
|
97210
|
+
|
|
97211
|
+
|
|
97212
|
+
|
|
97213
|
+
|
|
97214
|
+
const buildInlineMdProcessor = (safeMode) => {
|
|
97215
|
+
const micromarkExts = [mdxComponent(), syntax_gemoji(), legacyVariable(), magicBlock()];
|
|
97216
|
+
const fromMarkdownExts = [
|
|
97217
|
+
mdxComponentFromMarkdown(),
|
|
97218
|
+
gemojiFromMarkdown(),
|
|
97219
|
+
legacyVariableFromMarkdown(),
|
|
97220
|
+
emptyTaskListItemFromMarkdown(),
|
|
97221
|
+
magicBlockFromMarkdown(),
|
|
97222
|
+
];
|
|
97223
|
+
// Since evaluating expressions can be dangerous, do so only when safeMode is off
|
|
97224
|
+
if (!safeMode) {
|
|
97225
|
+
const mdxExprExt = mdxExpression({ allowEmpty: true });
|
|
97226
|
+
micromarkExts.push({ text: mdxExprExt.text });
|
|
97227
|
+
fromMarkdownExts.push(mdxExpressionFromMarkdown());
|
|
97228
|
+
}
|
|
97229
|
+
return unified()
|
|
97230
|
+
.data('micromarkExtensions', micromarkExts)
|
|
97231
|
+
.data('fromMarkdownExtensions', fromMarkdownExts)
|
|
97232
|
+
.use(remarkParse)
|
|
97233
|
+
.use(remarkGfm);
|
|
97234
|
+
};
|
|
97235
|
+
const processorCache = new Map();
|
|
97205
97236
|
/**
|
|
97206
|
-
*
|
|
97207
|
-
*
|
|
97208
|
-
*
|
|
97209
|
-
*
|
|
97237
|
+
* Unified processor for re-parsing the body of an MDX component
|
|
97238
|
+
* Memoized based on the argument value so we don't pay the construction cost on every parse
|
|
97239
|
+
* Currently the argument is only safeMode, but we could add more arguments in the future,
|
|
97240
|
+
* in which case the key would need to be extend to include the new arguments.
|
|
97210
97241
|
*/
|
|
97211
|
-
const
|
|
97212
|
-
|
|
97213
|
-
|
|
97214
|
-
|
|
97215
|
-
|
|
97242
|
+
const getInlineMdProcessor = ({ safeMode = false } = {}) => {
|
|
97243
|
+
let processor = processorCache.get(safeMode);
|
|
97244
|
+
if (!processor) {
|
|
97245
|
+
processor = buildInlineMdProcessor(safeMode);
|
|
97246
|
+
processorCache.set(safeMode, processor);
|
|
97247
|
+
}
|
|
97248
|
+
return processor;
|
|
97249
|
+
};
|
|
97216
97250
|
/**
|
|
97217
97251
|
* True when a tag name starts with an uppercase letter — ReadMe's marker for
|
|
97218
97252
|
* a custom MDX component (vs a lowercase HTML tag).
|
|
@@ -97253,11 +97287,11 @@ const toMdxJsxTextElement = (name, attributes, children, position) => ({
|
|
|
97253
97287
|
* rejects line endings), so the paragraph-flatten path covers every case we
|
|
97254
97288
|
* actually produce; other shapes fall back to empty children.
|
|
97255
97289
|
*/
|
|
97256
|
-
const parsePhrasingChildren = (value) => {
|
|
97290
|
+
const parsePhrasingChildren = (value, safeMode) => {
|
|
97257
97291
|
const trimmed = value.trim();
|
|
97258
97292
|
if (!trimmed)
|
|
97259
97293
|
return [];
|
|
97260
|
-
const [first] =
|
|
97294
|
+
const [first] = getInlineMdProcessor({ safeMode }).parse(trimmed).children;
|
|
97261
97295
|
return first?.type === 'paragraph' ? first.children : [];
|
|
97262
97296
|
};
|
|
97263
97297
|
/**
|
|
@@ -97270,7 +97304,7 @@ const parsePhrasingChildren = (value) => {
|
|
|
97270
97304
|
*
|
|
97271
97305
|
* Returns the original node unchanged when it doesn't qualify.
|
|
97272
97306
|
*/
|
|
97273
|
-
const promoteInlineHtml = (node, parseOpts) => {
|
|
97307
|
+
const promoteInlineHtml = (node, parseOpts, safeMode) => {
|
|
97274
97308
|
const parsed = parseTag((node.value ?? '').trim(), parseOpts);
|
|
97275
97309
|
if (!parsed)
|
|
97276
97310
|
return node;
|
|
@@ -97295,7 +97329,7 @@ const promoteInlineHtml = (node, parseOpts) => {
|
|
|
97295
97329
|
if (closeIdx < 0)
|
|
97296
97330
|
return node;
|
|
97297
97331
|
const inner = contentAfterTag.slice(0, closeIdx);
|
|
97298
|
-
return toMdxJsxTextElement(tag, attributes, parsePhrasingChildren(inner), node.position);
|
|
97332
|
+
return toMdxJsxTextElement(tag, attributes, parsePhrasingChildren(inner, safeMode), node.position);
|
|
97299
97333
|
};
|
|
97300
97334
|
/**
|
|
97301
97335
|
* Transform inline html nodes with expression attributes
|
|
@@ -97314,9 +97348,10 @@ const promoteInlineHtml = (node, parseOpts) => {
|
|
|
97314
97348
|
* `<a href="x">` stays as an html node for rehype-raw.
|
|
97315
97349
|
*/
|
|
97316
97350
|
const mdxishInlineMdxHtmlBlocks = (opts = {}) => tree => {
|
|
97317
|
-
const
|
|
97351
|
+
const safeMode = !!opts.safeMode;
|
|
97352
|
+
const parseOpts = { preserveExpressionsAsText: safeMode };
|
|
97318
97353
|
visit(tree, 'paragraph', (paragraph) => {
|
|
97319
|
-
paragraph.children = paragraph.children.map(child => child.type === 'html' ? promoteInlineHtml(child, parseOpts) : child);
|
|
97354
|
+
paragraph.children = paragraph.children.map(child => child.type === 'html' ? promoteInlineHtml(child, parseOpts, safeMode) : child);
|
|
97320
97355
|
});
|
|
97321
97356
|
};
|
|
97322
97357
|
/* harmony default export */ const inline_html = (mdxishInlineMdxHtmlBlocks);
|
|
@@ -97399,15 +97434,15 @@ function safeDeindent(text) {
|
|
|
97399
97434
|
* Dedents the content first to prevent indented component content
|
|
97400
97435
|
* (from nested components) from being treated as code blocks.
|
|
97401
97436
|
*/
|
|
97402
|
-
const parseMdChildren = (value) => {
|
|
97403
|
-
const parsed =
|
|
97437
|
+
const parseMdChildren = (value, safeMode) => {
|
|
97438
|
+
const parsed = getInlineMdProcessor({ safeMode }).parse(safeDeindent(value).trim());
|
|
97404
97439
|
return parsed.children || [];
|
|
97405
97440
|
};
|
|
97406
97441
|
/**
|
|
97407
97442
|
* Parse substring content of a node and update the parent's children to include the new nodes.
|
|
97408
97443
|
*/
|
|
97409
|
-
const parseSibling = (stack, parent, index, sibling) => {
|
|
97410
|
-
const siblingNodes = parseMdChildren(sibling);
|
|
97444
|
+
const parseSibling = (stack, parent, index, sibling, safeMode) => {
|
|
97445
|
+
const siblingNodes = parseMdChildren(sibling, safeMode);
|
|
97411
97446
|
// The new sibling nodes might contain new components to be processed
|
|
97412
97447
|
if (siblingNodes.length > 0) {
|
|
97413
97448
|
parent.children.splice(index + 1, 0, ...siblingNodes);
|
|
@@ -97459,7 +97494,8 @@ const substituteNodeWithMdxNode = (parent, index, mdxNode) => {
|
|
|
97459
97494
|
*/
|
|
97460
97495
|
const mdxishMdxComponentBlocks = (opts = {}) => tree => {
|
|
97461
97496
|
const stack = [tree];
|
|
97462
|
-
const
|
|
97497
|
+
const safeMode = !!opts.safeMode;
|
|
97498
|
+
const parseOpts = { preserveExpressionsAsText: safeMode };
|
|
97463
97499
|
const processChildNode = (parent, index) => {
|
|
97464
97500
|
const node = parent.children[index];
|
|
97465
97501
|
if (!node)
|
|
@@ -97505,7 +97541,7 @@ const mdxishMdxComponentBlocks = (opts = {}) => tree => {
|
|
|
97505
97541
|
// Check and parse if there's relevant content after the current closing tag
|
|
97506
97542
|
const remainingContent = contentAfterTag.trim();
|
|
97507
97543
|
if (remainingContent) {
|
|
97508
|
-
parseSibling(stack, parent, index, remainingContent);
|
|
97544
|
+
parseSibling(stack, parent, index, remainingContent, safeMode);
|
|
97509
97545
|
}
|
|
97510
97546
|
return;
|
|
97511
97547
|
}
|
|
@@ -97518,7 +97554,7 @@ const mdxishMdxComponentBlocks = (opts = {}) => tree => {
|
|
|
97518
97554
|
const componentInnerContent = contentAfterTag.substring(0, closingTagIndex);
|
|
97519
97555
|
const contentAfterClose = contentAfterTag.substring(closingTagIndex + closingTagStr.length).trim();
|
|
97520
97556
|
let parsedChildren = componentInnerContent.trim()
|
|
97521
|
-
? parseMdChildren(componentInnerContent)
|
|
97557
|
+
? parseMdChildren(componentInnerContent, safeMode)
|
|
97522
97558
|
: [];
|
|
97523
97559
|
// Lowercase HTML tags are usually inline (e.g. <a>, <span>). Remark wraps
|
|
97524
97560
|
// bare text in a paragraph; unwrap when there's exactly one paragraph so
|
|
@@ -97535,7 +97571,7 @@ const mdxishMdxComponentBlocks = (opts = {}) => tree => {
|
|
|
97535
97571
|
substituteNodeWithMdxNode(parent, index, componentNode);
|
|
97536
97572
|
// After the closing tag, there might be more content to be processed
|
|
97537
97573
|
if (contentAfterClose) {
|
|
97538
|
-
parseSibling(stack, parent, index, contentAfterClose);
|
|
97574
|
+
parseSibling(stack, parent, index, contentAfterClose, safeMode);
|
|
97539
97575
|
}
|
|
97540
97576
|
else if (componentNode.children.length > 0) {
|
|
97541
97577
|
// The content inside the component block might contain new components to be processed
|
|
@@ -99445,11 +99481,17 @@ const blockTypes = [
|
|
|
99445
99481
|
* Check if a node is a block-level node (cannot be inside a paragraph)
|
|
99446
99482
|
*/
|
|
99447
99483
|
const isBlockNode = (node) => blockTypes.includes(node.type);
|
|
99484
|
+
const isParagraph = (node) => node.type === 'paragraph';
|
|
99485
|
+
/**
|
|
99486
|
+
* True for phrasing content that contributes only whitespace at render time
|
|
99487
|
+
* (a soft `break` node or a text node with no non-whitespace characters).
|
|
99488
|
+
*/
|
|
99489
|
+
const isWhitespacePhrasing = (node) => node.type === 'break' || (node.type === 'text' && !node.value.trim());
|
|
99448
99490
|
/**
|
|
99449
99491
|
* Unified plugin that transforms magicBlock nodes into final MDAST nodes.
|
|
99450
99492
|
*/
|
|
99451
99493
|
const magicBlockTransformer = (options = {}) => tree => {
|
|
99452
|
-
const
|
|
99494
|
+
const lifts = [];
|
|
99453
99495
|
visitParents(tree, 'magicBlock', (node, ancestors) => {
|
|
99454
99496
|
const parent = ancestors[ancestors.length - 1]; // direct parent of the current node
|
|
99455
99497
|
const index = parent.children.indexOf(node);
|
|
@@ -99463,51 +99505,60 @@ const magicBlockTransformer = (options = {}) => tree => {
|
|
|
99463
99505
|
parent.children.splice(index, 1);
|
|
99464
99506
|
return;
|
|
99465
99507
|
}
|
|
99466
|
-
// If parent is a paragraph and we're inserting block nodes (which must not be in paragraphs)
|
|
99467
|
-
|
|
99508
|
+
// If parent is a paragraph and we're inserting block nodes (which must not be in paragraphs)
|
|
99509
|
+
// it means we need to lift them out
|
|
99510
|
+
if (isParagraph(parent) && children.some(isBlockNode)) {
|
|
99468
99511
|
const blockNodes = [];
|
|
99469
|
-
const inlineNodes = [];
|
|
99470
99512
|
children.forEach(child => {
|
|
99471
|
-
(isBlockNode(child)
|
|
99513
|
+
if (isBlockNode(child)) {
|
|
99514
|
+
blockNodes.push(child);
|
|
99515
|
+
}
|
|
99472
99516
|
});
|
|
99473
|
-
|
|
99474
|
-
|
|
99517
|
+
lifts.push({
|
|
99518
|
+
childrenBlockNodes: blockNodes,
|
|
99519
|
+
grandparent: ancestors[ancestors.length - 2] || tree, // grandparent of the current node
|
|
99520
|
+
node,
|
|
99475
99521
|
parent,
|
|
99476
|
-
blockNodes,
|
|
99477
|
-
inlineNodes,
|
|
99478
|
-
before: parent.children.slice(0, index),
|
|
99479
|
-
after: parent.children.slice(index + 1),
|
|
99480
99522
|
});
|
|
99481
99523
|
}
|
|
99482
99524
|
else {
|
|
99483
99525
|
parent.children.splice(index, 1, ...children);
|
|
99484
99526
|
}
|
|
99485
99527
|
});
|
|
99486
|
-
// Second pass: apply
|
|
99487
|
-
//
|
|
99488
|
-
|
|
99489
|
-
|
|
99490
|
-
const
|
|
99491
|
-
const
|
|
99492
|
-
|
|
99493
|
-
|
|
99528
|
+
// Second pass: apply lifts that move block nodes, and the content after them, out of paragraphs.
|
|
99529
|
+
// Operate on live state (find each node's current index now) and process in reverse so
|
|
99530
|
+
// that container insertions don't disturb earlier paragraphs' positions.
|
|
99531
|
+
for (let i = lifts.length - 1; i >= 0; i -= 1) {
|
|
99532
|
+
const { childrenBlockNodes: blockNodes, grandparent, node, parent: parentParagraph } = lifts[i];
|
|
99533
|
+
const nodePosition = parentParagraph.children.indexOf(node);
|
|
99534
|
+
const parentPosition = grandparent.children.indexOf(parentParagraph);
|
|
99535
|
+
if (nodePosition === -1 || parentPosition === -1) {
|
|
99494
99536
|
// eslint-disable-next-line no-continue
|
|
99495
99537
|
continue;
|
|
99496
99538
|
}
|
|
99497
|
-
|
|
99498
|
-
|
|
99499
|
-
|
|
99500
|
-
|
|
99501
|
-
|
|
99502
|
-
|
|
99503
|
-
|
|
99504
|
-
|
|
99539
|
+
// Snapshot live siblings to reconstruct the parent paragraph around the lifted node.
|
|
99540
|
+
const parentSiblingsBefore = parentParagraph.children.slice(0, nodePosition);
|
|
99541
|
+
const parentSiblingsAfter = parentParagraph.children.slice(nodePosition + 1);
|
|
99542
|
+
// Remove split-edge whitespace so lifted blocks do not render with extra blank lines.
|
|
99543
|
+
while (parentSiblingsBefore.length > 0 && isWhitespacePhrasing(parentSiblingsBefore[parentSiblingsBefore.length - 1]))
|
|
99544
|
+
parentSiblingsBefore.pop();
|
|
99545
|
+
while (parentSiblingsAfter.length > 0 && isWhitespacePhrasing(parentSiblingsAfter[0]))
|
|
99546
|
+
parentSiblingsAfter.shift();
|
|
99547
|
+
const splitOffContentFromParent = [...blockNodes];
|
|
99548
|
+
if (parentSiblingsAfter.length > 0) {
|
|
99549
|
+
// Keep trailing inline content grouped under a paragraph sibling as it might be an inline node
|
|
99550
|
+
// Even if it contains a block node, it will be hoisted out during its turn in the loop
|
|
99551
|
+
const trailingParagraph = { type: 'paragraph', children: parentSiblingsAfter };
|
|
99552
|
+
splitOffContentFromParent.push(trailingParagraph);
|
|
99553
|
+
}
|
|
99554
|
+
parentParagraph.children = [...parentSiblingsBefore];
|
|
99555
|
+
// If the parent paragraph is empty, just replace it with the lifted block nodes
|
|
99556
|
+
const shouldReplaceParent = parentParagraph.children.length === 0;
|
|
99557
|
+
if (shouldReplaceParent) {
|
|
99558
|
+
grandparent.children.splice(parentPosition, 1, ...splitOffContentFromParent);
|
|
99505
99559
|
}
|
|
99506
99560
|
else {
|
|
99507
|
-
|
|
99508
|
-
if (blockNodes.length > 0) {
|
|
99509
|
-
containerChildren.splice(paraIndex + 1, 0, ...blockNodes);
|
|
99510
|
-
}
|
|
99561
|
+
grandparent.children.splice(parentPosition + 1, 0, ...splitOffContentFromParent);
|
|
99511
99562
|
}
|
|
99512
99563
|
}
|
|
99513
99564
|
};
|
|
@@ -99577,29 +99628,56 @@ function protectHTMLBlockContent(content) {
|
|
|
99577
99628
|
function removeJSXComments(content) {
|
|
99578
99629
|
return content.replace(JSX_COMMENT_REGEX, '');
|
|
99579
99630
|
}
|
|
99631
|
+
const HTML_ELEM_PLACEHOLDER_PREFIX = '___MDXISH_HTML_ELEM_';
|
|
99632
|
+
const HTML_ELEM_PLACEHOLDER = new RegExp(`${HTML_ELEM_PLACEHOLDER_PREFIX}(\\d+)___`, 'g');
|
|
99633
|
+
// Matches an HTML element that starts at a line boundary and ends at a line boundary.
|
|
99634
|
+
// Allows optional leading indentation and lazily matches until the same closing tag.
|
|
99635
|
+
const BLOCK_HTML_RE = /(?<=^|\n)[ \t]*<([a-z][a-zA-Z0-9]*)(?:\s[^>]*)?>[\s\S]*?<\/\1>[ \t]*(?=\n|$)/g;
|
|
99580
99636
|
/**
|
|
99581
|
-
*
|
|
99582
|
-
*
|
|
99583
|
-
*
|
|
99637
|
+
* Hides line-anchored HTML elements from the brace-escaping pass so we don't leak `\{`
|
|
99638
|
+
* into rendered output (rehypeRaw renders the `\` literally, e.g. `<div>{foo</div>`).
|
|
99639
|
+
*
|
|
99640
|
+
* One carve-out: if an interior line at column 0 has bare text containing `{`, mdxish
|
|
99641
|
+
* parses that line as a paragraph and the mdxExpression step would throw without an
|
|
99642
|
+
* escape — so we leave that case to the brace balancer.
|
|
99584
99643
|
*/
|
|
99585
|
-
function
|
|
99586
|
-
// Skip HTML elements — their content should never be escaped because
|
|
99587
|
-
// rehypeRaw parses them into hast elements, making `\` literal text in output
|
|
99644
|
+
function protectHTMLElements(content) {
|
|
99588
99645
|
const htmlElements = [];
|
|
99589
|
-
const
|
|
99590
|
-
|
|
99646
|
+
const protectedContent = content.replace(BLOCK_HTML_RE, match => {
|
|
99647
|
+
// Look at the lines between the open and close tags. If any of them starts
|
|
99648
|
+
// at column 0 with bare text (not whitespace, not another tag) and contains
|
|
99649
|
+
// `{`, mdxish will parse that line as a paragraph and the brace as an MDX
|
|
99650
|
+
// expression, which would throw an error. So we let the brace balancer escape it.
|
|
99651
|
+
// Otherwise, we need to extract the sequence to protect it from the brace escaping.
|
|
99652
|
+
const interior = match.split('\n').slice(1, -1);
|
|
99653
|
+
const hazard = interior.some(line => line.length > 0 && line[0] !== ' ' && line[0] !== '\t' && line[0] !== '<' && line.includes('{'));
|
|
99654
|
+
if (hazard)
|
|
99655
|
+
return match;
|
|
99591
99656
|
htmlElements.push(match);
|
|
99592
|
-
return
|
|
99657
|
+
return `${HTML_ELEM_PLACEHOLDER_PREFIX}${htmlElements.length - 1}___`;
|
|
99593
99658
|
});
|
|
99594
|
-
|
|
99595
|
-
|
|
99596
|
-
|
|
99659
|
+
return { htmlElements, protectedContent };
|
|
99660
|
+
}
|
|
99661
|
+
function restoreHTMLElements(content, htmlElements) {
|
|
99662
|
+
if (htmlElements.length === 0)
|
|
99663
|
+
return content;
|
|
99664
|
+
return content.replace(HTML_ELEM_PLACEHOLDER, (_m, idx) => htmlElements[parseInt(idx, 10)]);
|
|
99665
|
+
}
|
|
99666
|
+
/**
|
|
99667
|
+
* Escapes unbalanced and paragraph-spanning braces so MDX doesn't trip on them.
|
|
99668
|
+
*/
|
|
99669
|
+
function escapeProblematicBraces(content) {
|
|
99670
|
+
const { htmlElements, protectedContent } = protectHTMLElements(content);
|
|
99597
99671
|
let strDelim = null;
|
|
99598
99672
|
let strEscaped = false;
|
|
99599
|
-
// Stack of open braces with their state
|
|
99600
|
-
const openStack = [];
|
|
99601
99673
|
// Track position of last newline (outside strings) to detect blank lines
|
|
99602
|
-
|
|
99674
|
+
// -2 means no recent newline
|
|
99675
|
+
let lastNewlinePos = -2;
|
|
99676
|
+
// Character state machine trackers
|
|
99677
|
+
const toEscape = new Set();
|
|
99678
|
+
// Convert to array of Unicode code points so that emojis and multi-byte characters are correctly tracked
|
|
99679
|
+
const chars = Array.from(protectedContent);
|
|
99680
|
+
const openStack = [];
|
|
99603
99681
|
for (let i = 0; i < chars.length; i += 1) {
|
|
99604
99682
|
const ch = chars[i];
|
|
99605
99683
|
// Track string delimiters inside expressions to ignore braces within them
|
|
@@ -99619,22 +99697,17 @@ function escapeProblematicBraces(content) {
|
|
|
99619
99697
|
// eslint-disable-next-line no-continue
|
|
99620
99698
|
continue;
|
|
99621
99699
|
}
|
|
99622
|
-
// Track newlines to detect blank lines (paragraph boundaries)
|
|
99623
99700
|
if (ch === '\n') {
|
|
99624
|
-
// Check if this newline creates a blank line (only whitespace since last newline)
|
|
99625
99701
|
if (lastNewlinePos >= 0) {
|
|
99626
99702
|
const between = chars.slice(lastNewlinePos + 1, i).join('');
|
|
99627
99703
|
if (/^[ \t]*$/.test(between)) {
|
|
99628
|
-
|
|
99629
|
-
openStack.forEach(entry => {
|
|
99630
|
-
entry.hasBlankLine = true;
|
|
99631
|
-
});
|
|
99704
|
+
openStack.forEach(entry => { entry.hasBlankLine = true; });
|
|
99632
99705
|
}
|
|
99633
99706
|
}
|
|
99634
99707
|
lastNewlinePos = i;
|
|
99635
99708
|
}
|
|
99636
99709
|
}
|
|
99637
|
-
// Skip already-escaped braces (
|
|
99710
|
+
// Skip already-escaped braces (odd run of preceding backslashes).
|
|
99638
99711
|
if (ch === '{' || ch === '}') {
|
|
99639
99712
|
let bs = 0;
|
|
99640
99713
|
for (let j = i - 1; j >= 0 && chars[j] === '\\'; j -= 1)
|
|
@@ -99645,10 +99718,9 @@ function escapeProblematicBraces(content) {
|
|
|
99645
99718
|
}
|
|
99646
99719
|
}
|
|
99647
99720
|
if (ch === '{') {
|
|
99648
|
-
//
|
|
99649
|
-
//
|
|
99650
|
-
//
|
|
99651
|
-
// won't split paragraphs — skip the blank-line check for these.
|
|
99721
|
+
// `=` (after whitespace) before `{` ⇒ JSX attribute expression. The
|
|
99722
|
+
// mdxComponent tokenizer captures the whole component, so blank lines
|
|
99723
|
+
// inside attribute values are harmless. Nested `{` inherits the flag.
|
|
99652
99724
|
let isAttrExpr = false;
|
|
99653
99725
|
for (let j = i - 1; j >= 0; j -= 1) {
|
|
99654
99726
|
const pc = chars[j];
|
|
@@ -99662,27 +99734,17 @@ function escapeProblematicBraces(content) {
|
|
|
99662
99734
|
// Nested `{ ... }` inside an attribute value (e.g. `data={[{ ... }]}` or
|
|
99663
99735
|
// `data={{ a: { b: 1 } }}`) must inherit the same exemption; only the
|
|
99664
99736
|
// outer `{` is directly after `=`.
|
|
99665
|
-
if (!isAttrExpr && openStack.length > 0) {
|
|
99666
|
-
|
|
99667
|
-
if (parent.isAttrExpr) {
|
|
99668
|
-
isAttrExpr = true;
|
|
99669
|
-
}
|
|
99737
|
+
if (!isAttrExpr && openStack.length > 0 && openStack[openStack.length - 1].isAttrExpr) {
|
|
99738
|
+
isAttrExpr = true;
|
|
99670
99739
|
}
|
|
99671
99740
|
openStack.push({ pos: i, hasBlankLine: false, isAttrExpr });
|
|
99672
|
-
lastNewlinePos = -2;
|
|
99741
|
+
lastNewlinePos = -2;
|
|
99673
99742
|
}
|
|
99674
99743
|
else if (ch === '}') {
|
|
99675
99744
|
if (openStack.length > 0) {
|
|
99676
99745
|
const entry = openStack.pop();
|
|
99677
|
-
//
|
|
99678
|
-
//
|
|
99679
|
-
// even if the body has blank lines in it. If we escape the braces here
|
|
99680
|
-
// the tokenizer never gets a shot at it.
|
|
99681
|
-
//
|
|
99682
|
-
// "Pure" means the braces open with `{/*` and close with `*/}` right
|
|
99683
|
-
// next to each other. Something like `{/* c */ expr\n\nmore}` is just
|
|
99684
|
-
// a regular expression that happens to start with a comment, so it
|
|
99685
|
-
// still needs the normal blank-line protection.
|
|
99746
|
+
// Pure `{/* ... */}` comments are handled downstream by the jsxComment
|
|
99747
|
+
// tokenizer — escaping their braces would prevent it from running.
|
|
99686
99748
|
const isPureJsxComment = chars[entry.pos + 1] === '/' &&
|
|
99687
99749
|
chars[entry.pos + 2] === '*' &&
|
|
99688
99750
|
chars[i - 1] === '/' &&
|
|
@@ -99693,21 +99755,15 @@ function escapeProblematicBraces(content) {
|
|
|
99693
99755
|
}
|
|
99694
99756
|
}
|
|
99695
99757
|
else {
|
|
99696
|
-
// Unbalanced closing brace (no matching open)
|
|
99697
99758
|
toEscape.add(i);
|
|
99698
99759
|
}
|
|
99699
99760
|
}
|
|
99700
99761
|
}
|
|
99701
|
-
//
|
|
99762
|
+
// Anything still open is unbalanced.
|
|
99702
99763
|
openStack.forEach(entry => toEscape.add(entry.pos));
|
|
99703
|
-
//
|
|
99704
|
-
|
|
99705
|
-
|
|
99706
|
-
// Restore HTML elements
|
|
99707
|
-
if (htmlElements.length > 0) {
|
|
99708
|
-
result = result.replace(/___HTML_ELEM_(\d+)___/g, (_m, idx) => htmlElements[parseInt(idx, 10)]);
|
|
99709
|
-
}
|
|
99710
|
-
return result;
|
|
99764
|
+
// Reconstruct the content with the escaped braces.
|
|
99765
|
+
const escapedContent = toEscape.size === 0 ? protectedContent : chars.map((ch, i) => (toEscape.has(i) ? `\\${ch}` : ch)).join('');
|
|
99766
|
+
return restoreHTMLElements(escapedContent, htmlElements);
|
|
99711
99767
|
}
|
|
99712
99768
|
/**
|
|
99713
99769
|
* Preprocesses JSX-like markdown content before parsing.
|
|
@@ -101853,15 +101909,18 @@ function mdxishAstProcessor(mdContent, opts = {}) {
|
|
|
101853
101909
|
.use(remarkParse)
|
|
101854
101910
|
.use(remarkFrontmatter)
|
|
101855
101911
|
.use(normalize_malformed_md_syntax)
|
|
101856
|
-
.use(magic_block_transformer)
|
|
101857
|
-
.use(transform_images, { isMdxish: true })
|
|
101858
|
-
.use(defaultTransformers)
|
|
101859
101912
|
.use(self_closing_blocks)
|
|
101860
101913
|
.use(mdx_blocks, { safeMode })
|
|
101861
101914
|
.use(inline_html, { safeMode })
|
|
101862
101915
|
.use(restore_snake_case_component_name, { mapping: snakeCaseMapping })
|
|
101863
101916
|
.use(mdxish_tables)
|
|
101864
101917
|
.use(mdxish_html_blocks)
|
|
101918
|
+
// The next few transformers must appear after mdxishMdxComponentBlocks
|
|
101919
|
+
// so nodes produced by the inline re-parse of component bodies
|
|
101920
|
+
// (e.g. code/image/embed inside <Tabs>) get visited too
|
|
101921
|
+
.use(magic_block_transformer)
|
|
101922
|
+
.use(transform_images, { isMdxish: true })
|
|
101923
|
+
.use(defaultTransformers)
|
|
101865
101924
|
.use(newEditorTypes ? inline_mdx_blocks : undefined) // Merge inline html components (e.g. <Anchor>) into MDAST nodes
|
|
101866
101925
|
.use(newEditorTypes ? mdxish_jsx_to_mdast : undefined) // Convert block JSX elements to MDAST types
|
|
101867
101926
|
.use(variables_text) // Parse {user.*} patterns from text nodes
|