@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.js
CHANGED
|
@@ -2030,7 +2030,7 @@ module.exports = function (it) {
|
|
|
2030
2030
|
|
|
2031
2031
|
"use strict";
|
|
2032
2032
|
|
|
2033
|
-
var create = __webpack_require__(
|
|
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
|
-
/***/
|
|
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__(
|
|
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__(
|
|
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-
|
|
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")
|
|
@@ -93699,6 +93676,10 @@ const parseInline = (text) => {
|
|
|
93699
93676
|
if (!text.trim())
|
|
93700
93677
|
return [{ type: 'text', value: '' }];
|
|
93701
93678
|
const tree = cellParser.runSync(cellParser.parse(text));
|
|
93679
|
+
// If there are multiple block-level nodes, keep them as-is to preserve the document structure and spacing
|
|
93680
|
+
if (tree.children.length > 1) {
|
|
93681
|
+
return tree.children;
|
|
93682
|
+
}
|
|
93702
93683
|
return tree.children.flatMap(n =>
|
|
93703
93684
|
// This unwraps the extra p node that might appear & wrapping the content
|
|
93704
93685
|
n.type === 'paragraph' && 'children' in n ? n.children : [n]);
|
|
@@ -93820,16 +93801,34 @@ function parseMagicBlock(raw, options = {}) {
|
|
|
93820
93801
|
const [icon, theme] = Array.isArray(resolvedType) ? resolvedType : ['👍', 'default'];
|
|
93821
93802
|
if (!(calloutJson.title || calloutJson.body))
|
|
93822
93803
|
return [];
|
|
93823
|
-
|
|
93824
|
-
|
|
93825
|
-
|
|
93826
|
-
|
|
93827
|
-
|
|
93828
|
-
|
|
93829
|
-
|
|
93830
|
-
|
|
93831
|
-
|
|
93832
|
-
|
|
93804
|
+
const titleBlocks = textToBlock(calloutJson.title || '');
|
|
93805
|
+
const bodyBlocks = textToBlock(calloutJson.body || '');
|
|
93806
|
+
const children = [];
|
|
93807
|
+
if (titleBlocks.length > 0 && titleBlocks[0].type === 'paragraph') {
|
|
93808
|
+
const firstTitle = titleBlocks[0];
|
|
93809
|
+
const heading = {
|
|
93810
|
+
type: 'heading',
|
|
93811
|
+
depth: 3,
|
|
93812
|
+
children: (firstTitle.children || []),
|
|
93813
|
+
};
|
|
93814
|
+
children.push(heading);
|
|
93815
|
+
children.push(...titleBlocks.slice(1), ...bodyBlocks);
|
|
93816
|
+
}
|
|
93817
|
+
else {
|
|
93818
|
+
children.push(...titleBlocks, ...bodyBlocks);
|
|
93819
|
+
}
|
|
93820
|
+
// Create mdxJsxFlowElement directly for mdxish
|
|
93821
|
+
const calloutElement = {
|
|
93822
|
+
type: 'mdxJsxFlowElement',
|
|
93823
|
+
name: 'Callout',
|
|
93824
|
+
attributes: toAttributes({ icon, theme: theme || 'default', type: theme || 'default' }, [
|
|
93825
|
+
'icon',
|
|
93826
|
+
'theme',
|
|
93827
|
+
'type',
|
|
93828
|
+
]),
|
|
93829
|
+
children: children,
|
|
93830
|
+
};
|
|
93831
|
+
return [wrapPinnedBlocks(calloutElement, json)];
|
|
93833
93832
|
}
|
|
93834
93833
|
// Parameters: renders as a table (used for API parameters, etc.)
|
|
93835
93834
|
case 'parameters': {
|
|
@@ -93903,6 +93902,25 @@ function parseMagicBlock(raw, options = {}) {
|
|
|
93903
93902
|
}, json),
|
|
93904
93903
|
];
|
|
93905
93904
|
}
|
|
93905
|
+
// Recipe/TutorialTile: renders as Recipe component
|
|
93906
|
+
case 'recipe':
|
|
93907
|
+
case 'tutorial-tile': {
|
|
93908
|
+
const recipeJson = json;
|
|
93909
|
+
if (!recipeJson.slug || !recipeJson.title)
|
|
93910
|
+
return [];
|
|
93911
|
+
// Create mdxJsxFlowElement directly for mdxish flow
|
|
93912
|
+
// Note: Don't wrap in pinned blocks for mdxish - rehypeMdxishComponents handles component resolution
|
|
93913
|
+
// The node structure matches what mdxishComponentBlocks creates for JSX tags
|
|
93914
|
+
const recipeNode = {
|
|
93915
|
+
type: 'mdxJsxFlowElement',
|
|
93916
|
+
name: 'Recipe',
|
|
93917
|
+
attributes: toAttributes(recipeJson, ['slug', 'title']),
|
|
93918
|
+
children: [],
|
|
93919
|
+
// Position is optional but helps with debugging
|
|
93920
|
+
position: undefined,
|
|
93921
|
+
};
|
|
93922
|
+
return [recipeNode];
|
|
93923
|
+
}
|
|
93906
93924
|
// Unknown block types: render as generic div with JSON properties
|
|
93907
93925
|
default: {
|
|
93908
93926
|
const text = json.text || json.html || '';
|
|
@@ -93912,6 +93930,12 @@ function parseMagicBlock(raw, options = {}) {
|
|
|
93912
93930
|
}
|
|
93913
93931
|
}
|
|
93914
93932
|
}
|
|
93933
|
+
/**
|
|
93934
|
+
* Check if a child node is a flow element that needs unwrapping (mdxJsxFlowElement, etc.)
|
|
93935
|
+
*/
|
|
93936
|
+
const needsUnwrapping = (child) => {
|
|
93937
|
+
return child.type === 'mdxJsxFlowElement';
|
|
93938
|
+
};
|
|
93915
93939
|
/**
|
|
93916
93940
|
* Unified plugin that restores magic blocks from placeholder tokens.
|
|
93917
93941
|
*
|
|
@@ -93925,21 +93949,271 @@ const magicBlockRestorer = ({ blocks }) => tree => {
|
|
|
93925
93949
|
// Map: key → original raw magic block content
|
|
93926
93950
|
const magicBlockKeys = new Map(blocks.map(({ key, raw }) => [key, raw]));
|
|
93927
93951
|
// Find inlineCode nodes that match our placeholder tokens
|
|
93952
|
+
const modifications = [];
|
|
93928
93953
|
visit(tree, 'inlineCode', (node, index, parent) => {
|
|
93929
93954
|
if (!parent || index == null)
|
|
93930
|
-
return;
|
|
93955
|
+
return undefined;
|
|
93931
93956
|
const raw = magicBlockKeys.get(node.value);
|
|
93932
93957
|
if (!raw)
|
|
93933
|
-
return;
|
|
93934
|
-
// Parse the original magic block and replace the placeholder with the result
|
|
93958
|
+
return undefined;
|
|
93935
93959
|
const children = parseMagicBlock(raw);
|
|
93936
93960
|
if (!children.length)
|
|
93937
|
-
return;
|
|
93961
|
+
return undefined;
|
|
93962
|
+
if (children[0] && needsUnwrapping(children[0]) && parent.type === 'paragraph') {
|
|
93963
|
+
// Find paragraph's parent and unwrap
|
|
93964
|
+
let paragraphParent;
|
|
93965
|
+
visit(tree, 'paragraph', (p, pIndex, pParent) => {
|
|
93966
|
+
if (p === parent && pParent && 'children' in pParent) {
|
|
93967
|
+
paragraphParent = pParent;
|
|
93968
|
+
return false;
|
|
93969
|
+
}
|
|
93970
|
+
return undefined;
|
|
93971
|
+
});
|
|
93972
|
+
if (paragraphParent) {
|
|
93973
|
+
const paragraphIndex = paragraphParent.children.indexOf(parent);
|
|
93974
|
+
if (paragraphIndex !== -1) {
|
|
93975
|
+
modifications.push({ children, index: paragraphIndex, parent: paragraphParent });
|
|
93976
|
+
}
|
|
93977
|
+
}
|
|
93978
|
+
return SKIP;
|
|
93979
|
+
}
|
|
93980
|
+
parent.children.splice(index, 1, ...children);
|
|
93981
|
+
return [SKIP, index + children.length];
|
|
93982
|
+
});
|
|
93983
|
+
// Apply modifications in reverse order to avoid index shifting
|
|
93984
|
+
modifications.reverse().forEach(({ children, index, parent }) => {
|
|
93938
93985
|
parent.children.splice(index, 1, ...children);
|
|
93939
93986
|
});
|
|
93940
93987
|
};
|
|
93941
93988
|
/* harmony default export */ const mdxish_magic_blocks = (magicBlockRestorer);
|
|
93942
93989
|
|
|
93990
|
+
;// ./lib/constants.ts
|
|
93991
|
+
/**
|
|
93992
|
+
* Pattern to match component tags (PascalCase or snake_case)
|
|
93993
|
+
*/
|
|
93994
|
+
const componentTagPattern = /<(\/?[A-Z][A-Za-z0-9_]*)([^>]*?)(\/?)>/g;
|
|
93995
|
+
|
|
93996
|
+
;// ./processor/transform/mdxish/mdxish-snake-case-components.ts
|
|
93997
|
+
|
|
93998
|
+
/**
|
|
93999
|
+
* Replaces snake_case component names with valid HTML placeholders.
|
|
94000
|
+
* Required because remark-parse rejects tags with underscores.
|
|
94001
|
+
* Example: `<Snake_case />` → `<MDXishSnakeCase0 />`
|
|
94002
|
+
*/
|
|
94003
|
+
function processSnakeCaseComponent(content) {
|
|
94004
|
+
// Early exit if no potential snake_case components
|
|
94005
|
+
if (!/[A-Z][A-Za-z0-9]*_[A-Za-z0-9_]*/.test(content)) {
|
|
94006
|
+
return { content, mapping: {} };
|
|
94007
|
+
}
|
|
94008
|
+
const mapping = {};
|
|
94009
|
+
const reverseMap = new Map();
|
|
94010
|
+
let counter = 0;
|
|
94011
|
+
const processedContent = content.replace(componentTagPattern, (match, tagName, attrs, selfClosing) => {
|
|
94012
|
+
if (!tagName.includes('_')) {
|
|
94013
|
+
return match;
|
|
94014
|
+
}
|
|
94015
|
+
const isClosing = tagName.startsWith('/');
|
|
94016
|
+
const cleanTagName = isClosing ? tagName.slice(1) : tagName;
|
|
94017
|
+
let placeholder = reverseMap.get(cleanTagName);
|
|
94018
|
+
if (!placeholder) {
|
|
94019
|
+
// eslint-disable-next-line no-plusplus
|
|
94020
|
+
placeholder = `MDXishSnakeCase${counter++}`;
|
|
94021
|
+
mapping[placeholder] = cleanTagName;
|
|
94022
|
+
reverseMap.set(cleanTagName, placeholder);
|
|
94023
|
+
}
|
|
94024
|
+
const processedTagName = isClosing ? `/${placeholder}` : placeholder;
|
|
94025
|
+
return `<${processedTagName}${attrs}${selfClosing}>`;
|
|
94026
|
+
});
|
|
94027
|
+
return {
|
|
94028
|
+
content: processedContent,
|
|
94029
|
+
mapping,
|
|
94030
|
+
};
|
|
94031
|
+
}
|
|
94032
|
+
/**
|
|
94033
|
+
* Restores placeholder name to original snake_case name.
|
|
94034
|
+
* Uses case-insensitive matching since HTML parsers normalize to lowercase.
|
|
94035
|
+
*/
|
|
94036
|
+
function restoreSnakeCase(placeholderName, mapping) {
|
|
94037
|
+
if (mapping[placeholderName]) {
|
|
94038
|
+
return mapping[placeholderName];
|
|
94039
|
+
}
|
|
94040
|
+
const lowerName = placeholderName.toLowerCase();
|
|
94041
|
+
const matchingKey = Object.keys(mapping).find(key => key.toLowerCase() === lowerName);
|
|
94042
|
+
return matchingKey ? mapping[matchingKey] : placeholderName;
|
|
94043
|
+
}
|
|
94044
|
+
|
|
94045
|
+
;// ./processor/transform/mdxish/normalize-malformed-md-syntax.ts
|
|
94046
|
+
|
|
94047
|
+
// Patterns to detect for bold (** and __) and italic (* and _) syntax:
|
|
94048
|
+
// Bold: ** text**, **text **, word** text**, ** text **
|
|
94049
|
+
// Italic: * text*, *text *, word* text*, * text *
|
|
94050
|
+
// Same patterns for underscore variants
|
|
94051
|
+
// We use separate patterns for each marker type to allow this flexibility.
|
|
94052
|
+
// Pattern for ** bold **
|
|
94053
|
+
// Groups: 1=wordBefore, 2=marker, 3=contentWithSpaceAfter, 4=trailingSpace1, 5=contentWithSpaceBefore, 6=trailingSpace2, 7=afterChar
|
|
94054
|
+
// trailingSpace1 is for "** text **" pattern, trailingSpace2 is for "**text **" pattern
|
|
94055
|
+
const asteriskBoldRegex = /([^*\s]+)?\s*(\*\*)(?:\s+((?:[^*\n]|\*(?!\*))+?)(\s*)\2|((?:[^*\n]|\*(?!\*))+?)(\s+)\2)(\S|$)?/g;
|
|
94056
|
+
// Pattern for __ bold __
|
|
94057
|
+
const underscoreBoldRegex = /([^_\s]+)?\s*(__)(?:\s+((?:[^_\n]|_(?!_))+?)(\s*)\2|((?:[^_\n]|_(?!_))+?)(\s+)\2)(\S|$)?/g;
|
|
94058
|
+
// Pattern for * italic *
|
|
94059
|
+
const asteriskItalicRegex = /([^*\s]+)?\s*(\*)(?!\*)(?:\s+([^*\n]+?)(\s*)\2|([^*\n]+?)(\s+)\2)(\S|$)?/g;
|
|
94060
|
+
// Pattern for _ italic _
|
|
94061
|
+
const underscoreItalicRegex = /([^_\s]+)?\s*(_)(?!_)(?:\s+([^_\n]+?)(\s*)\2|([^_\n]+?)(\s+)\2)(\S|$)?/g;
|
|
94062
|
+
/**
|
|
94063
|
+
* A remark plugin that normalizes malformed bold and italic markers in text nodes.
|
|
94064
|
+
* Detects patterns like `** bold**`, `Hello** Wrong Bold**`, `__ bold__`, `Hello__ Wrong Bold__`,
|
|
94065
|
+
* `* italic*`, `Hello* Wrong Italic*`, `_ italic_`, or `Hello_ Wrong Italic_`
|
|
94066
|
+
* and converts them to proper strong/emphasis nodes, matching the behavior of the legacy rdmd engine.
|
|
94067
|
+
*
|
|
94068
|
+
* Supports both asterisk (`**bold**`, `*italic*`) and underscore (`__bold__`, `_italic_`) syntax.
|
|
94069
|
+
* Also supports snake_case content like `** some_snake_case**`.
|
|
94070
|
+
*
|
|
94071
|
+
* This runs after remark-parse, which (in v11+) is strict and doesn't parse
|
|
94072
|
+
* malformed emphasis syntax. This plugin post-processes the AST to handle these cases.
|
|
94073
|
+
*/
|
|
94074
|
+
const normalizeEmphasisAST = () => (tree) => {
|
|
94075
|
+
visit(tree, 'text', function visitor(node, index, parent) {
|
|
94076
|
+
if (index === undefined || !parent)
|
|
94077
|
+
return undefined;
|
|
94078
|
+
// Skip if inside code blocks or inline code
|
|
94079
|
+
if (parent.type === 'inlineCode' || parent.type === 'code') {
|
|
94080
|
+
return undefined;
|
|
94081
|
+
}
|
|
94082
|
+
const text = node.value;
|
|
94083
|
+
const allMatches = [];
|
|
94084
|
+
[...text.matchAll(asteriskBoldRegex)].forEach(match => {
|
|
94085
|
+
allMatches.push({ isBold: true, marker: '**', match });
|
|
94086
|
+
});
|
|
94087
|
+
[...text.matchAll(underscoreBoldRegex)].forEach(match => {
|
|
94088
|
+
allMatches.push({ isBold: true, marker: '__', match });
|
|
94089
|
+
});
|
|
94090
|
+
[...text.matchAll(asteriskItalicRegex)].forEach(match => {
|
|
94091
|
+
allMatches.push({ isBold: false, marker: '*', match });
|
|
94092
|
+
});
|
|
94093
|
+
[...text.matchAll(underscoreItalicRegex)].forEach(match => {
|
|
94094
|
+
allMatches.push({ isBold: false, marker: '_', match });
|
|
94095
|
+
});
|
|
94096
|
+
if (allMatches.length === 0)
|
|
94097
|
+
return undefined;
|
|
94098
|
+
allMatches.sort((a, b) => (a.match.index ?? 0) - (b.match.index ?? 0));
|
|
94099
|
+
const filteredMatches = [];
|
|
94100
|
+
let lastEnd = 0;
|
|
94101
|
+
allMatches.forEach(info => {
|
|
94102
|
+
const start = info.match.index ?? 0;
|
|
94103
|
+
const end = start + info.match[0].length;
|
|
94104
|
+
if (start >= lastEnd) {
|
|
94105
|
+
filteredMatches.push(info);
|
|
94106
|
+
lastEnd = end;
|
|
94107
|
+
}
|
|
94108
|
+
});
|
|
94109
|
+
if (filteredMatches.length === 0)
|
|
94110
|
+
return undefined;
|
|
94111
|
+
const parts = [];
|
|
94112
|
+
let lastIndex = 0;
|
|
94113
|
+
filteredMatches.forEach(({ match, marker, isBold }) => {
|
|
94114
|
+
const matchIndex = match.index ?? 0;
|
|
94115
|
+
const fullMatch = match[0];
|
|
94116
|
+
if (matchIndex > lastIndex) {
|
|
94117
|
+
const beforeText = text.slice(lastIndex, matchIndex);
|
|
94118
|
+
if (beforeText) {
|
|
94119
|
+
parts.push({ type: 'text', value: beforeText });
|
|
94120
|
+
}
|
|
94121
|
+
}
|
|
94122
|
+
const wordBefore = match[1]; // e.g., "Hello" in "Hello** Wrong Bold**"
|
|
94123
|
+
const contentWithSpaceAfter = match[3]; // Content when there's a space after opening markers
|
|
94124
|
+
const trailingSpace1 = match[4] || ''; // Space before closing markers (for "** text **" pattern)
|
|
94125
|
+
const contentWithSpaceBefore = match[5]; // Content when there's only a space before closing markers
|
|
94126
|
+
const trailingSpace2 = match[6] || ''; // Space before closing markers (for "**text **" pattern)
|
|
94127
|
+
const trailingSpace = trailingSpace1 || trailingSpace2; // Combined trailing space
|
|
94128
|
+
const content = (contentWithSpaceAfter || contentWithSpaceBefore || '').trim();
|
|
94129
|
+
const afterChar = match[7]; // Character after closing markers (if any)
|
|
94130
|
+
const markerPos = fullMatch.indexOf(marker);
|
|
94131
|
+
const spacesBeforeMarkers = wordBefore
|
|
94132
|
+
? fullMatch.slice(wordBefore.length, markerPos)
|
|
94133
|
+
: fullMatch.slice(0, markerPos);
|
|
94134
|
+
const shouldAddSpace = !!contentWithSpaceAfter && !!wordBefore && !spacesBeforeMarkers;
|
|
94135
|
+
if (wordBefore) {
|
|
94136
|
+
const spacing = spacesBeforeMarkers + (shouldAddSpace ? ' ' : '');
|
|
94137
|
+
parts.push({ type: 'text', value: wordBefore + spacing });
|
|
94138
|
+
}
|
|
94139
|
+
else if (spacesBeforeMarkers) {
|
|
94140
|
+
parts.push({ type: 'text', value: spacesBeforeMarkers });
|
|
94141
|
+
}
|
|
94142
|
+
if (content) {
|
|
94143
|
+
if (isBold) {
|
|
94144
|
+
parts.push({
|
|
94145
|
+
type: 'strong',
|
|
94146
|
+
children: [{ type: 'text', value: content }],
|
|
94147
|
+
});
|
|
94148
|
+
}
|
|
94149
|
+
else {
|
|
94150
|
+
parts.push({
|
|
94151
|
+
type: 'emphasis',
|
|
94152
|
+
children: [{ type: 'text', value: content }],
|
|
94153
|
+
});
|
|
94154
|
+
}
|
|
94155
|
+
}
|
|
94156
|
+
if (afterChar) {
|
|
94157
|
+
const prefix = trailingSpace ? ' ' : '';
|
|
94158
|
+
parts.push({ type: 'text', value: prefix + afterChar });
|
|
94159
|
+
}
|
|
94160
|
+
lastIndex = matchIndex + fullMatch.length;
|
|
94161
|
+
});
|
|
94162
|
+
if (lastIndex < text.length) {
|
|
94163
|
+
const remainingText = text.slice(lastIndex);
|
|
94164
|
+
if (remainingText) {
|
|
94165
|
+
parts.push({ type: 'text', value: remainingText });
|
|
94166
|
+
}
|
|
94167
|
+
}
|
|
94168
|
+
if (parts.length > 0) {
|
|
94169
|
+
parent.children.splice(index, 1, ...parts);
|
|
94170
|
+
return [SKIP, index + parts.length];
|
|
94171
|
+
}
|
|
94172
|
+
return undefined;
|
|
94173
|
+
});
|
|
94174
|
+
return tree;
|
|
94175
|
+
};
|
|
94176
|
+
/* harmony default export */ const normalize_malformed_md_syntax = (normalizeEmphasisAST);
|
|
94177
|
+
|
|
94178
|
+
;// ./processor/transform/mdxish/restore-snake-case-component-name.ts
|
|
94179
|
+
|
|
94180
|
+
|
|
94181
|
+
/**
|
|
94182
|
+
* Restores snake_case component names from placeholders after parsing.
|
|
94183
|
+
* Runs after mdxishComponentBlocks converts HTML nodes to mdxJsxFlowElement.
|
|
94184
|
+
*/
|
|
94185
|
+
const restoreSnakeCaseComponentNames = (options) => {
|
|
94186
|
+
const { mapping } = options;
|
|
94187
|
+
return tree => {
|
|
94188
|
+
if (!mapping || Object.keys(mapping).length === 0) {
|
|
94189
|
+
return tree;
|
|
94190
|
+
}
|
|
94191
|
+
visit(tree, 'mdxJsxFlowElement', (node) => {
|
|
94192
|
+
if (node.name) {
|
|
94193
|
+
node.name = restoreSnakeCase(node.name, mapping);
|
|
94194
|
+
}
|
|
94195
|
+
});
|
|
94196
|
+
// Pre-compile regex patterns for better performance
|
|
94197
|
+
const regexPatterns = Object.entries(mapping).map(([placeholder, original]) => ({
|
|
94198
|
+
regex: new RegExp(`(<\\/?)(${placeholder})(\\s|\\/?>)`, 'gi'),
|
|
94199
|
+
original,
|
|
94200
|
+
}));
|
|
94201
|
+
visit(tree, 'html', (node) => {
|
|
94202
|
+
if (node.value) {
|
|
94203
|
+
let newValue = node.value;
|
|
94204
|
+
regexPatterns.forEach(({ regex, original }) => {
|
|
94205
|
+
newValue = newValue.replace(regex, `$1${original}$3`);
|
|
94206
|
+
});
|
|
94207
|
+
if (newValue !== node.value) {
|
|
94208
|
+
node.value = newValue;
|
|
94209
|
+
}
|
|
94210
|
+
}
|
|
94211
|
+
});
|
|
94212
|
+
return tree;
|
|
94213
|
+
};
|
|
94214
|
+
};
|
|
94215
|
+
/* harmony default export */ const restore_snake_case_component_name = (restoreSnakeCaseComponentNames);
|
|
94216
|
+
|
|
93943
94217
|
;// ./processor/transform/mdxish/variables-text.ts
|
|
93944
94218
|
|
|
93945
94219
|
|
|
@@ -94025,14 +94299,17 @@ function extractMagicBlocks(markdown) {
|
|
|
94025
94299
|
const replaced = markdown.replace(MAGIC_BLOCK_REGEX, match => {
|
|
94026
94300
|
/**
|
|
94027
94301
|
* 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
94302
|
*/
|
|
94034
94303
|
const key = `__MAGIC_BLOCK_${index}__`;
|
|
94035
|
-
|
|
94304
|
+
/**
|
|
94305
|
+
* Token is a wrapper around the `key` to serialize & influence how the
|
|
94306
|
+
* magic block is parsed in the remark pipeline.
|
|
94307
|
+
* - Use backticks so it becomes a code span, preventing `remarkParse` from
|
|
94308
|
+
* parsing special characters in the token as markdown syntax
|
|
94309
|
+
* - Prepend a newline to ensure it is parsed as a block level node
|
|
94310
|
+
* - Append a newline to ensure it is separated from following content
|
|
94311
|
+
*/
|
|
94312
|
+
const token = `\n\`${key}\`\n`;
|
|
94036
94313
|
blocks.push({ key, raw: match, token });
|
|
94037
94314
|
index += 1;
|
|
94038
94315
|
return token;
|
|
@@ -94043,17 +94320,16 @@ function extractMagicBlocks(markdown) {
|
|
|
94043
94320
|
* Restore extracted magic blocks back into a markdown string.
|
|
94044
94321
|
*/
|
|
94045
94322
|
function restoreMagicBlocks(replaced, blocks) {
|
|
94046
|
-
|
|
94047
|
-
//
|
|
94048
|
-
//
|
|
94049
|
-
//
|
|
94050
|
-
const
|
|
94051
|
-
|
|
94052
|
-
|
|
94053
|
-
|
|
94054
|
-
return blocks.reduce((acc, { token, raw }) => {
|
|
94055
|
-
return acc.split(token).join(raw);
|
|
94323
|
+
// If a magic block is at the start or end of the document, the extraction
|
|
94324
|
+
// token's newlines will have been trimmed during processing. We need to
|
|
94325
|
+
// account for that here to ensure the token is found and replaced correctly.
|
|
94326
|
+
// These extra newlines will be removed again when the final string is trimmed.
|
|
94327
|
+
const content = `\n${replaced}\n`;
|
|
94328
|
+
const restoredContent = blocks.reduce((acc, { token, raw }) => {
|
|
94329
|
+
// Ensure each magic block is separated by newlines when restored.
|
|
94330
|
+
return acc.split(token).join(`\n${raw}\n`);
|
|
94056
94331
|
}, content);
|
|
94332
|
+
return restoredContent.trim();
|
|
94057
94333
|
}
|
|
94058
94334
|
|
|
94059
94335
|
;// ./lib/utils/mdxish/mdxish-load-components.ts
|
|
@@ -94112,6 +94388,9 @@ function loadComponents() {
|
|
|
94112
94388
|
|
|
94113
94389
|
|
|
94114
94390
|
|
|
94391
|
+
|
|
94392
|
+
|
|
94393
|
+
|
|
94115
94394
|
|
|
94116
94395
|
|
|
94117
94396
|
|
|
@@ -94129,10 +94408,15 @@ function mdxish(mdContent, opts = {}) {
|
|
|
94129
94408
|
...loadComponents(),
|
|
94130
94409
|
...userComponents,
|
|
94131
94410
|
};
|
|
94132
|
-
//
|
|
94133
|
-
|
|
94134
|
-
const
|
|
94135
|
-
//
|
|
94411
|
+
// Preprocessing pipeline: Transform content to be parser-ready
|
|
94412
|
+
// Step 1: Extract legacy magic blocks
|
|
94413
|
+
const { replaced: contentAfterMagicBlocks, blocks } = extractMagicBlocks(mdContent);
|
|
94414
|
+
// Step 2: Evaluate JSX expressions in attributes
|
|
94415
|
+
const contentAfterJSXEvaluation = preprocessJSXExpressions(contentAfterMagicBlocks, jsxContext);
|
|
94416
|
+
// Step 3: Replace snake_case component names with parser-safe placeholders
|
|
94417
|
+
// (e.g., <Snake_case /> → <MDXishSnakeCase0 /> which will be restored after parsing)
|
|
94418
|
+
const { content: parserReadyContent, mapping: snakeCaseMapping } = processSnakeCaseComponent(contentAfterJSXEvaluation);
|
|
94419
|
+
// Create string map for tailwind transformer
|
|
94136
94420
|
const tempComponentsMap = Object.entries(components).reduce((acc, [key, value]) => {
|
|
94137
94421
|
acc[key] = String(value);
|
|
94138
94422
|
return acc;
|
|
@@ -94142,10 +94426,12 @@ function mdxish(mdContent, opts = {}) {
|
|
|
94142
94426
|
.data('fromMarkdownExtensions', [mdxExpressionFromMarkdown()])
|
|
94143
94427
|
.use(remarkParse)
|
|
94144
94428
|
.use(remarkFrontmatter)
|
|
94429
|
+
.use(normalize_malformed_md_syntax)
|
|
94145
94430
|
.use(mdxish_magic_blocks, { blocks })
|
|
94146
94431
|
.use(transform_images, { isMdxish: true })
|
|
94147
94432
|
.use(defaultTransformers)
|
|
94148
94433
|
.use(mdxish_component_blocks)
|
|
94434
|
+
.use(restore_snake_case_component_name, { mapping: snakeCaseMapping })
|
|
94149
94435
|
.use(mdxish_tables)
|
|
94150
94436
|
.use(mdxish_html_blocks)
|
|
94151
94437
|
.use(evaluate_expressions, { context: jsxContext }) // Evaluate MDX expressions using jsxContext
|
|
@@ -94159,8 +94445,8 @@ function mdxish(mdContent, opts = {}) {
|
|
|
94159
94445
|
components,
|
|
94160
94446
|
processMarkdown: (markdown) => mdxish(markdown, opts),
|
|
94161
94447
|
});
|
|
94162
|
-
const vfile = new VFile({ value:
|
|
94163
|
-
const hast = processor.runSync(processor.parse(
|
|
94448
|
+
const vfile = new VFile({ value: parserReadyContent });
|
|
94449
|
+
const hast = processor.runSync(processor.parse(parserReadyContent), vfile);
|
|
94164
94450
|
if (!hast) {
|
|
94165
94451
|
throw new Error('Markdown pipeline did not produce a HAST tree.');
|
|
94166
94452
|
}
|
|
@@ -94597,8 +94883,7 @@ const tags = (doc) => {
|
|
|
94597
94883
|
const mdxishTags_tags = (doc) => {
|
|
94598
94884
|
const { replaced: sanitizedDoc } = extractMagicBlocks(doc);
|
|
94599
94885
|
const set = new Set();
|
|
94600
|
-
const processor = remark()
|
|
94601
|
-
.use(mdxish_component_blocks);
|
|
94886
|
+
const processor = remark().use(mdxish_component_blocks);
|
|
94602
94887
|
const tree = processor.parse(sanitizedDoc);
|
|
94603
94888
|
visit(processor.runSync(tree), isMDXElement, (node) => {
|
|
94604
94889
|
if (node.name?.match(/^[A-Z]/)) {
|
|
@@ -94684,7 +94969,7 @@ async function stripComments(doc, { mdx } = {}) {
|
|
|
94684
94969
|
// Our markdown renderer uses this to group these code blocks into a tabbed interface.
|
|
94685
94970
|
(left, right) => {
|
|
94686
94971
|
// 0 = no newline between blocks
|
|
94687
|
-
return
|
|
94972
|
+
return left.type === 'code' && right.type === 'code' ? 0 : undefined;
|
|
94688
94973
|
},
|
|
94689
94974
|
],
|
|
94690
94975
|
});
|