@readme/markdown 11.12.0 → 11.13.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/components/Anchor.tsx +10 -1
- package/components/Code/index.tsx +3 -2
- package/components/CodeTabs/index.tsx +31 -12
- package/dist/index.d.ts +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/mdxish.d.ts +15 -1
- package/dist/main.js +421 -107
- package/dist/main.node.js +421 -107
- package/dist/main.node.js.map +1 -1
- package/dist/processor/transform/mdxish/mdxish-component-blocks.d.ts +63 -0
- package/dist/processor/transform/mdxish/mdxish-mermaid.d.ts +8 -0
- package/dist/processor/transform/mdxish/retain-boolean-attributes.d.ts +9 -0
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -11366,6 +11366,8 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
11366
11366
|
mdastV6: () => (/* reexport */ lib_mdastV6),
|
|
11367
11367
|
mdx: () => (/* reexport */ lib_mdx),
|
|
11368
11368
|
mdxish: () => (/* reexport */ lib_mdxish),
|
|
11369
|
+
mdxishAstProcessor: () => (/* reexport */ mdxishAstProcessor),
|
|
11370
|
+
mdxishMdastToMd: () => (/* reexport */ mdxishMdastToMd),
|
|
11369
11371
|
mdxishTags: () => (/* reexport */ mdxishTags),
|
|
11370
11372
|
migrate: () => (/* reexport */ lib_migrate),
|
|
11371
11373
|
mix: () => (/* reexport */ lib_mix),
|
|
@@ -11513,9 +11515,17 @@ function docLink(href) {
|
|
|
11513
11515
|
function Anchor(props) {
|
|
11514
11516
|
const { children, href = '', target = '', title = '', ...attrs } = props;
|
|
11515
11517
|
const baseUrl = (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useContext)(BaseUrl);
|
|
11518
|
+
// Unwrap any nested anchor elements that GFM's autolinker may have created.
|
|
11519
|
+
// This prevents invalid nested <a> tags when the Anchor's text content looks like a URL.
|
|
11520
|
+
const unwrappedChildren = external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().Children.map(children, child => {
|
|
11521
|
+
if (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().isValidElement(child) && child.type === 'a') {
|
|
11522
|
+
return child.props.children;
|
|
11523
|
+
}
|
|
11524
|
+
return child;
|
|
11525
|
+
});
|
|
11516
11526
|
return (
|
|
11517
11527
|
// eslint-disable-next-line react/jsx-props-no-spreading
|
|
11518
|
-
external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("a", { ...attrs, href: getHref(href, baseUrl), target: target, title: title, ...docLink(href) },
|
|
11528
|
+
external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("a", { ...attrs, href: getHref(href, baseUrl), target: target, title: title, ...docLink(href) }, unwrappedChildren));
|
|
11519
11529
|
}
|
|
11520
11530
|
/* harmony default export */ const components_Anchor = (Anchor);
|
|
11521
11531
|
|
|
@@ -11653,7 +11663,8 @@ const Code = (props) => {
|
|
|
11653
11663
|
const theme = (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useContext)(Theme);
|
|
11654
11664
|
const copyButtons = (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useContext)(CodeOpts) || props.copyButtons;
|
|
11655
11665
|
const isHydrated = useHydrated();
|
|
11656
|
-
const language =
|
|
11666
|
+
const language = canonicalLanguage(lang);
|
|
11667
|
+
const isMermaid = language === 'mermaid';
|
|
11657
11668
|
const codeRef = (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.createRef)();
|
|
11658
11669
|
const codeOpts = {
|
|
11659
11670
|
inline: !lang,
|
|
@@ -11664,7 +11675,7 @@ const Code = (props) => {
|
|
|
11664
11675
|
const highlightedCode = syntaxHighlighter && typeof syntaxHighlighter === 'function' && code && isHydrated
|
|
11665
11676
|
? syntaxHighlighter(code, language, codeOpts, { mdx: true })
|
|
11666
11677
|
: code;
|
|
11667
|
-
if (
|
|
11678
|
+
if (isHydrated && isMermaid) {
|
|
11668
11679
|
return code;
|
|
11669
11680
|
}
|
|
11670
11681
|
return (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement((external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default()).Fragment, null,
|
|
@@ -11680,15 +11691,28 @@ var dist_utils_default = /*#__PURE__*/__webpack_require__.n(dist_utils);
|
|
|
11680
11691
|
|
|
11681
11692
|
|
|
11682
11693
|
|
|
11694
|
+
|
|
11683
11695
|
let mermaid;
|
|
11684
11696
|
const { uppercase } = (dist_utils_default());
|
|
11685
11697
|
const CodeTabs = (props) => {
|
|
11686
11698
|
const { children } = props;
|
|
11687
11699
|
const theme = (0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useContext)(Theme);
|
|
11688
|
-
const
|
|
11689
|
-
//
|
|
11700
|
+
const isHydrated = useHydrated();
|
|
11701
|
+
// Handle both array (from rehype-react in rendering mdxish) and single element (MDX/JSX runtime) cases
|
|
11702
|
+
// The children here is the individual code block objects
|
|
11703
|
+
const childrenArray = Array.isArray(children) ? children : [children];
|
|
11704
|
+
// The structure varies depending on rendering context:
|
|
11705
|
+
// - When rendered via rehype-react: pre.props.children is an array where the first element is the Code component
|
|
11706
|
+
// - When rendered via MDX/JSX runtime: pre.props.children is directly the Code component
|
|
11707
|
+
const getCodeComponent = (pre) => {
|
|
11708
|
+
return Array.isArray(pre?.props?.children) ? pre.props.children[0] : pre?.props?.children;
|
|
11709
|
+
};
|
|
11710
|
+
const containAtLeastOneMermaid = childrenArray.some(pre => getCodeComponent(pre)?.props?.lang === 'mermaid');
|
|
11711
|
+
// Render Mermaid diagram
|
|
11690
11712
|
(0,external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_.useEffect)(() => {
|
|
11691
|
-
|
|
11713
|
+
// Ensure we only render mermaids when frontend is hydrated to avoid hydration errors
|
|
11714
|
+
// because mermaid mutates the DOM before react hydrates
|
|
11715
|
+
if (typeof window !== 'undefined' && containAtLeastOneMermaid && isHydrated) {
|
|
11692
11716
|
Promise.resolve(/* import() */).then(__webpack_require__.t.bind(__webpack_require__, 1387, 23)).then(module => {
|
|
11693
11717
|
mermaid = module.default;
|
|
11694
11718
|
mermaid.initialize({
|
|
@@ -11700,7 +11724,7 @@ const CodeTabs = (props) => {
|
|
|
11700
11724
|
});
|
|
11701
11725
|
});
|
|
11702
11726
|
}
|
|
11703
|
-
}, [
|
|
11727
|
+
}, [containAtLeastOneMermaid, theme, isHydrated]);
|
|
11704
11728
|
function handleClick({ target }, index) {
|
|
11705
11729
|
const $wrap = target.parentElement.parentElement;
|
|
11706
11730
|
const $open = [].slice.call($wrap.querySelectorAll('.CodeTabs_active'));
|
|
@@ -11710,19 +11734,22 @@ const CodeTabs = (props) => {
|
|
|
11710
11734
|
codeblocks[index].classList.add('CodeTabs_active');
|
|
11711
11735
|
target.classList.add('CodeTabs_active');
|
|
11712
11736
|
}
|
|
11713
|
-
// render single
|
|
11714
|
-
if (
|
|
11715
|
-
const
|
|
11716
|
-
|
|
11737
|
+
// We want to render single mermaid diagrams without the code tabs UI
|
|
11738
|
+
if (childrenArray.length === 1) {
|
|
11739
|
+
const codeComponent = getCodeComponent(childrenArray[0]);
|
|
11740
|
+
if (codeComponent?.props?.lang === 'mermaid') {
|
|
11741
|
+
const value = codeComponent?.props?.value;
|
|
11742
|
+
return external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("pre", { className: "mermaid-render mermaid_single" }, value);
|
|
11743
|
+
}
|
|
11717
11744
|
}
|
|
11718
11745
|
return (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("div", { className: `CodeTabs CodeTabs_initial theme-${theme}` },
|
|
11719
|
-
external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("div", { className: "CodeTabs-toolbar" },
|
|
11746
|
+
external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("div", { className: "CodeTabs-toolbar" }, childrenArray.map((pre, i) => {
|
|
11720
11747
|
// the first or only child should be our Code component
|
|
11721
|
-
const
|
|
11748
|
+
const tabCodeComponent = Array.isArray(pre.props?.children)
|
|
11722
11749
|
? pre.props.children[0]
|
|
11723
11750
|
: pre.props?.children;
|
|
11724
|
-
const lang =
|
|
11725
|
-
const meta =
|
|
11751
|
+
const lang = tabCodeComponent?.props?.lang;
|
|
11752
|
+
const meta = tabCodeComponent?.props?.meta;
|
|
11726
11753
|
/* istanbul ignore next */
|
|
11727
11754
|
return (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("button", { key: i, onClick: e => handleClick(e, i), type: "button", value: lang }, meta || `${!lang ? 'Text' : uppercase(lang)}`));
|
|
11728
11755
|
})),
|
|
@@ -70584,77 +70611,197 @@ const mdxToHast = () => tree => {
|
|
|
70584
70611
|
;// ./processor/transform/mdxish/mdxish-component-blocks.ts
|
|
70585
70612
|
|
|
70586
70613
|
|
|
70587
|
-
const
|
|
70588
|
-
const
|
|
70614
|
+
const pascalCaseTagPattern = /^<([A-Z][A-Za-z0-9_]*)([^>]*?)(\/?)>([\s\S]*)?$/;
|
|
70615
|
+
const tagAttributePattern = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*("[^"]*"|'[^']*'|[^\s"'>]+))?/g;
|
|
70616
|
+
/**
|
|
70617
|
+
* Maximum number of siblings to scan forward when looking for a closing tag
|
|
70618
|
+
* to avoid scanning too far and degrading performance
|
|
70619
|
+
*/
|
|
70620
|
+
const MAX_LOOKAHEAD = 30;
|
|
70621
|
+
/**
|
|
70622
|
+
* Tags that have dedicated transformers and should NOT be handled by this plugin.
|
|
70623
|
+
* These components have special parsing requirements that the generic component
|
|
70624
|
+
* block transformer cannot handle correctly.
|
|
70625
|
+
*/
|
|
70626
|
+
const EXCLUDED_TAGS = new Set(['HTMLBlock', 'Table']);
|
|
70589
70627
|
const inlineMdProcessor = unified().use(remarkParse);
|
|
70590
70628
|
const isClosingTag = (value, tag) => value.trim() === `</${tag}>`;
|
|
70591
|
-
|
|
70592
|
-
|
|
70593
|
-
|
|
70594
|
-
return { paragraph: node, found: false };
|
|
70595
|
-
const children = [...node.children];
|
|
70596
|
-
const closingIndex = children.findIndex(child => child.type === 'html' && isClosingTag(child.value || '', tag));
|
|
70597
|
-
if (closingIndex === -1)
|
|
70598
|
-
return { paragraph: node, found: false };
|
|
70599
|
-
children.splice(closingIndex, 1);
|
|
70600
|
-
return {
|
|
70601
|
-
paragraph: { ...node, children },
|
|
70602
|
-
found: true,
|
|
70603
|
-
};
|
|
70604
|
-
};
|
|
70605
|
-
// Replace two child nodes (opening HTML tag + paragraph) with a single replacement node
|
|
70606
|
-
const replaceChild = (parent, index, replacement) => {
|
|
70607
|
-
parent.children.splice(index, 2, replacement);
|
|
70608
|
-
};
|
|
70609
|
-
// Parse markdown inside a component's inline content into mdast children.
|
|
70629
|
+
/**
|
|
70630
|
+
* Parse markdown content into mdast children nodes.
|
|
70631
|
+
*/
|
|
70610
70632
|
const parseMdChildren = (value) => {
|
|
70611
70633
|
const parsed = inlineMdProcessor.parse(value);
|
|
70612
70634
|
return parsed.children || [];
|
|
70613
70635
|
};
|
|
70614
|
-
|
|
70615
|
-
|
|
70636
|
+
/**
|
|
70637
|
+
* Convert raw attribute string into mdxJsxAttribute entries.
|
|
70638
|
+
* Handles both key-value attributes (theme="info") and boolean attributes (empty).
|
|
70639
|
+
*/
|
|
70616
70640
|
const parseAttributes = (raw) => {
|
|
70617
70641
|
const attributes = [];
|
|
70618
70642
|
const attrString = raw.trim();
|
|
70619
70643
|
if (!attrString)
|
|
70620
70644
|
return attributes;
|
|
70621
|
-
|
|
70622
|
-
|
|
70623
|
-
let match = attributePattern.exec(attrString);
|
|
70645
|
+
tagAttributePattern.lastIndex = 0;
|
|
70646
|
+
let match = tagAttributePattern.exec(attrString);
|
|
70624
70647
|
while (match !== null) {
|
|
70625
70648
|
const [, attrName, attrValue] = match;
|
|
70626
|
-
// Boolean attribute (no value) -> set to null
|
|
70627
|
-
// Attribute with value -> clean and set string value
|
|
70628
|
-
// Note: Attribute value types can't directly be numbers & booleans. String, nulls, undefined are supported.
|
|
70629
70649
|
const value = attrValue ? attrValue.replace(/^['"]|['"]$/g, '') : null;
|
|
70630
|
-
attributes.push({
|
|
70631
|
-
|
|
70632
|
-
name: attrName,
|
|
70633
|
-
value,
|
|
70634
|
-
});
|
|
70635
|
-
match = attributePattern.exec(attrString);
|
|
70650
|
+
attributes.push({ type: 'mdxJsxAttribute', name: attrName, value });
|
|
70651
|
+
match = tagAttributePattern.exec(attrString);
|
|
70636
70652
|
}
|
|
70637
70653
|
return attributes;
|
|
70638
70654
|
};
|
|
70639
|
-
|
|
70655
|
+
/**
|
|
70656
|
+
* Parse an HTML tag string into structured data.
|
|
70657
|
+
*/
|
|
70640
70658
|
const parseTag = (value) => {
|
|
70641
|
-
const match = value.match(
|
|
70659
|
+
const match = value.match(pascalCaseTagPattern);
|
|
70642
70660
|
if (!match)
|
|
70643
70661
|
return null;
|
|
70644
|
-
const [, tag, attrString = '', selfClosing = '',
|
|
70645
|
-
const attributes = parseAttributes(attrString);
|
|
70662
|
+
const [, tag, attrString = '', selfClosing = '', contentAfterTag = ''] = match;
|
|
70646
70663
|
return {
|
|
70647
70664
|
tag,
|
|
70648
|
-
attributes,
|
|
70665
|
+
attributes: parseAttributes(attrString),
|
|
70649
70666
|
selfClosing: !!selfClosing,
|
|
70650
|
-
|
|
70667
|
+
contentAfterTag,
|
|
70651
70668
|
};
|
|
70652
70669
|
};
|
|
70653
|
-
|
|
70654
|
-
|
|
70670
|
+
/**
|
|
70671
|
+
* Create an MdxJsxFlowElement node from component data.
|
|
70672
|
+
*/
|
|
70673
|
+
const createComponentNode = ({ tag, attributes, children, startPosition, endPosition }) => ({
|
|
70674
|
+
type: 'mdxJsxFlowElement',
|
|
70675
|
+
name: tag,
|
|
70676
|
+
attributes,
|
|
70677
|
+
children,
|
|
70678
|
+
position: {
|
|
70679
|
+
start: startPosition?.start,
|
|
70680
|
+
end: endPosition?.end ?? startPosition?.end,
|
|
70681
|
+
},
|
|
70682
|
+
});
|
|
70683
|
+
/**
|
|
70684
|
+
* Remove a closing tag from a paragraph's children and return the updated paragraph.
|
|
70685
|
+
*/
|
|
70686
|
+
const stripClosingTagFromParagraph = (node, tag) => {
|
|
70687
|
+
if (!Array.isArray(node.children))
|
|
70688
|
+
return { paragraph: node, found: false };
|
|
70689
|
+
const children = [...node.children];
|
|
70690
|
+
const closingIndex = children.findIndex(child => child.type === 'html' && isClosingTag(child.value || '', tag));
|
|
70691
|
+
if (closingIndex === -1)
|
|
70692
|
+
return { paragraph: node, found: false };
|
|
70693
|
+
children.splice(closingIndex, 1);
|
|
70694
|
+
return { paragraph: { ...node, children }, found: true };
|
|
70695
|
+
};
|
|
70696
|
+
/**
|
|
70697
|
+
* Scan forward through siblings to find a closing tag.
|
|
70698
|
+
* Handles:
|
|
70699
|
+
* - Exact match HTML siblings (e.g., `</Tag>`)
|
|
70700
|
+
* - HTML siblings with embedded closing tag (e.g., `...\n</Tag>`)
|
|
70701
|
+
* - Paragraph siblings containing the closing tag as a child
|
|
70702
|
+
*
|
|
70703
|
+
* Returns null if not found within MAX_LOOKAHEAD siblings
|
|
70704
|
+
*/
|
|
70705
|
+
const scanForClosingTag = (parent, startIndex, tag) => {
|
|
70706
|
+
const closingTagStr = `</${tag}>`;
|
|
70707
|
+
const maxIndex = Math.min(startIndex + MAX_LOOKAHEAD, parent.children.length);
|
|
70708
|
+
let i = startIndex + 1;
|
|
70709
|
+
for (; i < maxIndex; i += 1) {
|
|
70710
|
+
const sibling = parent.children[i];
|
|
70711
|
+
// Check HTML siblings
|
|
70712
|
+
if (sibling.type === 'html') {
|
|
70713
|
+
const siblingValue = sibling.value || '';
|
|
70714
|
+
// Exact match (standalone closing tag)
|
|
70715
|
+
if (isClosingTag(siblingValue, tag)) {
|
|
70716
|
+
return { closingIndex: i, extraClosingChildren: [] };
|
|
70717
|
+
}
|
|
70718
|
+
// Embedded closing tag (closing tag at end of HTML block content)
|
|
70719
|
+
if (siblingValue.includes(closingTagStr)) {
|
|
70720
|
+
const contentBeforeClose = siblingValue.substring(0, siblingValue.lastIndexOf(closingTagStr)).trim();
|
|
70721
|
+
const extraChildren = contentBeforeClose
|
|
70722
|
+
? parseMdChildren(contentBeforeClose)
|
|
70723
|
+
: [];
|
|
70724
|
+
return { closingIndex: i, extraClosingChildren: extraChildren };
|
|
70725
|
+
}
|
|
70726
|
+
}
|
|
70727
|
+
// Check paragraph siblings
|
|
70728
|
+
if (sibling.type === 'paragraph') {
|
|
70729
|
+
const { paragraph, found } = stripClosingTagFromParagraph(sibling, tag);
|
|
70730
|
+
if (found) {
|
|
70731
|
+
return { closingIndex: i, extraClosingChildren: [], strippedParagraph: paragraph };
|
|
70732
|
+
}
|
|
70733
|
+
}
|
|
70734
|
+
}
|
|
70735
|
+
if (i < parent.children.length) {
|
|
70736
|
+
// eslint-disable-next-line no-console
|
|
70737
|
+
console.warn(`Closing tag </${tag}> not found within ${MAX_LOOKAHEAD} siblings, stopping scan`);
|
|
70738
|
+
}
|
|
70739
|
+
return null;
|
|
70740
|
+
};
|
|
70741
|
+
const substituteNodeWithMdxNode = (parent, index, mdxNode) => {
|
|
70742
|
+
parent.children.splice(index, 1, mdxNode);
|
|
70743
|
+
};
|
|
70744
|
+
/**
|
|
70745
|
+
* Transform PascalCase HTML nodes into mdxJsxFlowElement nodes.
|
|
70746
|
+
*
|
|
70747
|
+
* Remark parses unknown/custom component tags as raw HTML nodes.
|
|
70748
|
+
* These are the custom readme MDX syntax for components.
|
|
70749
|
+
* This transformer identifies these patterns and converts them to proper MDX JSX elements so they
|
|
70750
|
+
* can be accurately recognized and rendered later with their component definition code.
|
|
70751
|
+
* Though for some tags, we need to handle them specially
|
|
70752
|
+
*
|
|
70753
|
+
* ## Supported HTML Structures
|
|
70754
|
+
*
|
|
70755
|
+
* ### 1. Self-closing tags
|
|
70756
|
+
* ```
|
|
70757
|
+
* <Component />
|
|
70758
|
+
* ```
|
|
70759
|
+
* Parsed as: `html: "<Component />"`
|
|
70760
|
+
*
|
|
70761
|
+
* ### 2. Self-contained blocks (entire component in single HTML node)
|
|
70762
|
+
* ```
|
|
70763
|
+
* <Button>Click me</Button>
|
|
70764
|
+
* ```
|
|
70765
|
+
* ```
|
|
70766
|
+
* <Component>
|
|
70767
|
+
* <h2>Title</h2>
|
|
70768
|
+
* <p>Content</p>
|
|
70769
|
+
* </Component>
|
|
70770
|
+
* ```
|
|
70771
|
+
* Parsed as: `html: "<Component>\n <h2>Title</h2>\n <p>Content</p>\n</Component>"`
|
|
70772
|
+
* The opening tag, content, and closing tag are all captured in one HTML node.
|
|
70773
|
+
*
|
|
70774
|
+
* ### 3. Multi-sibling components (closing tag in a following sibling)
|
|
70775
|
+
* Handles various structures where the closing tag is in a later sibling, such as:
|
|
70776
|
+
*
|
|
70777
|
+
* #### 3a. Block components (closing tag in sibling paragraph)
|
|
70778
|
+
* ```
|
|
70779
|
+
* <Callout>
|
|
70780
|
+
* Some **markdown** content
|
|
70781
|
+
* </Callout>
|
|
70782
|
+
* ```
|
|
70783
|
+
*
|
|
70784
|
+
* #### 3b. Multi-paragraph components (closing tag several siblings away)
|
|
70785
|
+
* ```
|
|
70786
|
+
* <Callout>
|
|
70787
|
+
*
|
|
70788
|
+
* First paragraph
|
|
70789
|
+
*
|
|
70790
|
+
* Second paragraph
|
|
70791
|
+
* </Callout>
|
|
70792
|
+
* ```
|
|
70793
|
+
*
|
|
70794
|
+
* #### 3c. Nested components split by blank lines (closing tag embedded in HTML sibling)
|
|
70795
|
+
* ```
|
|
70796
|
+
* <Outer>
|
|
70797
|
+
* <Inner>content</Inner>
|
|
70798
|
+
*
|
|
70799
|
+
* <Inner>content</Inner>
|
|
70800
|
+
* </Outer>
|
|
70801
|
+
* ```
|
|
70802
|
+
*/
|
|
70655
70803
|
const mdxishComponentBlocks = () => tree => {
|
|
70656
70804
|
const stack = [tree];
|
|
70657
|
-
// Process children depth-first, rewriting opening/closing component HTML pairs
|
|
70658
70805
|
const processChildNode = (parent, index) => {
|
|
70659
70806
|
const node = parent.children[index];
|
|
70660
70807
|
if (!node)
|
|
@@ -70662,46 +70809,66 @@ const mdxishComponentBlocks = () => tree => {
|
|
|
70662
70809
|
if ('children' in node && Array.isArray(node.children)) {
|
|
70663
70810
|
stack.push(node);
|
|
70664
70811
|
}
|
|
70812
|
+
// Only visit HTML nodes with an actual html tag
|
|
70665
70813
|
const value = node.value;
|
|
70666
70814
|
if (node.type !== 'html' || typeof value !== 'string')
|
|
70667
70815
|
return;
|
|
70668
70816
|
const parsed = parseTag(value);
|
|
70669
70817
|
if (!parsed)
|
|
70670
70818
|
return;
|
|
70671
|
-
const { tag, attributes, selfClosing,
|
|
70672
|
-
|
|
70819
|
+
const { tag, attributes, selfClosing, contentAfterTag = '' } = parsed;
|
|
70820
|
+
// Skip tags that have dedicated transformers
|
|
70821
|
+
if (EXCLUDED_TAGS.has(tag))
|
|
70822
|
+
return;
|
|
70823
|
+
const closingTagStr = `</${tag}>`;
|
|
70824
|
+
// Case 1: Self-closing tag
|
|
70673
70825
|
if (selfClosing) {
|
|
70674
|
-
const componentNode = {
|
|
70675
|
-
|
|
70676
|
-
name: tag,
|
|
70826
|
+
const componentNode = createComponentNode({
|
|
70827
|
+
tag,
|
|
70677
70828
|
attributes,
|
|
70678
70829
|
children: [],
|
|
70679
|
-
|
|
70680
|
-
};
|
|
70681
|
-
parent
|
|
70830
|
+
startPosition: node.position,
|
|
70831
|
+
});
|
|
70832
|
+
substituteNodeWithMdxNode(parent, index, componentNode);
|
|
70682
70833
|
return;
|
|
70683
70834
|
}
|
|
70684
|
-
|
|
70685
|
-
if (
|
|
70835
|
+
// Case 2: Self-contained block (closing tag in content)
|
|
70836
|
+
if (contentAfterTag.includes(closingTagStr)) {
|
|
70837
|
+
const componentInnerContent = contentAfterTag.substring(0, contentAfterTag.lastIndexOf(closingTagStr)).trim();
|
|
70838
|
+
const componentNode = createComponentNode({
|
|
70839
|
+
tag,
|
|
70840
|
+
attributes,
|
|
70841
|
+
children: componentInnerContent ? parseMdChildren(componentInnerContent) : [],
|
|
70842
|
+
startPosition: node.position,
|
|
70843
|
+
});
|
|
70844
|
+
substituteNodeWithMdxNode(parent, index, componentNode);
|
|
70686
70845
|
return;
|
|
70687
|
-
|
|
70688
|
-
|
|
70846
|
+
}
|
|
70847
|
+
// Case 3: Multi-sibling component (closing tag in a following sibling)
|
|
70848
|
+
// Scans forward through siblings to find closing tag in HTML or paragraph nodes
|
|
70849
|
+
const scanResult = scanForClosingTag(parent, index, tag);
|
|
70850
|
+
if (!scanResult)
|
|
70689
70851
|
return;
|
|
70690
|
-
const
|
|
70691
|
-
|
|
70692
|
-
|
|
70852
|
+
const { closingIndex, extraClosingChildren, strippedParagraph } = scanResult;
|
|
70853
|
+
const extraChildren = contentAfterTag ? parseMdChildren(contentAfterTag.trimStart()) : [];
|
|
70854
|
+
// Collect all intermediate siblings between opening tag and closing tag
|
|
70855
|
+
const intermediateChildren = parent.children.slice(index + 1, closingIndex);
|
|
70856
|
+
// For paragraph siblings, include the paragraph's children (with closing tag stripped)
|
|
70857
|
+
// For HTML siblings, include any content parsed from before the closing tag
|
|
70858
|
+
const closingChildren = strippedParagraph
|
|
70859
|
+
? strippedParagraph.children
|
|
70860
|
+
: extraClosingChildren;
|
|
70861
|
+
const componentNode = createComponentNode({
|
|
70862
|
+
tag,
|
|
70693
70863
|
attributes,
|
|
70694
|
-
children: [
|
|
70695
|
-
|
|
70696
|
-
|
|
70697
|
-
|
|
70698
|
-
|
|
70699
|
-
|
|
70700
|
-
end: next.position?.end,
|
|
70701
|
-
},
|
|
70702
|
-
};
|
|
70703
|
-
replaceChild(parent, index, componentNode);
|
|
70864
|
+
children: [...extraChildren, ...intermediateChildren, ...closingChildren],
|
|
70865
|
+
startPosition: node.position,
|
|
70866
|
+
endPosition: parent.children[closingIndex]?.position,
|
|
70867
|
+
});
|
|
70868
|
+
// Remove all nodes from opening tag to closing tag (inclusive) and replace with component node
|
|
70869
|
+
parent.children.splice(index, closingIndex - index + 1, componentNode);
|
|
70704
70870
|
};
|
|
70871
|
+
// Travel the tree depth-first
|
|
70705
70872
|
while (stack.length) {
|
|
70706
70873
|
const parent = stack.pop();
|
|
70707
70874
|
if (parent?.children) {
|
|
@@ -71074,10 +71241,20 @@ const coerceJsxToMd = ({ components = {}, html = false } = {}) => (node, index,
|
|
|
71074
71241
|
hProperties.url = hProperties.href;
|
|
71075
71242
|
delete hProperties.href;
|
|
71076
71243
|
}
|
|
71244
|
+
// Unwrap any autolinked children to prevent nested links.
|
|
71245
|
+
// GFM's autolink feature can convert URL-like text inside Anchor children
|
|
71246
|
+
// into link nodes, which would create invalid nested links when Anchor
|
|
71247
|
+
// is converted back to a link node.
|
|
71248
|
+
const children = node.children.flatMap(child => {
|
|
71249
|
+
if (child.type === 'link') {
|
|
71250
|
+
return child.children;
|
|
71251
|
+
}
|
|
71252
|
+
return child;
|
|
71253
|
+
});
|
|
71077
71254
|
// @ts-expect-error we don't have a mechanism to enforce the URL attribute type right now
|
|
71078
71255
|
const mdNode = {
|
|
71079
71256
|
...hProperties,
|
|
71080
|
-
children
|
|
71257
|
+
children,
|
|
71081
71258
|
type: types[node.name],
|
|
71082
71259
|
position: node.position,
|
|
71083
71260
|
};
|
|
@@ -86366,16 +86543,17 @@ const tocHastToMdx = (toc, components) => {
|
|
|
86366
86543
|
|
|
86367
86544
|
|
|
86368
86545
|
|
|
86369
|
-
const { codeTabsTransformer: compile_codeTabsTransformer, ...transforms } = defaultTransforms;
|
|
86370
86546
|
const sanitizeSchema = cjs_default()(defaultSchema, {
|
|
86371
86547
|
protocols: ['doc', 'ref', 'blog', 'changelog', 'page'],
|
|
86372
86548
|
});
|
|
86373
86549
|
const compile_compile = (text, { components = {}, missingComponents, copyButtons, useTailwind, ...opts } = {}) => {
|
|
86550
|
+
// Destructure at runtime to avoid circular dependency issues
|
|
86551
|
+
const { codeTabsTransformer, ...transforms } = defaultTransforms;
|
|
86374
86552
|
const remarkPlugins = [
|
|
86375
86553
|
remarkFrontmatter,
|
|
86376
86554
|
remarkGfm,
|
|
86377
86555
|
...Object.values(transforms),
|
|
86378
|
-
[
|
|
86556
|
+
[codeTabsTransformer, { copyButtons }],
|
|
86379
86557
|
[
|
|
86380
86558
|
handle_missing_components,
|
|
86381
86559
|
{ components, missingComponents: ['ignore', 'throw'].includes(missingComponents) ? missingComponents : 'ignore' },
|
|
@@ -92845,8 +93023,11 @@ function smartCamelCase(str) {
|
|
|
92845
93023
|
}
|
|
92846
93024
|
// Sort by length (longest first) to prevent shorter matches (e.g., "column" in "columns")
|
|
92847
93025
|
const sortedBoundaries = [...allBoundaries].sort((a, b) => b.length - a.length);
|
|
93026
|
+
// Use case-sensitive matching ('g' not 'gi') so that once a letter is
|
|
93027
|
+
// capitalized by a longer boundary, shorter boundaries won't re-match it.
|
|
93028
|
+
// This prevents issues like 'iconcolor' becoming 'iconColOr' instead of 'iconColor'.
|
|
92848
93029
|
return sortedBoundaries.reduce((res, word) => {
|
|
92849
|
-
const regex = new RegExp(`(${word})([a-z])`, '
|
|
93030
|
+
const regex = new RegExp(`(${word})([a-z])`, 'g');
|
|
92850
93031
|
return res.replace(regex, (_, prefix, nextChar) => prefix.toLowerCase() + nextChar.toUpperCase());
|
|
92851
93032
|
}, str);
|
|
92852
93033
|
}
|
|
@@ -92972,7 +93153,21 @@ const htmlBlockHandler = (_state, node) => {
|
|
|
92972
93153
|
children: [],
|
|
92973
93154
|
};
|
|
92974
93155
|
};
|
|
93156
|
+
// Convert embed magic blocks to Embed components
|
|
93157
|
+
const embedHandler = (state, node) => {
|
|
93158
|
+
// Assert to get the minimum properties we need
|
|
93159
|
+
const { data } = node;
|
|
93160
|
+
return {
|
|
93161
|
+
type: 'element',
|
|
93162
|
+
// To differentiate between regular embeds and magic block embeds,
|
|
93163
|
+
// magic block embeds have a certain hName
|
|
93164
|
+
tagName: data?.hName === NodeTypes.embedBlock ? 'Embed' : 'embed',
|
|
93165
|
+
properties: data?.hProperties,
|
|
93166
|
+
children: state.all(node),
|
|
93167
|
+
};
|
|
93168
|
+
};
|
|
92975
93169
|
const mdxComponentHandlers = {
|
|
93170
|
+
embed: embedHandler,
|
|
92976
93171
|
mdxFlowExpression: mdxExpressionHandler,
|
|
92977
93172
|
mdxJsxFlowElement: mdxJsxElementHandler,
|
|
92978
93173
|
mdxJsxTextElement: mdxJsxElementHandler,
|
|
@@ -93636,8 +93831,6 @@ const mdxishHtmlBlocks = () => tree => {
|
|
|
93636
93831
|
* Taken from the v6 branch
|
|
93637
93832
|
*/
|
|
93638
93833
|
const RGXP = /^\s*\[block:([^\]]*)\]([^]+?)\[\/block\]/;
|
|
93639
|
-
/** Parses markdown in table cells */
|
|
93640
|
-
const cellParser = unified().use(remarkParse).use(remarkGfm);
|
|
93641
93834
|
/**
|
|
93642
93835
|
* Wraps a node in a "pinned" container if sidebar: true is set in the JSON.
|
|
93643
93836
|
* Pinned blocks are displayed in a sidebar/floating position in the UI.
|
|
@@ -93671,11 +93864,13 @@ const imgWidthBySize = new Proxy(imgSizeValues, {
|
|
|
93671
93864
|
const textToInline = (text) => [{ type: 'text', value: text }];
|
|
93672
93865
|
// Simple text to block nodes (wraps in paragraph)
|
|
93673
93866
|
const textToBlock = (text) => [{ children: textToInline(text), type: 'paragraph' }];
|
|
93867
|
+
/** Parses markdown and html to markdown nodes */
|
|
93868
|
+
const contentParser = unified().use(remarkParse).use(remarkGfm);
|
|
93674
93869
|
// Table cells may contain html or markdown content, so we need to parse it accordingly instead of keeping it as raw text
|
|
93675
|
-
const
|
|
93870
|
+
const parseTableCell = (text) => {
|
|
93676
93871
|
if (!text.trim())
|
|
93677
93872
|
return [{ type: 'text', value: '' }];
|
|
93678
|
-
const tree =
|
|
93873
|
+
const tree = contentParser.runSync(contentParser.parse(text));
|
|
93679
93874
|
// If there are multiple block-level nodes, keep them as-is to preserve the document structure and spacing
|
|
93680
93875
|
if (tree.children.length > 1) {
|
|
93681
93876
|
return tree.children;
|
|
@@ -93684,6 +93879,13 @@ const parseInline = (text) => {
|
|
|
93684
93879
|
// This unwraps the extra p node that might appear & wrapping the content
|
|
93685
93880
|
n.type === 'paragraph' && 'children' in n ? n.children : [n]);
|
|
93686
93881
|
};
|
|
93882
|
+
// Parse markdown/HTML into block-level nodes (preserves paragraphs, headings, lists, etc.)
|
|
93883
|
+
const parseBlock = (text) => {
|
|
93884
|
+
if (!text.trim())
|
|
93885
|
+
return [{ type: 'paragraph', children: [{ type: 'text', value: '' }] }];
|
|
93886
|
+
const tree = contentParser.runSync(contentParser.parse(text));
|
|
93887
|
+
return tree.children;
|
|
93888
|
+
};
|
|
93687
93889
|
/**
|
|
93688
93890
|
* Parse a magic block string and return MDAST nodes.
|
|
93689
93891
|
*
|
|
@@ -93762,7 +93964,7 @@ function parseMagicBlock(raw, options = {}) {
|
|
|
93762
93964
|
data: {
|
|
93763
93965
|
hProperties: {
|
|
93764
93966
|
...(imgData.align && { align: imgData.align }),
|
|
93765
|
-
|
|
93967
|
+
...(imgData.border && { border: imgData.border.toString() }),
|
|
93766
93968
|
...(imgData.sizing && { width: imgWidthBySize[imgData.sizing] }),
|
|
93767
93969
|
},
|
|
93768
93970
|
},
|
|
@@ -93801,8 +94003,9 @@ function parseMagicBlock(raw, options = {}) {
|
|
|
93801
94003
|
const [icon, theme] = Array.isArray(resolvedType) ? resolvedType : ['👍', 'default'];
|
|
93802
94004
|
if (!(calloutJson.title || calloutJson.body))
|
|
93803
94005
|
return [];
|
|
93804
|
-
|
|
93805
|
-
const
|
|
94006
|
+
// Parses html & markdown content
|
|
94007
|
+
const titleBlocks = parseBlock(calloutJson.title || '');
|
|
94008
|
+
const bodyBlocks = parseBlock(calloutJson.body || '');
|
|
93806
94009
|
const children = [];
|
|
93807
94010
|
if (titleBlocks.length > 0 && titleBlocks[0].type === 'paragraph') {
|
|
93808
94011
|
const firstTitle = titleBlocks[0];
|
|
@@ -93817,14 +94020,17 @@ function parseMagicBlock(raw, options = {}) {
|
|
|
93817
94020
|
else {
|
|
93818
94021
|
children.push(...titleBlocks, ...bodyBlocks);
|
|
93819
94022
|
}
|
|
94023
|
+
// If there is no title or title is empty
|
|
94024
|
+
const empty = !titleBlocks.length || !titleBlocks[0].children[0]?.value;
|
|
93820
94025
|
// Create mdxJsxFlowElement directly for mdxish
|
|
93821
94026
|
const calloutElement = {
|
|
93822
94027
|
type: 'mdxJsxFlowElement',
|
|
93823
94028
|
name: 'Callout',
|
|
93824
|
-
attributes: toAttributes({ icon, theme: theme || 'default', type: theme || 'default' }, [
|
|
94029
|
+
attributes: toAttributes({ icon, theme: theme || 'default', type: theme || 'default', empty }, [
|
|
93825
94030
|
'icon',
|
|
93826
94031
|
'theme',
|
|
93827
94032
|
'type',
|
|
94033
|
+
'empty',
|
|
93828
94034
|
]),
|
|
93829
94035
|
children: children,
|
|
93830
94036
|
};
|
|
@@ -93853,7 +94059,7 @@ function parseMagicBlock(raw, options = {}) {
|
|
|
93853
94059
|
return mapped;
|
|
93854
94060
|
}, []);
|
|
93855
94061
|
// In compatibility mode, wrap cell content in paragraphs; otherwise inline text
|
|
93856
|
-
const tokenizeCell = compatibilityMode ? textToBlock :
|
|
94062
|
+
const tokenizeCell = compatibilityMode ? textToBlock : parseTableCell;
|
|
93857
94063
|
const children = Array.from({ length: rows + 1 }, (_, y) => ({
|
|
93858
94064
|
children: Array.from({ length: cols }, (__, x) => ({
|
|
93859
94065
|
children: sparseData[y]?.[x] ? tokenizeCell(sparseData[y][x]) : [{ type: 'text', value: '' }],
|
|
@@ -93882,9 +94088,9 @@ function parseMagicBlock(raw, options = {}) {
|
|
|
93882
94088
|
return [
|
|
93883
94089
|
wrapPinnedBlocks({
|
|
93884
94090
|
children: [
|
|
93885
|
-
{ children: [{ type: 'text', value: title ||
|
|
94091
|
+
{ children: [{ type: 'text', value: title || '' }], title: embedJson.provider, type: 'link', url },
|
|
93886
94092
|
],
|
|
93887
|
-
data: { hName: '
|
|
94093
|
+
data: { hName: 'embed-block', hProperties: { ...embedJson, href: url, html, title, url } },
|
|
93888
94094
|
type: 'embed',
|
|
93889
94095
|
}, json),
|
|
93890
94096
|
];
|
|
@@ -93987,6 +94193,38 @@ const magicBlockRestorer = ({ blocks }) => tree => {
|
|
|
93987
94193
|
};
|
|
93988
94194
|
/* harmony default export */ const mdxish_magic_blocks = (magicBlockRestorer);
|
|
93989
94195
|
|
|
94196
|
+
;// ./processor/transform/mdxish/mdxish-mermaid.ts
|
|
94197
|
+
|
|
94198
|
+
/**
|
|
94199
|
+
* Rehype plugin for mdxish pipeline to add mermaid-render className to mermaid code blocks.
|
|
94200
|
+
* The mermaid-render class is used to identify the mermaid diagrams elements for the
|
|
94201
|
+
* mermaid library to transform. See components/CodeTabs/index.tsx for context
|
|
94202
|
+
*/
|
|
94203
|
+
const mdxishMermaidTransformer = () => (tree) => {
|
|
94204
|
+
visit(tree, 'element', (node) => {
|
|
94205
|
+
if (node.tagName !== 'pre' || node.children.length !== 1)
|
|
94206
|
+
return;
|
|
94207
|
+
const [child] = node.children;
|
|
94208
|
+
if (child.type === 'element' &&
|
|
94209
|
+
child.tagName === 'code' &&
|
|
94210
|
+
child.properties?.lang === 'mermaid') {
|
|
94211
|
+
// Combine existing className with the new mermaid-render class
|
|
94212
|
+
const existingClassName = node.properties?.className;
|
|
94213
|
+
const classNameArray = Array.isArray(existingClassName)
|
|
94214
|
+
? existingClassName.filter(c => typeof c === 'string' || typeof c === 'number')
|
|
94215
|
+
: existingClassName && (typeof existingClassName === 'string' || typeof existingClassName === 'number')
|
|
94216
|
+
? [existingClassName]
|
|
94217
|
+
: [];
|
|
94218
|
+
node.properties = {
|
|
94219
|
+
...node.properties,
|
|
94220
|
+
className: ['mermaid-render', ...classNameArray],
|
|
94221
|
+
};
|
|
94222
|
+
}
|
|
94223
|
+
});
|
|
94224
|
+
return tree;
|
|
94225
|
+
};
|
|
94226
|
+
/* harmony default export */ const mdxish_mermaid = (mdxishMermaidTransformer);
|
|
94227
|
+
|
|
93990
94228
|
;// ./lib/constants.ts
|
|
93991
94229
|
/**
|
|
93992
94230
|
* Pattern to match component tags (PascalCase or snake_case)
|
|
@@ -94214,6 +94452,45 @@ const restoreSnakeCaseComponentNames = (options) => {
|
|
|
94214
94452
|
};
|
|
94215
94453
|
/* harmony default export */ const restore_snake_case_component_name = (restoreSnakeCaseComponentNames);
|
|
94216
94454
|
|
|
94455
|
+
;// ./processor/transform/mdxish/retain-boolean-attributes.ts
|
|
94456
|
+
|
|
94457
|
+
// Private Use Area character (U+E000) which is extremely unlikely to appear in real content.
|
|
94458
|
+
const TEMP_TRUE_BOOLEAN_VALUE = 'readme-this-is-a-temporary-boolean-attribute-\uE000';
|
|
94459
|
+
const TEMP_FALSE_BOOLEAN_VALUE = 'readme-this-is-a-temporary-boolean-attribute-\uE001';
|
|
94460
|
+
/**
|
|
94461
|
+
* Preserves boolean properties when passed to rehypeRaw because
|
|
94462
|
+
* rehypeRaw converts boolean properties in nodes to strings (e.g. true -> ""),
|
|
94463
|
+
* which can change the truthiness of the property. Hence we need to preserve the boolean properties.
|
|
94464
|
+
*/
|
|
94465
|
+
const preserveBooleanProperties = () => tree => {
|
|
94466
|
+
visit(tree, 'element', (node) => {
|
|
94467
|
+
if (!node.properties)
|
|
94468
|
+
return;
|
|
94469
|
+
Object.entries(node.properties).forEach(([key, value]) => {
|
|
94470
|
+
if (typeof value === 'boolean') {
|
|
94471
|
+
node.properties[key] = value ? TEMP_TRUE_BOOLEAN_VALUE : TEMP_FALSE_BOOLEAN_VALUE;
|
|
94472
|
+
}
|
|
94473
|
+
});
|
|
94474
|
+
});
|
|
94475
|
+
return tree;
|
|
94476
|
+
};
|
|
94477
|
+
const restoreBooleanProperties = () => tree => {
|
|
94478
|
+
visit(tree, 'element', (node) => {
|
|
94479
|
+
if (!node.properties)
|
|
94480
|
+
return;
|
|
94481
|
+
Object.entries(node.properties).forEach(([key, value]) => {
|
|
94482
|
+
if (value === TEMP_TRUE_BOOLEAN_VALUE) {
|
|
94483
|
+
node.properties[key] = true;
|
|
94484
|
+
}
|
|
94485
|
+
else if (value === TEMP_FALSE_BOOLEAN_VALUE) {
|
|
94486
|
+
node.properties[key] = false;
|
|
94487
|
+
}
|
|
94488
|
+
});
|
|
94489
|
+
});
|
|
94490
|
+
return tree;
|
|
94491
|
+
};
|
|
94492
|
+
|
|
94493
|
+
|
|
94217
94494
|
;// ./processor/transform/mdxish/variables-text.ts
|
|
94218
94495
|
|
|
94219
94496
|
|
|
@@ -94241,6 +94518,8 @@ const variablesTextTransformer = () => tree => {
|
|
|
94241
94518
|
if (parent.type === 'inlineCode')
|
|
94242
94519
|
return;
|
|
94243
94520
|
const text = node.value;
|
|
94521
|
+
if (typeof text !== 'string' || !text.trim())
|
|
94522
|
+
return;
|
|
94244
94523
|
if (!text.includes('{user.') && !text.includes('{user['))
|
|
94245
94524
|
return;
|
|
94246
94525
|
const matches = [...text.matchAll(USER_VAR_REGEX)];
|
|
@@ -94390,19 +94669,17 @@ function loadComponents() {
|
|
|
94390
94669
|
|
|
94391
94670
|
|
|
94392
94671
|
|
|
94672
|
+
|
|
94673
|
+
|
|
94674
|
+
|
|
94675
|
+
|
|
94393
94676
|
|
|
94394
94677
|
|
|
94395
94678
|
|
|
94396
94679
|
|
|
94397
94680
|
|
|
94398
94681
|
const defaultTransformers = [callouts, code_tabs, gemoji_, transform_embeds];
|
|
94399
|
-
|
|
94400
|
-
* Process markdown content with MDX syntax support.
|
|
94401
|
-
* Detects and renders custom component tags from the components hash.
|
|
94402
|
-
*
|
|
94403
|
-
* @see {@link https://github.com/readmeio/rmdx/blob/main/docs/mdxish-flow.md}
|
|
94404
|
-
*/
|
|
94405
|
-
function mdxish(mdContent, opts = {}) {
|
|
94682
|
+
function mdxishAstProcessor(mdContent, opts = {}) {
|
|
94406
94683
|
const { components: userComponents = {}, jsxContext = {}, useTailwind } = opts;
|
|
94407
94684
|
const components = {
|
|
94408
94685
|
...loadComponents(),
|
|
@@ -94437,9 +94714,46 @@ function mdxish(mdContent, opts = {}) {
|
|
|
94437
94714
|
.use(evaluate_expressions, { context: jsxContext }) // Evaluate MDX expressions using jsxContext
|
|
94438
94715
|
.use(variables_text) // Parse {user.*} patterns from text (can't rely on remarkMdx)
|
|
94439
94716
|
.use(useTailwind ? transform_tailwind : undefined, { components: tempComponentsMap })
|
|
94440
|
-
.use(remarkGfm)
|
|
94717
|
+
.use(remarkGfm);
|
|
94718
|
+
return {
|
|
94719
|
+
processor,
|
|
94720
|
+
/**
|
|
94721
|
+
* @todo we need to return this transformed content for now
|
|
94722
|
+
* but ultimately need to properly tokenize our special markdown syntax
|
|
94723
|
+
* into hast nodes instead of relying on transformed content
|
|
94724
|
+
*/
|
|
94725
|
+
parserReadyContent,
|
|
94726
|
+
};
|
|
94727
|
+
}
|
|
94728
|
+
/**
|
|
94729
|
+
* Converts an Mdast to a Markdown string.
|
|
94730
|
+
*/
|
|
94731
|
+
function mdxishMdastToMd(mdast) {
|
|
94732
|
+
const md = unified().use(remarkGfm).use(processor_compile).use(remarkStringify, {
|
|
94733
|
+
bullet: '-',
|
|
94734
|
+
emphasis: '_',
|
|
94735
|
+
}).stringify(mdast);
|
|
94736
|
+
return md;
|
|
94737
|
+
}
|
|
94738
|
+
/**
|
|
94739
|
+
* Processes markdown content with MDX syntax support and returns a HAST.
|
|
94740
|
+
* Detects and renders custom component tags from the components hash.
|
|
94741
|
+
*
|
|
94742
|
+
* @see {@link https://github.com/readmeio/rmdx/blob/main/docs/mdxish-flow.md}
|
|
94743
|
+
*/
|
|
94744
|
+
function mdxish(mdContent, opts = {}) {
|
|
94745
|
+
const { components: userComponents = {} } = opts;
|
|
94746
|
+
const components = {
|
|
94747
|
+
...loadComponents(),
|
|
94748
|
+
...userComponents,
|
|
94749
|
+
};
|
|
94750
|
+
const { processor, parserReadyContent } = mdxishAstProcessor(mdContent, opts);
|
|
94751
|
+
processor
|
|
94441
94752
|
.use(remarkRehype, { allowDangerousHtml: true, handlers: mdxComponentHandlers })
|
|
94753
|
+
.use(preserveBooleanProperties) // RehypeRaw converts boolean properties to empty strings
|
|
94442
94754
|
.use(rehypeRaw, { passThrough: ['html-block'] })
|
|
94755
|
+
.use(restoreBooleanProperties)
|
|
94756
|
+
.use(mdxish_mermaid) // Add mermaid-render className to pre wrappers
|
|
94443
94757
|
.use(rehypeSlug)
|
|
94444
94758
|
.use(rehypeMdxishComponents, {
|
|
94445
94759
|
components,
|