@readme/markdown 11.10.1 → 11.11.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.
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Pattern to match component tags (PascalCase or snake_case)
3
+ */
4
+ export declare const componentTagPattern: RegExp;
package/dist/main.js CHANGED
@@ -2030,7 +2030,7 @@ module.exports = function (it) {
2030
2030
 
2031
2031
  "use strict";
2032
2032
 
2033
- var create = __webpack_require__(7100);
2033
+ var create = __webpack_require__(4719);
2034
2034
  var descriptor = __webpack_require__(1996);
2035
2035
  var setToStringTag = __webpack_require__(3844);
2036
2036
  var IteratorPrototype = {};
@@ -2209,7 +2209,7 @@ var meta = module.exports = {
2209
2209
 
2210
2210
  /***/ }),
2211
2211
 
2212
- /***/ 7100:
2212
+ /***/ 4719:
2213
2213
  /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
2214
2214
 
2215
2215
  // 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties])
@@ -2940,7 +2940,7 @@ var $Number = global[NUMBER];
2940
2940
  var Base = $Number;
2941
2941
  var proto = $Number.prototype;
2942
2942
  // Opera ~12 has broken Object#toString
2943
- var BROKEN_COF = cof(__webpack_require__(7100)(proto)) == NUMBER;
2943
+ var BROKEN_COF = cof(__webpack_require__(4719)(proto)) == NUMBER;
2944
2944
  var TRIM = 'trim' in String.prototype;
2945
2945
 
2946
2946
  // 7.1.3 ToNumber(argument)
@@ -3139,7 +3139,7 @@ var toObject = __webpack_require__(8270);
3139
3139
  var toIObject = __webpack_require__(7221);
3140
3140
  var toPrimitive = __webpack_require__(3048);
3141
3141
  var createDesc = __webpack_require__(1996);
3142
- var _create = __webpack_require__(7100);
3142
+ var _create = __webpack_require__(4719);
3143
3143
  var gOPNExt = __webpack_require__(4765);
3144
3144
  var $GOPD = __webpack_require__(8641);
3145
3145
  var $GOPS = __webpack_require__(1060);
