@readme/markdown 13.0.0 → 13.1.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/components/Tabs/style.scss +2 -2
- package/dist/lib/index.d.ts +1 -0
- package/dist/lib/mdxish.d.ts +10 -0
- package/dist/main.css +1 -1
- package/dist/main.css.map +1 -1
- package/dist/main.js +436 -151
- package/dist/main.node.js +436 -151
- package/dist/main.node.js.map +1 -1
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -53102,6 +53102,59 @@ const isCalloutStructure = (node) => {
|
|
|
53102
53102
|
const firstTextChild = firstChild.children?.[0];
|
|
53103
53103
|
return firstTextChild?.type === 'text';
|
|
53104
53104
|
};
|
|
53105
|
+
/**
|
|
53106
|
+
* Finds the first text node containing a newline in a paragraph's children.
|
|
53107
|
+
* Returns the index and the newline position within that text node.
|
|
53108
|
+
*/
|
|
53109
|
+
const findNewlineInParagraph = (paragraph) => {
|
|
53110
|
+
for (let i = 0; i < paragraph.children.length; i += 1) {
|
|
53111
|
+
const child = paragraph.children[i];
|
|
53112
|
+
if (child.type === 'text' && typeof child.value === 'string') {
|
|
53113
|
+
const newlineIndex = child.value.indexOf('\n');
|
|
53114
|
+
if (newlineIndex !== -1) {
|
|
53115
|
+
return { index: i, newlineIndex };
|
|
53116
|
+
}
|
|
53117
|
+
}
|
|
53118
|
+
}
|
|
53119
|
+
return null;
|
|
53120
|
+
};
|
|
53121
|
+
/**
|
|
53122
|
+
* Splits a paragraph at the first newline, separating heading content (before \n)
|
|
53123
|
+
* from body content (after \n). Mutates the paragraph to contain only heading children.
|
|
53124
|
+
*/
|
|
53125
|
+
const splitParagraphAtNewline = (paragraph) => {
|
|
53126
|
+
const splitPoint = findNewlineInParagraph(paragraph);
|
|
53127
|
+
if (!splitPoint)
|
|
53128
|
+
return null;
|
|
53129
|
+
const { index, newlineIndex } = splitPoint;
|
|
53130
|
+
const originalChildren = paragraph.children;
|
|
53131
|
+
const textNode = originalChildren[index];
|
|
53132
|
+
const beforeNewline = textNode.value.slice(0, newlineIndex);
|
|
53133
|
+
const afterNewline = textNode.value.slice(newlineIndex + 1);
|
|
53134
|
+
// Split paragraph: heading = children[0..index-1] + text before newline
|
|
53135
|
+
const headingChildren = originalChildren.slice(0, index);
|
|
53136
|
+
if (beforeNewline.length > 0 || headingChildren.length === 0) {
|
|
53137
|
+
headingChildren.push({ type: 'text', value: beforeNewline });
|
|
53138
|
+
}
|
|
53139
|
+
paragraph.children = headingChildren;
|
|
53140
|
+
// Body = text after newline + remaining children from original array
|
|
53141
|
+
const bodyChildren = [];
|
|
53142
|
+
if (afterNewline.length > 0) {
|
|
53143
|
+
bodyChildren.push({ type: 'text', value: afterNewline });
|
|
53144
|
+
}
|
|
53145
|
+
bodyChildren.push(...originalChildren.slice(index + 1));
|
|
53146
|
+
return bodyChildren.length > 0 ? bodyChildren : null;
|
|
53147
|
+
};
|
|
53148
|
+
/**
|
|
53149
|
+
* Removes the icon/match prefix from the first text node in a paragraph.
|
|
53150
|
+
* This is needed to clean up the raw AST after we've extracted the icon.
|
|
53151
|
+
*/
|
|
53152
|
+
const removeIconPrefix = (paragraph, prefixLength) => {
|
|
53153
|
+
const firstTextNode = findFirst(paragraph);
|
|
53154
|
+
if (firstTextNode && 'value' in firstTextNode && typeof firstTextNode.value === 'string') {
|
|
53155
|
+
firstTextNode.value = firstTextNode.value.slice(prefixLength);
|
|
53156
|
+
}
|
|
53157
|
+
};
|
|
53105
53158
|
const processBlockquote = (node, index, parent) => {
|
|
53106
53159
|
if (!isCalloutStructure(node)) {
|
|
53107
53160
|
// Only stringify empty blockquotes (no extractable text content)
|
|
@@ -53126,22 +53179,39 @@ const processBlockquote = (node, index, parent) => {
|
|
|
53126
53179
|
const firstParagraph = node.children[0];
|
|
53127
53180
|
const startText = lib_plain(firstParagraph).toString();
|
|
53128
53181
|
const [match, icon] = startText.match(callouts_regex) || [];
|
|
53182
|
+
const firstParagraphOriginalEnd = firstParagraph.position.end;
|
|
53129
53183
|
if (icon && match) {
|
|
53130
|
-
|
|
53131
|
-
|
|
53184
|
+
// Handle cases where heading and body are on the same line separated by a newline.
|
|
53185
|
+
// Example: "> ⚠️ **Bold heading**\nBody text here"
|
|
53186
|
+
const bodyChildren = splitParagraphAtNewline(firstParagraph);
|
|
53187
|
+
const didSplit = bodyChildren !== null;
|
|
53188
|
+
// Extract heading text after removing the icon prefix.
|
|
53189
|
+
// Use `plain()` to handle complex markdown structures (bold, inline code, etc.)
|
|
53190
|
+
const headingText = lib_plain(firstParagraph)
|
|
53191
|
+
.toString()
|
|
53192
|
+
.slice(match.length);
|
|
53193
|
+
// Clean up the raw AST by removing the icon prefix from the first text node
|
|
53194
|
+
removeIconPrefix(firstParagraph, match.length);
|
|
53195
|
+
const empty = !headingText.length && firstParagraph.children.length === 1;
|
|
53132
53196
|
const theme = themes[icon] || 'default';
|
|
53133
|
-
|
|
53134
|
-
if (
|
|
53135
|
-
firstChild.value = firstChild.value.slice(match.length);
|
|
53136
|
-
}
|
|
53137
|
-
if (heading) {
|
|
53197
|
+
// Convert the first paragraph (first children of node) to a heading if it has content or was split
|
|
53198
|
+
if (headingText || didSplit) {
|
|
53138
53199
|
node.children[0] = wrapHeading(node);
|
|
53139
|
-
//
|
|
53140
|
-
// character that was stripped off, so that the start position of the
|
|
53141
|
-
// heading/text matches where it actually starts.
|
|
53200
|
+
// Adjust position to account for the stripped icon prefix
|
|
53142
53201
|
node.children[0].position.start.offset += match.length;
|
|
53143
53202
|
node.children[0].position.start.column += match.length;
|
|
53144
53203
|
}
|
|
53204
|
+
// Insert body content as a separate paragraph after the heading
|
|
53205
|
+
if (bodyChildren) {
|
|
53206
|
+
node.children.splice(1, 0, {
|
|
53207
|
+
type: 'paragraph',
|
|
53208
|
+
children: bodyChildren,
|
|
53209
|
+
position: {
|
|
53210
|
+
start: node.children[0].position.end,
|
|
53211
|
+
end: firstParagraphOriginalEnd,
|
|
53212
|
+
},
|
|
53213
|
+
});
|
|
53214
|
+
}
|
|
53145
53215
|
Object.assign(node, {
|
|
53146
53216
|
type: NodeTypes.callout,
|
|
53147
53217
|
data: {
|
|
@@ -86556,7 +86626,7 @@ const CUSTOM_PROP_BOUNDARIES = [
|
|
|
86556
86626
|
/**
|
|
86557
86627
|
* Tags that should be passed through and handled at runtime (not by the mdxish plugin)
|
|
86558
86628
|
*/
|
|
86559
|
-
const RUNTIME_COMPONENT_TAGS = new Set(['Variable', 'variable', 'rdme-pin']);
|
|
86629
|
+
const RUNTIME_COMPONENT_TAGS = new Set(['Variable', 'variable', 'html-block', 'rdme-pin']);
|
|
86560
86630
|
/**
|
|
86561
86631
|
* Standard HTML tags that should never be treated as custom components.
|
|
86562
86632
|
* Uses the html-tags package, converted to a Set<string> for efficient lookups.
|
|
@@ -93852,6 +93922,349 @@ const evaluateExpressions = ({ context = {} } = {}) => tree => {
|
|
|
93852
93922
|
};
|
|
93853
93923
|
/* harmony default export */ const evaluate_expressions = (evaluateExpressions);
|
|
93854
93924
|
|
|
93925
|
+
;// ./processor/transform/mdxish/normalize-malformed-md-syntax.ts
|
|
93926
|
+
|
|
93927
|
+
// Marker patterns for multi-node emphasis detection
|
|
93928
|
+
const MARKER_PATTERNS = [
|
|
93929
|
+
{ isBold: true, marker: '**' },
|
|
93930
|
+
{ isBold: true, marker: '__' },
|
|
93931
|
+
{ isBold: false, marker: '*' },
|
|
93932
|
+
{ isBold: false, marker: '_' },
|
|
93933
|
+
];
|
|
93934
|
+
// Patterns to detect for bold (** and __) and italic (* and _) syntax:
|
|
93935
|
+
// Bold: ** text**, **text **, word** text**, ** text **
|
|
93936
|
+
// Italic: * text*, *text *, word* text*, * text *
|
|
93937
|
+
// Same patterns for underscore variants
|
|
93938
|
+
// We use separate patterns for each marker type to allow this flexibility.
|
|
93939
|
+
// Pattern for ** bold **
|
|
93940
|
+
// Groups: 1=wordBefore, 2=marker, 3=contentWithSpaceAfter, 4=trailingSpace1, 5=contentWithSpaceBefore, 6=trailingSpace2, 7=afterChar
|
|
93941
|
+
// trailingSpace1 is for "** text **" pattern, trailingSpace2 is for "**text **" pattern
|
|
93942
|
+
const asteriskBoldRegex = /([^*\s]+)?\s*(\*\*)(?:\s+((?:[^*\n]|\*(?!\*))+?)(\s*)\2|((?:[^*\n]|\*(?!\*))+?)(\s+)\2)(\S|$)?/g;
|
|
93943
|
+
// Pattern for __ bold __
|
|
93944
|
+
const underscoreBoldRegex = /([^_\s]+)?\s*(__)(?:\s+((?:[^_\n]|_(?!_))+?)(\s*)\2|((?:[^_\n]|_(?!_))+?)(\s+)\2)(\S|$)?/g;
|
|
93945
|
+
// Pattern for * italic *
|
|
93946
|
+
const asteriskItalicRegex = /([^*\s]+)?\s*(\*)(?!\*)(?:\s+([^*\n]+?)(\s*)\2|([^*\n]+?)(\s+)\2)(\S|$)?/g;
|
|
93947
|
+
// Pattern for _ italic _
|
|
93948
|
+
const underscoreItalicRegex = /([^_\s]+)?\s*(_)(?!_)(?:\s+([^_\n]+?)(\s*)\2|([^_\n]+?)(\s+)\2)(\S|$)?/g;
|
|
93949
|
+
// CommonMark ignores intraword underscores or asteriks, but we want to italicize/bold the inner part
|
|
93950
|
+
// Pattern for intraword _word_ in words like hello_world_
|
|
93951
|
+
const intrawordUnderscoreItalicRegex = /(\w)_(?!_)([a-zA-Z0-9]+)_(?![\w_])/g;
|
|
93952
|
+
// Pattern for intraword __word__ in words like hello__world__
|
|
93953
|
+
const intrawordUnderscoreBoldRegex = /(\w)__([a-zA-Z0-9]+)__(?![\w_])/g;
|
|
93954
|
+
// Pattern for intraword *word* in words like hello*world*
|
|
93955
|
+
const intrawordAsteriskItalicRegex = /(\w)\*(?!\*)([a-zA-Z0-9]+)\*(?![\w*])/g;
|
|
93956
|
+
// Pattern for intraword **word** in words like hello**world**
|
|
93957
|
+
const intrawordAsteriskBoldRegex = /(\w)\*\*([a-zA-Z0-9]+)\*\*(?![\w*])/g;
|
|
93958
|
+
/**
|
|
93959
|
+
* Finds opening emphasis marker in a text value.
|
|
93960
|
+
* Returns marker info if found, null otherwise.
|
|
93961
|
+
*/
|
|
93962
|
+
function findOpeningMarker(text) {
|
|
93963
|
+
const results = MARKER_PATTERNS.map(({ isBold, marker }) => {
|
|
93964
|
+
if (marker === '*' && text.startsWith('**'))
|
|
93965
|
+
return null;
|
|
93966
|
+
if (marker === '_' && text.startsWith('__'))
|
|
93967
|
+
return null;
|
|
93968
|
+
if (text.startsWith(marker) && text.length > marker.length) {
|
|
93969
|
+
return { isBold, marker, textAfter: text.slice(marker.length), textBefore: '' };
|
|
93970
|
+
}
|
|
93971
|
+
const idx = text.indexOf(marker);
|
|
93972
|
+
if (idx > 0 && !/\s/.test(text[idx - 1])) {
|
|
93973
|
+
if (marker === '*' && text.slice(idx).startsWith('**'))
|
|
93974
|
+
return null;
|
|
93975
|
+
if (marker === '_' && text.slice(idx).startsWith('__'))
|
|
93976
|
+
return null;
|
|
93977
|
+
const after = text.slice(idx + marker.length);
|
|
93978
|
+
if (after.length > 0) {
|
|
93979
|
+
return { isBold, marker, textAfter: after, textBefore: text.slice(0, idx) };
|
|
93980
|
+
}
|
|
93981
|
+
}
|
|
93982
|
+
return null;
|
|
93983
|
+
});
|
|
93984
|
+
return results.find(r => r !== null) ?? null;
|
|
93985
|
+
}
|
|
93986
|
+
/**
|
|
93987
|
+
* Finds the end/closing marker in a text node for multi-node emphasis.
|
|
93988
|
+
*/
|
|
93989
|
+
function findEndMarker(text, marker) {
|
|
93990
|
+
const spacePattern = ` ${marker}`;
|
|
93991
|
+
const spaceIdx = text.indexOf(spacePattern);
|
|
93992
|
+
if (spaceIdx >= 0) {
|
|
93993
|
+
if (marker === '*' && text.slice(spaceIdx + 1).startsWith('**'))
|
|
93994
|
+
return null;
|
|
93995
|
+
if (marker === '_' && text.slice(spaceIdx + 1).startsWith('__'))
|
|
93996
|
+
return null;
|
|
93997
|
+
return {
|
|
93998
|
+
textAfter: text.slice(spaceIdx + spacePattern.length),
|
|
93999
|
+
textBefore: text.slice(0, spaceIdx),
|
|
94000
|
+
};
|
|
94001
|
+
}
|
|
94002
|
+
if (text.startsWith(marker)) {
|
|
94003
|
+
if (marker === '*' && text.startsWith('**'))
|
|
94004
|
+
return null;
|
|
94005
|
+
if (marker === '_' && text.startsWith('__'))
|
|
94006
|
+
return null;
|
|
94007
|
+
return {
|
|
94008
|
+
textAfter: text.slice(marker.length),
|
|
94009
|
+
textBefore: '',
|
|
94010
|
+
};
|
|
94011
|
+
}
|
|
94012
|
+
return null;
|
|
94013
|
+
}
|
|
94014
|
+
/**
|
|
94015
|
+
* Scan children for an opening emphasis marker in a text node.
|
|
94016
|
+
*/
|
|
94017
|
+
function findOpeningInChildren(children) {
|
|
94018
|
+
let result = null;
|
|
94019
|
+
children.some((child, idx) => {
|
|
94020
|
+
if (child.type !== 'text')
|
|
94021
|
+
return false;
|
|
94022
|
+
const found = findOpeningMarker(child.value);
|
|
94023
|
+
if (found) {
|
|
94024
|
+
result = { idx, opening: found };
|
|
94025
|
+
return true;
|
|
94026
|
+
}
|
|
94027
|
+
return false;
|
|
94028
|
+
});
|
|
94029
|
+
return result;
|
|
94030
|
+
}
|
|
94031
|
+
/**
|
|
94032
|
+
* Scan children (after openingIdx) for a closing emphasis marker.
|
|
94033
|
+
*/
|
|
94034
|
+
function findClosingInChildren(children, openingIdx, marker) {
|
|
94035
|
+
let result = null;
|
|
94036
|
+
children.slice(openingIdx + 1).some((child, relativeIdx) => {
|
|
94037
|
+
if (child.type !== 'text')
|
|
94038
|
+
return false;
|
|
94039
|
+
const found = findEndMarker(child.value, marker);
|
|
94040
|
+
if (found) {
|
|
94041
|
+
result = { closingIdx: openingIdx + 1 + relativeIdx, closing: found };
|
|
94042
|
+
return true;
|
|
94043
|
+
}
|
|
94044
|
+
return false;
|
|
94045
|
+
});
|
|
94046
|
+
return result;
|
|
94047
|
+
}
|
|
94048
|
+
/**
|
|
94049
|
+
* Build the replacement nodes for a matched emphasis pair.
|
|
94050
|
+
*/
|
|
94051
|
+
function buildReplacementNodes(container, { opening, openingIdx, closing, closingIdx }) {
|
|
94052
|
+
const newNodes = [];
|
|
94053
|
+
if (opening.textBefore) {
|
|
94054
|
+
newNodes.push({ type: 'text', value: `${opening.textBefore} ` });
|
|
94055
|
+
}
|
|
94056
|
+
const emphasisChildren = [];
|
|
94057
|
+
const openingText = opening.textAfter.replace(/^\s+/, '');
|
|
94058
|
+
if (openingText) {
|
|
94059
|
+
emphasisChildren.push({ type: 'text', value: openingText });
|
|
94060
|
+
}
|
|
94061
|
+
container.children.slice(openingIdx + 1, closingIdx).forEach(child => {
|
|
94062
|
+
emphasisChildren.push(child);
|
|
94063
|
+
});
|
|
94064
|
+
const closingText = closing.textBefore.replace(/\s+$/, '');
|
|
94065
|
+
if (closingText) {
|
|
94066
|
+
emphasisChildren.push({ type: 'text', value: closingText });
|
|
94067
|
+
}
|
|
94068
|
+
if (emphasisChildren.length > 0) {
|
|
94069
|
+
const emphasisNode = opening.isBold
|
|
94070
|
+
? { type: 'strong', children: emphasisChildren }
|
|
94071
|
+
: { type: 'emphasis', children: emphasisChildren };
|
|
94072
|
+
newNodes.push(emphasisNode);
|
|
94073
|
+
}
|
|
94074
|
+
if (closing.textAfter) {
|
|
94075
|
+
newNodes.push({ type: 'text', value: closing.textAfter });
|
|
94076
|
+
}
|
|
94077
|
+
return newNodes;
|
|
94078
|
+
}
|
|
94079
|
+
/**
|
|
94080
|
+
* Find and transform one multi-node emphasis pair in the container.
|
|
94081
|
+
* Returns true if a pair was found and transformed, false otherwise.
|
|
94082
|
+
*/
|
|
94083
|
+
function processOneEmphasisPair(container) {
|
|
94084
|
+
const openingResult = findOpeningInChildren(container.children);
|
|
94085
|
+
if (!openingResult)
|
|
94086
|
+
return false;
|
|
94087
|
+
const { idx: openingIdx, opening } = openingResult;
|
|
94088
|
+
const closingResult = findClosingInChildren(container.children, openingIdx, opening.marker);
|
|
94089
|
+
if (!closingResult)
|
|
94090
|
+
return false;
|
|
94091
|
+
const { closingIdx, closing } = closingResult;
|
|
94092
|
+
const newNodes = buildReplacementNodes(container, { opening, openingIdx, closing, closingIdx });
|
|
94093
|
+
const deleteCount = closingIdx - openingIdx + 1;
|
|
94094
|
+
container.children.splice(openingIdx, deleteCount, ...newNodes);
|
|
94095
|
+
return true;
|
|
94096
|
+
}
|
|
94097
|
+
/**
|
|
94098
|
+
* Handle malformed emphasis that spans multiple AST nodes.
|
|
94099
|
+
* E.g., "**bold [link](url)**" where markers are in different text nodes.
|
|
94100
|
+
*/
|
|
94101
|
+
function visitMultiNodeEmphasis(tree) {
|
|
94102
|
+
const containerTypes = ['paragraph', 'heading', 'tableCell', 'listItem', 'blockquote'];
|
|
94103
|
+
visit(tree, node => {
|
|
94104
|
+
if (!containerTypes.includes(node.type))
|
|
94105
|
+
return;
|
|
94106
|
+
if (!('children' in node) || !Array.isArray(node.children))
|
|
94107
|
+
return;
|
|
94108
|
+
const container = node;
|
|
94109
|
+
let foundPair = true;
|
|
94110
|
+
while (foundPair) {
|
|
94111
|
+
foundPair = processOneEmphasisPair(container);
|
|
94112
|
+
}
|
|
94113
|
+
});
|
|
94114
|
+
}
|
|
94115
|
+
/**
|
|
94116
|
+
* A remark plugin that normalizes malformed bold and italic markers in text nodes.
|
|
94117
|
+
* Detects patterns like `** bold**`, `Hello** Wrong Bold**`, `__ bold__`, `Hello__ Wrong Bold__`,
|
|
94118
|
+
* `* italic*`, `Hello* Wrong Italic*`, `_ italic_`, or `Hello_ Wrong Italic_`
|
|
94119
|
+
* and converts them to proper strong/emphasis nodes, matching the behavior of the legacy rdmd engine.
|
|
94120
|
+
*
|
|
94121
|
+
* Supports both asterisk (`**bold**`, `*italic*`) and underscore (`__bold__`, `_italic_`) syntax.
|
|
94122
|
+
* Also supports snake_case content like `** some_snake_case**`.
|
|
94123
|
+
*
|
|
94124
|
+
* This runs after remark-parse, which (in v11+) is strict and doesn't parse
|
|
94125
|
+
* malformed emphasis syntax. This plugin post-processes the AST to handle these cases.
|
|
94126
|
+
*/
|
|
94127
|
+
const normalizeEmphasisAST = () => (tree) => {
|
|
94128
|
+
visit(tree, 'text', function visitor(node, index, parent) {
|
|
94129
|
+
if (index === undefined || !parent)
|
|
94130
|
+
return undefined;
|
|
94131
|
+
// Skip if inside code blocks or inline code
|
|
94132
|
+
if (parent.type === 'inlineCode' || parent.type === 'code') {
|
|
94133
|
+
return undefined;
|
|
94134
|
+
}
|
|
94135
|
+
const text = node.value;
|
|
94136
|
+
const allMatches = [];
|
|
94137
|
+
[...text.matchAll(asteriskBoldRegex)].forEach(match => {
|
|
94138
|
+
allMatches.push({ isBold: true, marker: '**', match });
|
|
94139
|
+
});
|
|
94140
|
+
[...text.matchAll(underscoreBoldRegex)].forEach(match => {
|
|
94141
|
+
allMatches.push({ isBold: true, marker: '__', match });
|
|
94142
|
+
});
|
|
94143
|
+
[...text.matchAll(asteriskItalicRegex)].forEach(match => {
|
|
94144
|
+
allMatches.push({ isBold: false, marker: '*', match });
|
|
94145
|
+
});
|
|
94146
|
+
[...text.matchAll(underscoreItalicRegex)].forEach(match => {
|
|
94147
|
+
allMatches.push({ isBold: false, marker: '_', match });
|
|
94148
|
+
});
|
|
94149
|
+
[...text.matchAll(intrawordUnderscoreItalicRegex)].forEach(match => {
|
|
94150
|
+
allMatches.push({ isBold: false, isIntraword: true, marker: '_', match });
|
|
94151
|
+
});
|
|
94152
|
+
[...text.matchAll(intrawordUnderscoreBoldRegex)].forEach(match => {
|
|
94153
|
+
allMatches.push({ isBold: true, isIntraword: true, marker: '__', match });
|
|
94154
|
+
});
|
|
94155
|
+
[...text.matchAll(intrawordAsteriskItalicRegex)].forEach(match => {
|
|
94156
|
+
allMatches.push({ isBold: false, isIntraword: true, marker: '*', match });
|
|
94157
|
+
});
|
|
94158
|
+
[...text.matchAll(intrawordAsteriskBoldRegex)].forEach(match => {
|
|
94159
|
+
allMatches.push({ isBold: true, isIntraword: true, marker: '**', match });
|
|
94160
|
+
});
|
|
94161
|
+
if (allMatches.length === 0)
|
|
94162
|
+
return undefined;
|
|
94163
|
+
allMatches.sort((a, b) => (a.match.index ?? 0) - (b.match.index ?? 0));
|
|
94164
|
+
const filteredMatches = [];
|
|
94165
|
+
let lastEnd = 0;
|
|
94166
|
+
allMatches.forEach(info => {
|
|
94167
|
+
const start = info.match.index ?? 0;
|
|
94168
|
+
const end = start + info.match[0].length;
|
|
94169
|
+
if (start >= lastEnd) {
|
|
94170
|
+
filteredMatches.push(info);
|
|
94171
|
+
lastEnd = end;
|
|
94172
|
+
}
|
|
94173
|
+
});
|
|
94174
|
+
if (filteredMatches.length === 0)
|
|
94175
|
+
return undefined;
|
|
94176
|
+
const parts = [];
|
|
94177
|
+
let lastIndex = 0;
|
|
94178
|
+
filteredMatches.forEach(({ isBold, isIntraword, marker, match }) => {
|
|
94179
|
+
const matchIndex = match.index ?? 0;
|
|
94180
|
+
const fullMatch = match[0];
|
|
94181
|
+
if (isIntraword) {
|
|
94182
|
+
// handles cases like hello_world_ where we only want to italicize 'world'
|
|
94183
|
+
const charBefore = match[1] || ''; // e.g., "l" in "hello_world_"
|
|
94184
|
+
const content = match[2]; // e.g., "world"
|
|
94185
|
+
const combinedBefore = text.slice(lastIndex, matchIndex) + charBefore;
|
|
94186
|
+
if (combinedBefore) {
|
|
94187
|
+
parts.push({ type: 'text', value: combinedBefore });
|
|
94188
|
+
}
|
|
94189
|
+
if (isBold) {
|
|
94190
|
+
parts.push({
|
|
94191
|
+
type: 'strong',
|
|
94192
|
+
children: [{ type: 'text', value: content }],
|
|
94193
|
+
});
|
|
94194
|
+
}
|
|
94195
|
+
else {
|
|
94196
|
+
parts.push({
|
|
94197
|
+
type: 'emphasis',
|
|
94198
|
+
children: [{ type: 'text', value: content }],
|
|
94199
|
+
});
|
|
94200
|
+
}
|
|
94201
|
+
lastIndex = matchIndex + fullMatch.length;
|
|
94202
|
+
return;
|
|
94203
|
+
}
|
|
94204
|
+
if (matchIndex > lastIndex) {
|
|
94205
|
+
const beforeText = text.slice(lastIndex, matchIndex);
|
|
94206
|
+
if (beforeText) {
|
|
94207
|
+
parts.push({ type: 'text', value: beforeText });
|
|
94208
|
+
}
|
|
94209
|
+
}
|
|
94210
|
+
const wordBefore = match[1]; // e.g., "Hello" in "Hello** Wrong Bold**"
|
|
94211
|
+
const contentWithSpaceAfter = match[3]; // Content when there's a space after opening markers
|
|
94212
|
+
const trailingSpace1 = match[4] || ''; // Space before closing markers (for "** text **" pattern)
|
|
94213
|
+
const contentWithSpaceBefore = match[5]; // Content when there's only a space before closing markers
|
|
94214
|
+
const trailingSpace2 = match[6] || ''; // Space before closing markers (for "**text **" pattern)
|
|
94215
|
+
const trailingSpace = trailingSpace1 || trailingSpace2; // Combined trailing space
|
|
94216
|
+
const content = (contentWithSpaceAfter || contentWithSpaceBefore || '').trim();
|
|
94217
|
+
const afterChar = match[7]; // Character after closing markers (if any)
|
|
94218
|
+
const markerPos = fullMatch.indexOf(marker);
|
|
94219
|
+
const spacesBeforeMarkers = wordBefore
|
|
94220
|
+
? fullMatch.slice(wordBefore.length, markerPos)
|
|
94221
|
+
: fullMatch.slice(0, markerPos);
|
|
94222
|
+
const shouldAddSpace = !!contentWithSpaceAfter && !!wordBefore && !spacesBeforeMarkers;
|
|
94223
|
+
if (wordBefore) {
|
|
94224
|
+
const spacing = spacesBeforeMarkers + (shouldAddSpace ? ' ' : '');
|
|
94225
|
+
parts.push({ type: 'text', value: wordBefore + spacing });
|
|
94226
|
+
}
|
|
94227
|
+
else if (spacesBeforeMarkers) {
|
|
94228
|
+
parts.push({ type: 'text', value: spacesBeforeMarkers });
|
|
94229
|
+
}
|
|
94230
|
+
if (content) {
|
|
94231
|
+
if (isBold) {
|
|
94232
|
+
parts.push({
|
|
94233
|
+
type: 'strong',
|
|
94234
|
+
children: [{ type: 'text', value: content }],
|
|
94235
|
+
});
|
|
94236
|
+
}
|
|
94237
|
+
else {
|
|
94238
|
+
parts.push({
|
|
94239
|
+
type: 'emphasis',
|
|
94240
|
+
children: [{ type: 'text', value: content }],
|
|
94241
|
+
});
|
|
94242
|
+
}
|
|
94243
|
+
}
|
|
94244
|
+
if (afterChar) {
|
|
94245
|
+
const prefix = trailingSpace ? ' ' : '';
|
|
94246
|
+
parts.push({ type: 'text', value: prefix + afterChar });
|
|
94247
|
+
}
|
|
94248
|
+
lastIndex = matchIndex + fullMatch.length;
|
|
94249
|
+
});
|
|
94250
|
+
if (lastIndex < text.length) {
|
|
94251
|
+
const remainingText = text.slice(lastIndex);
|
|
94252
|
+
if (remainingText) {
|
|
94253
|
+
parts.push({ type: 'text', value: remainingText });
|
|
94254
|
+
}
|
|
94255
|
+
}
|
|
94256
|
+
if (parts.length > 0) {
|
|
94257
|
+
parent.children.splice(index, 1, ...parts);
|
|
94258
|
+
return [SKIP, index + parts.length];
|
|
94259
|
+
}
|
|
94260
|
+
return undefined;
|
|
94261
|
+
});
|
|
94262
|
+
// Handle malformed emphasis spanning multiple nodes (e.g., **text [link](url) **)
|
|
94263
|
+
visitMultiNodeEmphasis(tree);
|
|
94264
|
+
return tree;
|
|
94265
|
+
};
|
|
94266
|
+
/* harmony default export */ const normalize_malformed_md_syntax = (normalizeEmphasisAST);
|
|
94267
|
+
|
|
93855
94268
|
;// ./processor/transform/mdxish/magic-blocks/placeholder.ts
|
|
93856
94269
|
const EMPTY_IMAGE_PLACEHOLDER = {
|
|
93857
94270
|
type: 'image',
|
|
@@ -93904,6 +94317,7 @@ const EMPTY_CODE_PLACEHOLDER = {
|
|
|
93904
94317
|
|
|
93905
94318
|
|
|
93906
94319
|
|
|
94320
|
+
|
|
93907
94321
|
/**
|
|
93908
94322
|
* Wraps a node in a "pinned" container if sidebar: true is set.
|
|
93909
94323
|
*/
|
|
@@ -93931,7 +94345,8 @@ const imgWidthBySize = new Proxy(imgSizeValues, {
|
|
|
93931
94345
|
});
|
|
93932
94346
|
const textToInline = (text) => [{ type: 'text', value: text }];
|
|
93933
94347
|
const textToBlock = (text) => [{ children: textToInline(text), type: 'paragraph' }];
|
|
93934
|
-
|
|
94348
|
+
/** Parses markdown and html to markdown nodes */
|
|
94349
|
+
const contentParser = unified().use(remarkParse).use(remarkGfm).use(normalize_malformed_md_syntax);
|
|
93935
94350
|
const parseTableCell = (text) => {
|
|
93936
94351
|
if (!text.trim())
|
|
93937
94352
|
return [{ type: 'text', value: '' }];
|
|
@@ -94969,139 +95384,6 @@ function restoreSnakeCase(placeholderName, mapping) {
|
|
|
94969
95384
|
return matchingKey ? mapping[matchingKey] : placeholderName;
|
|
94970
95385
|
}
|
|
94971
95386
|
|
|
94972
|
-
;// ./processor/transform/mdxish/normalize-malformed-md-syntax.ts
|
|
94973
|
-
|
|
94974
|
-
// Patterns to detect for bold (** and __) and italic (* and _) syntax:
|
|
94975
|
-
// Bold: ** text**, **text **, word** text**, ** text **
|
|
94976
|
-
// Italic: * text*, *text *, word* text*, * text *
|
|
94977
|
-
// Same patterns for underscore variants
|
|
94978
|
-
// We use separate patterns for each marker type to allow this flexibility.
|
|
94979
|
-
// Pattern for ** bold **
|
|
94980
|
-
// Groups: 1=wordBefore, 2=marker, 3=contentWithSpaceAfter, 4=trailingSpace1, 5=contentWithSpaceBefore, 6=trailingSpace2, 7=afterChar
|
|
94981
|
-
// trailingSpace1 is for "** text **" pattern, trailingSpace2 is for "**text **" pattern
|
|
94982
|
-
const asteriskBoldRegex = /([^*\s]+)?\s*(\*\*)(?:\s+((?:[^*\n]|\*(?!\*))+?)(\s*)\2|((?:[^*\n]|\*(?!\*))+?)(\s+)\2)(\S|$)?/g;
|
|
94983
|
-
// Pattern for __ bold __
|
|
94984
|
-
const underscoreBoldRegex = /([^_\s]+)?\s*(__)(?:\s+((?:[^_\n]|_(?!_))+?)(\s*)\2|((?:[^_\n]|_(?!_))+?)(\s+)\2)(\S|$)?/g;
|
|
94985
|
-
// Pattern for * italic *
|
|
94986
|
-
const asteriskItalicRegex = /([^*\s]+)?\s*(\*)(?!\*)(?:\s+([^*\n]+?)(\s*)\2|([^*\n]+?)(\s+)\2)(\S|$)?/g;
|
|
94987
|
-
// Pattern for _ italic _
|
|
94988
|
-
const underscoreItalicRegex = /([^_\s]+)?\s*(_)(?!_)(?:\s+([^_\n]+?)(\s*)\2|([^_\n]+?)(\s+)\2)(\S|$)?/g;
|
|
94989
|
-
/**
|
|
94990
|
-
* A remark plugin that normalizes malformed bold and italic markers in text nodes.
|
|
94991
|
-
* Detects patterns like `** bold**`, `Hello** Wrong Bold**`, `__ bold__`, `Hello__ Wrong Bold__`,
|
|
94992
|
-
* `* italic*`, `Hello* Wrong Italic*`, `_ italic_`, or `Hello_ Wrong Italic_`
|
|
94993
|
-
* and converts them to proper strong/emphasis nodes, matching the behavior of the legacy rdmd engine.
|
|
94994
|
-
*
|
|
94995
|
-
* Supports both asterisk (`**bold**`, `*italic*`) and underscore (`__bold__`, `_italic_`) syntax.
|
|
94996
|
-
* Also supports snake_case content like `** some_snake_case**`.
|
|
94997
|
-
*
|
|
94998
|
-
* This runs after remark-parse, which (in v11+) is strict and doesn't parse
|
|
94999
|
-
* malformed emphasis syntax. This plugin post-processes the AST to handle these cases.
|
|
95000
|
-
*/
|
|
95001
|
-
const normalizeEmphasisAST = () => (tree) => {
|
|
95002
|
-
visit(tree, 'text', function visitor(node, index, parent) {
|
|
95003
|
-
if (index === undefined || !parent)
|
|
95004
|
-
return undefined;
|
|
95005
|
-
// Skip if inside code blocks or inline code
|
|
95006
|
-
if (parent.type === 'inlineCode' || parent.type === 'code') {
|
|
95007
|
-
return undefined;
|
|
95008
|
-
}
|
|
95009
|
-
const text = node.value;
|
|
95010
|
-
const allMatches = [];
|
|
95011
|
-
[...text.matchAll(asteriskBoldRegex)].forEach(match => {
|
|
95012
|
-
allMatches.push({ isBold: true, marker: '**', match });
|
|
95013
|
-
});
|
|
95014
|
-
[...text.matchAll(underscoreBoldRegex)].forEach(match => {
|
|
95015
|
-
allMatches.push({ isBold: true, marker: '__', match });
|
|
95016
|
-
});
|
|
95017
|
-
[...text.matchAll(asteriskItalicRegex)].forEach(match => {
|
|
95018
|
-
allMatches.push({ isBold: false, marker: '*', match });
|
|
95019
|
-
});
|
|
95020
|
-
[...text.matchAll(underscoreItalicRegex)].forEach(match => {
|
|
95021
|
-
allMatches.push({ isBold: false, marker: '_', match });
|
|
95022
|
-
});
|
|
95023
|
-
if (allMatches.length === 0)
|
|
95024
|
-
return undefined;
|
|
95025
|
-
allMatches.sort((a, b) => (a.match.index ?? 0) - (b.match.index ?? 0));
|
|
95026
|
-
const filteredMatches = [];
|
|
95027
|
-
let lastEnd = 0;
|
|
95028
|
-
allMatches.forEach(info => {
|
|
95029
|
-
const start = info.match.index ?? 0;
|
|
95030
|
-
const end = start + info.match[0].length;
|
|
95031
|
-
if (start >= lastEnd) {
|
|
95032
|
-
filteredMatches.push(info);
|
|
95033
|
-
lastEnd = end;
|
|
95034
|
-
}
|
|
95035
|
-
});
|
|
95036
|
-
if (filteredMatches.length === 0)
|
|
95037
|
-
return undefined;
|
|
95038
|
-
const parts = [];
|
|
95039
|
-
let lastIndex = 0;
|
|
95040
|
-
filteredMatches.forEach(({ match, marker, isBold }) => {
|
|
95041
|
-
const matchIndex = match.index ?? 0;
|
|
95042
|
-
const fullMatch = match[0];
|
|
95043
|
-
if (matchIndex > lastIndex) {
|
|
95044
|
-
const beforeText = text.slice(lastIndex, matchIndex);
|
|
95045
|
-
if (beforeText) {
|
|
95046
|
-
parts.push({ type: 'text', value: beforeText });
|
|
95047
|
-
}
|
|
95048
|
-
}
|
|
95049
|
-
const wordBefore = match[1]; // e.g., "Hello" in "Hello** Wrong Bold**"
|
|
95050
|
-
const contentWithSpaceAfter = match[3]; // Content when there's a space after opening markers
|
|
95051
|
-
const trailingSpace1 = match[4] || ''; // Space before closing markers (for "** text **" pattern)
|
|
95052
|
-
const contentWithSpaceBefore = match[5]; // Content when there's only a space before closing markers
|
|
95053
|
-
const trailingSpace2 = match[6] || ''; // Space before closing markers (for "**text **" pattern)
|
|
95054
|
-
const trailingSpace = trailingSpace1 || trailingSpace2; // Combined trailing space
|
|
95055
|
-
const content = (contentWithSpaceAfter || contentWithSpaceBefore || '').trim();
|
|
95056
|
-
const afterChar = match[7]; // Character after closing markers (if any)
|
|
95057
|
-
const markerPos = fullMatch.indexOf(marker);
|
|
95058
|
-
const spacesBeforeMarkers = wordBefore
|
|
95059
|
-
? fullMatch.slice(wordBefore.length, markerPos)
|
|
95060
|
-
: fullMatch.slice(0, markerPos);
|
|
95061
|
-
const shouldAddSpace = !!contentWithSpaceAfter && !!wordBefore && !spacesBeforeMarkers;
|
|
95062
|
-
if (wordBefore) {
|
|
95063
|
-
const spacing = spacesBeforeMarkers + (shouldAddSpace ? ' ' : '');
|
|
95064
|
-
parts.push({ type: 'text', value: wordBefore + spacing });
|
|
95065
|
-
}
|
|
95066
|
-
else if (spacesBeforeMarkers) {
|
|
95067
|
-
parts.push({ type: 'text', value: spacesBeforeMarkers });
|
|
95068
|
-
}
|
|
95069
|
-
if (content) {
|
|
95070
|
-
if (isBold) {
|
|
95071
|
-
parts.push({
|
|
95072
|
-
type: 'strong',
|
|
95073
|
-
children: [{ type: 'text', value: content }],
|
|
95074
|
-
});
|
|
95075
|
-
}
|
|
95076
|
-
else {
|
|
95077
|
-
parts.push({
|
|
95078
|
-
type: 'emphasis',
|
|
95079
|
-
children: [{ type: 'text', value: content }],
|
|
95080
|
-
});
|
|
95081
|
-
}
|
|
95082
|
-
}
|
|
95083
|
-
if (afterChar) {
|
|
95084
|
-
const prefix = trailingSpace ? ' ' : '';
|
|
95085
|
-
parts.push({ type: 'text', value: prefix + afterChar });
|
|
95086
|
-
}
|
|
95087
|
-
lastIndex = matchIndex + fullMatch.length;
|
|
95088
|
-
});
|
|
95089
|
-
if (lastIndex < text.length) {
|
|
95090
|
-
const remainingText = text.slice(lastIndex);
|
|
95091
|
-
if (remainingText) {
|
|
95092
|
-
parts.push({ type: 'text', value: remainingText });
|
|
95093
|
-
}
|
|
95094
|
-
}
|
|
95095
|
-
if (parts.length > 0) {
|
|
95096
|
-
parent.children.splice(index, 1, ...parts);
|
|
95097
|
-
return [SKIP, index + parts.length];
|
|
95098
|
-
}
|
|
95099
|
-
return undefined;
|
|
95100
|
-
});
|
|
95101
|
-
return tree;
|
|
95102
|
-
};
|
|
95103
|
-
/* harmony default export */ const normalize_malformed_md_syntax = (normalizeEmphasisAST);
|
|
95104
|
-
|
|
95105
95387
|
;// ./processor/transform/mdxish/normalize-table-separator.ts
|
|
95106
95388
|
/**
|
|
95107
95389
|
* Preprocessor to normalize malformed GFM table separator syntax.
|
|
@@ -96573,7 +96855,7 @@ function loadComponents() {
|
|
|
96573
96855
|
|
|
96574
96856
|
const defaultTransformers = [callouts, code_tabs, gemoji_, transform_embeds];
|
|
96575
96857
|
function mdxishAstProcessor(mdContent, opts = {}) {
|
|
96576
|
-
const { components: userComponents = {}, jsxContext = {}, newEditorTypes = false, useTailwind } = opts;
|
|
96858
|
+
const { components: userComponents = {}, jsxContext = {}, newEditorTypes = false, safeMode = false, useTailwind, } = opts;
|
|
96577
96859
|
const components = {
|
|
96578
96860
|
...loadComponents(),
|
|
96579
96861
|
...userComponents,
|
|
@@ -96584,7 +96866,9 @@ function mdxishAstProcessor(mdContent, opts = {}) {
|
|
|
96584
96866
|
// Step 1: Normalize malformed table separator syntax (e.g., `|: ---` → `| :---`)
|
|
96585
96867
|
const contentAfterTableNormalization = normalizeTableSeparator(mdContent);
|
|
96586
96868
|
// Step 2: Evaluate JSX expressions in attributes
|
|
96587
|
-
const contentAfterJSXEvaluation =
|
|
96869
|
+
const contentAfterJSXEvaluation = safeMode
|
|
96870
|
+
? contentAfterTableNormalization
|
|
96871
|
+
: preprocessJSXExpressions(contentAfterTableNormalization, jsxContext);
|
|
96588
96872
|
// Step 3: Replace snake_case component names with parser-safe placeholders
|
|
96589
96873
|
const { content: parserReadyContent, mapping: snakeCaseMapping } = processSnakeCaseComponent(contentAfterJSXEvaluation, { knownComponents });
|
|
96590
96874
|
// Create string map for tailwind transformer
|
|
@@ -96599,8 +96883,8 @@ function mdxishAstProcessor(mdContent, opts = {}) {
|
|
|
96599
96883
|
text: mdxExprExt.text,
|
|
96600
96884
|
};
|
|
96601
96885
|
const processor = unified()
|
|
96602
|
-
.data('micromarkExtensions', [magicBlock(), mdxExprTextOnly])
|
|
96603
|
-
.data('fromMarkdownExtensions', [magicBlockFromMarkdown(), mdxExpressionFromMarkdown()])
|
|
96886
|
+
.data('micromarkExtensions', safeMode ? [magicBlock()] : [magicBlock(), mdxExprTextOnly])
|
|
96887
|
+
.data('fromMarkdownExtensions', safeMode ? [magicBlockFromMarkdown()] : [magicBlockFromMarkdown(), mdxExpressionFromMarkdown()])
|
|
96604
96888
|
.use(remarkParse)
|
|
96605
96889
|
.use(remarkFrontmatter)
|
|
96606
96890
|
.use(normalize_malformed_md_syntax)
|
|
@@ -96612,8 +96896,8 @@ function mdxishAstProcessor(mdContent, opts = {}) {
|
|
|
96612
96896
|
.use(mdxish_tables)
|
|
96613
96897
|
.use(mdxish_html_blocks)
|
|
96614
96898
|
.use(newEditorTypes ? mdxish_jsx_to_mdast : undefined) // Convert JSX elements to MDAST types
|
|
96615
|
-
.use(evaluate_expressions, { context: jsxContext }) // Evaluate MDX expressions using jsxContext
|
|
96616
|
-
.use(variables_text) // Parse {user.*} patterns from text
|
|
96899
|
+
.use(safeMode ? undefined : evaluate_expressions, { context: jsxContext }) // Evaluate MDX expressions using jsxContext
|
|
96900
|
+
.use(variables_text) // Parse {user.*} patterns from text
|
|
96617
96901
|
.use(useTailwind ? transform_tailwind : undefined, { components: tempComponentsMap })
|
|
96618
96902
|
.use(remarkGfm);
|
|
96619
96903
|
return {
|
|
@@ -97234,6 +97518,7 @@ async function stripComments(doc, { mdx, mdxish } = {}) {
|
|
|
97234
97518
|
|
|
97235
97519
|
|
|
97236
97520
|
|
|
97521
|
+
|
|
97237
97522
|
;// ./index.tsx
|
|
97238
97523
|
|
|
97239
97524
|
|