@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/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) }, children));
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 = isHydrated ? canonicalLanguage(lang) : '';
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 (language === 'mermaid') {
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 hasMermaid = !Array.isArray(children) && children.props?.children.props.lang === 'mermaid';
19351
- // render Mermaid diagram
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
- if (typeof window !== 'undefined' && hasMermaid) {
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
- }, [hasMermaid, theme]);
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 Mermaid diagram
19376
- if (hasMermaid) {
19377
- const value = children.props.children.props.value;
19378
- return external_react_default().createElement("pre", { className: "mermaid-render mermaid_single" }, value);
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" }, (Array.isArray(children) ? children : [children]).map((pre, i) => {
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 codeComponent = Array.isArray(pre.props?.children)
19410
+ const tabCodeComponent = Array.isArray(pre.props?.children)
19384
19411
  ? pre.props.children[0]
19385
19412
  : pre.props?.children;
19386
- const lang = codeComponent?.props?.lang;
19387
- const meta = codeComponent?.props?.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: node.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
- [compile_codeTabsTransformer, { copyButtons }],
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 parseInline = (text) => {
114074
+ const parseTableCell = (text) => {
114037
114075
  if (!text.trim())
114038
114076
  return [{ type: 'text', value: '' }];
114039
- const tree = cellParser.runSync(cellParser.parse(text));
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
- className: imgData.border ? 'border' : '',
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
- const titleBlocks = textToBlock(calloutJson.title || '');
114166
- const bodyBlocks = textToBlock(calloutJson.body || '');
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 : parseInline;
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,