@@ -70584,7 +70584,7 @@ const mdxToHast = () => tree => {
70584
70584
  ;// ./processor/transform/mdxish/mdxish-component-blocks.ts
70585
70585
 
70586
70586
 
70587
- const tagPattern = /^<([A-Z][A-Za-z0-9]*)([^>]*?)(\/?)>([\s\S]*)?$/;
70587
+ const tagPattern = /^<([A-Z][A-Za-z0-9_]*)([^>]*?)(\/?)>([\s\S]*)?$/;
70588
70588
  const attributePattern = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*("[^"]*"|'[^']*'|[^\s"'>]+))?/g;
70589
70589
  const inlineMdProcessor = unified().use(remarkParse);
70590
70590
  const isClosingTag = (value, tag) => value.trim() === `</${tag}>`;
@@ -92981,82 +92981,7 @@ const mdxComponentHandlers = {
92981
92981
  [NodeTypes.htmlBlock]: htmlBlockHandler,
92982
92982
  };
92983
92983
 
92984
- ;// ./processor/transform/mdxish/evaluate-expressions.ts
92985
-
92986
- /**
92987
- * AST transformer to evaluate MDX expressions using the provided context.
92988
- * Replaces mdxFlowExpression and mdxTextExpression nodes with their evaluated values.
92989
- */
92990
- const evaluateExpressions = ({ context = {} } = {}) => tree => {
92991
- visit(tree, ['mdxFlowExpression', 'mdxTextExpression'], (node, index, parent) => {
92992
- if (!parent || index === null || index === undefined)
92993
- return;
92994
- const expressionNode = node;
92995
- if (!('value' in expressionNode))
92996
- return;
92997
- // JSX attribute expressions are handled by preprocessing; code blocks are protected
92998
- const expression = expressionNode.value.trim();
92999
- // Skip if expression is empty (shouldn't happen, but defensive)
93000
- if (!expression)
93001
- return;
93002
- try {
93003
- // Evaluate the expression using the context
93004
- const contextKeys = Object.keys(context);
93005
- const contextValues = Object.values(context);
93006
- // If no context provided, leave expression as-is
93007
- if (contextKeys.length === 0) {
93008
- parent.children.splice(index, 1, {
93009
- type: 'text',
93010
- value: `{${expression}}`,
93011
- position: node.position,
93012
- });
93013
- return;
93014
- }
93015
- // eslint-disable-next-line no-new-func
93016
- const func = new Function(...contextKeys, `return ${expression}`);
93017
- const result = func(...contextValues);
93018
- // Convert result to text node(s)
93019
- if (result === null || result === undefined) {
93020
- // Replace with empty text node (don't remove, as it affects positioning)
93021
- parent.children.splice(index, 1, {
93022
- type: 'text',
93023
- value: '',
93024
- position: node.position,
93025
- });
93026
- return;
93027
- }
93028
- let textValue;
93029
- if (typeof result === 'object') {
93030
- textValue = JSON.stringify(result);
93031
- }
93032
- else {
93033
- textValue = String(result).replace(/\s+/g, ' ').trim();
93034
- }
93035
- // Replace expression node with text node
93036
- parent.children.splice(index, 1, {
93037
- type: 'text',
93038
- value: textValue,
93039
- position: node.position,
93040
- });
93041
- }
93042
- catch (_error) {
93043
- // If evaluation fails, leave the expression as-is (fallback to text)
93044
- parent.children.splice(index, 1, {
93045
- type: 'text',
93046
- value: `{${expression}}`,
93047
- position: node.position,
93048
- });
93049
- }
93050
- });
93051
- return tree;
93052
- };
93053
- /* harmony default export */ const evaluate_expressions = (evaluateExpressions);
93054
-
93055
92984
  ;// ./processor/transform/mdxish/preprocess-jsx-expressions.ts
93056
- /**
93057
- * Pre-processes JSX-like expressions before markdown parsing.
93058
- * Converts href={'value'} to href="value", evaluates {expressions}, etc.
93059
- */
93060
92985
  // Base64 encode (Node.js + browser compatible)
93061
92986
  function base64Encode(str) {
93062
92987
  if (typeof Buffer !== 'undefined') {
@@ -93312,6 +93237,57 @@ function preprocessJSXExpressions(content, context = {}) {
93312
93237
  return processed;
93313
93238
  }
93314
93239
 
93240
+ ;// ./processor/transform/mdxish/evaluate-expressions.ts
93241
+
93242
+
93243
+ /**
93244
+ * AST transformer to evaluate MDX expressions using the provided context.
93245
+ * Replaces mdxFlowExpression and mdxTextExpression nodes with their evaluated values.
93246
+ */
93247
+ const evaluateExpressions = ({ context = {} } = {}) => tree => {
93248
+ visit(tree, ['mdxFlowExpression', 'mdxTextExpression'], (node, index, parent) => {
93249
+ if (!parent || index === null || index === undefined)
93250
+ return;
93251
+ const expressionNode = node;
93252
+ if (!('value' in expressionNode))
93253
+ return;
93254
+ const expression = expressionNode.value.trim();
93255
+ // Skip if expression is empty (shouldn't happen, but defensive)
93256
+ if (!expression)
93257
+ return;
93258
+ try {
93259
+ const result = evaluateExpression(expression, context);
93260
+ // Extract evaluated value text
93261
+ let textValue;
93262
+ if (result === null || result === undefined) {
93263
+ textValue = '';
93264
+ }
93265
+ else if (typeof result === 'object') {
93266
+ textValue = JSON.stringify(result);
93267
+ }
93268
+ else {
93269
+ textValue = String(result).replace(/\s+/g, ' ').trim();
93270
+ }
93271
+ // Replace expression node with text node since the expression is conceptually a text
93272
+ parent.children.splice(index, 1, {
93273
+ type: 'text',
93274
+ value: textValue,
93275
+ position: node.position,
93276
+ });
93277
+ }
93278
+ catch (_error) {
93279
+ // If evaluation fails, leave the expression as-is (fallback to text)
93280
+ parent.children.splice(index, 1, {
93281
+ type: 'text',
93282
+ value: `{${expression}}`,
93283
+ position: node.position,
93284
+ });
93285
+ }
93286
+ });
93287
+ return tree;
93288
+ };
93289
+ /* harmony default export */ const evaluate_expressions = (evaluateExpressions);
93290
+
93315
93291
  ;// ./processor/transform/mdxish/mdxish-html-blocks.ts
93316
93292
 
93317
93293
 
@@ -93652,6 +93628,7 @@ const mdxishHtmlBlocks = () => tree => {
93652
93628
 
93653
93629
 
93654
93630
 
93631
+
93655
93632
  /**
93656
93633
  * Matches legacy magic block syntax: [block:TYPE]...JSON...[/block]
93657
93634
  * Group 1: block type (e.g., "image", "code", "callout")
@@ -93820,16 +93797,34 @@ function parseMagicBlock(raw, options = {}) {
93820
93797
  const [icon, theme] = Array.isArray(resolvedType) ? resolvedType : ['👍', 'default'];
93821
93798
  if (!(calloutJson.title || calloutJson.body))
93822
93799
  return [];
93823
- return [
93824
- wrapPinnedBlocks({
93825
- children: [...textToBlock(calloutJson.title || ''), ...textToBlock(calloutJson.body || '')],
93826
- data: {
93827
- hName: 'rdme-callout',
93828
- hProperties: { icon, theme: theme || 'default', title: calloutJson.title, value: calloutJson.body },
93829
- },
93830
- type: 'rdme-callout',
93831
- }, json),
93832
- ];
93800
+ const titleBlocks = textToBlock(calloutJson.title || '');
93801
+ const bodyBlocks = textToBlock(calloutJson.body || '');
93802
+ const children = [];
93803
+ if (titleBlocks.length > 0 && titleBlocks[0].type === 'paragraph') {
93804
+ const firstTitle = titleBlocks[0];
93805
+ const heading = {
93806
+ type: 'heading',
93807
+ depth: 3,
93808
+ children: (firstTitle.children || []),
93809
+ };
93810
+ children.push(heading);
93811
+ children.push(...titleBlocks.slice(1), ...bodyBlocks);
93812
+ }
93813
+ else {
93814
+ children.push(...titleBlocks, ...bodyBlocks);
93815
+ }
93816
+ // Create mdxJsxFlowElement directly for mdxish
93817
+ const calloutElement = {
93818
+ type: 'mdxJsxFlowElement',
93819
+ name: 'Callout',
93820
+ attributes: toAttributes({ icon, theme: theme || 'default', type: theme || 'default' }, [
93821
+ 'icon',
93822
+ 'theme',
93823
+ 'type',
93824
+ ]),
93825
+ children: children,
93826
+ };
93827
+ return [wrapPinnedBlocks(calloutElement, json)];
93833
93828
  }
93834
93829
  // Parameters: renders as a table (used for API parameters, etc.)
93835
93830
  case 'parameters': {
@@ -93912,6 +93907,12 @@ function parseMagicBlock(raw, options = {}) {
93912
93907
  }
93913
93908
  }
93914
93909
  }
93910
+ /**
93911
+ * Check if a child node is a flow element that needs unwrapping (mdxJsxFlowElement, etc.)
93912
+ */
93913
+ const needsUnwrapping = (child) => {
93914
+ return child.type === 'mdxJsxFlowElement';
93915
+ };
93915
93916
  /**
93916
93917
  * Unified plugin that restores magic blocks from placeholder tokens.
93917
93918
  *
@@ -93925,21 +93926,271 @@ const magicBlockRestorer = ({ blocks }) => tree => {
93925
93926
  // Map: key → original raw magic block content
93926
93927
  const magicBlockKeys = new Map(blocks.map(({ key, raw }) => [key, raw]));
93927
93928
  // Find inlineCode nodes that match our placeholder tokens
93929
+ const modifications = [];
93928
93930
  visit(tree, 'inlineCode', (node, index, parent) => {
93929
93931
  if (!parent || index == null)
93930
- return;
93932
+ return undefined;
93931
93933
  const raw = magicBlockKeys.get(node.value);
93932
93934
  if (!raw)
93933
- return;
93934
- // Parse the original magic block and replace the placeholder with the result
93935
+ return undefined;
93935
93936
  const children = parseMagicBlock(raw);
93936
93937
  if (!children.length)
93937
- return;
93938
+ return undefined;
93939
+ if (children[0] && needsUnwrapping(children[0]) && parent.type === 'paragraph') {
93940
+ // Find paragraph's parent and unwrap
93941
+ let paragraphParent;
93942
+ visit(tree, 'paragraph', (p, pIndex, pParent) => {
93943
+ if (p === parent && pParent && 'children' in pParent) {
93944
+ paragraphParent = pParent;
93945
+ return false;
93946
+ }
93947
+ return undefined;
93948
+ });
93949
+ if (paragraphParent) {
93950
+ const paragraphIndex = paragraphParent.children.indexOf(parent);
93951
+ if (paragraphIndex !== -1) {
93952
+ modifications.push({ children, index: paragraphIndex, parent: paragraphParent });
93953
+ }
93954
+ }
93955
+ return SKIP;
93956
+ }
93957
+ parent.children.splice(index, 1, ...children);
93958
+ return [SKIP, index + children.length];
93959
+ });
93960
+ // Apply modifications in reverse order to avoid index shifting
93961
+ modifications.reverse().forEach(({ children, index, parent }) => {
93938
93962
  parent.children.splice(index, 1, ...children);
93939
93963
  });
93940
93964
  };
93941
93965
  /* harmony default export */ const mdxish_magic_blocks = (magicBlockRestorer);
93942
93966
 
93967
+ ;// ./lib/constants.ts
93968
+ /**
93969
+ * Pattern to match component tags (PascalCase or snake_case)
93970
+ */
93971
+ const componentTagPattern = /<(\/?[A-Z][A-Za-z0-9_]*)([^>]*?)(\/?)>/g;
93972
+
93973
+ ;// ./processor/transform/mdxish/mdxish-snake-case-components.ts
93974
+
93975
+ /**
93976
+ * Replaces snake_case component names with valid HTML placeholders.
93977
+ * Required because remark-parse rejects tags with underscores.
93978
+ * Example: `<Snake_case />` → `<MDXishSnakeCase0 />`
93979
+ */
93980
+ function processSnakeCaseComponent(content) {
93981
+ // Early exit if no potential snake_case components
93982
+ if (!/[A-Z][A-Za-z0-9]*_[A-Za-z0-9_]*/.test(content)) {
93983
+ return { content, mapping: {} };
93984
+ }
93985
+ const mapping = {};
93986
+ const reverseMap = new Map();
93987
+ let counter = 0;
93988
+ const processedContent = content.replace(componentTagPattern, (match, tagName, attrs, selfClosing) => {
93989
+ if (!tagName.includes('_')) {
93990
+ return match;
93991
+ }
93992
+ const isClosing = tagName.startsWith('/');
93993
+ const cleanTagName = isClosing ? tagName.slice(1) : tagName;
93994
+ let placeholder = reverseMap.get(cleanTagName);
93995
+ if (!placeholder) {
93996
+ // eslint-disable-next-line no-plusplus
93997
+ placeholder = `MDXishSnakeCase${counter++}`;
93998
+ mapping[placeholder] = cleanTagName;
93999
+ reverseMap.set(cleanTagName, placeholder);
94000
+ }
94001
+ const processedTagName = isClosing ? `/${placeholder}` : placeholder;
94002
+ return `<${processedTagName}${attrs}${selfClosing}>`;
94003
+ });
94004
+ return {
94005
+ content: processedContent,
94006
+ mapping,
94007
+ };
94008
+ }
94009
+ /**
94010
+ * Restores placeholder name to original snake_case name.
94011
+ * Uses case-insensitive matching since HTML parsers normalize to lowercase.
94012
+ */
94013
+ function restoreSnakeCase(placeholderName, mapping) {
94014
+ if (mapping[placeholderName]) {
94015
+ return mapping[placeholderName];
94016
+ }
94017
+ const lowerName = placeholderName.toLowerCase();
94018
+ const matchingKey = Object.keys(mapping).find(key => key.toLowerCase() === lowerName);
94019
+ return matchingKey ? mapping[matchingKey] : placeholderName;
94020
+ }
94021
+
94022
+ ;// ./processor/transform/mdxish/normalize-malformed-md-syntax.ts
94023
+
94024
+ // Patterns to detect for bold (** and __) and italic (* and _) syntax:
94025
+ // Bold: ** text**, **text **, word** text**, ** text **
94026
+ // Italic: * text*, *text *, word* text*, * text *
94027
+ // Same patterns for underscore variants
94028
+ // We use separate patterns for each marker type to allow this flexibility.
94029
+ // Pattern for ** bold **
94030
+ // Groups: 1=wordBefore, 2=marker, 3=contentWithSpaceAfter, 4=trailingSpace1, 5=contentWithSpaceBefore, 6=trailingSpace2, 7=afterChar
94031
+ // trailingSpace1 is for "** text **" pattern, trailingSpace2 is for "**text **" pattern
94032
+ const asteriskBoldRegex = /([^*\s]+)?\s*(\*\*)(?:\s+((?:[^*\n]|\*(?!\*))+?)(\s*)\2|((?:[^*\n]|\*(?!\*))+?)(\s+)\2)(\S|$)?/g;
94033
+ // Pattern for __ bold __
94034
+ const underscoreBoldRegex = /([^_\s]+)?\s*(__)(?:\s+((?:[^_\n]|_(?!_))+?)(\s*)\2|((?:[^_\n]|_(?!_))+?)(\s+)\2)(\S|$)?/g;
94035
+ // Pattern for * italic *
94036
+ const asteriskItalicRegex = /([^*\s]+)?\s*(\*)(?!\*)(?:\s+([^*\n]+?)(\s*)\2|([^*\n]+?)(\s+)\2)(\S|$)?/g;
94037
+ // Pattern for _ italic _
94038
+ const underscoreItalicRegex = /([^_\s]+)?\s*(_)(?!_)(?:\s+([^_\n]+?)(\s*)\2|([^_\n]+?)(\s+)\2)(\S|$)?/g;
94039
+ /**
94040
+ * A remark plugin that normalizes malformed bold and italic markers in text nodes.
94041
+ * Detects patterns like `** bold**`, `Hello** Wrong Bold**`, `__ bold__`, `Hello__ Wrong Bold__`,
94042
+ * `* italic*`, `Hello* Wrong Italic*`, `_ italic_`, or `Hello_ Wrong Italic_`
94043
+ * and converts them to proper strong/emphasis nodes, matching the behavior of the legacy rdmd engine.
94044
+ *
94045
+ * Supports both asterisk (`**bold**`, `*italic*`) and underscore (`__bold__`, `_italic_`) syntax.
94046
+ * Also supports snake_case content like `** some_snake_case**`.
94047
+ *
94048
+ * This runs after remark-parse, which (in v11+) is strict and doesn't parse
94049
+ * malformed emphasis syntax. This plugin post-processes the AST to handle these cases.
94050
+ */
94051
+ const normalizeEmphasisAST = () => (tree) => {
94052
+ visit(tree, 'text', function visitor(node, index, parent) {
94053
+ if (index === undefined || !parent)
94054
+ return undefined;
94055
+ // Skip if inside code blocks or inline code
94056
+ if (parent.type === 'inlineCode' || parent.type === 'code') {
94057
+ return undefined;
94058
+ }
94059
+ const text = node.value;
94060
+ const allMatches = [];
94061
+ [...text.matchAll(asteriskBoldRegex)].forEach(match => {
94062
+ allMatches.push({ isBold: true, marker: '**', match });
94063
+ });
94064
+ [...text.matchAll(underscoreBoldRegex)].forEach(match => {
94065
+ allMatches.push({ isBold: true, marker: '__', match });
94066
+ });
94067
+ [...text.matchAll(asteriskItalicRegex)].forEach(match => {
94068
+ allMatches.push({ isBold: false, marker: '*', match });
94069
+ });
94070
+ [...text.matchAll(underscoreItalicRegex)].forEach(match => {
94071
+ allMatches.push({ isBold: false, marker: '_', match });
94072
+ });
94073
+ if (allMatches.length === 0)
94074
+ return undefined;
94075
+ allMatches.sort((a, b) => (a.match.index ?? 0) - (b.match.index ?? 0));
94076
+ const filteredMatches = [];
94077
+ let lastEnd = 0;
94078
+ allMatches.forEach(info => {
94079
+ const start = info.match.index ?? 0;
94080
+ const end = start + info.match[0].length;
94081
+ if (start >= lastEnd) {
94082
+ filteredMatches.push(info);
94083
+ lastEnd = end;
94084
+ }
94085
+ });
94086
+ if (filteredMatches.length === 0)
94087
+ return undefined;
94088
+ const parts = [];
94089
+ let lastIndex = 0;
94090
+ filteredMatches.forEach(({ match, marker, isBold }) => {
94091
+ const matchIndex = match.index ?? 0;
94092
+ const fullMatch = match[0];
94093
+ if (matchIndex > lastIndex) {
94094
+ const beforeText = text.slice(lastIndex, matchIndex);
94095
+ if (beforeText) {
94096
+ parts.push({ type: 'text', value: beforeText });
94097
+ }
94098
+ }
94099
+ const wordBefore = match[1]; // e.g., "Hello" in "Hello** Wrong Bold**"
94100
+ const contentWithSpaceAfter = match[3]; // Content when there's a space after opening markers
94101
+ const trailingSpace1 = match[4] || ''; // Space before closing markers (for "** text **" pattern)
94102
+ const contentWithSpaceBefore = match[5]; // Content when there's only a space before closing markers
94103
+ const trailingSpace2 = match[6] || ''; // Space before closing markers (for "**text **" pattern)
94104
+ const trailingSpace = trailingSpace1 || trailingSpace2; // Combined trailing space
94105
+ const content = (contentWithSpaceAfter || contentWithSpaceBefore || '').trim();
94106
+ const afterChar = match[7]; // Character after closing markers (if any)
94107
+ const markerPos = fullMatch.indexOf(marker);
94108
+ const spacesBeforeMarkers = wordBefore
94109
+ ? fullMatch.slice(wordBefore.length, markerPos)
94110
+ : fullMatch.slice(0, markerPos);
94111
+ const shouldAddSpace = !!contentWithSpaceAfter && !!wordBefore && !spacesBeforeMarkers;
94112
+ if (wordBefore) {
94113
+ const spacing = spacesBeforeMarkers + (shouldAddSpace ? ' ' : '');
94114
+ parts.push({ type: 'text', value: wordBefore + spacing });
94115
+ }
94116
+ else if (spacesBeforeMarkers) {
94117
+ parts.push({ type: 'text', value: spacesBeforeMarkers });
94118
+ }
94119
+ if (content) {
94120
+ if (isBold) {
94121
+ parts.push({
94122
+ type: 'strong',
94123
+ children: [{ type: 'text', value: content }],
94124
+ });
94125
+ }
94126
+ else {
94127
+ parts.push({
94128
+ type: 'emphasis',
94129
+ children: [{ type: 'text', value: content }],
94130
+ });
94131
+ }
94132
+ }
94133
+ if (afterChar) {
94134
+ const prefix = trailingSpace ? ' ' : '';
94135
+ parts.push({ type: 'text', value: prefix + afterChar });
94136
+ }
94137
+ lastIndex = matchIndex + fullMatch.length;
94138
+ });
94139
+ if (lastIndex < text.length) {
94140
+ const remainingText = text.slice(lastIndex);
94141
+ if (remainingText) {
94142
+ parts.push({ type: 'text', value: remainingText });
94143
+ }
94144
+ }
94145
+ if (parts.length > 0) {
94146
+ parent.children.splice(index, 1, ...parts);
94147
+ return [SKIP, index + parts.length];
94148
+ }
94149
+ return undefined;
94150
+ });
94151
+ return tree;
94152
+ };
94153
+ /* harmony default export */ const normalize_malformed_md_syntax = (normalizeEmphasisAST);
94154
+
94155
+ ;// ./processor/transform/mdxish/restore-snake-case-component-name.ts
94156
+
94157
+
94158
+ /**
94159
+ * Restores snake_case component names from placeholders after parsing.
94160
+ * Runs after mdxishComponentBlocks converts HTML nodes to mdxJsxFlowElement.
94161
+ */
94162
+ const restoreSnakeCaseComponentNames = (options) => {
94163
+ const { mapping } = options;
94164
+ return tree => {
94165
+ if (!mapping || Object.keys(mapping).length === 0) {
94166
+ return tree;
94167
+ }
94168
+ visit(tree, 'mdxJsxFlowElement', (node) => {
94169
+ if (node.name) {
94170
+ node.name = restoreSnakeCase(node.name, mapping);
94171
+ }
94172
+ });
94173
+ // Pre-compile regex patterns for better performance
94174
+ const regexPatterns = Object.entries(mapping).map(([placeholder, original]) => ({
94175
+ regex: new RegExp(`(<\\/?)(${placeholder})(\\s|\\/?>)`, 'gi'),
94176
+ original,
94177
+ }));
94178
+ visit(tree, 'html', (node) => {
94179
+ if (node.value) {
94180
+ let newValue = node.value;
94181
+ regexPatterns.forEach(({ regex, original }) => {
94182
+ newValue = newValue.replace(regex, `$1${original}$3`);
94183
+ });
94184
+ if (newValue !== node.value) {
94185
+ node.value = newValue;
94186
+ }
94187
+ }
94188
+ });
94189
+ return tree;
94190
+ };
94191
+ };
94192
+ /* harmony default export */ const restore_snake_case_component_name = (restoreSnakeCaseComponentNames);
94193
+
93943
94194
  ;// ./processor/transform/mdxish/variables-text.ts
93944
94195
 
93945
94196
 
@@ -94025,14 +94276,17 @@ function extractMagicBlocks(markdown) {
94025
94276
  const replaced = markdown.replace(MAGIC_BLOCK_REGEX, match => {
94026
94277
  /**
94027
94278
  * Key is the unique identifier for the magic block
94028
- * Token is a wrapper around the key to serialize & influences how the block is parsed in the pipeline
94029
- * with the temporary key
94030
- * - Use backticks so it becomes a code span, preventing remarkParse from parsing
94031
- * special characters in the token as markdown syntax
94032
- * - Prepend a newline to the token to ensure it is parsed as a block level node
94033
94279
  */
94034
94280
  const key = `__MAGIC_BLOCK_${index}__`;
94035
- const token = `\n\`${key}\``;
94281
+ /**
94282
+ * Token is a wrapper around the `key` to serialize & influence how the
94283
+ * magic block is parsed in the remark pipeline.
94284
+ * - Use backticks so it becomes a code span, preventing `remarkParse` from
94285
+ * parsing special characters in the token as markdown syntax
94286
+ * - Prepend a newline to ensure it is parsed as a block level node
94287
+ * - Append a newline to ensure it is separated from following content
94288
+ */
94289
+ const token = `\n\`${key}\`\n`;
94036
94290
  blocks.push({ key, raw: match, token });
94037
94291
  index += 1;
94038
94292
  return token;
@@ -94043,17 +94297,16 @@ function extractMagicBlocks(markdown) {
94043
94297
  * Restore extracted magic blocks back into a markdown string.
94044
94298
  */
94045
94299
  function restoreMagicBlocks(replaced, blocks) {
94046
- let content = replaced;
94047
- // If a magic block is at the start of the document, the extraction token's prepended
94048
- // newline will have been trimmed during processing. We need to account for that here
94049
- // to ensure the token is found and replaced correctly.
94050
- const isTokenAtStart = content.startsWith(blocks[0]?.token.trimStart());
94051
- if (isTokenAtStart) {
94052
- content = `\n${content}`;
94053
- }
94054
- return blocks.reduce((acc, { token, raw }) => {
94055
- return acc.split(token).join(raw);
94300
+ // If a magic block is at the start or end of the document, the extraction
94301
+ // token's newlines will have been trimmed during processing. We need to
94302
+ // account for that here to ensure the token is found and replaced correctly.
94303
+ // These extra newlines will be removed again when the final string is trimmed.
94304
+ const content = `\n${replaced}\n`;
94305
+ const restoredContent = blocks.reduce((acc, { token, raw }) => {
94306
+ // Ensure each magic block is separated by newlines when restored.
94307
+ return acc.split(token).join(`\n${raw}\n`);
94056
94308
  }, content);
94309
+ return restoredContent.trim();
94057
94310
  }
94058
94311
 
94059
94312
  ;// ./lib/utils/mdxish/mdxish-load-components.ts
@@ -94112,6 +94365,9 @@ function loadComponents() {
94112
94365
 
94113
94366
 
94114
94367
 
94368
+
94369
+
94370
+
94115
94371
 
94116
94372
 
94117
94373
 
@@ -94129,10 +94385,15 @@ function mdxish(mdContent, opts = {}) {
94129
94385
  ...loadComponents(),
94130
94386
  ...userComponents,
94131
94387
  };
94132
- // Preprocess content: extract legacy magic blocks and evaluate JSX attribute expressions
94133
- const { replaced, blocks } = extractMagicBlocks(mdContent);
94134
- const processedContent = preprocessJSXExpressions(replaced, jsxContext);
94135
- // Create string map of components for tailwind transformer
94388
+ // Preprocessing pipeline: Transform content to be parser-ready
94389
+ // Step 1: Extract legacy magic blocks
94390
+ const { replaced: contentAfterMagicBlocks, blocks } = extractMagicBlocks(mdContent);
94391
+ // Step 2: Evaluate JSX expressions in attributes
94392
+ const contentAfterJSXEvaluation = preprocessJSXExpressions(contentAfterMagicBlocks, jsxContext);
94393
+ // Step 3: Replace snake_case component names with parser-safe placeholders
94394
+ // (e.g., <Snake_case /> → <MDXishSnakeCase0 /> which will be restored after parsing)
94395
+ const { content: parserReadyContent, mapping: snakeCaseMapping } = processSnakeCaseComponent(contentAfterJSXEvaluation);
94396
+ // Create string map for tailwind transformer
94136
94397
  const tempComponentsMap = Object.entries(components).reduce((acc, [key, value]) => {
94137
94398
  acc[key] = String(value);
94138
94399
  return acc;
@@ -94142,10 +94403,12 @@ function mdxish(mdContent, opts = {}) {
94142
94403
  .data('fromMarkdownExtensions', [mdxExpressionFromMarkdown()])
94143
94404
  .use(remarkParse)
94144
94405
  .use(remarkFrontmatter)
94406
+ .use(normalize_malformed_md_syntax)
94145
94407
  .use(mdxish_magic_blocks, { blocks })
94146
94408
  .use(transform_images, { isMdxish: true })
94147
94409
  .use(defaultTransformers)
94148
94410
  .use(mdxish_component_blocks)
94411
+ .use(restore_snake_case_component_name, { mapping: snakeCaseMapping })
94149
94412
  .use(mdxish_tables)
94150
94413
  .use(mdxish_html_blocks)
94151
94414
  .use(evaluate_expressions, { context: jsxContext }) // Evaluate MDX expressions using jsxContext
@@ -94159,8 +94422,8 @@ function mdxish(mdContent, opts = {}) {
94159
94422
  components,
94160
94423
  processMarkdown: (markdown) => mdxish(markdown, opts),
94161
94424
  });
94162
- const vfile = new VFile({ value: processedContent });
94163
- const hast = processor.runSync(processor.parse(processedContent), vfile);
94425
+ const vfile = new VFile({ value: parserReadyContent });
94426
+ const hast = processor.runSync(processor.parse(parserReadyContent), vfile);
94164
94427
  if (!hast) {
94165
94428
  throw new Error('Markdown pipeline did not produce a HAST tree.');
94166
94429
  }
@@ -94597,8 +94860,7 @@ const tags = (doc) => {
94597
94860
  const mdxishTags_tags = (doc) => {
94598
94861
  const { replaced: sanitizedDoc } = extractMagicBlocks(doc);
94599
94862
  const set = new Set();
94600
- const processor = remark()
94601
- .use(mdxish_component_blocks);
94863
+ const processor = remark().use(mdxish_component_blocks);
94602
94864
  const tree = processor.parse(sanitizedDoc);
94603
94865
  visit(processor.runSync(tree), isMDXElement, (node) => {
94604
94866
  if (node.name?.match(/^[A-Z]/)) {
@@ -94684,7 +94946,7 @@ async function stripComments(doc, { mdx } = {}) {
94684
94946
  // Our markdown renderer uses this to group these code blocks into a tabbed interface.
94685
94947
  (left, right) => {
94686
94948
  // 0 = no newline between blocks
94687
- return (left.type === 'code' && right.type === 'code') ? 0 : undefined;
94949
+ return left.type === 'code' && right.type === 'code' ? 0 : undefined;
94688
94950
  },
94689
94951
  ],
94690
94952
  });