@readme/markdown 11.10.1 → 11.12.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/lib/constants.d.ts +4 -0
- package/dist/main.js +404 -119
- package/dist/main.node.js +400 -115
- package/dist/main.node.js.map +1 -1
- package/dist/processor/transform/mdxish/evaluate-expressions.d.ts +1 -1
- package/dist/processor/transform/mdxish/mdxish-snake-case-components.d.ts +16 -0
- package/dist/processor/transform/mdxish/normalize-malformed-md-syntax.d.ts +15 -0
- package/dist/processor/transform/mdxish/preprocess-jsx-expressions.d.ts +17 -3
- package/dist/processor/transform/mdxish/restore-snake-case-component-name.d.ts +12 -0
- package/package.json +1 -1
package/dist/main.node.js
CHANGED
|
@@ -90788,7 +90788,7 @@ const mdxToHast = () => tree => {
|
|
|
90788
90788
|
;// ./processor/transform/mdxish/mdxish-component-blocks.ts
|
|
90789
90789
|
|
|
90790
90790
|
|
|
90791
|
-
const tagPattern = /^<([A-Z][A-Za-z0-
|
|
90791
|
+
const tagPattern = /^<([A-Z][A-Za-z0-9_]*)([^>]*?)(\/?)>([\s\S]*)?$/;
|
|
90792
90792
|
const attributePattern = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*("[^"]*"|'[^']*'|[^\s"'>]+))?/g;
|
|
90793
90793
|
const inlineMdProcessor = unified().use(remarkParse);
|
|
90794
90794
|
const isClosingTag = (value, tag) => value.trim() === `</${tag}>`;
|
|
@@ -113185,82 +113185,7 @@ const mdxComponentHandlers = {
|
|
|
113185
113185
|
[NodeTypes.htmlBlock]: htmlBlockHandler,
|
|
113186
113186
|
};
|
|
113187
113187
|
|
|
113188
|
-
;// ./processor/transform/mdxish/evaluate-expressions.ts
|
|
113189
|
-
|
|
113190
|
-
/**
|
|
113191
|
-
* AST transformer to evaluate MDX expressions using the provided context.
|
|
113192
|
-
* Replaces mdxFlowExpression and mdxTextExpression nodes with their evaluated values.
|
|
113193
|
-
*/
|
|
113194
|
-
const evaluateExpressions = ({ context = {} } = {}) => tree => {
|
|
113195
|
-
visit(tree, ['mdxFlowExpression', 'mdxTextExpression'], (node, index, parent) => {
|
|
113196
|
-
if (!parent || index === null || index === undefined)
|
|
113197
|
-
return;
|
|
113198
|
-
const expressionNode = node;
|
|
113199
|
-
if (!('value' in expressionNode))
|
|
113200
|
-
return;
|
|
113201
|
-
// JSX attribute expressions are handled by preprocessing; code blocks are protected
|
|
113202
|
-
const expression = expressionNode.value.trim();
|
|
113203
|
-
// Skip if expression is empty (shouldn't happen, but defensive)
|
|
113204
|
-
if (!expression)
|
|
113205
|
-
return;
|
|
113206
|
-
try {
|
|
113207
|
-
// Evaluate the expression using the context
|
|
113208
|
-
const contextKeys = Object.keys(context);
|
|
113209
|
-
const contextValues = Object.values(context);
|
|
113210
|
-
// If no context provided, leave expression as-is
|
|
113211
|
-
if (contextKeys.length === 0) {
|
|
113212
|
-
parent.children.splice(index, 1, {
|
|
113213
|
-
type: 'text',
|
|
113214
|
-
value: `{${expression}}`,
|
|
113215
|
-
position: node.position,
|
|
113216
|
-
});
|
|
113217
|
-
return;
|
|
113218
|
-
}
|
|
113219
|
-
// eslint-disable-next-line no-new-func
|
|
113220
|
-
const func = new Function(...contextKeys, `return ${expression}`);
|
|
113221
|
-
const result = func(...contextValues);
|
|
113222
|
-
// Convert result to text node(s)
|
|
113223
|
-
if (result === null || result === undefined) {
|
|
113224
|
-
// Replace with empty text node (don't remove, as it affects positioning)
|
|
113225
|
-
parent.children.splice(index, 1, {
|
|
113226
|
-
type: 'text',
|
|
113227
|
-
value: '',
|
|
113228
|
-
position: node.position,
|
|
113229
|
-
});
|
|
113230
|
-
return;
|
|
113231
|
-
}
|
|
113232
|
-
let textValue;
|
|
113233
|
-
if (typeof result === 'object') {
|
|
113234
|
-
textValue = JSON.stringify(result);
|
|
113235
|
-
}
|
|
113236
|
-
else {
|
|
113237
|
-
textValue = String(result).replace(/\s+/g, ' ').trim();
|
|
113238
|
-
}
|
|
113239
|
-
// Replace expression node with text node
|
|
113240
|
-
parent.children.splice(index, 1, {
|
|
113241
|
-
type: 'text',
|
|
113242
|
-
value: textValue,
|
|
113243
|
-
position: node.position,
|
|
113244
|
-
});
|
|
113245
|
-
}
|
|
113246
|
-
catch (_error) {
|
|
113247
|
-
// If evaluation fails, leave the expression as-is (fallback to text)
|
|
113248
|
-
parent.children.splice(index, 1, {
|
|
113249
|
-
type: 'text',
|
|
113250
|
-
value: `{${expression}}`,
|
|
113251
|
-
position: node.position,
|
|
113252
|
-
});
|
|
113253
|
-
}
|
|
113254
|
-
});
|
|
113255
|
-
return tree;
|
|
113256
|
-
};
|
|
113257
|
-
/* harmony default export */ const evaluate_expressions = (evaluateExpressions);
|
|
113258
|
-
|
|
113259
113188
|
;// ./processor/transform/mdxish/preprocess-jsx-expressions.ts
|
|
113260
|
-
/**
|
|
113261
|
-
* Pre-processes JSX-like expressions before markdown parsing.
|
|
113262
|
-
* Converts href={'value'} to href="value", evaluates {expressions}, etc.
|
|
113263
|
-
*/
|
|
113264
113189
|
// Base64 encode (Node.js + browser compatible)
|
|
113265
113190
|
function base64Encode(str) {
|
|
113266
113191
|
if (typeof Buffer !== 'undefined') {
|
|
@@ -113516,6 +113441,57 @@ function preprocessJSXExpressions(content, context = {}) {
|
|
|
113516
113441
|
return processed;
|
|
113517
113442
|
}
|
|
113518
113443
|
|
|
113444
|
+
;// ./processor/transform/mdxish/evaluate-expressions.ts
|
|
113445
|
+
|
|
113446
|
+
|
|
113447
|
+
/**
|
|
113448
|
+
* AST transformer to evaluate MDX expressions using the provided context.
|
|
113449
|
+
* Replaces mdxFlowExpression and mdxTextExpression nodes with their evaluated values.
|
|
113450
|
+
*/
|
|
113451
|
+
const evaluateExpressions = ({ context = {} } = {}) => tree => {
|
|
113452
|
+
visit(tree, ['mdxFlowExpression', 'mdxTextExpression'], (node, index, parent) => {
|
|
113453
|
+
if (!parent || index === null || index === undefined)
|
|
113454
|
+
return;
|
|
113455
|
+
const expressionNode = node;
|
|
113456
|
+
if (!('value' in expressionNode))
|
|
113457
|
+
return;
|
|
113458
|
+
const expression = expressionNode.value.trim();
|
|
113459
|
+
// Skip if expression is empty (shouldn't happen, but defensive)
|
|
113460
|
+
if (!expression)
|
|
113461
|
+
return;
|
|
113462
|
+
try {
|
|
113463
|
+
const result = evaluateExpression(expression, context);
|
|
113464
|
+
// Extract evaluated value text
|
|
113465
|
+
let textValue;
|
|
113466
|
+
if (result === null || result === undefined) {
|
|
113467
|
+
textValue = '';
|
|
113468
|
+
}
|
|
113469
|
+
else if (typeof result === 'object') {
|
|
113470
|
+
textValue = JSON.stringify(result);
|
|
113471
|
+
}
|
|
113472
|
+
else {
|
|
113473
|
+
textValue = String(result).replace(/\s+/g, ' ').trim();
|
|
113474
|
+
}
|
|
113475
|
+
// Replace expression node with text node since the expression is conceptually a text
|
|
113476
|
+
parent.children.splice(index, 1, {
|
|
113477
|
+
type: 'text',
|
|
113478
|
+
value: textValue,
|
|
113479
|
+
position: node.position,
|
|
113480
|
+
});
|
|
113481
|
+
}
|
|
113482
|
+
catch (_error) {
|
|
113483
|
+
// If evaluation fails, leave the expression as-is (fallback to text)
|
|
113484
|
+
parent.children.splice(index, 1, {
|
|
113485
|
+
type: 'text',
|
|
113486
|
+
value: `{${expression}}`,
|
|
113487
|
+
position: node.position,
|
|
113488
|
+
});
|
|
113489
|
+
}
|
|
113490
|
+
});
|
|
113491
|
+
return tree;
|
|
113492
|
+
};
|
|
113493
|
+
/* harmony default export */ const evaluate_expressions = (evaluateExpressions);
|
|
113494
|
+
|
|
113519
113495
|
;// ./processor/transform/mdxish/mdxish-html-blocks.ts
|
|
113520
113496
|
|
|
113521
113497
|
|
|
@@ -113856,6 +113832,7 @@ const mdxishHtmlBlocks = () => tree => {
|
|
|
113856
113832
|
|
|
113857
113833
|
|
|
113858
113834
|
|
|
113835
|
+
|
|
113859
113836
|
/**
|
|
113860
113837
|
* Matches legacy magic block syntax: [block:TYPE]...JSON...[/block]
|
|
113861
113838
|
* Group 1: block type (e.g., "image", "code", "callout")
|
|
@@ -113903,6 +113880,10 @@ const parseInline = (text) => {
|
|
|
113903
113880
|
if (!text.trim())
|
|
113904
113881
|
return [{ type: 'text', value: '' }];
|
|
113905
113882
|
const tree = cellParser.runSync(cellParser.parse(text));
|
|
113883
|
+
// If there are multiple block-level nodes, keep them as-is to preserve the document structure and spacing
|
|
113884
|
+
if (tree.children.length > 1) {
|
|
113885
|
+
return tree.children;
|
|
113886
|
+
}
|
|
113906
113887
|
return tree.children.flatMap(n =>
|
|
113907
113888
|
// This unwraps the extra p node that might appear & wrapping the content
|
|
113908
113889
|
n.type === 'paragraph' && 'children' in n ? n.children : [n]);
|
|
@@ -114024,16 +114005,34 @@ function parseMagicBlock(raw, options = {}) {
|
|
|
114024
114005
|
const [icon, theme] = Array.isArray(resolvedType) ? resolvedType : ['👍', 'default'];
|
|
114025
114006
|
if (!(calloutJson.title || calloutJson.body))
|
|
114026
114007
|
return [];
|
|
114027
|
-
|
|
114028
|
-
|
|
114029
|
-
|
|
114030
|
-
|
|
114031
|
-
|
|
114032
|
-
|
|
114033
|
-
|
|
114034
|
-
|
|
114035
|
-
|
|
114036
|
-
|
|
114008
|
+
const titleBlocks = textToBlock(calloutJson.title || '');
|
|
114009
|
+
const bodyBlocks = textToBlock(calloutJson.body || '');
|
|
114010
|
+
const children = [];
|
|
114011
|
+
if (titleBlocks.length > 0 && titleBlocks[0].type === 'paragraph') {
|
|
114012
|
+
const firstTitle = titleBlocks[0];
|
|
114013
|
+
const heading = {
|
|
114014
|
+
type: 'heading',
|
|
114015
|
+
depth: 3,
|
|
114016
|
+
children: (firstTitle.children || []),
|
|
114017
|
+
};
|
|
114018
|
+
children.push(heading);
|
|
114019
|
+
children.push(...titleBlocks.slice(1), ...bodyBlocks);
|
|
114020
|
+
}
|
|
114021
|
+
else {
|
|
114022
|
+
children.push(...titleBlocks, ...bodyBlocks);
|
|
114023
|
+
}
|
|
114024
|
+
// Create mdxJsxFlowElement directly for mdxish
|
|
114025
|
+
const calloutElement = {
|
|
114026
|
+
type: 'mdxJsxFlowElement',
|
|
114027
|
+
name: 'Callout',
|
|
114028
|
+
attributes: toAttributes({ icon, theme: theme || 'default', type: theme || 'default' }, [
|
|
114029
|
+
'icon',
|
|
114030
|
+
'theme',
|
|
114031
|
+
'type',
|
|
114032
|
+
]),
|
|
114033
|
+
children: children,
|
|
114034
|
+
};
|
|
114035
|
+
return [wrapPinnedBlocks(calloutElement, json)];
|
|
114037
114036
|
}
|
|
114038
114037
|
// Parameters: renders as a table (used for API parameters, etc.)
|
|
114039
114038
|
case 'parameters': {
|
|
@@ -114107,6 +114106,25 @@ function parseMagicBlock(raw, options = {}) {
|
|
|
114107
114106
|
}, json),
|
|
114108
114107
|
];
|
|
114109
114108
|
}
|
|
114109
|
+
// Recipe/TutorialTile: renders as Recipe component
|
|
114110
|
+
case 'recipe':
|
|
114111
|
+
case 'tutorial-tile': {
|
|
114112
|
+
const recipeJson = json;
|
|
114113
|
+
if (!recipeJson.slug || !recipeJson.title)
|
|
114114
|
+
return [];
|
|
114115
|
+
// Create mdxJsxFlowElement directly for mdxish flow
|
|
114116
|
+
// Note: Don't wrap in pinned blocks for mdxish - rehypeMdxishComponents handles component resolution
|
|
114117
|
+
// The node structure matches what mdxishComponentBlocks creates for JSX tags
|
|
114118
|
+
const recipeNode = {
|
|
114119
|
+
type: 'mdxJsxFlowElement',
|
|
114120
|
+
name: 'Recipe',
|
|
114121
|
+
attributes: toAttributes(recipeJson, ['slug', 'title']),
|
|
114122
|
+
children: [],
|
|
114123
|
+
// Position is optional but helps with debugging
|
|
114124
|
+
position: undefined,
|
|
114125
|
+
};
|
|
114126
|
+
return [recipeNode];
|
|
114127
|
+
}
|
|
114110
114128
|
// Unknown block types: render as generic div with JSON properties
|
|
114111
114129
|
default: {
|
|
114112
114130
|
const text = json.text || json.html || '';
|
|
@@ -114116,6 +114134,12 @@ function parseMagicBlock(raw, options = {}) {
|
|
|
114116
114134
|
}
|
|
114117
114135
|
}
|
|
114118
114136
|
}
|
|
114137
|
+
/**
|
|
114138
|
+
* Check if a child node is a flow element that needs unwrapping (mdxJsxFlowElement, etc.)
|
|
114139
|
+
*/
|
|
114140
|
+
const needsUnwrapping = (child) => {
|
|
114141
|
+
return child.type === 'mdxJsxFlowElement';
|
|
114142
|
+
};
|
|
114119
114143
|
/**
|
|
114120
114144
|
* Unified plugin that restores magic blocks from placeholder tokens.
|
|
114121
114145
|
*
|
|
@@ -114129,21 +114153,271 @@ const magicBlockRestorer = ({ blocks }) => tree => {
|
|
|
114129
114153
|
// Map: key → original raw magic block content
|
|
114130
114154
|
const magicBlockKeys = new Map(blocks.map(({ key, raw }) => [key, raw]));
|
|
114131
114155
|
// Find inlineCode nodes that match our placeholder tokens
|
|
114156
|
+
const modifications = [];
|
|
114132
114157
|
visit(tree, 'inlineCode', (node, index, parent) => {
|
|
114133
114158
|
if (!parent || index == null)
|
|
114134
|
-
return;
|
|
114159
|
+
return undefined;
|
|
114135
114160
|
const raw = magicBlockKeys.get(node.value);
|
|
114136
114161
|
if (!raw)
|
|
114137
|
-
return;
|
|
114138
|
-
// Parse the original magic block and replace the placeholder with the result
|
|
114162
|
+
return undefined;
|
|
114139
114163
|
const children = parseMagicBlock(raw);
|
|
114140
114164
|
if (!children.length)
|
|
114141
|
-
return;
|
|
114165
|
+
return undefined;
|
|
114166
|
+
if (children[0] && needsUnwrapping(children[0]) && parent.type === 'paragraph') {
|
|
114167
|
+
// Find paragraph's parent and unwrap
|
|
114168
|
+
let paragraphParent;
|
|
114169
|
+
visit(tree, 'paragraph', (p, pIndex, pParent) => {
|
|
114170
|
+
if (p === parent && pParent && 'children' in pParent) {
|
|
114171
|
+
paragraphParent = pParent;
|
|
114172
|
+
return false;
|
|
114173
|
+
}
|
|
114174
|
+
return undefined;
|
|
114175
|
+
});
|
|
114176
|
+
if (paragraphParent) {
|
|
114177
|
+
const paragraphIndex = paragraphParent.children.indexOf(parent);
|
|
114178
|
+
if (paragraphIndex !== -1) {
|
|
114179
|
+
modifications.push({ children, index: paragraphIndex, parent: paragraphParent });
|
|
114180
|
+
}
|
|
114181
|
+
}
|
|
114182
|
+
return SKIP;
|
|
114183
|
+
}
|
|
114184
|
+
parent.children.splice(index, 1, ...children);
|
|
114185
|
+
return [SKIP, index + children.length];
|
|
114186
|
+
});
|
|
114187
|
+
// Apply modifications in reverse order to avoid index shifting
|
|
114188
|
+
modifications.reverse().forEach(({ children, index, parent }) => {
|
|
114142
114189
|
parent.children.splice(index, 1, ...children);
|
|
114143
114190
|
});
|
|
114144
114191
|
};
|
|
114145
114192
|
/* harmony default export */ const mdxish_magic_blocks = (magicBlockRestorer);
|
|
114146
114193
|
|
|
114194
|
+
;// ./lib/constants.ts
|
|
114195
|
+
/**
|
|
114196
|
+
* Pattern to match component tags (PascalCase or snake_case)
|
|
114197
|
+
*/
|
|
114198
|
+
const componentTagPattern = /<(\/?[A-Z][A-Za-z0-9_]*)([^>]*?)(\/?)>/g;
|
|
114199
|
+
|
|
114200
|
+
;// ./processor/transform/mdxish/mdxish-snake-case-components.ts
|
|
114201
|
+
|
|
114202
|
+
/**
|
|
114203
|
+
* Replaces snake_case component names with valid HTML placeholders.
|
|
114204
|
+
* Required because remark-parse rejects tags with underscores.
|
|
114205
|
+
* Example: `<Snake_case />` → `<MDXishSnakeCase0 />`
|
|
114206
|
+
*/
|
|
114207
|
+
function processSnakeCaseComponent(content) {
|
|
114208
|
+
// Early exit if no potential snake_case components
|
|
114209
|
+
if (!/[A-Z][A-Za-z0-9]*_[A-Za-z0-9_]*/.test(content)) {
|
|
114210
|
+
return { content, mapping: {} };
|
|
114211
|
+
}
|
|
114212
|
+
const mapping = {};
|
|
114213
|
+
const reverseMap = new Map();
|
|
114214
|
+
let counter = 0;
|
|
114215
|
+
const processedContent = content.replace(componentTagPattern, (match, tagName, attrs, selfClosing) => {
|
|
114216
|
+
if (!tagName.includes('_')) {
|
|
114217
|
+
return match;
|
|
114218
|
+
}
|
|
114219
|
+
const isClosing = tagName.startsWith('/');
|
|
114220
|
+
const cleanTagName = isClosing ? tagName.slice(1) : tagName;
|
|
114221
|
+
let placeholder = reverseMap.get(cleanTagName);
|
|
114222
|
+
if (!placeholder) {
|
|
114223
|
+
// eslint-disable-next-line no-plusplus
|
|
114224
|
+
placeholder = `MDXishSnakeCase${counter++}`;
|
|
114225
|
+
mapping[placeholder] = cleanTagName;
|
|
114226
|
+
reverseMap.set(cleanTagName, placeholder);
|
|
114227
|
+
}
|
|
114228
|
+
const processedTagName = isClosing ? `/${placeholder}` : placeholder;
|
|
114229
|
+
return `<${processedTagName}${attrs}${selfClosing}>`;
|
|
114230
|
+
});
|
|
114231
|
+
return {
|
|
114232
|
+
content: processedContent,
|
|
114233
|
+
mapping,
|
|
114234
|
+
};
|
|
114235
|
+
}
|
|
114236
|
+
/**
|
|
114237
|
+
* Restores placeholder name to original snake_case name.
|
|
114238
|
+
* Uses case-insensitive matching since HTML parsers normalize to lowercase.
|
|
114239
|
+
*/
|
|
114240
|
+
function restoreSnakeCase(placeholderName, mapping) {
|
|
114241
|
+
if (mapping[placeholderName]) {
|
|
114242
|
+
return mapping[placeholderName];
|
|
114243
|
+
}
|
|
114244
|
+
const lowerName = placeholderName.toLowerCase();
|
|
114245
|
+
const matchingKey = Object.keys(mapping).find(key => key.toLowerCase() === lowerName);
|
|
114246
|
+
return matchingKey ? mapping[matchingKey] : placeholderName;
|
|
114247
|
+
}
|
|
114248
|
+
|
|
114249
|
+
;// ./processor/transform/mdxish/normalize-malformed-md-syntax.ts
|
|
114250
|
+
|
|
114251
|
+
// Patterns to detect for bold (** and __) and italic (* and _) syntax:
|
|
114252
|
+
// Bold: ** text**, **text **, word** text**, ** text **
|
|
114253
|
+
// Italic: * text*, *text *, word* text*, * text *
|
|
114254
|
+
// Same patterns for underscore variants
|
|
114255
|
+
// We use separate patterns for each marker type to allow this flexibility.
|
|
114256
|
+
// Pattern for ** bold **
|
|
114257
|
+
// Groups: 1=wordBefore, 2=marker, 3=contentWithSpaceAfter, 4=trailingSpace1, 5=contentWithSpaceBefore, 6=trailingSpace2, 7=afterChar
|
|
114258
|
+
// trailingSpace1 is for "** text **" pattern, trailingSpace2 is for "**text **" pattern
|
|
114259
|
+
const asteriskBoldRegex = /([^*\s]+)?\s*(\*\*)(?:\s+((?:[^*\n]|\*(?!\*))+?)(\s*)\2|((?:[^*\n]|\*(?!\*))+?)(\s+)\2)(\S|$)?/g;
|
|
114260
|
+
// Pattern for __ bold __
|
|
114261
|
+
const underscoreBoldRegex = /([^_\s]+)?\s*(__)(?:\s+((?:[^_\n]|_(?!_))+?)(\s*)\2|((?:[^_\n]|_(?!_))+?)(\s+)\2)(\S|$)?/g;
|
|
114262
|
+
// Pattern for * italic *
|
|
114263
|
+
const asteriskItalicRegex = /([^*\s]+)?\s*(\*)(?!\*)(?:\s+([^*\n]+?)(\s*)\2|([^*\n]+?)(\s+)\2)(\S|$)?/g;
|
|
114264
|
+
// Pattern for _ italic _
|
|
114265
|
+
const underscoreItalicRegex = /([^_\s]+)?\s*(_)(?!_)(?:\s+([^_\n]+?)(\s*)\2|([^_\n]+?)(\s+)\2)(\S|$)?/g;
|
|
114266
|
+
/**
|
|
114267
|
+
* A remark plugin that normalizes malformed bold and italic markers in text nodes.
|
|
114268
|
+
* Detects patterns like `** bold**`, `Hello** Wrong Bold**`, `__ bold__`, `Hello__ Wrong Bold__`,
|
|
114269
|
+
* `* italic*`, `Hello* Wrong Italic*`, `_ italic_`, or `Hello_ Wrong Italic_`
|
|
114270
|
+
* and converts them to proper strong/emphasis nodes, matching the behavior of the legacy rdmd engine.
|
|
114271
|
+
*
|
|
114272
|
+
* Supports both asterisk (`**bold**`, `*italic*`) and underscore (`__bold__`, `_italic_`) syntax.
|
|
114273
|
+
* Also supports snake_case content like `** some_snake_case**`.
|
|
114274
|
+
*
|
|
114275
|
+
* This runs after remark-parse, which (in v11+) is strict and doesn't parse
|
|
114276
|
+
* malformed emphasis syntax. This plugin post-processes the AST to handle these cases.
|
|
114277
|
+
*/
|
|
114278
|
+
const normalizeEmphasisAST = () => (tree) => {
|
|
114279
|
+
visit(tree, 'text', function visitor(node, index, parent) {
|
|
114280
|
+
if (index === undefined || !parent)
|
|
114281
|
+
return undefined;
|
|
114282
|
+
// Skip if inside code blocks or inline code
|
|
114283
|
+
if (parent.type === 'inlineCode' || parent.type === 'code') {
|
|
114284
|
+
return undefined;
|
|
114285
|
+
}
|
|
114286
|
+
const text = node.value;
|
|
114287
|
+
const allMatches = [];
|
|
114288
|
+
[...text.matchAll(asteriskBoldRegex)].forEach(match => {
|
|
114289
|
+
allMatches.push({ isBold: true, marker: '**', match });
|
|
114290
|
+
});
|
|
114291
|
+
[...text.matchAll(underscoreBoldRegex)].forEach(match => {
|
|
114292
|
+
allMatches.push({ isBold: true, marker: '__', match });
|
|
114293
|
+
});
|
|
114294
|
+
[...text.matchAll(asteriskItalicRegex)].forEach(match => {
|
|
114295
|
+
allMatches.push({ isBold: false, marker: '*', match });
|
|
114296
|
+
});
|
|
114297
|
+
[...text.matchAll(underscoreItalicRegex)].forEach(match => {
|
|
114298
|
+
allMatches.push({ isBold: false, marker: '_', match });
|
|
114299
|
+
});
|
|
114300
|
+
if (allMatches.length === 0)
|
|
114301
|
+
return undefined;
|
|
114302
|
+
allMatches.sort((a, b) => (a.match.index ?? 0) - (b.match.index ?? 0));
|
|
114303
|
+
const filteredMatches = [];
|
|
114304
|
+
let lastEnd = 0;
|
|
114305
|
+
allMatches.forEach(info => {
|
|
114306
|
+
const start = info.match.index ?? 0;
|
|
114307
|
+
const end = start + info.match[0].length;
|
|
114308
|
+
if (start >= lastEnd) {
|
|
114309
|
+
filteredMatches.push(info);
|
|
114310
|
+
lastEnd = end;
|
|
114311
|
+
}
|
|
114312
|
+
});
|
|
114313
|
+
if (filteredMatches.length === 0)
|
|
114314
|
+
return undefined;
|
|
114315
|
+
const parts = [];
|
|
114316
|
+
let lastIndex = 0;
|
|
114317
|
+
filteredMatches.forEach(({ match, marker, isBold }) => {
|
|
114318
|
+
const matchIndex = match.index ?? 0;
|
|
114319
|
+
const fullMatch = match[0];
|
|
114320
|
+
if (matchIndex > lastIndex) {
|
|
114321
|
+
const beforeText = text.slice(lastIndex, matchIndex);
|
|
114322
|
+
if (beforeText) {
|
|
114323
|
+
parts.push({ type: 'text', value: beforeText });
|
|
114324
|
+
}
|
|
114325
|
+
}
|
|
114326
|
+
const wordBefore = match[1]; // e.g., "Hello" in "Hello** Wrong Bold**"
|
|
114327
|
+
const contentWithSpaceAfter = match[3]; // Content when there's a space after opening markers
|
|
114328
|
+
const trailingSpace1 = match[4] || ''; // Space before closing markers (for "** text **" pattern)
|
|
114329
|
+
const contentWithSpaceBefore = match[5]; // Content when there's only a space before closing markers
|
|
114330
|
+
const trailingSpace2 = match[6] || ''; // Space before closing markers (for "**text **" pattern)
|
|
114331
|
+
const trailingSpace = trailingSpace1 || trailingSpace2; // Combined trailing space
|
|
114332
|
+
const content = (contentWithSpaceAfter || contentWithSpaceBefore || '').trim();
|
|
114333
|
+
const afterChar = match[7]; // Character after closing markers (if any)
|
|
114334
|
+
const markerPos = fullMatch.indexOf(marker);
|
|
114335
|
+
const spacesBeforeMarkers = wordBefore
|
|
114336
|
+
? fullMatch.slice(wordBefore.length, markerPos)
|
|
114337
|
+
: fullMatch.slice(0, markerPos);
|
|
114338
|
+
const shouldAddSpace = !!contentWithSpaceAfter && !!wordBefore && !spacesBeforeMarkers;
|
|
114339
|
+
if (wordBefore) {
|
|
114340
|
+
const spacing = spacesBeforeMarkers + (shouldAddSpace ? ' ' : '');
|
|
114341
|
+
parts.push({ type: 'text', value: wordBefore + spacing });
|
|
114342
|
+
}
|
|
114343
|
+
else if (spacesBeforeMarkers) {
|
|
114344
|
+
parts.push({ type: 'text', value: spacesBeforeMarkers });
|
|
114345
|
+
}
|
|
114346
|
+
if (content) {
|
|
114347
|
+
if (isBold) {
|
|
114348
|
+
parts.push({
|
|
114349
|
+
type: 'strong',
|
|
114350
|
+
children: [{ type: 'text', value: content }],
|
|
114351
|
+
});
|
|
114352
|
+
}
|
|
114353
|
+
else {
|
|
114354
|
+
parts.push({
|
|
114355
|
+
type: 'emphasis',
|
|
114356
|
+
children: [{ type: 'text', value: content }],
|
|
114357
|
+
});
|
|
114358
|
+
}
|
|
114359
|
+
}
|
|
114360
|
+
if (afterChar) {
|
|
114361
|
+
const prefix = trailingSpace ? ' ' : '';
|
|
114362
|
+
parts.push({ type: 'text', value: prefix + afterChar });
|
|
114363
|
+
}
|
|
114364
|
+
lastIndex = matchIndex + fullMatch.length;
|
|
114365
|
+
});
|
|
114366
|
+
if (lastIndex < text.length) {
|
|
114367
|
+
const remainingText = text.slice(lastIndex);
|
|
114368
|
+
if (remainingText) {
|
|
114369
|
+
parts.push({ type: 'text', value: remainingText });
|
|
114370
|
+
}
|
|
114371
|
+
}
|
|
114372
|
+
if (parts.length > 0) {
|
|
114373
|
+
parent.children.splice(index, 1, ...parts);
|
|
114374
|
+
return [SKIP, index + parts.length];
|
|
114375
|
+
}
|
|
114376
|
+
return undefined;
|
|
114377
|
+
});
|
|
114378
|
+
return tree;
|
|
114379
|
+
};
|
|
114380
|
+
/* harmony default export */ const normalize_malformed_md_syntax = (normalizeEmphasisAST);
|
|
114381
|
+
|
|
114382
|
+
;// ./processor/transform/mdxish/restore-snake-case-component-name.ts
|
|
114383
|
+
|
|
114384
|
+
|
|
114385
|
+
/**
|
|
114386
|
+
* Restores snake_case component names from placeholders after parsing.
|
|
114387
|
+
* Runs after mdxishComponentBlocks converts HTML nodes to mdxJsxFlowElement.
|
|
114388
|
+
*/
|
|
114389
|
+
const restoreSnakeCaseComponentNames = (options) => {
|
|
114390
|
+
const { mapping } = options;
|
|
114391
|
+
return tree => {
|
|
114392
|
+
if (!mapping || Object.keys(mapping).length === 0) {
|
|
114393
|
+
return tree;
|
|
114394
|
+
}
|
|
114395
|
+
visit(tree, 'mdxJsxFlowElement', (node) => {
|
|
114396
|
+
if (node.name) {
|
|
114397
|
+
node.name = restoreSnakeCase(node.name, mapping);
|
|
114398
|
+
}
|
|
114399
|
+
});
|
|
114400
|
+
// Pre-compile regex patterns for better performance
|
|
114401
|
+
const regexPatterns = Object.entries(mapping).map(([placeholder, original]) => ({
|
|
114402
|
+
regex: new RegExp(`(<\\/?)(${placeholder})(\\s|\\/?>)`, 'gi'),
|
|
114403
|
+
original,
|
|
114404
|
+
}));
|
|
114405
|
+
visit(tree, 'html', (node) => {
|
|
114406
|
+
if (node.value) {
|
|
114407
|
+
let newValue = node.value;
|
|
114408
|
+
regexPatterns.forEach(({ regex, original }) => {
|
|
114409
|
+
newValue = newValue.replace(regex, `$1${original}$3`);
|
|
114410
|
+
});
|
|
114411
|
+
if (newValue !== node.value) {
|
|
114412
|
+
node.value = newValue;
|
|
114413
|
+
}
|
|
114414
|
+
}
|
|
114415
|
+
});
|
|
114416
|
+
return tree;
|
|
114417
|
+
};
|
|
114418
|
+
};
|
|
114419
|
+
/* harmony default export */ const restore_snake_case_component_name = (restoreSnakeCaseComponentNames);
|
|
114420
|
+
|
|
114147
114421
|
;// ./processor/transform/mdxish/variables-text.ts
|
|
114148
114422
|
|
|
114149
114423
|
|
|
@@ -114229,14 +114503,17 @@ function extractMagicBlocks(markdown) {
|
|
|
114229
114503
|
const replaced = markdown.replace(MAGIC_BLOCK_REGEX, match => {
|
|
114230
114504
|
/**
|
|
114231
114505
|
* Key is the unique identifier for the magic block
|
|
114232
|
-
* Token is a wrapper around the key to serialize & influences how the block is parsed in the pipeline
|
|
114233
|
-
* with the temporary key
|
|
114234
|
-
* - Use backticks so it becomes a code span, preventing remarkParse from parsing
|
|
114235
|
-
* special characters in the token as markdown syntax
|
|
114236
|
-
* - Prepend a newline to the token to ensure it is parsed as a block level node
|
|
114237
114506
|
*/
|
|
114238
114507
|
const key = `__MAGIC_BLOCK_${index}__`;
|
|
114239
|
-
|
|
114508
|
+
/**
|
|
114509
|
+
* Token is a wrapper around the `key` to serialize & influence how the
|
|
114510
|
+
* magic block is parsed in the remark pipeline.
|
|
114511
|
+
* - Use backticks so it becomes a code span, preventing `remarkParse` from
|
|
114512
|
+
* parsing special characters in the token as markdown syntax
|
|
114513
|
+
* - Prepend a newline to ensure it is parsed as a block level node
|
|
114514
|
+
* - Append a newline to ensure it is separated from following content
|
|
114515
|
+
*/
|
|
114516
|
+
const token = `\n\`${key}\`\n`;
|
|
114240
114517
|
blocks.push({ key, raw: match, token });
|
|
114241
114518
|
index += 1;
|
|
114242
114519
|
return token;
|
|
@@ -114247,17 +114524,16 @@ function extractMagicBlocks(markdown) {
|
|
|
114247
114524
|
* Restore extracted magic blocks back into a markdown string.
|
|
114248
114525
|
*/
|
|
114249
114526
|
function restoreMagicBlocks(replaced, blocks) {
|
|
114250
|
-
|
|
114251
|
-
//
|
|
114252
|
-
//
|
|
114253
|
-
//
|
|
114254
|
-
const
|
|
114255
|
-
|
|
114256
|
-
|
|
114257
|
-
|
|
114258
|
-
return blocks.reduce((acc, { token, raw }) => {
|
|
114259
|
-
return acc.split(token).join(raw);
|
|
114527
|
+
// If a magic block is at the start or end of the document, the extraction
|
|
114528
|
+
// token's newlines will have been trimmed during processing. We need to
|
|
114529
|
+
// account for that here to ensure the token is found and replaced correctly.
|
|
114530
|
+
// These extra newlines will be removed again when the final string is trimmed.
|
|
114531
|
+
const content = `\n${replaced}\n`;
|
|
114532
|
+
const restoredContent = blocks.reduce((acc, { token, raw }) => {
|
|
114533
|
+
// Ensure each magic block is separated by newlines when restored.
|
|
114534
|
+
return acc.split(token).join(`\n${raw}\n`);
|
|
114260
114535
|
}, content);
|
|
114536
|
+
return restoredContent.trim();
|
|
114261
114537
|
}
|
|
114262
114538
|
|
|
114263
114539
|
;// ./lib/utils/mdxish/mdxish-load-components.ts
|
|
@@ -114316,6 +114592,9 @@ function loadComponents() {
|
|
|
114316
114592
|
|
|
114317
114593
|
|
|
114318
114594
|
|
|
114595
|
+
|
|
114596
|
+
|
|
114597
|
+
|
|
114319
114598
|
|
|
114320
114599
|
|
|
114321
114600
|
|
|
@@ -114333,10 +114612,15 @@ function mdxish(mdContent, opts = {}) {
|
|
|
114333
114612
|
...loadComponents(),
|
|
114334
114613
|
...userComponents,
|
|
114335
114614
|
};
|
|
114336
|
-
//
|
|
114337
|
-
|
|
114338
|
-
const
|
|
114339
|
-
//
|
|
114615
|
+
// Preprocessing pipeline: Transform content to be parser-ready
|
|
114616
|
+
// Step 1: Extract legacy magic blocks
|
|
114617
|
+
const { replaced: contentAfterMagicBlocks, blocks } = extractMagicBlocks(mdContent);
|
|
114618
|
+
// Step 2: Evaluate JSX expressions in attributes
|
|
114619
|
+
const contentAfterJSXEvaluation = preprocessJSXExpressions(contentAfterMagicBlocks, jsxContext);
|
|
114620
|
+
// Step 3: Replace snake_case component names with parser-safe placeholders
|
|
114621
|
+
// (e.g., <Snake_case /> → <MDXishSnakeCase0 /> which will be restored after parsing)
|
|
114622
|
+
const { content: parserReadyContent, mapping: snakeCaseMapping } = processSnakeCaseComponent(contentAfterJSXEvaluation);
|
|
114623
|
+
// Create string map for tailwind transformer
|
|
114340
114624
|
const tempComponentsMap = Object.entries(components).reduce((acc, [key, value]) => {
|
|
114341
114625
|
acc[key] = String(value);
|
|
114342
114626
|
return acc;
|
|
@@ -114346,10 +114630,12 @@ function mdxish(mdContent, opts = {}) {
|
|
|
114346
114630
|
.data('fromMarkdownExtensions', [mdxExpressionFromMarkdown()])
|
|
114347
114631
|
.use(remarkParse)
|
|
114348
114632
|
.use(remarkFrontmatter)
|
|
114633
|
+
.use(normalize_malformed_md_syntax)
|
|
114349
114634
|
.use(mdxish_magic_blocks, { blocks })
|
|
114350
114635
|
.use(transform_images, { isMdxish: true })
|
|
114351
114636
|
.use(defaultTransformers)
|
|
114352
114637
|
.use(mdxish_component_blocks)
|
|
114638
|
+
.use(restore_snake_case_component_name, { mapping: snakeCaseMapping })
|
|
114353
114639
|
.use(mdxish_tables)
|
|
114354
114640
|
.use(mdxish_html_blocks)
|
|
114355
114641
|
.use(evaluate_expressions, { context: jsxContext }) // Evaluate MDX expressions using jsxContext
|
|
@@ -114363,8 +114649,8 @@ function mdxish(mdContent, opts = {}) {
|
|
|
114363
114649
|
components,
|
|
114364
114650
|
processMarkdown: (markdown) => mdxish(markdown, opts),
|
|
114365
114651
|
});
|
|
114366
|
-
const vfile = new VFile({ value:
|
|
114367
|
-
const hast = processor.runSync(processor.parse(
|
|
114652
|
+
const vfile = new VFile({ value: parserReadyContent });
|
|
114653
|
+
const hast = processor.runSync(processor.parse(parserReadyContent), vfile);
|
|
114368
114654
|
if (!hast) {
|
|
114369
114655
|
throw new Error('Markdown pipeline did not produce a HAST tree.');
|
|
114370
114656
|
}
|
|
@@ -114801,8 +115087,7 @@ const tags = (doc) => {
|
|
|
114801
115087
|
const mdxishTags_tags = (doc) => {
|
|
114802
115088
|
const { replaced: sanitizedDoc } = extractMagicBlocks(doc);
|
|
114803
115089
|
const set = new Set();
|
|
114804
|
-
const processor = remark()
|
|
114805
|
-
.use(mdxish_component_blocks);
|
|
115090
|
+
const processor = remark().use(mdxish_component_blocks);
|
|
114806
115091
|
const tree = processor.parse(sanitizedDoc);
|
|
114807
115092
|
visit(processor.runSync(tree), isMDXElement, (node) => {
|
|
114808
115093
|
if (node.name?.match(/^[A-Z]/)) {
|
|
@@ -114888,7 +115173,7 @@ async function stripComments(doc, { mdx } = {}) {
|
|
|
114888
115173
|
// Our markdown renderer uses this to group these code blocks into a tabbed interface.
|
|
114889
115174
|
(left, right) => {
|
|
114890
115175
|
// 0 = no newline between blocks
|
|
114891
|
-
return
|
|
115176
|
+
return left.type === 'code' && right.type === 'code' ? 0 : undefined;
|
|
114892
115177
|
},
|
|
114893
115178
|
],
|
|
114894
115179
|
});
|