@readme/markdown 13.1.1 → 13.1.2

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.js CHANGED
@@ -13007,8 +13007,7 @@ function color(d) {
13007
13007
 
13008
13008
  ;// ./node_modules/unist-util-visit-parents/lib/index.js
13009
13009
  /**
13010
- * @typedef {import('unist').Node} UnistNode
13011
- * @typedef {import('unist').Parent} UnistParent
13010
+ * @import {Node as UnistNode, Parent as UnistParent} from 'unist'
13012
13011
  */
13013
13012
 
13014
13013
  /**
@@ -13056,8 +13055,10 @@ function color(d) {
13056
13055
 
13057
13056
  /**
13058
13057
  * @typedef {(
13059
- * Check extends Array<any>
13060
- * ? MatchesOne<Value, Check[keyof Check]>
13058
+ * Check extends ReadonlyArray<infer T>
13059
+ * ? MatchesOne<Value, T>
13060
+ * : Check extends Array<infer T>
13061
+ * ? MatchesOne<Value, T>
13061
13062
  * : MatchesOne<Value, Check>
13062
13063
  * )} Matches
13063
13064
  * Check whether a node matches a check in the type system.
@@ -13327,9 +13328,9 @@ function visitParents(tree, test, visitor, reverse) {
13327
13328
  typeof value.tagName === 'string'
13328
13329
  ? value.tagName
13329
13330
  : // `xast`
13330
- typeof value.name === 'string'
13331
- ? value.name
13332
- : undefined
13331
+ typeof value.name === 'string'
13332
+ ? value.name
13333
+ : undefined
13333
13334
 
13334
13335
  Object.defineProperty(visit, 'name', {
13335
13336
  value:
@@ -71516,6 +71517,19 @@ const coerceJsxToMd = ({ components = {}, html = false } = {}) => (node, index,
71516
71517
  };
71517
71518
  parent.children[index] = mdNode;
71518
71519
  }
71520
+ else if (node.name === 'Recipe' || node.name === 'TutorialTile') {
71521
+ const hProperties = getAttrs(node);
71522
+ const mdNode = {
71523
+ ...hProperties,
71524
+ type: types[node.name],
71525
+ data: {
71526
+ hName: node.name,
71527
+ ...(Object.keys(hProperties).length && { hProperties }),
71528
+ },
71529
+ position: node.position,
71530
+ };
71531
+ parent.children[index] = mdNode;
71532
+ }
71519
71533
  else if (node.name in types) {
71520
71534
  const hProperties = getAttrs(node);
71521
71535
  const mdNode = {
@@ -93244,6 +93258,63 @@ function rehypeStringify(options) {
93244
93258
  }
93245
93259
  }
93246
93260
 
93261
+ ;// ./node_modules/mdast-util-newline-to-break/lib/index.js
93262
+ /**
93263
+ * @typedef {import('mdast').Nodes} Nodes
93264
+ * @typedef {import('mdast-util-find-and-replace').ReplaceFunction} ReplaceFunction
93265
+ */
93266
+
93267
+
93268
+
93269
+ /**
93270
+ * Turn normal line endings into hard breaks.
93271
+ *
93272
+ * @param {Nodes} tree
93273
+ * Tree to change.
93274
+ * @returns {undefined}
93275
+ * Nothing.
93276
+ */
93277
+ function newlineToBreak(tree) {
93278
+ findAndReplace(tree, [/\r?\n|\r/g, lib_replace])
93279
+ }
93280
+
93281
+ /**
93282
+ * Replace line endings.
93283
+ *
93284
+ * @type {ReplaceFunction}
93285
+ */
93286
+ function lib_replace() {
93287
+ return {type: 'break'}
93288
+ }
93289
+
93290
+ ;// ./node_modules/remark-breaks/lib/index.js
93291
+ /**
93292
+ * @typedef {import('mdast').Root} Root
93293
+ */
93294
+
93295
+
93296
+
93297
+ /**
93298
+ * Support hard breaks without needing spaces or escapes (turns enters into
93299
+ * `<br>`s).
93300
+ *
93301
+ * @returns
93302
+ * Transform.
93303
+ */
93304
+ function remarkBreaks() {
93305
+ /**
93306
+ * Transform.
93307
+ *
93308
+ * @param {Root} tree
93309
+ * Tree.
93310
+ * @returns {undefined}
93311
+ * Nothing.
93312
+ */
93313
+ return function (tree) {
93314
+ newlineToBreak(tree)
93315
+ }
93316
+ }
93317
+
93247
93318
  ;// ./lib/utils/mdxish/mdxish-get-component-name.ts
93248
93319
  /** Convert a string to PascalCase */
93249
93320
  function toPascalCase(str) {
@@ -93922,6 +93993,71 @@ const evaluateExpressions = ({ context = {} } = {}) => tree => {
93922
93993
  };
93923
93994
  /* harmony default export */ const evaluate_expressions = (evaluateExpressions);
93924
93995
 
93996
+ ;// ./node_modules/rehype-parse/lib/index.js
93997
+ /**
93998
+ * @import {Root} from 'hast'
93999
+ * @import {Options as FromHtmlOptions} from 'hast-util-from-html'
94000
+ * @import {Parser, Processor} from 'unified'
94001
+ */
94002
+
94003
+ /**
94004
+ * @typedef {Omit<FromHtmlOptions, 'onerror'> & RehypeParseFields} Options
94005
+ * Configuration.
94006
+ *
94007
+ * @typedef RehypeParseFields
94008
+ * Extra fields.
94009
+ * @property {boolean | null | undefined} [emitParseErrors=false]
94010
+ * Whether to emit parse errors while parsing (default: `false`).
94011
+ *
94012
+ * > 👉 **Note**: parse errors are currently being added to HTML.
94013
+ * > Not all errors emitted by parse5 (or us) are specced yet.
94014
+ * > Some documentation may still be missing.
94015
+ */
94016
+
94017
+
94018
+
94019
+ /**
94020
+ * Plugin to add support for parsing from HTML.
94021
+ *
94022
+ * > 👉 **Note**: this is not an XML parser.
94023
+ * > It supports SVG as embedded in HTML.
94024
+ * > It does not support the features available in XML.
94025
+ * > Passing SVG files might break but fragments of modern SVG should be fine.
94026
+ * > Use [`xast-util-from-xml`][xast-util-from-xml] to parse XML.
94027
+ *
94028
+ * @param {Options | null | undefined} [options]
94029
+ * Configuration (optional).
94030
+ * @returns {undefined}
94031
+ * Nothing.
94032
+ */
94033
+ function rehypeParse(options) {
94034
+ /** @type {Processor<Root>} */
94035
+ // @ts-expect-error: TS in JSDoc generates wrong types if `this` is typed regularly.
94036
+ const self = this
94037
+ const {emitParseErrors, ...settings} = {...self.data('settings'), ...options}
94038
+
94039
+ self.parser = parser
94040
+
94041
+ /**
94042
+ * @type {Parser<Root>}
94043
+ */
94044
+ function parser(document, file) {
94045
+ return fromHtml(document, {
94046
+ ...settings,
94047
+ onerror: emitParseErrors
94048
+ ? function (message) {
94049
+ if (file.path) {
94050
+ message.name = file.path + ':' + message.name
94051
+ message.file = file.path
94052
+ }
94053
+
94054
+ file.messages.push(message)
94055
+ }
94056
+ : undefined
94057
+ })
94058
+ }
94059
+ }
94060
+
93925
94061
  ;// ./processor/transform/mdxish/normalize-malformed-md-syntax.ts
93926
94062
 
93927
94063
  // Marker patterns for multi-node emphasis detection
@@ -94265,6 +94401,18 @@ const normalizeEmphasisAST = () => (tree) => {
94265
94401
  };
94266
94402
  /* harmony default export */ const normalize_malformed_md_syntax = (normalizeEmphasisAST);
94267
94403
 
94404
+ ;// ./processor/transform/mdxish/magic-blocks/patterns.ts
94405
+ /** Matches HTML tags (open, close, self-closing) with optional attributes. */
94406
+ const HTML_TAG_RE = /<\/?([a-zA-Z][a-zA-Z0-9-]*)((?:[^>"']*(?:"[^"]*"|'[^']*'))*[^>"']*)>/g;
94407
+ /** Matches an HTML element from its opening tag to the matching closing tag. */
94408
+ const HTML_ELEMENT_BLOCK_RE = /<([a-zA-Z][a-zA-Z0-9-]*)[\s>][\s\S]*?<\/\1>/g;
94409
+ /** Matches a newline with surrounding horizontal whitespace. */
94410
+ const NEWLINE_WITH_WHITESPACE_RE = /[^\S\n]*\n[^\S\n]*/g;
94411
+ /** Matches a closing block-level tag followed by non-tag text or by a newline then non-blank content. */
94412
+ const CLOSE_BLOCK_TAG_BOUNDARY_RE = /<\/([a-zA-Z][a-zA-Z0-9-]*)>\s*(?:(?!<)(\S)|\n([^\n]))/g;
94413
+ /** Tests whether a string contains a complete HTML element (open + close tag). */
94414
+ const COMPLETE_HTML_ELEMENT_RE = /<[a-zA-Z][^>]*>[\s\S]*<\/[a-zA-Z]/;
94415
+
94268
94416
  ;// ./processor/transform/mdxish/magic-blocks/placeholder.ts
94269
94417
  const EMPTY_IMAGE_PLACEHOLDER = {
94270
94418
  type: 'image',
@@ -94318,6 +94466,14 @@ const EMPTY_CODE_PLACEHOLDER = {
94318
94466
 
94319
94467
 
94320
94468
 
94469
+
94470
+
94471
+
94472
+
94473
+
94474
+
94475
+
94476
+
94321
94477
  /**
94322
94478
  * Wraps a node in a "pinned" container if sidebar: true is set.
94323
94479
  */
@@ -94345,12 +94501,125 @@ const imgWidthBySize = new Proxy(imgSizeValues, {
94345
94501
  });
94346
94502
  const textToInline = (text) => [{ type: 'text', value: text }];
94347
94503
  const textToBlock = (text) => [{ children: textToInline(text), type: 'paragraph' }];
94348
- /** Parses markdown and html to markdown nodes */
94349
- const contentParser = unified().use(remarkParse).use(remarkGfm).use(normalize_malformed_md_syntax);
94504
+ /**
94505
+ * Converts leading newlines in magic block content to `<br>` tags.
94506
+ * Leading newlines are stripped by remark-parse before they become soft break nodes,
94507
+ * so remark-breaks cannot handle them. We convert them to HTML `<br>` tags instead.
94508
+ */
94509
+ const ensureLeadingBreaks = (text) => text.replace(/^\n+/, match => '<br>'.repeat(match.length));
94510
+ /** Preprocesses magic block body content before parsing. */
94511
+ const preprocessBody = (text) => {
94512
+ return ensureLeadingBreaks(text);
94513
+ };
94514
+ /** Markdown parser */
94515
+ const contentParser = unified().use(remarkParse).use(remarkBreaks).use(remarkGfm).use(normalize_malformed_md_syntax);
94516
+ /** Markdown to HTML processor (mdast → hast → HTML string) */
94517
+ const markdownToHtml = unified()
94518
+ .use(remarkParse)
94519
+ .use(remarkGfm)
94520
+ .use(normalize_malformed_md_syntax)
94521
+ .use(remarkRehype)
94522
+ .use(rehypeStringify);
94523
+ /** HTML parser (HTML string → hast) */
94524
+ const htmlParser = unified().use(rehypeParse, { fragment: true });
94525
+ /** HTML stringifier (hast → HTML string) */
94526
+ const htmlStringifier = unified().use(rehypeStringify);
94527
+ /** Process \|, \<, \> backslash escapes. Only < is entity-escaped; > is left literal to avoid double-encoding by rehype. */
94528
+ const processBackslashEscapes = (text) => text.replace(/\\<([^>]*)>/g, '&lt;$1>').replace(/\\([<>|])/g, (_, c) => (c === '<' ? '&lt;' : c === '>' ? '>' : c));
94529
+ /** Block-level HTML tags that trigger CommonMark type 6 HTML blocks (condition 6). */
94530
+ const BLOCK_LEVEL_TAGS = new Set(htmlBlockNames);
94531
+ const escapeInvalidTags = (str) => str.replace(HTML_TAG_RE, (match, tag, rest) => {
94532
+ const tagName = tag.replace(/^\//, '');
94533
+ if (STANDARD_HTML_TAGS.has(tagName.toLowerCase()))
94534
+ return match;
94535
+ // Preserve PascalCase tags (custom components like <Glossary>) for the main pipeline
94536
+ if (/^[A-Z]/.test(tagName))
94537
+ return match;
94538
+ return `&lt;${tag}${rest}&gt;`;
94539
+ });
94540
+ /**
94541
+ * Process markdown within HTML string.
94542
+ * 1. Parse HTML to HAST
94543
+ * 2. Find text nodes, parse as markdown, convert to HAST
94544
+ * 3. Stringify back to HTML
94545
+ *
94546
+ * PascalCase component tags (e.g. `<Glossary>`) are temporarily replaced with
94547
+ * placeholders before HTML parsing so `rehype-parse` doesn't mangle them
94548
+ * (it treats unknown tags as void elements, stripping their children).
94549
+ */
94550
+ const processMarkdownInHtmlString = (html) => {
94551
+ const placeholders = [];
94552
+ let counter = 0;
94553
+ const safened = escapeInvalidTags(html).replace(HTML_TAG_RE, match => {
94554
+ if (!/^<\/?[A-Z]/.test(match))
94555
+ return match;
94556
+ const id = `<!--PC${(counter += 1)}-->`;
94557
+ placeholders.push([id, match]);
94558
+ return id;
94559
+ });
94560
+ const hast = htmlParser.parse(safened);
94561
+ const textToHast = (text) => {
94562
+ if (!text.trim())
94563
+ return [{ type: 'text', value: text }];
94564
+ const parsed = markdownToHtml.runSync(markdownToHtml.parse(escapeInvalidTags(text)));
94565
+ const nodes = parsed.children.flatMap(n => n.type === 'element' && n.tagName === 'p' ? n.children : [n]);
94566
+ const leading = text.match(/^\s+/)?.[0];
94567
+ const trailing = text.match(/\s+$/)?.[0];
94568
+ if (leading)
94569
+ nodes.unshift({ type: 'text', value: leading });
94570
+ if (trailing)
94571
+ nodes.push({ type: 'text', value: trailing });
94572
+ return nodes;
94573
+ };
94574
+ const processChildren = (children) => children.flatMap(child => (child.type === 'text' ? textToHast(child.value) : [child]));
94575
+ hast.children = processChildren(hast.children);
94576
+ visit(hast, 'element', (node) => {
94577
+ node.children = processChildren(node.children);
94578
+ });
94579
+ return placeholders.reduce((res, [id, original]) => res.replace(id, original), htmlStringifier.stringify(hast));
94580
+ };
94581
+ /**
94582
+ * Separate a closing block-level tag from the content that follows it.
94583
+ *
94584
+ * Each \n in the original text becomes a <br> tag to preserve spacing, then a
94585
+ * blank line (\n\n) is appended so CommonMark ends the HTML block and parses
94586
+ * the following content as markdown.
94587
+ */
94588
+ const separateBlockTagFromContent = (match, tag, inlineChar, nextLineChar) => {
94589
+ if (!BLOCK_LEVEL_TAGS.has(tag.toLowerCase()))
94590
+ return match;
94591
+ const newlineCount = (match.match(/\n/g) ?? []).length;
94592
+ const breaks = '<br>'.repeat(newlineCount);
94593
+ return `</${tag}>${breaks}\n\n${inlineChar || nextLineChar}`;
94594
+ };
94595
+ /**
94596
+ * CommonMark doesn't process markdown inside HTML blocks -
94597
+ * so `<ul><li>_text_</li></ul>` won't convert underscores to emphasis.
94598
+ * We parse first, then visit html nodes and process their text content.
94599
+ */
94350
94600
  const parseTableCell = (text) => {
94351
94601
  if (!text.trim())
94352
94602
  return [{ type: 'text', value: '' }];
94353
- const tree = contentParser.runSync(contentParser.parse(text));
94603
+ // Convert \n (and surrounding whitespace) to <br> inside HTML blocks so
94604
+ // CommonMark doesn't split them on blank lines.
94605
+ // Then strip leading whitespace to prevent indented code blocks.
94606
+ const escaped = processBackslashEscapes(text);
94607
+ const normalized = escaped
94608
+ .replace(HTML_ELEMENT_BLOCK_RE, match => match.replace(NEWLINE_WITH_WHITESPACE_RE, '<br>'))
94609
+ .replace(CLOSE_BLOCK_TAG_BOUNDARY_RE, separateBlockTagFromContent);
94610
+ const trimmedLines = normalized.split('\n').map(line => line.trimStart());
94611
+ const processed = trimmedLines.join('\n');
94612
+ const tree = contentParser.runSync(contentParser.parse(processed));
94613
+ // Process markdown inside complete HTML elements (e.g. _emphasis_ within <li>).
94614
+ // Bare tags like "<i>" are left for rehypeRaw since rehype-parse would mangle them.
94615
+ visit(tree, 'html', (node) => {
94616
+ if (COMPLETE_HTML_ELEMENT_RE.test(node.value)) {
94617
+ node.value = processMarkdownInHtmlString(node.value);
94618
+ }
94619
+ else {
94620
+ node.value = escapeInvalidTags(node.value);
94621
+ }
94622
+ });
94354
94623
  if (tree.children.length > 1) {
94355
94624
  return tree.children;
94356
94625
  }
@@ -94505,7 +94774,7 @@ function transformMagicBlock(blockType, data, rawValue, options = {}) {
94505
94774
  });
94506
94775
  }
94507
94776
  if (hasBody) {
94508
- const bodyBlocks = parseBlock(calloutJson.body || '');
94777
+ const bodyBlocks = parseBlock(preprocessBody(calloutJson.body || ''));
94509
94778
  children.push(...bodyBlocks);
94510
94779
  }
94511
94780
  const calloutElement = {
@@ -94540,7 +94809,7 @@ function transformMagicBlock(blockType, data, rawValue, options = {}) {
94540
94809
  const tokenizeCell = compatibilityMode ? textToBlock : parseTableCell;
94541
94810
  const tableChildren = Array.from({ length: rows + 1 }, (_, y) => ({
94542
94811
  children: Array.from({ length: cols }, (__, x) => ({
94543
- children: sparseData[y]?.[x] ? tokenizeCell(sparseData[y][x]) : [{ type: 'text', value: '' }],
94812
+ children: sparseData[y]?.[x] ? tokenizeCell(preprocessBody(sparseData[y][x])) : [{ type: 'text', value: '' }],
94544
94813
  type: y === 0 ? 'tableHead' : 'tableCell',
94545
94814
  })),
94546
94815
  type: 'tableRow',
@@ -94641,79 +94910,63 @@ const isBlockNode = (node) => blockTypes.includes(node.type);
94641
94910
  */
94642
94911
  const magicBlockTransformer = (options = {}) => tree => {
94643
94912
  const replacements = [];
94644
- visit(tree, 'magicBlock', (node, index, parent) => {
94645
- if (!parent || index === undefined)
94646
- return undefined;
94913
+ visitParents(tree, 'magicBlock', (node, ancestors) => {
94914
+ const parent = ancestors[ancestors.length - 1]; // direct parent of the current node
94915
+ const index = parent.children.indexOf(node);
94916
+ if (index === -1)
94917
+ return;
94647
94918
  const children = transformMagicBlock(node.blockType, node.data, node.value, options);
94648
94919
  if (!children.length) {
94649
- // Remove the node if transformation returns nothing
94920
+ // `visitParents` doesn't support [Action, Index] returns like `visit` does;
94921
+ // a bare return after splicing is sufficient since `visitParents` walks by
94922
+ // tree structure rather than index.
94650
94923
  parent.children.splice(index, 1);
94651
- return [SKIP, index];
94924
+ return;
94652
94925
  }
94653
94926
  // If parent is a paragraph and we're inserting block nodes (which must not be in paragraphs), lift them out
94654
94927
  if (parent.type === 'paragraph' && children.some(child => isBlockNode(child))) {
94655
94928
  const blockNodes = [];
94656
94929
  const inlineNodes = [];
94657
- // Separate block and inline nodes
94658
94930
  children.forEach(child => {
94659
- if (isBlockNode(child)) {
94660
- blockNodes.push(child);
94661
- }
94662
- else {
94663
- inlineNodes.push(child);
94664
- }
94931
+ (isBlockNode(child) ? blockNodes : inlineNodes).push(child);
94665
94932
  });
94666
- const before = parent.children.slice(0, index);
94667
- const after = parent.children.slice(index + 1);
94668
94933
  replacements.push({
94934
+ container: ancestors[ancestors.length - 2] || tree, // grandparent of the current node
94669
94935
  parent,
94670
94936
  blockNodes,
94671
94937
  inlineNodes,
94672
- before,
94673
- after,
94938
+ before: parent.children.slice(0, index),
94939
+ after: parent.children.slice(index + 1),
94674
94940
  });
94675
94941
  }
94676
94942
  else {
94677
- // Normal case: just replace the inlineCode with the children
94678
94943
  parent.children.splice(index, 1, ...children);
94679
94944
  }
94680
- return undefined;
94681
94945
  });
94682
94946
  // Second pass: apply replacements that require lifting block nodes out of paragraphs
94683
94947
  // Process in reverse order to maintain correct indices
94684
94948
  for (let i = replacements.length - 1; i >= 0; i -= 1) {
94685
- const { after, before, blockNodes, inlineNodes, parent } = replacements[i];
94686
- // Find the paragraph's position in the root
94687
- const rootChildren = tree.children;
94688
- const paraIndex = rootChildren.findIndex(child => child === parent);
94949
+ const { after, before, blockNodes, container, inlineNodes, parent } = replacements[i];
94950
+ const containerChildren = container.children;
94951
+ const paraIndex = containerChildren.indexOf(parent);
94689
94952
  if (paraIndex === -1) {
94690
- // Paragraph not found in root - fall back to normal replacement
94691
- // This shouldn't happen normally, but handle it gracefully
94692
- // Reconstruct the original index from before.length
94693
- const originalIndex = before.length;
94694
- parent.children.splice(originalIndex, 1, ...blockNodes, ...inlineNodes);
94953
+ parent.children.splice(before.length, 1, ...blockNodes, ...inlineNodes);
94695
94954
  // eslint-disable-next-line no-continue
94696
94955
  continue;
94697
94956
  }
94698
- // Update or remove the paragraph
94699
94957
  if (inlineNodes.length > 0) {
94700
- // Keep paragraph with inline nodes
94701
94958
  parent.children = [...before, ...inlineNodes, ...after];
94702
- // Insert block nodes after the paragraph
94703
94959
  if (blockNodes.length > 0) {
94704
- rootChildren.splice(paraIndex + 1, 0, ...blockNodes);
94960
+ containerChildren.splice(paraIndex + 1, 0, ...blockNodes);
94705
94961
  }
94706
94962
  }
94707
94963
  else if (before.length === 0 && after.length === 0) {
94708
- // Remove empty paragraph and replace with block nodes
94709
- rootChildren.splice(paraIndex, 1, ...blockNodes);
94964
+ containerChildren.splice(paraIndex, 1, ...blockNodes);
94710
94965
  }
94711
94966
  else {
94712
- // Keep paragraph with remaining content
94713
94967
  parent.children = [...before, ...after];
94714
- // Insert block nodes after the paragraph
94715
94968
  if (blockNodes.length > 0) {
94716
- rootChildren.splice(paraIndex + 1, 0, ...blockNodes);
94969
+ containerChildren.splice(paraIndex + 1, 0, ...blockNodes);
94717
94970
  }
94718
94971
  }
94719
94972
  }
@@ -95548,6 +95801,45 @@ const restoreBooleanProperties = () => tree => {
95548
95801
  };
95549
95802
 
95550
95803
 
95804
+ ;// ./processor/transform/mdxish/terminate-html-flow-blocks.ts
95805
+
95806
+ const STANDALONE_HTML_LINE_REGEX = /^(<[a-z][^<>]*>|<\/[a-z][^<>]*>)+\s*$/;
95807
+ const HTML_LINE_WITH_CONTENT_REGEX = /^<[a-z][^<>]*>.*<\/[a-z][^<>]*>(?:[^<]*)$/;
95808
+ /**
95809
+ * Preprocessor to terminate HTML flow blocks.
95810
+ *
95811
+ * In CommonMark, HTML blocks (types 6 and 7) only terminate on a blank line.
95812
+ * Without one, any content on the next line is consumed as part of the HTML block
95813
+ * and never parsed as its own construct. For example, a `[block:callout]` immediately
95814
+ * following `<div><p></p></div>` gets swallowed into the HTML flow token.
95815
+ *
95816
+ * @link https://spec.commonmark.org/0.29/#html-blocks
95817
+ *
95818
+ * This preprocessor inserts a blank line after standalone HTML lines when the
95819
+ * next line is non-blank, ensuring micromark's HTML flow tokenizer terminates
95820
+ * and subsequent content is parsed independently.
95821
+ *
95822
+ * Only targets non-indented lines with lowercase tag names. Uppercase tags
95823
+ * (e.g., `<Table>`, `<MyComponent>`) are JSX custom components and don't
95824
+ * trigger CommonMark HTML blocks, so they are left untouched.
95825
+ *
95826
+ * Lines inside fenced code blocks are skipped entirely.
95827
+ */
95828
+ function terminateHtmlFlowBlocks(content) {
95829
+ const { protectedContent, protectedCode } = protectCodeBlocks(content);
95830
+ const lines = protectedContent.split('\n');
95831
+ const result = [];
95832
+ for (let i = 0; i < lines.length; i += 1) {
95833
+ result.push(lines[i]);
95834
+ if (i < lines.length - 1 &&
95835
+ (STANDALONE_HTML_LINE_REGEX.test(lines[i]) || HTML_LINE_WITH_CONTENT_REGEX.test(lines[i])) &&
95836
+ lines[i + 1].trim().length > 0) {
95837
+ result.push('');
95838
+ }
95839
+ }
95840
+ return restoreCodeBlocks(result.join('\n'), protectedCode);
95841
+ }
95842
+
95551
95843
  ;// ./processor/transform/mdxish/variables-text.ts
95552
95844
 
95553
95845
 
@@ -96850,10 +97142,29 @@ function loadComponents() {
96850
97142
 
96851
97143
 
96852
97144
 
97145
+
97146
+
96853
97147
 
96854
97148
 
96855
97149
 
96856
97150
  const defaultTransformers = [callouts, code_tabs, gemoji_, transform_embeds];
97151
+ /**
97152
+ * Preprocessing pipeline: applies string-level transformations to work around
97153
+ * CommonMark/remark limitations and reach parity with legacy (rdmd) rendering.
97154
+ *
97155
+ * Runs a series of string-level transformations before micromark/remark parsing:
97156
+ * 1. Normalize malformed table separator syntax (e.g., `|: ---` → `| :---`)
97157
+ * 2. Terminate HTML flow blocks so subsequent content isn't swallowed
97158
+ * 3. Evaluate JSX expressions in attributes (unless safeMode)
97159
+ * 4. Replace snake_case component names with parser-safe placeholders
97160
+ */
97161
+ function preprocessContent(content, opts) {
97162
+ const { safeMode, jsxContext, knownComponents } = opts;
97163
+ let result = normalizeTableSeparator(content);
97164
+ result = terminateHtmlFlowBlocks(result);
97165
+ result = safeMode ? result : preprocessJSXExpressions(result, jsxContext);
97166
+ return processSnakeCaseComponent(result, { knownComponents });
97167
+ }
96857
97168
  function mdxishAstProcessor(mdContent, opts = {}) {
96858
97169
  const { components: userComponents = {}, jsxContext = {}, newEditorTypes = false, safeMode = false, useTailwind, } = opts;
96859
97170
  const components = {
@@ -96862,15 +97173,11 @@ function mdxishAstProcessor(mdContent, opts = {}) {
96862
97173
  };
96863
97174
  // Build set of known component names for snake_case filtering
96864
97175
  const knownComponents = new Set(Object.keys(components));
96865
- // Preprocessing pipeline: Transform content to be parser-ready
96866
- // Step 1: Normalize malformed table separator syntax (e.g., `|: ---` → `| :---`)
96867
- const contentAfterTableNormalization = normalizeTableSeparator(mdContent);
96868
- // Step 2: Evaluate JSX expressions in attributes
96869
- const contentAfterJSXEvaluation = safeMode
96870
- ? contentAfterTableNormalization
96871
- : preprocessJSXExpressions(contentAfterTableNormalization, jsxContext);
96872
- // Step 3: Replace snake_case component names with parser-safe placeholders
96873
- const { content: parserReadyContent, mapping: snakeCaseMapping } = processSnakeCaseComponent(contentAfterJSXEvaluation, { knownComponents });
97176
+ const { content: parserReadyContent, mapping: snakeCaseMapping } = preprocessContent(mdContent, {
97177
+ safeMode,
97178
+ jsxContext,
97179
+ knownComponents,
97180
+ });
96874
97181
  // Create string map for tailwind transformer
96875
97182
  const tempComponentsMap = Object.entries(components).reduce((acc, [key, value]) => {
96876
97183
  acc[key] = String(value);
@@ -96938,6 +97245,7 @@ function mdxish(mdContent, opts = {}) {
96938
97245
  };
96939
97246
  const { processor, parserReadyContent } = mdxishAstProcessor(mdContent, opts);
96940
97247
  processor
97248
+ .use(remarkBreaks)
96941
97249
  .use(remarkRehype, { allowDangerousHtml: true, handlers: mdxComponentHandlers })
96942
97250
  .use(preserveBooleanProperties) // RehypeRaw converts boolean properties to empty strings
96943
97251
  .use(rehypeRaw, { passThrough: ['html-block'] })
@@ -97450,18 +97758,19 @@ const mdxishTags_tags = (doc) => {
97450
97758
  * Removes Markdown and MDX comments.
97451
97759
  */
97452
97760
  async function stripComments(doc, { mdx, mdxish } = {}) {
97453
- const processor = unified()
97454
- .data('micromarkExtensions', [magicBlock()])
97455
- .data('fromMarkdownExtensions', [magicBlockFromMarkdown()])
97456
- .data('toMarkdownExtensions', [magicBlockToMarkdown()]);
97761
+ const micromarkExtensions = [magicBlock()];
97762
+ const fromMarkdownExtensions = [magicBlockFromMarkdown()];
97457
97763
  // we still require these two extensions because:
97458
- // 1. we can rely on remarkMdx to parse MDXish
97764
+ // 1. we cant rely on remarkMdx to parse MDXish
97459
97765
  // 2. we need to parse JSX comments into mdxTextExpression nodes so that the transformers can pick them up
97460
97766
  if (mdxish) {
97461
- processor
97462
- .data('micromarkExtensions', [mdxExpression({ allowEmpty: true })])
97463
- .data('fromMarkdownExtensions', [mdxExpressionFromMarkdown()]);
97767
+ micromarkExtensions.push(mdxExpression({ allowEmpty: true }));
97768
+ fromMarkdownExtensions.push(mdxExpressionFromMarkdown());
97464
97769
  }
97770
+ const processor = unified()
97771
+ .data('micromarkExtensions', micromarkExtensions)
97772
+ .data('fromMarkdownExtensions', fromMarkdownExtensions)
97773
+ .data('toMarkdownExtensions', [magicBlockToMarkdown()]);
97465
97774
  processor
97466
97775
  .use(remarkParse)
97467
97776
  .use(normalize_malformed_md_syntax)