@readme/markdown 13.7.1 → 13.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/CodeTabs/index.tsx +62 -19
- package/components/TailwindStyle/index.tsx +18 -7
- package/dist/lib/mdxish.d.ts +1 -1
- package/dist/main.js +708 -444
- package/dist/main.node.js +708 -444
- package/dist/main.node.js.map +1 -1
- package/dist/processor/transform/mdxish/mdxish-tables-to-jsx.d.ts +11 -0
- package/package.json +2 -2
package/dist/main.node.js
CHANGED
|
@@ -19358,10 +19358,47 @@ var dist_utils_default = /*#__PURE__*/__webpack_require__.n(dist_utils);
|
|
|
19358
19358
|
|
|
19359
19359
|
let mermaid;
|
|
19360
19360
|
const { uppercase } = (dist_utils_default());
|
|
19361
|
+
// Module-level queue that batches mermaid nodes across all CodeTabs instances into a
|
|
19362
|
+
// single mermaid.run() call. This is necessary because mermaid generates SVG element IDs
|
|
19363
|
+
// using Date.now(), which collides when multiple diagrams render in the same millisecond.
|
|
19364
|
+
// Colliding IDs cause diagrams to overlap or break layout.
|
|
19365
|
+
//
|
|
19366
|
+
// Why not use `deterministicIDSeed` with a unique ID per diagram? Mermaid's implementation
|
|
19367
|
+
// only uses seed.length (not the seed value) to compute the starting ID, so every UUID
|
|
19368
|
+
// (36 chars) produces the same `mermaid-36` prefix — the collision remains.
|
|
19369
|
+
// See: https://github.com/mermaid-js/mermaid/blob/mermaid%4011.12.0/packages/mermaid/src/utils.ts#L755-L761
|
|
19370
|
+
//
|
|
19371
|
+
// These vars must be module-scoped (not per-instance refs) because the batching requires
|
|
19372
|
+
// cross-instance coordination. They are short-lived: the queue drains on the next macrotask
|
|
19373
|
+
// and cleanup clears everything on unmount.
|
|
19374
|
+
let mermaidQueue = [];
|
|
19375
|
+
let mermaidFlushTimer = null;
|
|
19376
|
+
let currentTheme;
|
|
19377
|
+
function queueMermaidNode(node, theme) {
|
|
19378
|
+
mermaidQueue.push(node);
|
|
19379
|
+
currentTheme = theme;
|
|
19380
|
+
if (!mermaidFlushTimer) {
|
|
19381
|
+
// setTimeout(0) defers to a macrotask, after all useEffects have queued their nodes
|
|
19382
|
+
mermaidFlushTimer = setTimeout(async () => {
|
|
19383
|
+
const nodes = [...mermaidQueue];
|
|
19384
|
+
mermaidQueue = [];
|
|
19385
|
+
mermaidFlushTimer = null;
|
|
19386
|
+
const module = await __webpack_require__.e(/* import() */ 486).then(__webpack_require__.bind(__webpack_require__, 5486));
|
|
19387
|
+
mermaid = module.default;
|
|
19388
|
+
mermaid.initialize({
|
|
19389
|
+
startOnLoad: false,
|
|
19390
|
+
theme: currentTheme === 'dark' ? 'dark' : 'default',
|
|
19391
|
+
deterministicIds: true,
|
|
19392
|
+
});
|
|
19393
|
+
await mermaid.run({ nodes });
|
|
19394
|
+
}, 0);
|
|
19395
|
+
}
|
|
19396
|
+
}
|
|
19361
19397
|
const CodeTabs = (props) => {
|
|
19362
19398
|
const { children } = props;
|
|
19363
19399
|
const theme = (0,external_react_.useContext)(Theme);
|
|
19364
19400
|
const isHydrated = useHydrated();
|
|
19401
|
+
const mermaidRef = (0,external_react_.useRef)(null);
|
|
19365
19402
|
// Handle both array (from rehype-react in rendering mdxish) and single element (MDX/JSX runtime) cases
|
|
19366
19403
|
// The children here is the individual code block objects
|
|
19367
19404
|
const childrenArray = Array.isArray(children) ? children : [children];
|
|
@@ -19372,22 +19409,20 @@ const CodeTabs = (props) => {
|
|
|
19372
19409
|
return Array.isArray(pre?.props?.children) ? pre.props.children[0] : pre?.props?.children;
|
|
19373
19410
|
};
|
|
19374
19411
|
const containAtLeastOneMermaid = childrenArray.some(pre => getCodeComponent(pre)?.props?.lang === 'mermaid');
|
|
19375
|
-
// Render Mermaid diagram
|
|
19376
19412
|
(0,external_react_.useEffect)(() => {
|
|
19377
|
-
//
|
|
19378
|
-
|
|
19379
|
-
|
|
19380
|
-
|
|
19381
|
-
|
|
19382
|
-
|
|
19383
|
-
|
|
19384
|
-
|
|
19385
|
-
|
|
19386
|
-
|
|
19387
|
-
|
|
19388
|
-
|
|
19389
|
-
|
|
19390
|
-
}
|
|
19413
|
+
// Wait for hydration so mermaid's DOM mutations don't cause mismatches
|
|
19414
|
+
if (typeof window !== 'undefined' && containAtLeastOneMermaid && isHydrated && mermaidRef.current) {
|
|
19415
|
+
queueMermaidNode(mermaidRef.current, theme);
|
|
19416
|
+
}
|
|
19417
|
+
return () => {
|
|
19418
|
+
// Clear the batch timer on unmount to prevent mermaid from running
|
|
19419
|
+
// after the DOM is torn down
|
|
19420
|
+
if (mermaidFlushTimer) {
|
|
19421
|
+
clearTimeout(mermaidFlushTimer);
|
|
19422
|
+
mermaidFlushTimer = null;
|
|
19423
|
+
mermaidQueue = [];
|
|
19424
|
+
}
|
|
19425
|
+
};
|
|
19391
19426
|
}, [containAtLeastOneMermaid, theme, isHydrated]);
|
|
19392
19427
|
function handleClick({ target }, index) {
|
|
19393
19428
|
const $wrap = target.parentElement.parentElement;
|
|
@@ -19403,15 +19438,13 @@ const CodeTabs = (props) => {
|
|
|
19403
19438
|
const codeComponent = getCodeComponent(childrenArray[0]);
|
|
19404
19439
|
if (codeComponent?.props?.lang === 'mermaid') {
|
|
19405
19440
|
const value = codeComponent?.props?.value;
|
|
19406
|
-
return external_react_default().createElement("pre", { className: "mermaid-render mermaid_single" }, value);
|
|
19441
|
+
return (external_react_default().createElement("pre", { ref: mermaidRef, className: "mermaid-render mermaid_single" }, value));
|
|
19407
19442
|
}
|
|
19408
19443
|
}
|
|
19409
19444
|
return (external_react_default().createElement("div", { className: `CodeTabs CodeTabs_initial theme-${theme}` },
|
|
19410
19445
|
external_react_default().createElement("div", { className: "CodeTabs-toolbar" }, childrenArray.map((pre, i) => {
|
|
19411
19446
|
// the first or only child should be our Code component
|
|
19412
|
-
const tabCodeComponent = Array.isArray(pre.props?.children)
|
|
19413
|
-
? pre.props.children[0]
|
|
19414
|
-
: pre.props?.children;
|
|
19447
|
+
const tabCodeComponent = Array.isArray(pre.props?.children) ? pre.props.children[0] : pre.props?.children;
|
|
19415
19448
|
const lang = tabCodeComponent?.props?.lang;
|
|
19416
19449
|
const meta = tabCodeComponent?.props?.meta;
|
|
19417
19450
|
/* istanbul ignore next */
|
|
@@ -24905,10 +24938,19 @@ const TailwindStyle = ({ children, darkModeDataAttribute }) => {
|
|
|
24905
24938
|
records.forEach(record => {
|
|
24906
24939
|
if (record.type === 'childList') {
|
|
24907
24940
|
record.addedNodes.forEach(node => {
|
|
24908
|
-
if (!(node instanceof HTMLElement)
|
|
24941
|
+
if (!(node instanceof HTMLElement))
|
|
24909
24942
|
return;
|
|
24910
|
-
|
|
24911
|
-
|
|
24943
|
+
// Check the added node itself
|
|
24944
|
+
if (node.classList.contains(tailwindPrefix)) {
|
|
24945
|
+
traverse(node, addClasses);
|
|
24946
|
+
shouldUpdate = true;
|
|
24947
|
+
}
|
|
24948
|
+
// Also check descendants — React may insert a parent node
|
|
24949
|
+
// whose children contain TailwindRoot elements
|
|
24950
|
+
node.querySelectorAll(`.${tailwindPrefix}`).forEach(child => {
|
|
24951
|
+
traverse(child, addClasses);
|
|
24952
|
+
shouldUpdate = true;
|
|
24953
|
+
});
|
|
24912
24954
|
});
|
|
24913
24955
|
}
|
|
24914
24956
|
else if (record.type === 'attributes') {
|
|
@@ -24917,10 +24959,10 @@ const TailwindStyle = ({ children, darkModeDataAttribute }) => {
|
|
|
24917
24959
|
addClasses(record.target);
|
|
24918
24960
|
shouldUpdate = true;
|
|
24919
24961
|
}
|
|
24920
|
-
if (shouldUpdate) {
|
|
24921
|
-
setClasses(Array.from(classesSet.current));
|
|
24922
|
-
}
|
|
24923
24962
|
});
|
|
24963
|
+
if (shouldUpdate) {
|
|
24964
|
+
setClasses(Array.from(classesSet.current));
|
|
24965
|
+
}
|
|
24924
24966
|
});
|
|
24925
24967
|
observer.observe(ref.current.parentElement, {
|
|
24926
24968
|
subtree: true,
|
|
@@ -90604,9 +90646,416 @@ const mdast = (text, opts = {}) => {
|
|
|
90604
90646
|
};
|
|
90605
90647
|
/* harmony default export */ const lib_mdast = (mdast);
|
|
90606
90648
|
|
|
90649
|
+
;// ./lib/utils/mdxish/protect-code-blocks.ts
|
|
90650
|
+
/**
|
|
90651
|
+
* Replaces code blocks and inline code with placeholders to protect them from preprocessing.
|
|
90652
|
+
*
|
|
90653
|
+
* @param content - The markdown content to process
|
|
90654
|
+
* @returns Object containing protected content and arrays of original code blocks
|
|
90655
|
+
* @example
|
|
90656
|
+
* ```typescript
|
|
90657
|
+
* const input = 'Text with `inline code` and ```fenced block```';
|
|
90658
|
+
* protectCodeBlocks(input)
|
|
90659
|
+
* // Returns: {
|
|
90660
|
+
* // protectedCode: {
|
|
90661
|
+
* // codeBlocks: ['```fenced block```'],
|
|
90662
|
+
* // inlineCode: ['`inline code`']
|
|
90663
|
+
* // },
|
|
90664
|
+
* // protectedContent: 'Text with ___INLINE_CODE_0___ and ___CODE_BLOCK_0___'
|
|
90665
|
+
* // }
|
|
90666
|
+
* ```
|
|
90667
|
+
*/
|
|
90668
|
+
function protectCodeBlocks(content) {
|
|
90669
|
+
const codeBlocks = [];
|
|
90670
|
+
const inlineCode = [];
|
|
90671
|
+
let protectedContent = '';
|
|
90672
|
+
let remaining = content;
|
|
90673
|
+
let codeBlockStart = remaining.indexOf('```');
|
|
90674
|
+
while (codeBlockStart !== -1) {
|
|
90675
|
+
protectedContent += remaining.slice(0, codeBlockStart);
|
|
90676
|
+
remaining = remaining.slice(codeBlockStart);
|
|
90677
|
+
const codeBlockEnd = remaining.indexOf('```', 3);
|
|
90678
|
+
if (codeBlockEnd === -1) {
|
|
90679
|
+
break;
|
|
90680
|
+
}
|
|
90681
|
+
const match = remaining.slice(0, codeBlockEnd + 3);
|
|
90682
|
+
const index = codeBlocks.length;
|
|
90683
|
+
codeBlocks.push(match);
|
|
90684
|
+
protectedContent += `___CODE_BLOCK_${index}___`;
|
|
90685
|
+
remaining = remaining.slice(codeBlockEnd + 3);
|
|
90686
|
+
codeBlockStart = remaining.indexOf('```');
|
|
90687
|
+
}
|
|
90688
|
+
protectedContent += remaining;
|
|
90689
|
+
protectedContent = protectedContent.replace(/`([^`\n]+)`/g, match => {
|
|
90690
|
+
const index = inlineCode.length;
|
|
90691
|
+
inlineCode.push(match);
|
|
90692
|
+
return `___INLINE_CODE_${index}___`;
|
|
90693
|
+
});
|
|
90694
|
+
return { protectedCode: { codeBlocks, inlineCode }, protectedContent };
|
|
90695
|
+
}
|
|
90696
|
+
/**
|
|
90697
|
+
* Restores inline code by replacing placeholders with original content.
|
|
90698
|
+
*
|
|
90699
|
+
* @param content - Content with inline code placeholders
|
|
90700
|
+
* @param protectedCode - The protected code arrays
|
|
90701
|
+
* @returns Content with inline code restored
|
|
90702
|
+
*/
|
|
90703
|
+
function restoreInlineCode(content, protectedCode) {
|
|
90704
|
+
return content.replace(/___INLINE_CODE_(\d+)___/g, (_m, idx) => {
|
|
90705
|
+
return protectedCode.inlineCode[parseInt(idx, 10)];
|
|
90706
|
+
});
|
|
90707
|
+
}
|
|
90708
|
+
/**
|
|
90709
|
+
* Restores fenced code blocks by replacing placeholders with original content.
|
|
90710
|
+
*
|
|
90711
|
+
* @param content - Content with code block placeholders
|
|
90712
|
+
* @param protectedCode - The protected code arrays
|
|
90713
|
+
* @returns Content with code blocks restored
|
|
90714
|
+
*/
|
|
90715
|
+
function restoreFencedCodeBlocks(content, protectedCode) {
|
|
90716
|
+
return content.replace(/___CODE_BLOCK_(\d+)___/g, (_m, idx) => {
|
|
90717
|
+
return protectedCode.codeBlocks[parseInt(idx, 10)];
|
|
90718
|
+
});
|
|
90719
|
+
}
|
|
90720
|
+
/**
|
|
90721
|
+
* Restores all code blocks and inline code by replacing placeholders with original content.
|
|
90722
|
+
*
|
|
90723
|
+
* @param content - Content with code placeholders
|
|
90724
|
+
* @param protectedCode - The protected code arrays
|
|
90725
|
+
* @returns Content with all code blocks and inline code restored
|
|
90726
|
+
* @example
|
|
90727
|
+
* ```typescript
|
|
90728
|
+
* const content = 'Text with ___INLINE_CODE_0___ and ___CODE_BLOCK_0___';
|
|
90729
|
+
* const protectedCode = {
|
|
90730
|
+
* codeBlocks: ['```js\ncode\n```'],
|
|
90731
|
+
* inlineCode: ['`inline`']
|
|
90732
|
+
* };
|
|
90733
|
+
* restoreCodeBlocks(content, protectedCode)
|
|
90734
|
+
* // Returns: 'Text with `inline` and ```js\ncode\n```'
|
|
90735
|
+
* ```
|
|
90736
|
+
*/
|
|
90737
|
+
function restoreCodeBlocks(content, protectedCode) {
|
|
90738
|
+
let restored = restoreFencedCodeBlocks(content, protectedCode);
|
|
90739
|
+
restored = restoreInlineCode(restored, protectedCode);
|
|
90740
|
+
return restored;
|
|
90741
|
+
}
|
|
90742
|
+
|
|
90743
|
+
;// ./processor/transform/mdxish/preprocess-jsx-expressions.ts
|
|
90744
|
+
|
|
90745
|
+
// Base64 encode (Node.js + browser compatible)
|
|
90746
|
+
function base64Encode(str) {
|
|
90747
|
+
if (typeof Buffer !== 'undefined') {
|
|
90748
|
+
return Buffer.from(str, 'utf-8').toString('base64');
|
|
90749
|
+
}
|
|
90750
|
+
return btoa(unescape(encodeURIComponent(str)));
|
|
90751
|
+
}
|
|
90752
|
+
// Base64 decode (Node.js + browser compatible)
|
|
90753
|
+
function base64Decode(str) {
|
|
90754
|
+
if (typeof Buffer !== 'undefined') {
|
|
90755
|
+
return Buffer.from(str, 'base64').toString('utf-8');
|
|
90756
|
+
}
|
|
90757
|
+
return decodeURIComponent(escape(atob(str)));
|
|
90758
|
+
}
|
|
90759
|
+
function escapeHtmlAttribute(value) {
|
|
90760
|
+
return value
|
|
90761
|
+
.replace(/&/g, '&')
|
|
90762
|
+
.replace(/"/g, '"')
|
|
90763
|
+
.replace(/</g, '<')
|
|
90764
|
+
.replace(/>/g, '>')
|
|
90765
|
+
.replace(/\n/g, ' ');
|
|
90766
|
+
}
|
|
90767
|
+
// Marker prefix for JSON-serialized complex values (arrays/objects)
|
|
90768
|
+
// Using a prefix that won't conflict with regular string values
|
|
90769
|
+
const JSON_VALUE_MARKER = '__MDXISH_JSON__';
|
|
90770
|
+
// Markers for protected HTMLBlock content (HTML comments avoid markdown parsing issues)
|
|
90771
|
+
const HTML_BLOCK_CONTENT_START = '<!--RDMX_HTMLBLOCK:';
|
|
90772
|
+
const HTML_BLOCK_CONTENT_END = ':RDMX_HTMLBLOCK-->';
|
|
90773
|
+
/**
|
|
90774
|
+
* Evaluates a JavaScript expression using context variables.
|
|
90775
|
+
*
|
|
90776
|
+
* @param expression
|
|
90777
|
+
* @param context
|
|
90778
|
+
* @returns The evaluated result
|
|
90779
|
+
* @example
|
|
90780
|
+
* ```typescript
|
|
90781
|
+
* const context = { baseUrl: 'https://example.com', path: '/api' };
|
|
90782
|
+
* evaluateExpression('baseUrl + path', context)
|
|
90783
|
+
* // Returns: 'https://example.com/api'
|
|
90784
|
+
* ```
|
|
90785
|
+
*/
|
|
90786
|
+
function evaluateExpression(expression, context) {
|
|
90787
|
+
const contextKeys = Object.keys(context);
|
|
90788
|
+
const contextValues = Object.values(context);
|
|
90789
|
+
// eslint-disable-next-line no-new-func
|
|
90790
|
+
const func = new Function(...contextKeys, `return ${expression}`);
|
|
90791
|
+
return func(...contextValues);
|
|
90792
|
+
}
|
|
90793
|
+
/**
|
|
90794
|
+
* Base64 encodes HTMLBlock template literal content to prevent markdown parser from consuming <script>/<style> tags.
|
|
90795
|
+
*
|
|
90796
|
+
* @param content
|
|
90797
|
+
* @returns Content with HTMLBlock template literals base64 encoded in HTML comments
|
|
90798
|
+
* @example
|
|
90799
|
+
* ```typescript
|
|
90800
|
+
* const input = '<HTMLBlock>{`<script>alert("xss")</script>`}</HTMLBlock>';
|
|
90801
|
+
* protectHTMLBlockContent(input)
|
|
90802
|
+
* // Returns: '<HTMLBlock><!--RDMX_HTMLBLOCK:PHNjcmlwdD5hbGVydCgieHNzIik8L3NjcmlwdD4=:RDMX_HTMLBLOCK--></HTMLBlock>'
|
|
90803
|
+
* ```
|
|
90804
|
+
*/
|
|
90805
|
+
function protectHTMLBlockContent(content) {
|
|
90806
|
+
return content.replace(/(<HTMLBlock[^>]*>)\{\s*`((?:[^`\\]|\\.)*)`\s*\}(<\/HTMLBlock>)/g, (_match, openTag, templateContent, closeTag) => {
|
|
90807
|
+
const encoded = base64Encode(templateContent);
|
|
90808
|
+
return `${openTag}${HTML_BLOCK_CONTENT_START}${encoded}${HTML_BLOCK_CONTENT_END}${closeTag}`;
|
|
90809
|
+
});
|
|
90810
|
+
}
|
|
90811
|
+
/**
|
|
90812
|
+
* Removes JSX-style comments (e.g., { /* comment *\/ }) from content.
|
|
90813
|
+
*
|
|
90814
|
+
* @param content
|
|
90815
|
+
* @returns Content with JSX comments removed
|
|
90816
|
+
* @example
|
|
90817
|
+
* ```typescript
|
|
90818
|
+
* removeJSXComments('Text { /* comment *\/ } more text')
|
|
90819
|
+
* // Returns: 'Text more text'
|
|
90820
|
+
* ```
|
|
90821
|
+
*/
|
|
90822
|
+
function removeJSXComments(content) {
|
|
90823
|
+
return content.replace(/\{\s*\/\*[^*]*(?:\*(?!\/)[^*]*)*\*\/\s*\}/g, '');
|
|
90824
|
+
}
|
|
90825
|
+
/**
|
|
90826
|
+
* Extracts content between balanced braces, handling nested braces.
|
|
90827
|
+
*
|
|
90828
|
+
* @param content
|
|
90829
|
+
* @param start
|
|
90830
|
+
* @returns Object with extracted content and end position, or null if braces are unbalanced
|
|
90831
|
+
* @example
|
|
90832
|
+
* ```typescript
|
|
90833
|
+
* const input = 'foo{bar{baz}qux}end';
|
|
90834
|
+
* extractBalancedBraces(input, 3) // start at position 3 (after '{')
|
|
90835
|
+
* // Returns: { content: 'bar{baz}qux', end: 16 }
|
|
90836
|
+
* ```
|
|
90837
|
+
*/
|
|
90838
|
+
function extractBalancedBraces(content, start) {
|
|
90839
|
+
let depth = 1;
|
|
90840
|
+
let pos = start;
|
|
90841
|
+
while (pos < content.length && depth > 0) {
|
|
90842
|
+
const char = content[pos];
|
|
90843
|
+
if (char === '{')
|
|
90844
|
+
depth += 1;
|
|
90845
|
+
else if (char === '}')
|
|
90846
|
+
depth -= 1;
|
|
90847
|
+
pos += 1;
|
|
90848
|
+
}
|
|
90849
|
+
if (depth !== 0)
|
|
90850
|
+
return null;
|
|
90851
|
+
return { content: content.slice(start, pos - 1), end: pos };
|
|
90852
|
+
}
|
|
90853
|
+
/**
|
|
90854
|
+
* Escapes problematic braces in content to prevent MDX expression parsing errors.
|
|
90855
|
+
* Handles three cases:
|
|
90856
|
+
* 1. Unbalanced braces (e.g., `{foo` without closing `}`)
|
|
90857
|
+
* 2. Paragraph-spanning expressions (e.g., `{\n\n}` where blank line splits paragraphs)
|
|
90858
|
+
* 3. Skips HTML elements to prevent backslashes appearing in output
|
|
90859
|
+
*
|
|
90860
|
+
*/
|
|
90861
|
+
function escapeProblematicBraces(content) {
|
|
90862
|
+
// Skip HTML elements — their content should never be escaped because
|
|
90863
|
+
// rehypeRaw parses them into hast elements, making `\` literal text in output
|
|
90864
|
+
const htmlElements = [];
|
|
90865
|
+
const safe = content.replace(/<([a-z][a-zA-Z0-9]*)(?:\s[^>]*)?>[\s\S]*?<\/\1>/g, match => {
|
|
90866
|
+
const idx = htmlElements.length;
|
|
90867
|
+
htmlElements.push(match);
|
|
90868
|
+
return `___HTML_ELEM_${idx}___`;
|
|
90869
|
+
});
|
|
90870
|
+
const toEscape = new Set();
|
|
90871
|
+
// Convert to array of Unicode code points to handle emojis and multi-byte characters correctly
|
|
90872
|
+
const chars = Array.from(safe);
|
|
90873
|
+
let strDelim = null;
|
|
90874
|
+
let strEscaped = false;
|
|
90875
|
+
// Stack of open braces with their state
|
|
90876
|
+
const openStack = [];
|
|
90877
|
+
// Track position of last newline (outside strings) to detect blank lines
|
|
90878
|
+
let lastNewlinePos = -2; // -2 means no recent newline
|
|
90879
|
+
for (let i = 0; i < chars.length; i += 1) {
|
|
90880
|
+
const ch = chars[i];
|
|
90881
|
+
// Track string delimiters inside expressions to ignore braces within them
|
|
90882
|
+
if (openStack.length > 0) {
|
|
90883
|
+
if (strDelim) {
|
|
90884
|
+
if (strEscaped)
|
|
90885
|
+
strEscaped = false;
|
|
90886
|
+
else if (ch === '\\')
|
|
90887
|
+
strEscaped = true;
|
|
90888
|
+
else if (ch === strDelim)
|
|
90889
|
+
strDelim = null;
|
|
90890
|
+
// eslint-disable-next-line no-continue
|
|
90891
|
+
continue;
|
|
90892
|
+
}
|
|
90893
|
+
if (ch === '"' || ch === "'" || ch === '`') {
|
|
90894
|
+
strDelim = ch;
|
|
90895
|
+
// eslint-disable-next-line no-continue
|
|
90896
|
+
continue;
|
|
90897
|
+
}
|
|
90898
|
+
// Track newlines to detect blank lines (paragraph boundaries)
|
|
90899
|
+
if (ch === '\n') {
|
|
90900
|
+
// Check if this newline creates a blank line (only whitespace since last newline)
|
|
90901
|
+
if (lastNewlinePos >= 0) {
|
|
90902
|
+
const between = chars.slice(lastNewlinePos + 1, i).join('');
|
|
90903
|
+
if (/^[ \t]*$/.test(between)) {
|
|
90904
|
+
// This is a blank line - mark all open expressions as paragraph-spanning
|
|
90905
|
+
openStack.forEach(entry => {
|
|
90906
|
+
entry.hasBlankLine = true;
|
|
90907
|
+
});
|
|
90908
|
+
}
|
|
90909
|
+
}
|
|
90910
|
+
lastNewlinePos = i;
|
|
90911
|
+
}
|
|
90912
|
+
}
|
|
90913
|
+
// Skip already-escaped braces (count preceding backslashes)
|
|
90914
|
+
if (ch === '{' || ch === '}') {
|
|
90915
|
+
let bs = 0;
|
|
90916
|
+
for (let j = i - 1; j >= 0 && chars[j] === '\\'; j -= 1)
|
|
90917
|
+
bs += 1;
|
|
90918
|
+
if (bs % 2 === 1) {
|
|
90919
|
+
// eslint-disable-next-line no-continue
|
|
90920
|
+
continue;
|
|
90921
|
+
}
|
|
90922
|
+
}
|
|
90923
|
+
if (ch === '{') {
|
|
90924
|
+
openStack.push({ pos: i, hasBlankLine: false });
|
|
90925
|
+
lastNewlinePos = -2; // Reset newline tracking for new expression
|
|
90926
|
+
}
|
|
90927
|
+
else if (ch === '}') {
|
|
90928
|
+
if (openStack.length > 0) {
|
|
90929
|
+
const entry = openStack.pop();
|
|
90930
|
+
// If expression spans paragraph boundary, escape both braces
|
|
90931
|
+
if (entry.hasBlankLine) {
|
|
90932
|
+
toEscape.add(entry.pos);
|
|
90933
|
+
toEscape.add(i);
|
|
90934
|
+
}
|
|
90935
|
+
}
|
|
90936
|
+
else {
|
|
90937
|
+
// Unbalanced closing brace (no matching open)
|
|
90938
|
+
toEscape.add(i);
|
|
90939
|
+
}
|
|
90940
|
+
}
|
|
90941
|
+
}
|
|
90942
|
+
// Any remaining open braces are unbalanced
|
|
90943
|
+
openStack.forEach(entry => toEscape.add(entry.pos));
|
|
90944
|
+
// If there are no problematic braces, return safe content as-is;
|
|
90945
|
+
// otherwise, escape each problematic `{` or `}` so MDX doesn't treat them as expressions.
|
|
90946
|
+
let result = toEscape.size === 0
|
|
90947
|
+
? safe
|
|
90948
|
+
: chars.map((ch, i) => (toEscape.has(i) ? `\\${ch}` : ch)).join('');
|
|
90949
|
+
// Restore HTML elements
|
|
90950
|
+
if (htmlElements.length > 0) {
|
|
90951
|
+
result = result.replace(/___HTML_ELEM_(\d+)___/g, (_m, idx) => htmlElements[parseInt(idx, 10)]);
|
|
90952
|
+
}
|
|
90953
|
+
return result;
|
|
90954
|
+
}
|
|
90955
|
+
/**
|
|
90956
|
+
* Converts JSX attribute expressions (attribute={expression}) to HTML attributes (attribute="value").
|
|
90957
|
+
* Handles style objects (camelCase → kebab-case), className → class, and JSON stringifies objects.
|
|
90958
|
+
*
|
|
90959
|
+
* @param content
|
|
90960
|
+
* @param context
|
|
90961
|
+
* @returns Content with attribute expressions evaluated and converted to HTML attributes
|
|
90962
|
+
* @example
|
|
90963
|
+
* ```typescript
|
|
90964
|
+
* const context = { baseUrl: 'https://example.com' };
|
|
90965
|
+
* const input = '<a href={baseUrl}>Link</a>';
|
|
90966
|
+
* evaluateAttributeExpressions(input, context)
|
|
90967
|
+
* // Returns: '<a href="https://example.com">Link</a>'
|
|
90968
|
+
* ```
|
|
90969
|
+
*/
|
|
90970
|
+
function evaluateAttributeExpressions(content, context, protectedCode) {
|
|
90971
|
+
const attrStartRegex = /(\w+)=\{/g;
|
|
90972
|
+
let result = '';
|
|
90973
|
+
let lastEnd = 0;
|
|
90974
|
+
let match = attrStartRegex.exec(content);
|
|
90975
|
+
while (match !== null) {
|
|
90976
|
+
const attributeName = match[1];
|
|
90977
|
+
const braceStart = match.index + match[0].length;
|
|
90978
|
+
const extracted = extractBalancedBraces(content, braceStart);
|
|
90979
|
+
if (extracted) {
|
|
90980
|
+
// The expression might contain template literals in MDX component tag props
|
|
90981
|
+
// E.g. <Component greeting={`Hello World!`} />
|
|
90982
|
+
// that is marked as inline code. So we need to restore the inline codes
|
|
90983
|
+
// in the expression to evaluate it
|
|
90984
|
+
let expression = extracted.content;
|
|
90985
|
+
if (protectedCode) {
|
|
90986
|
+
expression = restoreInlineCode(expression, protectedCode);
|
|
90987
|
+
}
|
|
90988
|
+
const fullMatchEnd = extracted.end;
|
|
90989
|
+
result += content.slice(lastEnd, match.index);
|
|
90990
|
+
try {
|
|
90991
|
+
const evalResult = evaluateExpression(expression, context);
|
|
90992
|
+
if (typeof evalResult === 'object' && evalResult !== null) {
|
|
90993
|
+
if (attributeName === 'style') {
|
|
90994
|
+
const cssString = Object.entries(evalResult)
|
|
90995
|
+
.map(([key, value]) => {
|
|
90996
|
+
const cssKey = key.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
90997
|
+
return `${cssKey}: ${value}`;
|
|
90998
|
+
})
|
|
90999
|
+
.join('; ');
|
|
91000
|
+
result += `style="${cssString}"`;
|
|
91001
|
+
}
|
|
91002
|
+
else {
|
|
91003
|
+
// These are arrays / objects attribute values
|
|
91004
|
+
// Mark JSON-serialized values with a prefix so they can be parsed back correctly
|
|
91005
|
+
const jsonValue = escapeHtmlAttribute(JSON_VALUE_MARKER + JSON.stringify(evalResult));
|
|
91006
|
+
// Use double quotes so that multi-paragraph values are not split into multiple attributes by the processors
|
|
91007
|
+
result += `${attributeName}="${jsonValue}"`;
|
|
91008
|
+
}
|
|
91009
|
+
}
|
|
91010
|
+
else if (attributeName === 'className') {
|
|
91011
|
+
// Escape special characters so that it doesn't break and split the attribute value to nodes
|
|
91012
|
+
// This will be restored later in the pipeline
|
|
91013
|
+
result += `class="${escapeHtmlAttribute(String(evalResult))}"`;
|
|
91014
|
+
}
|
|
91015
|
+
else {
|
|
91016
|
+
result += `${attributeName}="${escapeHtmlAttribute(String(evalResult))}"`;
|
|
91017
|
+
}
|
|
91018
|
+
}
|
|
91019
|
+
catch (_error) {
|
|
91020
|
+
result += content.slice(match.index, fullMatchEnd);
|
|
91021
|
+
}
|
|
91022
|
+
lastEnd = fullMatchEnd;
|
|
91023
|
+
attrStartRegex.lastIndex = fullMatchEnd;
|
|
91024
|
+
}
|
|
91025
|
+
match = attrStartRegex.exec(content);
|
|
91026
|
+
}
|
|
91027
|
+
result += content.slice(lastEnd);
|
|
91028
|
+
return result;
|
|
91029
|
+
}
|
|
91030
|
+
/**
|
|
91031
|
+
* Preprocesses JSX-like expressions in markdown before parsing.
|
|
91032
|
+
* Inline expressions are handled separately; attribute expressions are processed here.
|
|
91033
|
+
*
|
|
91034
|
+
* @param content
|
|
91035
|
+
* @param context
|
|
91036
|
+
* @returns Preprocessed content ready for markdown parsing
|
|
91037
|
+
*/
|
|
91038
|
+
function preprocessJSXExpressions(content, context = {}) {
|
|
91039
|
+
// Step 0: Base64 encode HTMLBlock content
|
|
91040
|
+
let processed = protectHTMLBlockContent(content);
|
|
91041
|
+
// Step 1: Protect code blocks and inline code
|
|
91042
|
+
const { protectedCode, protectedContent } = protectCodeBlocks(processed);
|
|
91043
|
+
// Step 2: Evaluate attribute expressions (JSX attribute syntax: href={baseUrl})
|
|
91044
|
+
// For inline expressions, we use a library to parse the expression & evaluate it later
|
|
91045
|
+
// For attribute expressions, it was difficult to use a library to parse them, so do it manually
|
|
91046
|
+
processed = evaluateAttributeExpressions(protectedContent, context, protectedCode);
|
|
91047
|
+
// Step 3: Escape problematic braces to prevent MDX expression parsing errors
|
|
91048
|
+
// This handles both unbalanced braces and paragraph-spanning expressions in one pass
|
|
91049
|
+
processed = escapeProblematicBraces(processed);
|
|
91050
|
+
// Step 4: Restore protected code blocks
|
|
91051
|
+
processed = restoreCodeBlocks(processed, protectedCode);
|
|
91052
|
+
return processed;
|
|
91053
|
+
}
|
|
91054
|
+
|
|
90607
91055
|
;// ./processor/utils.ts
|
|
90608
91056
|
|
|
90609
91057
|
|
|
91058
|
+
|
|
90610
91059
|
/**
|
|
90611
91060
|
* Formats the hProperties of a node as a string, so they can be compiled back into JSX/MDX.
|
|
90612
91061
|
* This currently sets all the values to a string since we process/compile the MDX on the fly
|
|
@@ -90662,7 +91111,17 @@ const getHPropKeys = (node) => {
|
|
|
90662
91111
|
const getAttrs = (jsx) => jsx.attributes.reduce((memo, attr) => {
|
|
90663
91112
|
if ('name' in attr) {
|
|
90664
91113
|
if (typeof attr.value === 'string') {
|
|
90665
|
-
|
|
91114
|
+
if (attr.value.startsWith(JSON_VALUE_MARKER)) {
|
|
91115
|
+
try {
|
|
91116
|
+
memo[attr.name] = JSON.parse(attr.value.slice(JSON_VALUE_MARKER.length));
|
|
91117
|
+
}
|
|
91118
|
+
catch {
|
|
91119
|
+
memo[attr.name] = attr.value;
|
|
91120
|
+
}
|
|
91121
|
+
}
|
|
91122
|
+
else {
|
|
91123
|
+
memo[attr.name] = attr.value;
|
|
91124
|
+
}
|
|
90666
91125
|
}
|
|
90667
91126
|
else if (attr.value === null) {
|
|
90668
91127
|
memo[attr.name] = true;
|
|
@@ -91436,10 +91895,10 @@ const hasFlowContent = (nodes) => {
|
|
|
91436
91895
|
* Process a Table node: re-parse text-only cell content, then output as
|
|
91437
91896
|
* a markdown table (phrasing-only) or keep as JSX <Table> (has flow content).
|
|
91438
91897
|
*/
|
|
91439
|
-
const processTableNode = (node, index, parent) => {
|
|
91898
|
+
const processTableNode = (node, index, parent, documentPosition) => {
|
|
91440
91899
|
if (node.name !== 'Table')
|
|
91441
91900
|
return;
|
|
91442
|
-
const
|
|
91901
|
+
const position = documentPosition ?? node.position;
|
|
91443
91902
|
const { align: alignAttr } = getAttrs(node);
|
|
91444
91903
|
const align = Array.isArray(alignAttr) ? alignAttr : null;
|
|
91445
91904
|
let tableHasFlowContent = false;
|
|
@@ -91562,7 +92021,7 @@ const mdxishTables = () => tree => {
|
|
|
91562
92021
|
const parsed = tableNodeProcessor.runSync(tableNodeProcessor.parse(node.value));
|
|
91563
92022
|
visit(parsed, isMDXElement, (tableNode) => {
|
|
91564
92023
|
if (tableNode.name === 'Table') {
|
|
91565
|
-
processTableNode(tableNode, index, parent);
|
|
92024
|
+
processTableNode(tableNode, index, parent, node.position);
|
|
91566
92025
|
// Stop after the outermost Table so nested Tables don't overwrite parent.children[index]
|
|
91567
92026
|
// we let it get handled naturally
|
|
91568
92027
|
return EXIT;
|
|
@@ -114037,412 +114496,6 @@ const mdxComponentHandlers = {
|
|
|
114037
114496
|
[NodeTypes.htmlBlock]: htmlBlockHandler,
|
|
114038
114497
|
};
|
|
114039
114498
|
|
|
114040
|
-
;// ./lib/utils/mdxish/protect-code-blocks.ts
|
|
114041
|
-
/**
|
|
114042
|
-
* Replaces code blocks and inline code with placeholders to protect them from preprocessing.
|
|
114043
|
-
*
|
|
114044
|
-
* @param content - The markdown content to process
|
|
114045
|
-
* @returns Object containing protected content and arrays of original code blocks
|
|
114046
|
-
* @example
|
|
114047
|
-
* ```typescript
|
|
114048
|
-
* const input = 'Text with `inline code` and ```fenced block```';
|
|
114049
|
-
* protectCodeBlocks(input)
|
|
114050
|
-
* // Returns: {
|
|
114051
|
-
* // protectedCode: {
|
|
114052
|
-
* // codeBlocks: ['```fenced block```'],
|
|
114053
|
-
* // inlineCode: ['`inline code`']
|
|
114054
|
-
* // },
|
|
114055
|
-
* // protectedContent: 'Text with ___INLINE_CODE_0___ and ___CODE_BLOCK_0___'
|
|
114056
|
-
* // }
|
|
114057
|
-
* ```
|
|
114058
|
-
*/
|
|
114059
|
-
function protectCodeBlocks(content) {
|
|
114060
|
-
const codeBlocks = [];
|
|
114061
|
-
const inlineCode = [];
|
|
114062
|
-
let protectedContent = '';
|
|
114063
|
-
let remaining = content;
|
|
114064
|
-
let codeBlockStart = remaining.indexOf('```');
|
|
114065
|
-
while (codeBlockStart !== -1) {
|
|
114066
|
-
protectedContent += remaining.slice(0, codeBlockStart);
|
|
114067
|
-
remaining = remaining.slice(codeBlockStart);
|
|
114068
|
-
const codeBlockEnd = remaining.indexOf('```', 3);
|
|
114069
|
-
if (codeBlockEnd === -1) {
|
|
114070
|
-
break;
|
|
114071
|
-
}
|
|
114072
|
-
const match = remaining.slice(0, codeBlockEnd + 3);
|
|
114073
|
-
const index = codeBlocks.length;
|
|
114074
|
-
codeBlocks.push(match);
|
|
114075
|
-
protectedContent += `___CODE_BLOCK_${index}___`;
|
|
114076
|
-
remaining = remaining.slice(codeBlockEnd + 3);
|
|
114077
|
-
codeBlockStart = remaining.indexOf('```');
|
|
114078
|
-
}
|
|
114079
|
-
protectedContent += remaining;
|
|
114080
|
-
protectedContent = protectedContent.replace(/`([^`\n]+)`/g, match => {
|
|
114081
|
-
const index = inlineCode.length;
|
|
114082
|
-
inlineCode.push(match);
|
|
114083
|
-
return `___INLINE_CODE_${index}___`;
|
|
114084
|
-
});
|
|
114085
|
-
return { protectedCode: { codeBlocks, inlineCode }, protectedContent };
|
|
114086
|
-
}
|
|
114087
|
-
/**
|
|
114088
|
-
* Restores inline code by replacing placeholders with original content.
|
|
114089
|
-
*
|
|
114090
|
-
* @param content - Content with inline code placeholders
|
|
114091
|
-
* @param protectedCode - The protected code arrays
|
|
114092
|
-
* @returns Content with inline code restored
|
|
114093
|
-
*/
|
|
114094
|
-
function restoreInlineCode(content, protectedCode) {
|
|
114095
|
-
return content.replace(/___INLINE_CODE_(\d+)___/g, (_m, idx) => {
|
|
114096
|
-
return protectedCode.inlineCode[parseInt(idx, 10)];
|
|
114097
|
-
});
|
|
114098
|
-
}
|
|
114099
|
-
/**
|
|
114100
|
-
* Restores fenced code blocks by replacing placeholders with original content.
|
|
114101
|
-
*
|
|
114102
|
-
* @param content - Content with code block placeholders
|
|
114103
|
-
* @param protectedCode - The protected code arrays
|
|
114104
|
-
* @returns Content with code blocks restored
|
|
114105
|
-
*/
|
|
114106
|
-
function restoreFencedCodeBlocks(content, protectedCode) {
|
|
114107
|
-
return content.replace(/___CODE_BLOCK_(\d+)___/g, (_m, idx) => {
|
|
114108
|
-
return protectedCode.codeBlocks[parseInt(idx, 10)];
|
|
114109
|
-
});
|
|
114110
|
-
}
|
|
114111
|
-
/**
|
|
114112
|
-
* Restores all code blocks and inline code by replacing placeholders with original content.
|
|
114113
|
-
*
|
|
114114
|
-
* @param content - Content with code placeholders
|
|
114115
|
-
* @param protectedCode - The protected code arrays
|
|
114116
|
-
* @returns Content with all code blocks and inline code restored
|
|
114117
|
-
* @example
|
|
114118
|
-
* ```typescript
|
|
114119
|
-
* const content = 'Text with ___INLINE_CODE_0___ and ___CODE_BLOCK_0___';
|
|
114120
|
-
* const protectedCode = {
|
|
114121
|
-
* codeBlocks: ['```js\ncode\n```'],
|
|
114122
|
-
* inlineCode: ['`inline`']
|
|
114123
|
-
* };
|
|
114124
|
-
* restoreCodeBlocks(content, protectedCode)
|
|
114125
|
-
* // Returns: 'Text with `inline` and ```js\ncode\n```'
|
|
114126
|
-
* ```
|
|
114127
|
-
*/
|
|
114128
|
-
function restoreCodeBlocks(content, protectedCode) {
|
|
114129
|
-
let restored = restoreFencedCodeBlocks(content, protectedCode);
|
|
114130
|
-
restored = restoreInlineCode(restored, protectedCode);
|
|
114131
|
-
return restored;
|
|
114132
|
-
}
|
|
114133
|
-
|
|
114134
|
-
;// ./processor/transform/mdxish/preprocess-jsx-expressions.ts
|
|
114135
|
-
|
|
114136
|
-
// Base64 encode (Node.js + browser compatible)
|
|
114137
|
-
function base64Encode(str) {
|
|
114138
|
-
if (typeof Buffer !== 'undefined') {
|
|
114139
|
-
return Buffer.from(str, 'utf-8').toString('base64');
|
|
114140
|
-
}
|
|
114141
|
-
return btoa(unescape(encodeURIComponent(str)));
|
|
114142
|
-
}
|
|
114143
|
-
// Base64 decode (Node.js + browser compatible)
|
|
114144
|
-
function base64Decode(str) {
|
|
114145
|
-
if (typeof Buffer !== 'undefined') {
|
|
114146
|
-
return Buffer.from(str, 'base64').toString('utf-8');
|
|
114147
|
-
}
|
|
114148
|
-
return decodeURIComponent(escape(atob(str)));
|
|
114149
|
-
}
|
|
114150
|
-
function escapeHtmlAttribute(value) {
|
|
114151
|
-
return value
|
|
114152
|
-
.replace(/&/g, '&')
|
|
114153
|
-
.replace(/"/g, '"')
|
|
114154
|
-
.replace(/</g, '<')
|
|
114155
|
-
.replace(/>/g, '>')
|
|
114156
|
-
.replace(/\n/g, ' ');
|
|
114157
|
-
}
|
|
114158
|
-
// Marker prefix for JSON-serialized complex values (arrays/objects)
|
|
114159
|
-
// Using a prefix that won't conflict with regular string values
|
|
114160
|
-
const JSON_VALUE_MARKER = '__MDXISH_JSON__';
|
|
114161
|
-
// Markers for protected HTMLBlock content (HTML comments avoid markdown parsing issues)
|
|
114162
|
-
const HTML_BLOCK_CONTENT_START = '<!--RDMX_HTMLBLOCK:';
|
|
114163
|
-
const HTML_BLOCK_CONTENT_END = ':RDMX_HTMLBLOCK-->';
|
|
114164
|
-
/**
|
|
114165
|
-
* Evaluates a JavaScript expression using context variables.
|
|
114166
|
-
*
|
|
114167
|
-
* @param expression
|
|
114168
|
-
* @param context
|
|
114169
|
-
* @returns The evaluated result
|
|
114170
|
-
* @example
|
|
114171
|
-
* ```typescript
|
|
114172
|
-
* const context = { baseUrl: 'https://example.com', path: '/api' };
|
|
114173
|
-
* evaluateExpression('baseUrl + path', context)
|
|
114174
|
-
* // Returns: 'https://example.com/api'
|
|
114175
|
-
* ```
|
|
114176
|
-
*/
|
|
114177
|
-
function evaluateExpression(expression, context) {
|
|
114178
|
-
const contextKeys = Object.keys(context);
|
|
114179
|
-
const contextValues = Object.values(context);
|
|
114180
|
-
// eslint-disable-next-line no-new-func
|
|
114181
|
-
const func = new Function(...contextKeys, `return ${expression}`);
|
|
114182
|
-
return func(...contextValues);
|
|
114183
|
-
}
|
|
114184
|
-
/**
|
|
114185
|
-
* Base64 encodes HTMLBlock template literal content to prevent markdown parser from consuming <script>/<style> tags.
|
|
114186
|
-
*
|
|
114187
|
-
* @param content
|
|
114188
|
-
* @returns Content with HTMLBlock template literals base64 encoded in HTML comments
|
|
114189
|
-
* @example
|
|
114190
|
-
* ```typescript
|
|
114191
|
-
* const input = '<HTMLBlock>{`<script>alert("xss")</script>`}</HTMLBlock>';
|
|
114192
|
-
* protectHTMLBlockContent(input)
|
|
114193
|
-
* // Returns: '<HTMLBlock><!--RDMX_HTMLBLOCK:PHNjcmlwdD5hbGVydCgieHNzIik8L3NjcmlwdD4=:RDMX_HTMLBLOCK--></HTMLBlock>'
|
|
114194
|
-
* ```
|
|
114195
|
-
*/
|
|
114196
|
-
function protectHTMLBlockContent(content) {
|
|
114197
|
-
return content.replace(/(<HTMLBlock[^>]*>)\{\s*`((?:[^`\\]|\\.)*)`\s*\}(<\/HTMLBlock>)/g, (_match, openTag, templateContent, closeTag) => {
|
|
114198
|
-
const encoded = base64Encode(templateContent);
|
|
114199
|
-
return `${openTag}${HTML_BLOCK_CONTENT_START}${encoded}${HTML_BLOCK_CONTENT_END}${closeTag}`;
|
|
114200
|
-
});
|
|
114201
|
-
}
|
|
114202
|
-
/**
|
|
114203
|
-
* Removes JSX-style comments (e.g., { /* comment *\/ }) from content.
|
|
114204
|
-
*
|
|
114205
|
-
* @param content
|
|
114206
|
-
* @returns Content with JSX comments removed
|
|
114207
|
-
* @example
|
|
114208
|
-
* ```typescript
|
|
114209
|
-
* removeJSXComments('Text { /* comment *\/ } more text')
|
|
114210
|
-
* // Returns: 'Text more text'
|
|
114211
|
-
* ```
|
|
114212
|
-
*/
|
|
114213
|
-
function removeJSXComments(content) {
|
|
114214
|
-
return content.replace(/\{\s*\/\*[^*]*(?:\*(?!\/)[^*]*)*\*\/\s*\}/g, '');
|
|
114215
|
-
}
|
|
114216
|
-
/**
|
|
114217
|
-
* Extracts content between balanced braces, handling nested braces.
|
|
114218
|
-
*
|
|
114219
|
-
* @param content
|
|
114220
|
-
* @param start
|
|
114221
|
-
* @returns Object with extracted content and end position, or null if braces are unbalanced
|
|
114222
|
-
* @example
|
|
114223
|
-
* ```typescript
|
|
114224
|
-
* const input = 'foo{bar{baz}qux}end';
|
|
114225
|
-
* extractBalancedBraces(input, 3) // start at position 3 (after '{')
|
|
114226
|
-
* // Returns: { content: 'bar{baz}qux', end: 16 }
|
|
114227
|
-
* ```
|
|
114228
|
-
*/
|
|
114229
|
-
function extractBalancedBraces(content, start) {
|
|
114230
|
-
let depth = 1;
|
|
114231
|
-
let pos = start;
|
|
114232
|
-
while (pos < content.length && depth > 0) {
|
|
114233
|
-
const char = content[pos];
|
|
114234
|
-
if (char === '{')
|
|
114235
|
-
depth += 1;
|
|
114236
|
-
else if (char === '}')
|
|
114237
|
-
depth -= 1;
|
|
114238
|
-
pos += 1;
|
|
114239
|
-
}
|
|
114240
|
-
if (depth !== 0)
|
|
114241
|
-
return null;
|
|
114242
|
-
return { content: content.slice(start, pos - 1), end: pos };
|
|
114243
|
-
}
|
|
114244
|
-
/**
|
|
114245
|
-
* Escapes problematic braces in content to prevent MDX expression parsing errors.
|
|
114246
|
-
* Handles three cases:
|
|
114247
|
-
* 1. Unbalanced braces (e.g., `{foo` without closing `}`)
|
|
114248
|
-
* 2. Paragraph-spanning expressions (e.g., `{\n\n}` where blank line splits paragraphs)
|
|
114249
|
-
* 3. Skips HTML elements to prevent backslashes appearing in output
|
|
114250
|
-
*
|
|
114251
|
-
*/
|
|
114252
|
-
function escapeProblematicBraces(content) {
|
|
114253
|
-
// Skip HTML elements — their content should never be escaped because
|
|
114254
|
-
// rehypeRaw parses them into hast elements, making `\` literal text in output
|
|
114255
|
-
const htmlElements = [];
|
|
114256
|
-
const safe = content.replace(/<([a-z][a-zA-Z0-9]*)(?:\s[^>]*)?>[\s\S]*?<\/\1>/g, match => {
|
|
114257
|
-
const idx = htmlElements.length;
|
|
114258
|
-
htmlElements.push(match);
|
|
114259
|
-
return `___HTML_ELEM_${idx}___`;
|
|
114260
|
-
});
|
|
114261
|
-
const toEscape = new Set();
|
|
114262
|
-
// Convert to array of Unicode code points to handle emojis and multi-byte characters correctly
|
|
114263
|
-
const chars = Array.from(safe);
|
|
114264
|
-
let strDelim = null;
|
|
114265
|
-
let strEscaped = false;
|
|
114266
|
-
// Stack of open braces with their state
|
|
114267
|
-
const openStack = [];
|
|
114268
|
-
// Track position of last newline (outside strings) to detect blank lines
|
|
114269
|
-
let lastNewlinePos = -2; // -2 means no recent newline
|
|
114270
|
-
for (let i = 0; i < chars.length; i += 1) {
|
|
114271
|
-
const ch = chars[i];
|
|
114272
|
-
// Track string delimiters inside expressions to ignore braces within them
|
|
114273
|
-
if (openStack.length > 0) {
|
|
114274
|
-
if (strDelim) {
|
|
114275
|
-
if (strEscaped)
|
|
114276
|
-
strEscaped = false;
|
|
114277
|
-
else if (ch === '\\')
|
|
114278
|
-
strEscaped = true;
|
|
114279
|
-
else if (ch === strDelim)
|
|
114280
|
-
strDelim = null;
|
|
114281
|
-
// eslint-disable-next-line no-continue
|
|
114282
|
-
continue;
|
|
114283
|
-
}
|
|
114284
|
-
if (ch === '"' || ch === "'" || ch === '`') {
|
|
114285
|
-
strDelim = ch;
|
|
114286
|
-
// eslint-disable-next-line no-continue
|
|
114287
|
-
continue;
|
|
114288
|
-
}
|
|
114289
|
-
// Track newlines to detect blank lines (paragraph boundaries)
|
|
114290
|
-
if (ch === '\n') {
|
|
114291
|
-
// Check if this newline creates a blank line (only whitespace since last newline)
|
|
114292
|
-
if (lastNewlinePos >= 0) {
|
|
114293
|
-
const between = chars.slice(lastNewlinePos + 1, i).join('');
|
|
114294
|
-
if (/^[ \t]*$/.test(between)) {
|
|
114295
|
-
// This is a blank line - mark all open expressions as paragraph-spanning
|
|
114296
|
-
openStack.forEach(entry => {
|
|
114297
|
-
entry.hasBlankLine = true;
|
|
114298
|
-
});
|
|
114299
|
-
}
|
|
114300
|
-
}
|
|
114301
|
-
lastNewlinePos = i;
|
|
114302
|
-
}
|
|
114303
|
-
}
|
|
114304
|
-
// Skip already-escaped braces (count preceding backslashes)
|
|
114305
|
-
if (ch === '{' || ch === '}') {
|
|
114306
|
-
let bs = 0;
|
|
114307
|
-
for (let j = i - 1; j >= 0 && chars[j] === '\\'; j -= 1)
|
|
114308
|
-
bs += 1;
|
|
114309
|
-
if (bs % 2 === 1) {
|
|
114310
|
-
// eslint-disable-next-line no-continue
|
|
114311
|
-
continue;
|
|
114312
|
-
}
|
|
114313
|
-
}
|
|
114314
|
-
if (ch === '{') {
|
|
114315
|
-
openStack.push({ pos: i, hasBlankLine: false });
|
|
114316
|
-
lastNewlinePos = -2; // Reset newline tracking for new expression
|
|
114317
|
-
}
|
|
114318
|
-
else if (ch === '}') {
|
|
114319
|
-
if (openStack.length > 0) {
|
|
114320
|
-
const entry = openStack.pop();
|
|
114321
|
-
// If expression spans paragraph boundary, escape both braces
|
|
114322
|
-
if (entry.hasBlankLine) {
|
|
114323
|
-
toEscape.add(entry.pos);
|
|
114324
|
-
toEscape.add(i);
|
|
114325
|
-
}
|
|
114326
|
-
}
|
|
114327
|
-
else {
|
|
114328
|
-
// Unbalanced closing brace (no matching open)
|
|
114329
|
-
toEscape.add(i);
|
|
114330
|
-
}
|
|
114331
|
-
}
|
|
114332
|
-
}
|
|
114333
|
-
// Any remaining open braces are unbalanced
|
|
114334
|
-
openStack.forEach(entry => toEscape.add(entry.pos));
|
|
114335
|
-
// If there are no problematic braces, return safe content as-is;
|
|
114336
|
-
// otherwise, escape each problematic `{` or `}` so MDX doesn't treat them as expressions.
|
|
114337
|
-
let result = toEscape.size === 0
|
|
114338
|
-
? safe
|
|
114339
|
-
: chars.map((ch, i) => (toEscape.has(i) ? `\\${ch}` : ch)).join('');
|
|
114340
|
-
// Restore HTML elements
|
|
114341
|
-
if (htmlElements.length > 0) {
|
|
114342
|
-
result = result.replace(/___HTML_ELEM_(\d+)___/g, (_m, idx) => htmlElements[parseInt(idx, 10)]);
|
|
114343
|
-
}
|
|
114344
|
-
return result;
|
|
114345
|
-
}
|
|
114346
|
-
/**
|
|
114347
|
-
* Converts JSX attribute expressions (attribute={expression}) to HTML attributes (attribute="value").
|
|
114348
|
-
* Handles style objects (camelCase → kebab-case), className → class, and JSON stringifies objects.
|
|
114349
|
-
*
|
|
114350
|
-
* @param content
|
|
114351
|
-
* @param context
|
|
114352
|
-
* @returns Content with attribute expressions evaluated and converted to HTML attributes
|
|
114353
|
-
* @example
|
|
114354
|
-
* ```typescript
|
|
114355
|
-
* const context = { baseUrl: 'https://example.com' };
|
|
114356
|
-
* const input = '<a href={baseUrl}>Link</a>';
|
|
114357
|
-
* evaluateAttributeExpressions(input, context)
|
|
114358
|
-
* // Returns: '<a href="https://example.com">Link</a>'
|
|
114359
|
-
* ```
|
|
114360
|
-
*/
|
|
114361
|
-
function evaluateAttributeExpressions(content, context, protectedCode) {
|
|
114362
|
-
const attrStartRegex = /(\w+)=\{/g;
|
|
114363
|
-
let result = '';
|
|
114364
|
-
let lastEnd = 0;
|
|
114365
|
-
let match = attrStartRegex.exec(content);
|
|
114366
|
-
while (match !== null) {
|
|
114367
|
-
const attributeName = match[1];
|
|
114368
|
-
const braceStart = match.index + match[0].length;
|
|
114369
|
-
const extracted = extractBalancedBraces(content, braceStart);
|
|
114370
|
-
if (extracted) {
|
|
114371
|
-
// The expression might contain template literals in MDX component tag props
|
|
114372
|
-
// E.g. <Component greeting={`Hello World!`} />
|
|
114373
|
-
// that is marked as inline code. So we need to restore the inline codes
|
|
114374
|
-
// in the expression to evaluate it
|
|
114375
|
-
let expression = extracted.content;
|
|
114376
|
-
if (protectedCode) {
|
|
114377
|
-
expression = restoreInlineCode(expression, protectedCode);
|
|
114378
|
-
}
|
|
114379
|
-
const fullMatchEnd = extracted.end;
|
|
114380
|
-
result += content.slice(lastEnd, match.index);
|
|
114381
|
-
try {
|
|
114382
|
-
const evalResult = evaluateExpression(expression, context);
|
|
114383
|
-
if (typeof evalResult === 'object' && evalResult !== null) {
|
|
114384
|
-
if (attributeName === 'style') {
|
|
114385
|
-
const cssString = Object.entries(evalResult)
|
|
114386
|
-
.map(([key, value]) => {
|
|
114387
|
-
const cssKey = key.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
114388
|
-
return `${cssKey}: ${value}`;
|
|
114389
|
-
})
|
|
114390
|
-
.join('; ');
|
|
114391
|
-
result += `style="${cssString}"`;
|
|
114392
|
-
}
|
|
114393
|
-
else {
|
|
114394
|
-
// These are arrays / objects attribute values
|
|
114395
|
-
// Mark JSON-serialized values with a prefix so they can be parsed back correctly
|
|
114396
|
-
const jsonValue = escapeHtmlAttribute(JSON_VALUE_MARKER + JSON.stringify(evalResult));
|
|
114397
|
-
// Use double quotes so that multi-paragraph values are not split into multiple attributes by the processors
|
|
114398
|
-
result += `${attributeName}="${jsonValue}"`;
|
|
114399
|
-
}
|
|
114400
|
-
}
|
|
114401
|
-
else if (attributeName === 'className') {
|
|
114402
|
-
// Escape special characters so that it doesn't break and split the attribute value to nodes
|
|
114403
|
-
// This will be restored later in the pipeline
|
|
114404
|
-
result += `class="${escapeHtmlAttribute(String(evalResult))}"`;
|
|
114405
|
-
}
|
|
114406
|
-
else {
|
|
114407
|
-
result += `${attributeName}="${escapeHtmlAttribute(String(evalResult))}"`;
|
|
114408
|
-
}
|
|
114409
|
-
}
|
|
114410
|
-
catch (_error) {
|
|
114411
|
-
result += content.slice(match.index, fullMatchEnd);
|
|
114412
|
-
}
|
|
114413
|
-
lastEnd = fullMatchEnd;
|
|
114414
|
-
attrStartRegex.lastIndex = fullMatchEnd;
|
|
114415
|
-
}
|
|
114416
|
-
match = attrStartRegex.exec(content);
|
|
114417
|
-
}
|
|
114418
|
-
result += content.slice(lastEnd);
|
|
114419
|
-
return result;
|
|
114420
|
-
}
|
|
114421
|
-
/**
|
|
114422
|
-
* Preprocesses JSX-like expressions in markdown before parsing.
|
|
114423
|
-
* Inline expressions are handled separately; attribute expressions are processed here.
|
|
114424
|
-
*
|
|
114425
|
-
* @param content
|
|
114426
|
-
* @param context
|
|
114427
|
-
* @returns Preprocessed content ready for markdown parsing
|
|
114428
|
-
*/
|
|
114429
|
-
function preprocessJSXExpressions(content, context = {}) {
|
|
114430
|
-
// Step 0: Base64 encode HTMLBlock content
|
|
114431
|
-
let processed = protectHTMLBlockContent(content);
|
|
114432
|
-
// Step 1: Protect code blocks and inline code
|
|
114433
|
-
const { protectedCode, protectedContent } = protectCodeBlocks(processed);
|
|
114434
|
-
// Step 2: Evaluate attribute expressions (JSX attribute syntax: href={baseUrl})
|
|
114435
|
-
// For inline expressions, we use a library to parse the expression & evaluate it later
|
|
114436
|
-
// For attribute expressions, it was difficult to use a library to parse them, so do it manually
|
|
114437
|
-
processed = evaluateAttributeExpressions(protectedContent, context, protectedCode);
|
|
114438
|
-
// Step 3: Escape problematic braces to prevent MDX expression parsing errors
|
|
114439
|
-
// This handles both unbalanced braces and paragraph-spanning expressions in one pass
|
|
114440
|
-
processed = escapeProblematicBraces(processed);
|
|
114441
|
-
// Step 4: Restore protected code blocks
|
|
114442
|
-
processed = restoreCodeBlocks(processed, protectedCode);
|
|
114443
|
-
return processed;
|
|
114444
|
-
}
|
|
114445
|
-
|
|
114446
114499
|
;// ./processor/transform/mdxish/evaluate-expressions.ts
|
|
114447
114500
|
|
|
114448
114501
|
|
|
@@ -116236,11 +116289,33 @@ const parseBlock = (text) => {
|
|
|
116236
116289
|
const tree = contentParser.runSync(contentParser.parse(text));
|
|
116237
116290
|
return tree.children;
|
|
116238
116291
|
};
|
|
116239
|
-
|
|
116292
|
+
/**
|
|
116293
|
+
* Minimal parser for api-header titles.
|
|
116294
|
+
* Disables markdown constructs that are not parsed in legacy (headings, lists)
|
|
116295
|
+
*/
|
|
116296
|
+
const apiHeaderTitleParser = unified()
|
|
116297
|
+
.data('micromarkExtensions', [
|
|
116298
|
+
legacyVariable(),
|
|
116299
|
+
looseHtmlEntity(),
|
|
116300
|
+
{
|
|
116301
|
+
disable: {
|
|
116302
|
+
null: [
|
|
116303
|
+
'blockQuote',
|
|
116304
|
+
'headingAtx',
|
|
116305
|
+
'list',
|
|
116306
|
+
'thematicBreak',
|
|
116307
|
+
],
|
|
116308
|
+
},
|
|
116309
|
+
},
|
|
116310
|
+
])
|
|
116311
|
+
.data('fromMarkdownExtensions', [legacyVariableFromMarkdown(), looseHtmlEntityFromMarkdown()])
|
|
116312
|
+
.use(remarkParse)
|
|
116313
|
+
.use(remarkGfm);
|
|
116314
|
+
const parseApiHeaderTitle = (text) => {
|
|
116240
116315
|
if (!text.trim())
|
|
116241
116316
|
return textToInline(text);
|
|
116242
|
-
const tree =
|
|
116243
|
-
return tree.children;
|
|
116317
|
+
const tree = apiHeaderTitleParser.runSync(apiHeaderTitleParser.parse(text));
|
|
116318
|
+
return tree.children.flatMap(n => n.type === 'paragraph' && 'children' in n ? n.children : [n]);
|
|
116244
116319
|
};
|
|
116245
116320
|
/**
|
|
116246
116321
|
* Transform a magicBlock node into final MDAST nodes.
|
|
@@ -116299,7 +116374,7 @@ function transformMagicBlock(blockType, data, rawValue, options = {}) {
|
|
|
116299
116374
|
const depth = headerJson.level || (compatibilityMode ? 1 : 2);
|
|
116300
116375
|
return [
|
|
116301
116376
|
wrapPinnedBlocks({
|
|
116302
|
-
children: 'title' in headerJson ?
|
|
116377
|
+
children: 'title' in headerJson ? parseApiHeaderTitle(headerJson.title || '') : [],
|
|
116303
116378
|
depth,
|
|
116304
116379
|
type: 'heading',
|
|
116305
116380
|
}, data),
|
|
@@ -117531,11 +117606,66 @@ const transformMagicBlockEmbed = (node) => {
|
|
|
117531
117606
|
position,
|
|
117532
117607
|
};
|
|
117533
117608
|
};
|
|
117609
|
+
const mdxish_jsx_to_mdast_isTableCell = (node) => isMDXElement(node) && ['th', 'td'].includes(node.name);
|
|
117610
|
+
/**
|
|
117611
|
+
* Converts a JSX <Table> element to an MDAST table node with alignment.
|
|
117612
|
+
* Returns null for header-less tables since MDAST always promotes the first row to <thead>.
|
|
117613
|
+
*/
|
|
117614
|
+
const transformTable = (jsx) => {
|
|
117615
|
+
let hasThead = false;
|
|
117616
|
+
visit(jsx, isMDXElement, (child) => {
|
|
117617
|
+
if (child.name === 'thead')
|
|
117618
|
+
hasThead = true;
|
|
117619
|
+
});
|
|
117620
|
+
if (!hasThead)
|
|
117621
|
+
return null;
|
|
117622
|
+
const { align: alignAttr } = getAttrs(jsx);
|
|
117623
|
+
const align = Array.isArray(alignAttr) ? alignAttr : null;
|
|
117624
|
+
const rows = [];
|
|
117625
|
+
visit(jsx, isMDXElement, (child) => {
|
|
117626
|
+
if (child.name !== 'thead' && child.name !== 'tbody')
|
|
117627
|
+
return;
|
|
117628
|
+
visit(child, isMDXElement, (row) => {
|
|
117629
|
+
if (row.name !== 'tr')
|
|
117630
|
+
return;
|
|
117631
|
+
const cells = [];
|
|
117632
|
+
visit(row, mdxish_jsx_to_mdast_isTableCell, (cell) => {
|
|
117633
|
+
const parsedChildren = cell.children.flatMap(parsedNode => {
|
|
117634
|
+
if (parsedNode.type === 'paragraph' && 'children' in parsedNode && parsedNode.children) {
|
|
117635
|
+
return parsedNode.children;
|
|
117636
|
+
}
|
|
117637
|
+
return [parsedNode];
|
|
117638
|
+
});
|
|
117639
|
+
cells.push({
|
|
117640
|
+
type: 'tableCell',
|
|
117641
|
+
children: parsedChildren,
|
|
117642
|
+
position: cell.position,
|
|
117643
|
+
});
|
|
117644
|
+
});
|
|
117645
|
+
rows.push({
|
|
117646
|
+
type: 'tableRow',
|
|
117647
|
+
children: cells,
|
|
117648
|
+
position: row.position,
|
|
117649
|
+
});
|
|
117650
|
+
});
|
|
117651
|
+
});
|
|
117652
|
+
const columnCount = rows[0]?.children?.length || 0;
|
|
117653
|
+
const alignArray = align && columnCount > 0
|
|
117654
|
+
? align.slice(0, columnCount).concat(Array.from({ length: Math.max(0, columnCount - align.length) }, () => null))
|
|
117655
|
+
: Array.from({ length: columnCount }, () => null);
|
|
117656
|
+
return {
|
|
117657
|
+
type: 'table',
|
|
117658
|
+
align: alignArray,
|
|
117659
|
+
position: jsx.position,
|
|
117660
|
+
children: rows,
|
|
117661
|
+
};
|
|
117662
|
+
};
|
|
117534
117663
|
const COMPONENT_MAP = {
|
|
117535
117664
|
Callout: transformCallout,
|
|
117536
117665
|
Embed: transformEmbed,
|
|
117537
117666
|
Image: transformImage,
|
|
117538
117667
|
Recipe: transformRecipe,
|
|
117668
|
+
Table: transformTable,
|
|
117539
117669
|
};
|
|
117540
117670
|
/**
|
|
117541
117671
|
* Transform mdxJsxFlowElement nodes and magic block nodes into proper MDAST node types.
|
|
@@ -117558,6 +117688,8 @@ const mdxishJsxToMdast = () => tree => {
|
|
|
117558
117688
|
if (!transformer)
|
|
117559
117689
|
return;
|
|
117560
117690
|
const newNode = transformer(node);
|
|
117691
|
+
if (!newNode)
|
|
117692
|
+
return;
|
|
117561
117693
|
// Replace the JSX node with the MDAST node
|
|
117562
117694
|
parent.children[index] = newNode;
|
|
117563
117695
|
});
|
|
@@ -117838,6 +117970,126 @@ function restoreSnakeCase(placeholderName, mapping) {
|
|
|
117838
117970
|
return matchingKey ? mapping[matchingKey] : placeholderName;
|
|
117839
117971
|
}
|
|
117840
117972
|
|
|
117973
|
+
;// ./processor/transform/mdxish/mdxish-tables-to-jsx.ts
|
|
117974
|
+
|
|
117975
|
+
|
|
117976
|
+
const mdxish_tables_to_jsx_alignToStyle = (align) => {
|
|
117977
|
+
if (!align || align === 'left')
|
|
117978
|
+
return null;
|
|
117979
|
+
return {
|
|
117980
|
+
type: 'mdxJsxAttribute',
|
|
117981
|
+
name: 'style',
|
|
117982
|
+
value: {
|
|
117983
|
+
type: 'mdxJsxAttributeValueExpression',
|
|
117984
|
+
value: `{ textAlign: "${align}" }`,
|
|
117985
|
+
},
|
|
117986
|
+
};
|
|
117987
|
+
};
|
|
117988
|
+
const mdxish_tables_to_jsx_isTableCell = (node) => ['tableHead', 'tableCell'].includes(node.type);
|
|
117989
|
+
const mdxish_tables_to_jsx_isLiteral = (node) => 'value' in node;
|
|
117990
|
+
/**
|
|
117991
|
+
* Mdxish-specific version of `tablesToJsx`. Differs from the shared MDX version:
|
|
117992
|
+
*
|
|
117993
|
+
* - Excludes `html` nodes from triggering JSX conversion because raw HTML
|
|
117994
|
+
* inside JSX `<Table>` breaks remarkMdx parsing on the deserialization roundtrip.
|
|
117995
|
+
* - Skips empty cells instead of aborting the entire visit so that flow content
|
|
117996
|
+
* in later cells is still detected.
|
|
117997
|
+
*/
|
|
117998
|
+
const mdxishTablesToJsx = () => tree => {
|
|
117999
|
+
visit(tree, (node) => ['table', 'tableau'].includes(node.type), (table, index, parent) => {
|
|
118000
|
+
let hasFlowContent = false;
|
|
118001
|
+
visit(table, mdxish_tables_to_jsx_isTableCell, (cell) => {
|
|
118002
|
+
if (cell.children.length === 0)
|
|
118003
|
+
return;
|
|
118004
|
+
const content = cell.children.length === 1 && cell.children[0].type === 'paragraph'
|
|
118005
|
+
? cell.children[0].children[0]
|
|
118006
|
+
: cell.children[0];
|
|
118007
|
+
if (!content)
|
|
118008
|
+
return;
|
|
118009
|
+
visit(cell, 'break', (_, breakIndex, breakParent) => {
|
|
118010
|
+
breakParent.children.splice(breakIndex, 1, { type: 'text', value: '\n' });
|
|
118011
|
+
});
|
|
118012
|
+
if (!(phrasing(content) || content.type === 'plain') && content.type !== 'escape') {
|
|
118013
|
+
if (content.type === 'html')
|
|
118014
|
+
return;
|
|
118015
|
+
hasFlowContent = true;
|
|
118016
|
+
return EXIT;
|
|
118017
|
+
}
|
|
118018
|
+
visit(cell, mdxish_tables_to_jsx_isLiteral, (node) => {
|
|
118019
|
+
if (node.value.match(/\n/)) {
|
|
118020
|
+
hasFlowContent = true;
|
|
118021
|
+
return EXIT;
|
|
118022
|
+
}
|
|
118023
|
+
});
|
|
118024
|
+
});
|
|
118025
|
+
if (!hasFlowContent) {
|
|
118026
|
+
table.type = 'table';
|
|
118027
|
+
return;
|
|
118028
|
+
}
|
|
118029
|
+
const styles = table.align.map(mdxish_tables_to_jsx_alignToStyle);
|
|
118030
|
+
const head = {
|
|
118031
|
+
attributes: [],
|
|
118032
|
+
type: 'mdxJsxFlowElement',
|
|
118033
|
+
name: 'thead',
|
|
118034
|
+
children: [
|
|
118035
|
+
{
|
|
118036
|
+
attributes: [],
|
|
118037
|
+
type: 'mdxJsxFlowElement',
|
|
118038
|
+
name: 'tr',
|
|
118039
|
+
children: table.children[0].children.map((cell, cellIndex) => {
|
|
118040
|
+
return {
|
|
118041
|
+
attributes: [],
|
|
118042
|
+
type: 'mdxJsxFlowElement',
|
|
118043
|
+
name: 'th',
|
|
118044
|
+
children: cell.children,
|
|
118045
|
+
...(styles[cellIndex] && { attributes: [styles[cellIndex]] }),
|
|
118046
|
+
};
|
|
118047
|
+
}),
|
|
118048
|
+
},
|
|
118049
|
+
],
|
|
118050
|
+
};
|
|
118051
|
+
const body = {
|
|
118052
|
+
attributes: [],
|
|
118053
|
+
type: 'mdxJsxFlowElement',
|
|
118054
|
+
name: 'tbody',
|
|
118055
|
+
children: table.children.splice(1).map(row => {
|
|
118056
|
+
return {
|
|
118057
|
+
attributes: [],
|
|
118058
|
+
type: 'mdxJsxFlowElement',
|
|
118059
|
+
name: 'tr',
|
|
118060
|
+
children: row.children.map((cell, cellIndex) => {
|
|
118061
|
+
return {
|
|
118062
|
+
type: 'mdxJsxFlowElement',
|
|
118063
|
+
name: 'td',
|
|
118064
|
+
children: cell.children,
|
|
118065
|
+
...(styles[cellIndex] && { attributes: [styles[cellIndex]] }),
|
|
118066
|
+
};
|
|
118067
|
+
}),
|
|
118068
|
+
};
|
|
118069
|
+
}),
|
|
118070
|
+
};
|
|
118071
|
+
const attributes = [
|
|
118072
|
+
{
|
|
118073
|
+
type: 'mdxJsxAttribute',
|
|
118074
|
+
name: 'align',
|
|
118075
|
+
value: {
|
|
118076
|
+
type: 'mdxJsxAttributeValueExpression',
|
|
118077
|
+
value: JSON.stringify(table.align),
|
|
118078
|
+
},
|
|
118079
|
+
},
|
|
118080
|
+
];
|
|
118081
|
+
const jsx = {
|
|
118082
|
+
type: 'mdxJsxFlowElement',
|
|
118083
|
+
name: 'Table',
|
|
118084
|
+
attributes: table.align.find(a => a) ? attributes : [],
|
|
118085
|
+
children: [head, body],
|
|
118086
|
+
};
|
|
118087
|
+
parent.children[index] = jsx;
|
|
118088
|
+
});
|
|
118089
|
+
return tree;
|
|
118090
|
+
};
|
|
118091
|
+
/* harmony default export */ const mdxish_tables_to_jsx = (mdxishTablesToJsx);
|
|
118092
|
+
|
|
117841
118093
|
;// ./processor/transform/mdxish/normalize-table-separator.ts
|
|
117842
118094
|
/**
|
|
117843
118095
|
* Preprocessor to normalize malformed GFM table separator syntax.
|
|
@@ -120006,6 +120258,8 @@ function loadComponents() {
|
|
|
120006
120258
|
|
|
120007
120259
|
|
|
120008
120260
|
|
|
120261
|
+
|
|
120262
|
+
|
|
120009
120263
|
|
|
120010
120264
|
|
|
120011
120265
|
|
|
@@ -120103,18 +120357,28 @@ function mdxishAstProcessor(mdContent, opts = {}) {
|
|
|
120103
120357
|
};
|
|
120104
120358
|
}
|
|
120105
120359
|
/**
|
|
120106
|
-
*
|
|
120360
|
+
* Registers the mdx-jsx serialization extension so remark-stringify
|
|
120361
|
+
* can convert JSX nodes (e.g. `<Table>`) to markdown.
|
|
120362
|
+
*/
|
|
120363
|
+
function mdxJsxStringify() {
|
|
120364
|
+
const data = this.data();
|
|
120365
|
+
const extensions = data.toMarkdownExtensions || (data.toMarkdownExtensions = []);
|
|
120366
|
+
extensions.push({ extensions: [mdxJsxToMarkdown()] });
|
|
120367
|
+
}
|
|
120368
|
+
/**
|
|
120369
|
+
* Serializes an Mdast back into a markdown string.
|
|
120107
120370
|
*/
|
|
120108
120371
|
function mdxishMdastToMd(mdast) {
|
|
120109
|
-
const
|
|
120372
|
+
const processor = unified()
|
|
120110
120373
|
.use(remarkGfm)
|
|
120374
|
+
.use(mdxish_tables_to_jsx)
|
|
120111
120375
|
.use(mdxishCompilers)
|
|
120376
|
+
.use(mdxJsxStringify)
|
|
120112
120377
|
.use(remarkStringify, {
|
|
120113
120378
|
bullet: '-',
|
|
120114
120379
|
emphasis: '_',
|
|
120115
|
-
})
|
|
120116
|
-
|
|
120117
|
-
return md;
|
|
120380
|
+
});
|
|
120381
|
+
return processor.stringify(processor.runSync(mdast));
|
|
120118
120382
|
}
|
|
120119
120383
|
/**
|
|
120120
120384
|
* Processes markdown content with MDX syntax support and returns a HAST.
|