@readme/markdown 11.12.1 → 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 +144 -34
- package/dist/main.node.js +144 -34
- package/dist/main.node.js.map +1 -1
- package/dist/processor/transform/mdxish/mdxish-mermaid.d.ts +8 -0
- package/package.json +1 -1
package/dist/main.node.js
CHANGED
|
@@ -19028,6 +19028,8 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
19028
19028
|
mdastV6: () => (/* reexport */ lib_mdastV6),
|
|
19029
19029
|
mdx: () => (/* reexport */ lib_mdx),
|
|
19030
19030
|
mdxish: () => (/* reexport */ lib_mdxish),
|
|
19031
|
+
mdxishAstProcessor: () => (/* reexport */ mdxishAstProcessor),
|
|
19032
|
+
mdxishMdastToMd: () => (/* reexport */ mdxishMdastToMd),
|
|
19031
19033
|
mdxishTags: () => (/* reexport */ mdxishTags),
|
|
19032
19034
|
migrate: () => (/* reexport */ lib_migrate),
|
|
19033
19035
|
mix: () => (/* reexport */ lib_mix),
|
|
@@ -19175,9 +19177,17 @@ function docLink(href) {
|
|
|
19175
19177
|
function Anchor(props) {
|
|
19176
19178
|
const { children, href = '', target = '', title = '', ...attrs } = props;
|
|
19177
19179
|
const baseUrl = (0,external_react_.useContext)(BaseUrl);
|
|
19180
|
+
// Unwrap any nested anchor elements that GFM's autolinker may have created.
|
|
19181
|
+
// This prevents invalid nested <a> tags when the Anchor's text content looks like a URL.
|
|
19182
|
+
const unwrappedChildren = external_react_default().Children.map(children, child => {
|
|
19183
|
+
if (external_react_default().isValidElement(child) && child.type === 'a') {
|
|
19184
|
+
return child.props.children;
|
|
19185
|
+
}
|
|
19186
|
+
return child;
|
|
19187
|
+
});
|
|
19178
19188
|
return (
|
|
19179
19189
|
// eslint-disable-next-line react/jsx-props-no-spreading
|
|
19180
|
-
external_react_default().createElement("a", { ...attrs, href: getHref(href, baseUrl), target: target, title: title, ...docLink(href) },
|
|
19190
|
+
external_react_default().createElement("a", { ...attrs, href: getHref(href, baseUrl), target: target, title: title, ...docLink(href) }, unwrappedChildren));
|
|
19181
19191
|
}
|
|
19182
19192
|
/* harmony default export */ const components_Anchor = (Anchor);
|
|
19183
19193
|
|
|
@@ -19315,7 +19325,8 @@ const Code = (props) => {
|
|
|
19315
19325
|
const theme = (0,external_react_.useContext)(Theme);
|
|
19316
19326
|
const copyButtons = (0,external_react_.useContext)(CodeOpts) || props.copyButtons;
|
|
19317
19327
|
const isHydrated = useHydrated();
|
|
19318
|
-
const language =
|
|
19328
|
+
const language = canonicalLanguage(lang);
|
|
19329
|
+
const isMermaid = language === 'mermaid';
|
|
19319
19330
|
const codeRef = (0,external_react_.createRef)();
|
|
19320
19331
|
const codeOpts = {
|
|
19321
19332
|
inline: !lang,
|
|
@@ -19326,7 +19337,7 @@ const Code = (props) => {
|
|
|
19326
19337
|
const highlightedCode = syntaxHighlighter && typeof syntaxHighlighter === 'function' && code && isHydrated
|
|
19327
19338
|
? syntaxHighlighter(code, language, codeOpts, { mdx: true })
|
|
19328
19339
|
: code;
|
|
19329
|
-
if (
|
|
19340
|
+
if (isHydrated && isMermaid) {
|
|
19330
19341
|
return code;
|
|
19331
19342
|
}
|
|
19332
19343
|
return (external_react_default().createElement((external_react_default()).Fragment, null,
|
|
@@ -19342,15 +19353,28 @@ var dist_utils_default = /*#__PURE__*/__webpack_require__.n(dist_utils);
|
|
|
19342
19353
|
|
|
19343
19354
|
|
|
19344
19355
|
|
|
19356
|
+
|
|
19345
19357
|
let mermaid;
|
|
19346
19358
|
const { uppercase } = (dist_utils_default());
|
|
19347
19359
|
const CodeTabs = (props) => {
|
|
19348
19360
|
const { children } = props;
|
|
19349
19361
|
const theme = (0,external_react_.useContext)(Theme);
|
|
19350
|
-
const
|
|
19351
|
-
//
|
|
19362
|
+
const isHydrated = useHydrated();
|
|
19363
|
+
// Handle both array (from rehype-react in rendering mdxish) and single element (MDX/JSX runtime) cases
|
|
19364
|
+
// The children here is the individual code block objects
|
|
19365
|
+
const childrenArray = Array.isArray(children) ? children : [children];
|
|
19366
|
+
// The structure varies depending on rendering context:
|
|
19367
|
+
// - When rendered via rehype-react: pre.props.children is an array where the first element is the Code component
|
|
19368
|
+
// - When rendered via MDX/JSX runtime: pre.props.children is directly the Code component
|
|
19369
|
+
const getCodeComponent = (pre) => {
|
|
19370
|
+
return Array.isArray(pre?.props?.children) ? pre.props.children[0] : pre?.props?.children;
|
|
19371
|
+
};
|
|
19372
|
+
const containAtLeastOneMermaid = childrenArray.some(pre => getCodeComponent(pre)?.props?.lang === 'mermaid');
|
|
19373
|
+
// Render Mermaid diagram
|
|
19352
19374
|
(0,external_react_.useEffect)(() => {
|
|
19353
|
-
|
|
19375
|
+
// Ensure we only render mermaids when frontend is hydrated to avoid hydration errors
|
|
19376
|
+
// because mermaid mutates the DOM before react hydrates
|
|
19377
|
+
if (typeof window !== 'undefined' && containAtLeastOneMermaid && isHydrated) {
|
|
19354
19378
|
__webpack_require__.e(/* import() */ 486).then(__webpack_require__.bind(__webpack_require__, 5486)).then(module => {
|
|
19355
19379
|
mermaid = module.default;
|
|
19356
19380
|
mermaid.initialize({
|
|
@@ -19362,7 +19386,7 @@ const CodeTabs = (props) => {
|
|
|
19362
19386
|
});
|
|
19363
19387
|
});
|
|
19364
19388
|
}
|
|
19365
|
-
}, [
|
|
19389
|
+
}, [containAtLeastOneMermaid, theme, isHydrated]);
|
|
19366
19390
|
function handleClick({ target }, index) {
|
|
19367
19391
|
const $wrap = target.parentElement.parentElement;
|
|
19368
19392
|
const $open = [].slice.call($wrap.querySelectorAll('.CodeTabs_active'));
|
|
@@ -19372,19 +19396,22 @@ const CodeTabs = (props) => {
|
|
|
19372
19396
|
codeblocks[index].classList.add('CodeTabs_active');
|
|
19373
19397
|
target.classList.add('CodeTabs_active');
|
|
19374
19398
|
}
|
|
19375
|
-
// render single
|
|
19376
|
-
if (
|
|
19377
|
-
const
|
|
19378
|
-
|
|
19399
|
+
// We want to render single mermaid diagrams without the code tabs UI
|
|
19400
|
+
if (childrenArray.length === 1) {
|
|
19401
|
+
const codeComponent = getCodeComponent(childrenArray[0]);
|
|
19402
|
+
if (codeComponent?.props?.lang === 'mermaid') {
|
|
19403
|
+
const value = codeComponent?.props?.value;
|
|
19404
|
+
return external_react_default().createElement("pre", { className: "mermaid-render mermaid_single" }, value);
|
|
19405
|
+
}
|
|
19379
19406
|
}
|
|
19380
19407
|
return (external_react_default().createElement("div", { className: `CodeTabs CodeTabs_initial theme-${theme}` },
|
|
19381
|
-
external_react_default().createElement("div", { className: "CodeTabs-toolbar" },
|
|
19408
|
+
external_react_default().createElement("div", { className: "CodeTabs-toolbar" }, childrenArray.map((pre, i) => {
|
|
19382
19409
|
// the first or only child should be our Code component
|
|
19383
|
-
const
|
|
19410
|
+
const tabCodeComponent = Array.isArray(pre.props?.children)
|
|
19384
19411
|
? pre.props.children[0]
|
|
19385
19412
|
: pre.props?.children;
|
|
19386
|
-
const lang =
|
|
19387
|
-
const meta =
|
|
19413
|
+
const lang = tabCodeComponent?.props?.lang;
|
|
19414
|
+
const meta = tabCodeComponent?.props?.meta;
|
|
19388
19415
|
/* istanbul ignore next */
|
|
19389
19416
|
return (external_react_default().createElement("button", { key: i, onClick: e => handleClick(e, i), type: "button", value: lang }, meta || `${!lang ? 'Text' : uppercase(lang)}`));
|
|
19390
19417
|
})),
|
|
@@ -91418,10 +91445,20 @@ const coerceJsxToMd = ({ components = {}, html = false } = {}) => (node, index,
|
|
|
91418
91445
|
hProperties.url = hProperties.href;
|
|
91419
91446
|
delete hProperties.href;
|
|
91420
91447
|
}
|
|
91448
|
+
// Unwrap any autolinked children to prevent nested links.
|
|
91449
|
+
// GFM's autolink feature can convert URL-like text inside Anchor children
|
|
91450
|
+
// into link nodes, which would create invalid nested links when Anchor
|
|
91451
|
+
// is converted back to a link node.
|
|
91452
|
+
const children = node.children.flatMap(child => {
|
|
91453
|
+
if (child.type === 'link') {
|
|
91454
|
+
return child.children;
|
|
91455
|
+
}
|
|
91456
|
+
return child;
|
|
91457
|
+
});
|
|
91421
91458
|
// @ts-expect-error we don't have a mechanism to enforce the URL attribute type right now
|
|
91422
91459
|
const mdNode = {
|
|
91423
91460
|
...hProperties,
|
|
91424
|
-
children
|
|
91461
|
+
children,
|
|
91425
91462
|
type: readme_components_types[node.name],
|
|
91426
91463
|
position: node.position,
|
|
91427
91464
|
};
|
|
@@ -106710,16 +106747,17 @@ const tocHastToMdx = (toc, components) => {
|
|
|
106710
106747
|
|
|
106711
106748
|
|
|
106712
106749
|
|
|
106713
|
-
const { codeTabsTransformer: compile_codeTabsTransformer, ...transforms } = defaultTransforms;
|
|
106714
106750
|
const sanitizeSchema = cjs_default()(defaultSchema, {
|
|
106715
106751
|
protocols: ['doc', 'ref', 'blog', 'changelog', 'page'],
|
|
106716
106752
|
});
|
|
106717
106753
|
const compile_compile = (text, { components = {}, missingComponents, copyButtons, useTailwind, ...opts } = {}) => {
|
|
106754
|
+
// Destructure at runtime to avoid circular dependency issues
|
|
106755
|
+
const { codeTabsTransformer, ...transforms } = defaultTransforms;
|
|
106718
106756
|
const remarkPlugins = [
|
|
106719
106757
|
remarkFrontmatter,
|
|
106720
106758
|
remarkGfm,
|
|
106721
106759
|
...Object.values(transforms),
|
|
106722
|
-
[
|
|
106760
|
+
[codeTabsTransformer, { copyButtons }],
|
|
106723
106761
|
[
|
|
106724
106762
|
handle_missing_components,
|
|
106725
106763
|
{ components, missingComponents: ['ignore', 'throw'].includes(missingComponents) ? missingComponents : 'ignore' },
|
|
@@ -113997,8 +114035,6 @@ const mdxishHtmlBlocks = () => tree => {
|
|
|
113997
114035
|
* Taken from the v6 branch
|
|
113998
114036
|
*/
|
|
113999
114037
|
const RGXP = /^\s*\[block:([^\]]*)\]([^]+?)\[\/block\]/;
|
|
114000
|
-
/** Parses markdown in table cells */
|
|
114001
|
-
const cellParser = unified().use(remarkParse).use(remarkGfm);
|
|
114002
114038
|
/**
|
|
114003
114039
|
* Wraps a node in a "pinned" container if sidebar: true is set in the JSON.
|
|
114004
114040
|
* Pinned blocks are displayed in a sidebar/floating position in the UI.
|
|
@@ -114032,11 +114068,13 @@ const imgWidthBySize = new Proxy(imgSizeValues, {
|
|
|
114032
114068
|
const textToInline = (text) => [{ type: 'text', value: text }];
|
|
114033
114069
|
// Simple text to block nodes (wraps in paragraph)
|
|
114034
114070
|
const textToBlock = (text) => [{ children: textToInline(text), type: 'paragraph' }];
|
|
114071
|
+
/** Parses markdown and html to markdown nodes */
|
|
114072
|
+
const contentParser = unified().use(remarkParse).use(remarkGfm);
|
|
114035
114073
|
// Table cells may contain html or markdown content, so we need to parse it accordingly instead of keeping it as raw text
|
|
114036
|
-
const
|
|
114074
|
+
const parseTableCell = (text) => {
|
|
114037
114075
|
if (!text.trim())
|
|
114038
114076
|
return [{ type: 'text', value: '' }];
|
|
114039
|
-
const tree =
|
|
114077
|
+
const tree = contentParser.runSync(contentParser.parse(text));
|
|
114040
114078
|
// If there are multiple block-level nodes, keep them as-is to preserve the document structure and spacing
|
|
114041
114079
|
if (tree.children.length > 1) {
|
|
114042
114080
|
return tree.children;
|
|
@@ -114045,6 +114083,13 @@ const parseInline = (text) => {
|
|
|
114045
114083
|
// This unwraps the extra p node that might appear & wrapping the content
|
|
114046
114084
|
n.type === 'paragraph' && 'children' in n ? n.children : [n]);
|
|
114047
114085
|
};
|
|
114086
|
+
// Parse markdown/HTML into block-level nodes (preserves paragraphs, headings, lists, etc.)
|
|
114087
|
+
const parseBlock = (text) => {
|
|
114088
|
+
if (!text.trim())
|
|
114089
|
+
return [{ type: 'paragraph', children: [{ type: 'text', value: '' }] }];
|
|
114090
|
+
const tree = contentParser.runSync(contentParser.parse(text));
|
|
114091
|
+
return tree.children;
|
|
114092
|
+
};
|
|
114048
114093
|
/**
|
|
114049
114094
|
* Parse a magic block string and return MDAST nodes.
|
|
114050
114095
|
*
|
|
@@ -114123,7 +114168,7 @@ function parseMagicBlock(raw, options = {}) {
|
|
|
114123
114168
|
data: {
|
|
114124
114169
|
hProperties: {
|
|
114125
114170
|
...(imgData.align && { align: imgData.align }),
|
|
114126
|
-
|
|
114171
|
+
...(imgData.border && { border: imgData.border.toString() }),
|
|
114127
114172
|
...(imgData.sizing && { width: imgWidthBySize[imgData.sizing] }),
|
|
114128
114173
|
},
|
|
114129
114174
|
},
|
|
@@ -114162,8 +114207,9 @@ function parseMagicBlock(raw, options = {}) {
|
|
|
114162
114207
|
const [icon, theme] = Array.isArray(resolvedType) ? resolvedType : ['👍', 'default'];
|
|
114163
114208
|
if (!(calloutJson.title || calloutJson.body))
|
|
114164
114209
|
return [];
|
|
114165
|
-
|
|
114166
|
-
const
|
|
114210
|
+
// Parses html & markdown content
|
|
114211
|
+
const titleBlocks = parseBlock(calloutJson.title || '');
|
|
114212
|
+
const bodyBlocks = parseBlock(calloutJson.body || '');
|
|
114167
114213
|
const children = [];
|
|
114168
114214
|
if (titleBlocks.length > 0 && titleBlocks[0].type === 'paragraph') {
|
|
114169
114215
|
const firstTitle = titleBlocks[0];
|
|
@@ -114217,7 +114263,7 @@ function parseMagicBlock(raw, options = {}) {
|
|
|
114217
114263
|
return mapped;
|
|
114218
114264
|
}, []);
|
|
114219
114265
|
// In compatibility mode, wrap cell content in paragraphs; otherwise inline text
|
|
114220
|
-
const tokenizeCell = compatibilityMode ? textToBlock :
|
|
114266
|
+
const tokenizeCell = compatibilityMode ? textToBlock : parseTableCell;
|
|
114221
114267
|
const children = Array.from({ length: rows + 1 }, (_, y) => ({
|
|
114222
114268
|
children: Array.from({ length: cols }, (__, x) => ({
|
|
114223
114269
|
children: sparseData[y]?.[x] ? tokenizeCell(sparseData[y][x]) : [{ type: 'text', value: '' }],
|
|
@@ -114351,6 +114397,38 @@ const magicBlockRestorer = ({ blocks }) => tree => {
|
|
|
114351
114397
|
};
|
|
114352
114398
|
/* harmony default export */ const mdxish_magic_blocks = (magicBlockRestorer);
|
|
114353
114399
|
|
|
114400
|
+
;// ./processor/transform/mdxish/mdxish-mermaid.ts
|
|
114401
|
+
|
|
114402
|
+
/**
|
|
114403
|
+
* Rehype plugin for mdxish pipeline to add mermaid-render className to mermaid code blocks.
|
|
114404
|
+
* The mermaid-render class is used to identify the mermaid diagrams elements for the
|
|
114405
|
+
* mermaid library to transform. See components/CodeTabs/index.tsx for context
|
|
114406
|
+
*/
|
|
114407
|
+
const mdxishMermaidTransformer = () => (tree) => {
|
|
114408
|
+
visit(tree, 'element', (node) => {
|
|
114409
|
+
if (node.tagName !== 'pre' || node.children.length !== 1)
|
|
114410
|
+
return;
|
|
114411
|
+
const [child] = node.children;
|
|
114412
|
+
if (child.type === 'element' &&
|
|
114413
|
+
child.tagName === 'code' &&
|
|
114414
|
+
child.properties?.lang === 'mermaid') {
|
|
114415
|
+
// Combine existing className with the new mermaid-render class
|
|
114416
|
+
const existingClassName = node.properties?.className;
|
|
114417
|
+
const classNameArray = Array.isArray(existingClassName)
|
|
114418
|
+
? existingClassName.filter(c => typeof c === 'string' || typeof c === 'number')
|
|
114419
|
+
: existingClassName && (typeof existingClassName === 'string' || typeof existingClassName === 'number')
|
|
114420
|
+
? [existingClassName]
|
|
114421
|
+
: [];
|
|
114422
|
+
node.properties = {
|
|
114423
|
+
...node.properties,
|
|
114424
|
+
className: ['mermaid-render', ...classNameArray],
|
|
114425
|
+
};
|
|
114426
|
+
}
|
|
114427
|
+
});
|
|
114428
|
+
return tree;
|
|
114429
|
+
};
|
|
114430
|
+
/* harmony default export */ const mdxish_mermaid = (mdxishMermaidTransformer);
|
|
114431
|
+
|
|
114354
114432
|
;// ./lib/constants.ts
|
|
114355
114433
|
/**
|
|
114356
114434
|
* Pattern to match component tags (PascalCase or snake_case)
|
|
@@ -114797,18 +114875,15 @@ function loadComponents() {
|
|
|
114797
114875
|
|
|
114798
114876
|
|
|
114799
114877
|
|
|
114878
|
+
|
|
114879
|
+
|
|
114880
|
+
|
|
114800
114881
|
|
|
114801
114882
|
|
|
114802
114883
|
|
|
114803
114884
|
|
|
114804
114885
|
const defaultTransformers = [callouts, code_tabs, gemoji_, transform_embeds];
|
|
114805
|
-
|
|
114806
|
-
* Process markdown content with MDX syntax support.
|
|
114807
|
-
* Detects and renders custom component tags from the components hash.
|
|
114808
|
-
*
|
|
114809
|
-
* @see {@link https://github.com/readmeio/rmdx/blob/main/docs/mdxish-flow.md}
|
|
114810
|
-
*/
|
|
114811
|
-
function mdxish(mdContent, opts = {}) {
|
|
114886
|
+
function mdxishAstProcessor(mdContent, opts = {}) {
|
|
114812
114887
|
const { components: userComponents = {}, jsxContext = {}, useTailwind } = opts;
|
|
114813
114888
|
const components = {
|
|
114814
114889
|
...loadComponents(),
|
|
@@ -114843,11 +114918,46 @@ function mdxish(mdContent, opts = {}) {
|
|
|
114843
114918
|
.use(evaluate_expressions, { context: jsxContext }) // Evaluate MDX expressions using jsxContext
|
|
114844
114919
|
.use(variables_text) // Parse {user.*} patterns from text (can't rely on remarkMdx)
|
|
114845
114920
|
.use(useTailwind ? transform_tailwind : undefined, { components: tempComponentsMap })
|
|
114846
|
-
.use(remarkGfm)
|
|
114921
|
+
.use(remarkGfm);
|
|
114922
|
+
return {
|
|
114923
|
+
processor,
|
|
114924
|
+
/**
|
|
114925
|
+
* @todo we need to return this transformed content for now
|
|
114926
|
+
* but ultimately need to properly tokenize our special markdown syntax
|
|
114927
|
+
* into hast nodes instead of relying on transformed content
|
|
114928
|
+
*/
|
|
114929
|
+
parserReadyContent,
|
|
114930
|
+
};
|
|
114931
|
+
}
|
|
114932
|
+
/**
|
|
114933
|
+
* Converts an Mdast to a Markdown string.
|
|
114934
|
+
*/
|
|
114935
|
+
function mdxishMdastToMd(mdast) {
|
|
114936
|
+
const md = unified().use(remarkGfm).use(processor_compile).use(remarkStringify, {
|
|
114937
|
+
bullet: '-',
|
|
114938
|
+
emphasis: '_',
|
|
114939
|
+
}).stringify(mdast);
|
|
114940
|
+
return md;
|
|
114941
|
+
}
|
|
114942
|
+
/**
|
|
114943
|
+
* Processes markdown content with MDX syntax support and returns a HAST.
|
|
114944
|
+
* Detects and renders custom component tags from the components hash.
|
|
114945
|
+
*
|
|
114946
|
+
* @see {@link https://github.com/readmeio/rmdx/blob/main/docs/mdxish-flow.md}
|
|
114947
|
+
*/
|
|
114948
|
+
function mdxish(mdContent, opts = {}) {
|
|
114949
|
+
const { components: userComponents = {} } = opts;
|
|
114950
|
+
const components = {
|
|
114951
|
+
...loadComponents(),
|
|
114952
|
+
...userComponents,
|
|
114953
|
+
};
|
|
114954
|
+
const { processor, parserReadyContent } = mdxishAstProcessor(mdContent, opts);
|
|
114955
|
+
processor
|
|
114847
114956
|
.use(remarkRehype, { allowDangerousHtml: true, handlers: mdxComponentHandlers })
|
|
114848
114957
|
.use(preserveBooleanProperties) // RehypeRaw converts boolean properties to empty strings
|
|
114849
114958
|
.use(rehypeRaw, { passThrough: ['html-block'] })
|
|
114850
114959
|
.use(restoreBooleanProperties)
|
|
114960
|
+
.use(mdxish_mermaid) // Add mermaid-render className to pre wrappers
|
|
114851
114961
|
.use(rehypeSlug)
|
|
114852
114962
|
.use(rehypeMdxishComponents, {
|
|
114853
114963
|
components,
|