@readme/markdown 14.12.1 → 14.13.1

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
@@ -1893,7 +1893,7 @@ module.exports = function (exec) {
1893
1893
 
1894
1894
  /***/ }),
1895
1895
 
1896
- /***/ 1842:
1896
+ /***/ 9461:
1897
1897
  /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
1898
1898
 
1899
1899
  module.exports = __webpack_require__(4556)('native-function-to-string', Function.toString);
@@ -2493,7 +2493,7 @@ var global = __webpack_require__(7526);
2493
2493
  var hide = __webpack_require__(3341);
2494
2494
  var has = __webpack_require__(7917);
2495
2495
  var SRC = __webpack_require__(4415)('src');
2496
- var $toString = __webpack_require__(1842);
2496
+ var $toString = __webpack_require__(9461);
2497
2497
  var TO_STRING = 'toString';
2498
2498
  var TPL = ('' + $toString).split(TO_STRING);
2499
2499
 
@@ -11839,8 +11839,8 @@ const Callout = (props) => {
11839
11839
 
11840
11840
 
11841
11841
 
11842
- const Card = ({ badge, children, href, kind = 'card', icon, iconColor, target, title }) => {
11843
- const Tag = href ? 'a' : 'div';
11842
+ const Card = ({ badge, children, href, kind = 'card', icon, iconColor, LinkComponent = 'a', target, title, }) => {
11843
+ const Tag = href ? LinkComponent : 'div';
11844
11844
  return (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement(Tag, { className: `Card Card_${kind}`, href: href, target: target },
11845
11845
  icon && external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement(components_Icon, { className: "Card-icon", icon: icon, iconColor: iconColor }),
11846
11846
  external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("div", { className: "Card-content" },
@@ -76301,6 +76301,21 @@ const HTML_TABLE_STRUCTURE_TAGS = new Set([
76301
76301
  'caption',
76302
76302
  'colgroup',
76303
76303
  ]);
76304
+ /**
76305
+ * Tags whose bodies a later mdxish transform keeps raw and never re-parses as
76306
+ * markdown. Both layers depend on this property, not on the tags being figures:
76307
+ * the transformer treats them as non-promotable, and the tokenizer must not claim
76308
+ * markdown islands inside them (a claimed island would never be re-parsed and would
76309
+ * leak as literal text). Currently just the figure tags, whose bodies are owned by
76310
+ * the figure reassembly transform (`mdxishJsxToMdast`).
76311
+ */
76312
+ const NON_REPARSED_BODY_TAGS = new Set(['figure', 'figcaption']);
76313
+ /**
76314
+ * The two HTML "foreign content" namespaces: SVG and MathML. Their descendants
76315
+ * (`<path>`, `<mrow>`, …) are namespaced XML, not HTML tags or components. A closed
76316
+ * set per the HTML spec, so transforms can treat these roots as opaque islands.
76317
+ */
76318
+ const FOREIGN_CONTENT_TAGS = ['svg', 'math'];
76304
76319
  /**
76305
76320
  * HTML void elements — elements that have no closing tag and no children.
76306
76321
  *
@@ -98930,6 +98945,9 @@ function getComponentName(componentName, components) {
98930
98945
 
98931
98946
 
98932
98947
 
98948
+ // Foreign-content (SVG/MathML) roots — subtrees the component transform leaves
98949
+ // untouched (their children are namespaced XML, not HTML tags/components).
98950
+ const FOREIGN_CONTENT_ROOTS = new Set(FOREIGN_CONTENT_TAGS);
98933
98951
  function isElementContentNode(node) {
98934
98952
  return node.type === 'element' || node.type === 'text' || node.type === 'comment';
98935
98953
  }
@@ -99105,6 +99123,12 @@ const rehypeMdxishComponents = ({ components, processMarkdown }) => {
99105
99123
  visit(tree, 'element', (node, index, parent) => {
99106
99124
  if (index === undefined || !parent)
99107
99125
  return;
99126
+ // Skip foreign-content subtrees: their namespaced children (<path>, <mrow>, …)
99127
+ // aren't HTML tags or components, so the "unknown component" removal below would
99128
+ // otherwise delete them. (svg/math themselves are standard HTML tags, kept.)
99129
+ // eslint-disable-next-line consistent-return
99130
+ if (FOREIGN_CONTENT_ROOTS.has(node.tagName))
99131
+ return SKIP;
99108
99132
  // Parse Image caption as markdown so it renders formatted (bold, code,
99109
99133
  // decoded entities) in the figcaption instead of as a raw string.
99110
99134
  // rehypeRaw strips children from <img> (void element), so we must
@@ -99416,6 +99440,81 @@ function closeSelfClosingHtmlTags(content) {
99416
99440
  return restoreCodeBlocks(result, protectedCode);
99417
99441
  }
99418
99442
 
99443
+ ;// ./processor/transform/mdxish/collapse-foreign-content-blank-lines.ts
99444
+
99445
+
99446
+ // `svg|math`, from the canonical list so this stays in sync with the component transform.
99447
+ const ROOT_ALT = FOREIGN_CONTENT_TAGS.join('|');
99448
+ // A foreign-content opener. The `[\s/>]` boundary requires a real tag delimiter after the
99449
+ // root name, so lookalikes like `<svgfoo>` and custom elements like `<svg-icon>` are ignored.
99450
+ const ANY_ROOT_RE = new RegExp(`<(?:${ROOT_ALT})(?=[\\s/>])`, 'i');
99451
+ // Tag body: swallows whole quoted attribute values so a `>` inside a quote (e.g.
99452
+ // `<svg data-x="a > b" />`) can't be mistaken for the tag terminator; other non-`>`
99453
+ // chars (including newlines) are consumed one at a time.
99454
+ const TAG_BODY = '(?:"[^"]*"|\'[^\']*\'|[^>\'"])*?';
99455
+ // One whole svg/math tag (opener, self-closer, or closer), matched whole so attributes
99456
+ // and `>` may span lines. The `[\s/>]` boundary after the root name keeps `<svgfoo>`/
99457
+ // `<svg-icon>` out. Group 1 is `/` only for a self-closer.
99458
+ const FOREIGN_TAG_RE = new RegExp(`<(?:${ROOT_ALT})(?=[\\s/>])${TAG_BODY}(/)?>|</(?:${ROOT_ALT})(?=[\\s/>])${TAG_BODY}>`, 'gi');
99459
+ // An HTML comment. Foreign markup inside one is inert and must not open an island.
99460
+ const HTML_COMMENT_RE = /<!--[\s\S]*?-->/g;
99461
+ const withinAny = (spans, offset) => spans.some(([start, end]) => offset >= start && offset < end);
99462
+ /**
99463
+ * `[start, end)` spans of every *matched* SVG/MathML pair — the regions whose blank
99464
+ * lines are known-insignificant XML. Matching whole tags (not per-line open/close
99465
+ * counts) keeps multi-line openers and self-closers balanced, so a wrapped
99466
+ * `<svg … />` can't latch and swallow the doc (#1545).
99467
+ *
99468
+ * Tags are paired innermost-first, as a parser would; an opener still unpaired at EOF
99469
+ * closed nothing and so covers nothing. That keeps a stray `<svg>` in prose from
99470
+ * swallowing every blank line after it, without hiding the real islands that follow.
99471
+ */
99472
+ function findForeignContentSpans(text) {
99473
+ const spans = [];
99474
+ // Foreign tags inside an HTML comment are inert; a stray `<svg>`/`<math>` in a comment
99475
+ // must not open an island and latch onto the rest of the doc.
99476
+ const comments = [...text.matchAll(HTML_COMMENT_RE)].map((m) => [m.index ?? 0, (m.index ?? 0) + m[0].length]);
99477
+ // Offsets of openers still waiting for their closer, innermost last.
99478
+ const openOffsets = [];
99479
+ [...text.matchAll(FOREIGN_TAG_RE)].forEach(match => {
99480
+ const offset = match.index ?? 0;
99481
+ if (withinAny(comments, offset))
99482
+ return; // markup inside an HTML comment is inert
99483
+ if (match[1] === '/')
99484
+ return; // self-closing tag opens no island
99485
+ if (match[0].startsWith('</')) {
99486
+ const start = openOffsets.pop();
99487
+ if (start !== undefined)
99488
+ spans.push([start, offset + match[0].length]); // a closer with no opener closes nothing
99489
+ }
99490
+ else {
99491
+ openOffsets.push(offset);
99492
+ }
99493
+ });
99494
+ return spans;
99495
+ }
99496
+ /**
99497
+ * Drop blank lines inside `<svg>`/`<math>` islands: their whitespace is
99498
+ * insignificant XML, but a blank line ends the CommonMark HTML block and spills the
99499
+ * children out as a code block (#1545). Collapsing keeps the island one block.
99500
+ */
99501
+ function collapseForeignContentBlankLines(content) {
99502
+ // Fast path: nothing to do when the doc has no foreign-content island.
99503
+ if (!ANY_ROOT_RE.test(content))
99504
+ return content;
99505
+ const { protectedContent, protectedCode } = protectCodeBlocks(content);
99506
+ const islands = findForeignContentSpans(protectedContent);
99507
+ // Drop blank lines inside an island; keep everything else verbatim.
99508
+ const lines = [];
99509
+ let lineStart = 0;
99510
+ protectedContent.split('\n').forEach(line => {
99511
+ if (line.trim().length > 0 || !withinAny(islands, lineStart))
99512
+ lines.push(line);
99513
+ lineStart += line.length + 1; // +1 for the '\n' that split() removed
99514
+ });
99515
+ return restoreCodeBlocks(lines.join('\n'), protectedCode);
99516
+ }
99517
+
99419
99518
  ;// ./lib/utils/mdxish/mdxish-component-tag-parser.ts
99420
99519
  // Extract the tag name (PascalCase or lowercase HTML) at the start of a tag string.
99421
99520
  const tagNamePattern = /^<([A-Za-z][A-Za-z0-9_-]*)/;
@@ -101408,12 +101507,95 @@ function tokenizeMagicBlockText(effects, ok, nok) {
101408
101507
  */
101409
101508
 
101410
101509
 
101510
+ ;// ./lib/micromark/mdx-component/continuation-checks.ts
101511
+
101512
+
101513
+ /**
101514
+ * Partial constructs the `mdxComponent` tokenizer runs via `effects.check` to
101515
+ * decide whether the next line continues the block. They live here (not in
101516
+ * `syntax.ts`) because they hold none of `createTokenize`'s closure state — each
101517
+ * is a self-contained, single-line lookahead.
101518
+ */
101519
+ function continuation_checks_tokenizeNonLazyContinuationStart(effects, ok, nok) {
101520
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
101521
+ const self = this;
101522
+ return start;
101523
+ function start(code) {
101524
+ if (markdownLineEnding(code)) {
101525
+ effects.enter(types_types.lineEnding);
101526
+ effects.consume(code);
101527
+ effects.exit(types_types.lineEnding);
101528
+ return after;
101529
+ }
101530
+ return nok(code);
101531
+ }
101532
+ function after(code) {
101533
+ if (self.parser.lazy[self.now().line]) {
101534
+ return nok(code);
101535
+ }
101536
+ return ok(code);
101537
+ }
101538
+ }
101539
+ // A markup-only line opens with a tag (`<x`/`</x`) and ends (ignoring trailing
101540
+ // spaces) at a `>`. That distinguishes a structural continuation like
101541
+ // `<span>b</span></div>` from a paragraph like `<b>Note:</b> read *this*`.
101542
+ function tokenizeMarkupOnlyContinuation(effects, ok, nok) {
101543
+ let lastNonSpace = null;
101544
+ return start;
101545
+ function start(code) {
101546
+ // Caller guarantees we are at `<` at the (already de-indented) line start.
101547
+ effects.enter(types_types.data);
101548
+ effects.consume(code);
101549
+ return afterLessThan;
101550
+ }
101551
+ function afterLessThan(code) {
101552
+ if (code === codes.slash) {
101553
+ effects.consume(code);
101554
+ return afterSlash;
101555
+ }
101556
+ return afterSlash(code);
101557
+ }
101558
+ // The `<` (or `</`) must introduce a real tag, not a stray `<` in prose.
101559
+ function afterSlash(code) {
101560
+ if (asciiAlpha(code)) {
101561
+ lastNonSpace = code;
101562
+ effects.consume(code);
101563
+ return scanToLineEnd;
101564
+ }
101565
+ effects.exit(types_types.data);
101566
+ return nok(code);
101567
+ }
101568
+ function scanToLineEnd(code) {
101569
+ if (code === null || markdownLineEnding(code)) {
101570
+ effects.exit(types_types.data);
101571
+ return lastNonSpace === codes.greaterThan ? ok(code) : nok(code);
101572
+ }
101573
+ if (!markdownSpace(code))
101574
+ lastNonSpace = code;
101575
+ effects.consume(code);
101576
+ return scanToLineEnd;
101577
+ }
101578
+ }
101579
+ // A line ending whose next line isn't a lazy paragraph continuation. Checked so a
101580
+ // component body's blank/continuation lines aren't stolen by an interrupted paragraph.
101581
+ const continuation_checks_nonLazyContinuationStart = {
101582
+ tokenize: continuation_checks_tokenizeNonLazyContinuationStart,
101583
+ partial: true,
101584
+ };
101585
+ // Lookahead for `plainClaimLineStart`: is this line markup-only, or a paragraph
101586
+ // that merely starts with a tag? Run via `effects.check` so it never consumes.
101587
+ const markupOnlyContinuation = {
101588
+ tokenize: tokenizeMarkupOnlyContinuation,
101589
+ partial: true,
101590
+ };
101591
+
101411
101592
  ;// ./lib/micromark/mdx-component/syntax.ts
101412
101593
 
101413
101594
 
101414
101595
 
101415
101596
 
101416
101597
 
101598
+
101417
101599
  // Raw tags (type-1: pre/script/style/textarea) and block tags (type-6: div,
101418
101600
  // section, …) always start a block, so they stay flow even with trailing
101419
101601
  // content. Other lowercase tags (i, span, …) follow the type-7 rule and only
@@ -101423,16 +101605,12 @@ const htmlFlowTagNames = new Set([...htmlRawNames, ...htmlBlockNames]);
101423
101605
  // blank lines between nested JSX siblings don't fragment the block. Excludes table
101424
101606
  // tags (mdxishTables owns their blank lines) and voids (never close).
101425
101607
  const plainBlockClaimTagNames = new Set([...htmlBlockNames].filter(tag => !HTML_TABLE_STRUCTURE_TAGS.has(tag) && !HTML_VOID_ELEMENTS.has(tag)));
101426
- const mdx_component_syntax_nonLazyContinuationStart = {
101427
- tokenize: mdx_component_syntax_tokenizeNonLazyContinuationStart,
101428
- partial: true,
101429
- };
101430
- // Lookahead for `plainClaimLineStart`: is this line markup-only, or a paragraph
101431
- // that merely starts with a tag? Run via `effects.check` so it never consumes.
101432
- const markupOnlyContinuation = {
101433
- tokenize: tokenizeMarkupOnlyContinuation,
101434
- partial: true,
101435
- };
101608
+ // Both are 4 columns per CommonMark, but they mean different things: a tab advances
101609
+ // to the next multiple of TAB_STOP_WIDTH, and INDENTED_CODE_MIN_COLUMNS is the depth
101610
+ // at which a line would fragment into indented code. Named separately so the two
101611
+ // concepts don't read as one incidental literal.
101612
+ const TAB_STOP_WIDTH = 4;
101613
+ const INDENTED_CODE_MIN_COLUMNS = 4;
101436
101614
  function resolveToMdxComponent(events) {
101437
101615
  let index = events.length;
101438
101616
  while (index > 0) {
@@ -101491,6 +101669,18 @@ function createTokenize(mode) {
101491
101669
  // `plainClaimLineStart`: after a blank line it may only continue on a tag line.
101492
101670
  let isPlainBlockClaim = false;
101493
101671
  let pendingBlankLine = false;
101672
+ // Leading indent columns of the current plain-claim line, reset per line; ≥4 is
101673
+ // where CommonMark would fragment the island as indented code. Tabs advance to the
101674
+ // next 4-column stop — the same rule `expandIndentToColumns`
101675
+ // (processor/transform/mdxish/indentation.ts) applies, kept in sync by hand since
101676
+ // this side works on a `Code` stream, not a string. NB: do NOT swap this for
101677
+ // `self.now().column`; micromark bumps the point column by 1 per `horizontalTab`
101678
+ // code (the trailing `virtualSpace` codes don't move it), so it measures a tab as
101679
+ // 1 column, reviving the tab-under-measurement bug this math exists to avoid.
101680
+ let plainClaimIndentColumns = 0;
101681
+ // True once a non-blank line follows the opener: a deep island below it is nested
101682
+ // (cosmetic indent), not top-of-body indented code.
101683
+ let sawPlainBlockBodyContent = false;
101494
101684
  // Code span tracking
101495
101685
  let codeSpanOpenSize = 0;
101496
101686
  let codeSpanCloseSize = 0;
@@ -101790,7 +101980,7 @@ function createTokenize(mode) {
101790
101980
  }
101791
101981
  // Continuation for multi-line opening tags
101792
101982
  function openTagContinuationStart(code) {
101793
- return effects.check(mdx_component_syntax_nonLazyContinuationStart, openTagContinuationNonLazy, continuationAfter)(code);
101983
+ return effects.check(continuation_checks_nonLazyContinuationStart, openTagContinuationNonLazy, continuationAfter)(code);
101794
101984
  }
101795
101985
  function openTagContinuationNonLazy(code) {
101796
101986
  sawLineEnding = true;
@@ -101835,6 +102025,9 @@ function createTokenize(mode) {
101835
102025
  }
101836
102026
  if (code !== codes.space && code !== codes.horizontalTab) {
101837
102027
  openerLineHasContent = true;
102028
+ // Continuation content marks a later deep island as nested, not indented code.
102029
+ if (!onOpenerLine)
102030
+ sawPlainBlockBodyContent = true;
101838
102031
  }
101839
102032
  if (code === codes.backslash) {
101840
102033
  effects.consume(code);
@@ -101915,7 +102108,7 @@ function createTokenize(mode) {
101915
102108
  return inFencedCode;
101916
102109
  }
101917
102110
  function fencedCodeContinuationStart(code) {
101918
- return effects.check(mdx_component_syntax_nonLazyContinuationStart, fencedCodeContinuationNonLazy, continuationAfter)(code);
102111
+ return effects.check(continuation_checks_nonLazyContinuationStart, fencedCodeContinuationNonLazy, continuationAfter)(code);
101919
102112
  }
101920
102113
  function fencedCodeContinuationNonLazy(code) {
101921
102114
  sawLineEnding = true;
@@ -102123,7 +102316,7 @@ function createTokenize(mode) {
102123
102316
  }
102124
102317
  // ── Body continuation (line endings) ───────────────────────────────────
102125
102318
  function bodyContinuationStart(code) {
102126
- return effects.check(mdx_component_syntax_nonLazyContinuationStart, bodyContinuationNonLazy, continuationAfter)(code);
102319
+ return effects.check(continuation_checks_nonLazyContinuationStart, bodyContinuationNonLazy, continuationAfter)(code);
102127
102320
  }
102128
102321
  function bodyContinuationNonLazy(code) {
102129
102322
  sawLineEnding = true;
@@ -102149,8 +102342,10 @@ function createTokenize(mode) {
102149
102342
  return inBodyBraceString(code);
102150
102343
  return inBodyBraceExpr(code);
102151
102344
  }
102152
- if (isPlainBlockClaim)
102345
+ if (isPlainBlockClaim) {
102346
+ plainClaimIndentColumns = 0;
102153
102347
  return plainClaimLineStart(code);
102348
+ }
102154
102349
  return bodyLineStart(code);
102155
102350
  }
102156
102351
  // Dispatch a non-blank continuation line: fenced code at line start, else body.
@@ -102180,6 +102375,8 @@ function createTokenize(mode) {
102180
102375
  function plainClaimLineStart(code) {
102181
102376
  // Leading whitespace only → treat as a blank line, matching CommonMark.
102182
102377
  if (code === codes.space || code === codes.horizontalTab) {
102378
+ plainClaimIndentColumns +=
102379
+ code === codes.horizontalTab ? TAB_STOP_WIDTH - (plainClaimIndentColumns % TAB_STOP_WIDTH) : 1;
102183
102380
  effects.consume(code);
102184
102381
  return plainClaimLineStart;
102185
102382
  }
@@ -102188,10 +102385,18 @@ function createTokenize(mode) {
102188
102385
  effects.exit('mdxComponentData');
102189
102386
  return bodyContinuationStart(code);
102190
102387
  }
102191
- // Across a blank line the block only continues onto a markup-only line; a
102192
- // paragraph that merely starts with a tag must fall back so its markdown
102193
- // parses and rehype-raw re-nests it into the wrapper.
102194
102388
  if (pendingBlankLine) {
102389
+ // A 4+ col island nested under other tags is cosmetic nesting indent, not code:
102390
+ // keep claiming so promotion dedents + re-parses it as markdown (RM-17560).
102391
+ // Tags whose bodies stay raw are excluded — a claimed island there would never
102392
+ // be re-parsed and would leak as literal text.
102393
+ if (plainClaimIndentColumns >= INDENTED_CODE_MIN_COLUMNS &&
102394
+ sawPlainBlockBodyContent &&
102395
+ !NON_REPARSED_BODY_TAGS.has(tagName)) {
102396
+ return plainClaimContinue(code);
102397
+ }
102398
+ // Otherwise only a markup-only tag line continues; markdown/prose falls back to
102399
+ // CommonMark so it parses and rehype-raw re-nests it into the wrapper.
102195
102400
  if (code !== codes.lessThan)
102196
102401
  return nok(code);
102197
102402
  return effects.check(markupOnlyContinuation, plainClaimContinue, nok)(code);
@@ -102212,66 +102417,6 @@ function createTokenize(mode) {
102212
102417
  }
102213
102418
  };
102214
102419
  }
102215
- function mdx_component_syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
102216
- // eslint-disable-next-line @typescript-eslint/no-this-alias
102217
- const self = this;
102218
- return start;
102219
- function start(code) {
102220
- if (markdownLineEnding(code)) {
102221
- effects.enter(types_types.lineEnding);
102222
- effects.consume(code);
102223
- effects.exit(types_types.lineEnding);
102224
- return after;
102225
- }
102226
- return nok(code);
102227
- }
102228
- function after(code) {
102229
- if (self.parser.lazy[self.now().line]) {
102230
- return nok(code);
102231
- }
102232
- return ok(code);
102233
- }
102234
- }
102235
- // A markup-only line opens with a tag (`<x`/`</x`) and ends (ignoring trailing
102236
- // spaces) at a `>`. That distinguishes a structural continuation like
102237
- // `<span>b</span></div>` from a paragraph like `<b>Note:</b> read *this*`.
102238
- function tokenizeMarkupOnlyContinuation(effects, ok, nok) {
102239
- let lastNonSpace = null;
102240
- return start;
102241
- function start(code) {
102242
- // Caller guarantees we are at `<` at the (already de-indented) line start.
102243
- effects.enter(types_types.data);
102244
- effects.consume(code);
102245
- return afterLessThan;
102246
- }
102247
- function afterLessThan(code) {
102248
- if (code === codes.slash) {
102249
- effects.consume(code);
102250
- return afterSlash;
102251
- }
102252
- return afterSlash(code);
102253
- }
102254
- // The `<` (or `</`) must introduce a real tag, not a stray `<` in prose.
102255
- function afterSlash(code) {
102256
- if (asciiAlpha(code)) {
102257
- lastNonSpace = code;
102258
- effects.consume(code);
102259
- return scanToLineEnd;
102260
- }
102261
- effects.exit(types_types.data);
102262
- return nok(code);
102263
- }
102264
- function scanToLineEnd(code) {
102265
- if (code === null || markdownLineEnding(code)) {
102266
- effects.exit(types_types.data);
102267
- return lastNonSpace === codes.greaterThan ? ok(code) : nok(code);
102268
- }
102269
- if (!markdownSpace(code))
102270
- lastNonSpace = code;
102271
- effects.consume(code);
102272
- return scanToLineEnd;
102273
- }
102274
- }
102275
102420
  /**
102276
102421
  * Micromark extension that tokenizes MDX-like components.
102277
102422
  *
@@ -102325,6 +102470,7 @@ function mdxComponent() {
102325
102470
 
102326
102471
 
102327
102472
 
102473
+
102328
102474
 
102329
102475
  const buildInlineMdProcessor = (safeMode) => {
102330
102476
  // `jsxTable` must be present so a `<Table>`/`<table>` nested in a component
@@ -102396,7 +102542,7 @@ const toMdxJsxTextElement = (name, attributes, children, position) => ({
102396
102542
  // Raw-body tags (pre/script/style/textarea) must stay byte-exact; table
102397
102543
  // structure (`table` + `tableTags`) is owned by `mdxishTables` and figures by
102398
102544
  // `mdxishJsxToMdast`, both of which run later on raw html nodes.
102399
- const NON_PROMOTABLE_PLAIN_TAGS = new Set([...htmlRawNames, ...tableTags, 'table', 'figure', 'figcaption']);
102545
+ const NON_PROMOTABLE_PLAIN_TAGS = new Set([...htmlRawNames, ...tableTags, 'table', ...NON_REPARSED_BODY_TAGS]);
102400
102546
  const NESTED_TABLE_RE = /<table[\s>]/i;
102401
102547
  const isMarkdownPromotableHtmlTag = (tag) => !NON_PROMOTABLE_PLAIN_TAGS.has(tag);
102402
102548
  // Expression nodes count as plain so `<div>{1+1}</div>` keeps its current
@@ -102755,15 +102901,22 @@ function safeDeindent(text) {
102755
102901
  */
102756
102902
  const parseMdChildren = (value, safeMode) => {
102757
102903
  const parsed = getInlineMdProcessor({ safeMode }).parse(terminateHtmlFlowBlocks(safeDeindent(value).trim()));
102904
+ // Promote nested wrappers bottom-up so an outer wrapper sees markdown buried in a
102905
+ // child claimed whole (e.g. `<li>` in `<ol>`) before its containsMarkdownConstruct check (RM-17560).
102906
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define -- mutually recursive; hoisted decl, safe at runtime
102907
+ promoteComponentBlocks(parsed, safeMode, null);
102758
102908
  return parsed.children || [];
102759
102909
  };
102760
- // Parses trailing content into sibling nodes and re-queues the parent so any
102761
- // components among them get processed.
102762
- const parseSibling = (stack, parent, index, sibling, safeMode) => {
102910
+ // Splices trailing content in as sibling nodes. parseMdChildren has already
102911
+ // promoted any components nested among them (bottom-up); the main loop's
102912
+ // index-based walk then reaches these spliced siblings and the original children
102913
+ // they shift down, so no parent re-queue is needed. Each spliced subtree is marked
102914
+ // `promoted` so the walk doesn't redundantly re-descend into it (its html is gone).
102915
+ const parseSibling = (parent, index, sibling, safeMode, promoted) => {
102763
102916
  const siblingNodes = parseMdChildren(sibling, safeMode);
102764
102917
  if (siblingNodes.length > 0) {
102765
102918
  parent.children.splice(index + 1, 0, ...siblingNodes);
102766
- stack.push(parent);
102919
+ siblingNodes.forEach(siblingNode => promoted.add(siblingNode));
102767
102920
  }
102768
102921
  };
102769
102922
  // Ends the position at `consumedLength` so the component doesn't claim trailing
@@ -102829,16 +102982,19 @@ const substituteNodeWithMdxNode = (parent, index, mdxNode) => {
102829
102982
  * The opening tag, content, and closing tag are all captured in one HTML node
102830
102983
  * (guaranteed by the mdx-component tokenizer).
102831
102984
  */
102832
- const mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
102985
+ function promoteComponentBlocks(tree, safeMode, source) {
102833
102986
  const stack = [tree];
102834
- const safeMode = !!opts.safeMode;
102835
- const source = file?.value ? String(file.value) : null;
102836
102987
  const parseOpts = { preserveExpressionsAsText: safeMode };
102988
+ // Subtrees a nested parseMdChildren already promoted wholesale (spliced siblings):
102989
+ // re-descending them finds no html to promote, so skip them.
102990
+ const promoted = new WeakSet();
102837
102991
  const processChildNode = (parent, index) => {
102838
102992
  const node = parent.children[index];
102839
102993
  if (!node)
102840
102994
  return;
102841
- if ('children' in node && Array.isArray(node.children)) {
102995
+ // Descend into container nodes (lists, blockquotes, …) so their html children
102996
+ // are reached — unless the subtree was already promoted upstream.
102997
+ if ('children' in node && Array.isArray(node.children) && !promoted.has(node)) {
102842
102998
  stack.push(node);
102843
102999
  }
102844
103000
  // Only html nodes can be an unparsed MDX component.
@@ -102893,7 +103049,7 @@ const mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
102893
103049
  substituteNodeWithMdxNode(parent, index, componentNode);
102894
103050
  const remainingContent = contentAfterTag.trim();
102895
103051
  if (remainingContent) {
102896
- parseSibling(stack, parent, index, remainingContent, safeMode);
103052
+ parseSibling(parent, index, remainingContent, safeMode, promoted);
102897
103053
  }
102898
103054
  return;
102899
103055
  }
@@ -102920,43 +103076,57 @@ const mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
102920
103076
  return;
102921
103077
  // Lowercase tags are usually inline; unwrap a sole paragraph so their
102922
103078
  // phrasing content isn't spuriously block-wrapped.
103079
+ let unwrappedSoleParagraph = false;
102923
103080
  if (!isPascal && parsedChildren.length === 1 && parsedChildren[0].type === 'paragraph') {
102924
103081
  parsedChildren = parsedChildren[0].children;
103082
+ unwrappedSoleParagraph = true;
103083
+ }
103084
+ // Without trailing content the whole node position is correct. With it, end
103085
+ // precisely at the closing tag — preferring source offsets when available (the
103086
+ // node's value strips blockquote/list prefixes), else the consumed span.
103087
+ let endPosition = node.position;
103088
+ if (contentAfterClose) {
103089
+ endPosition = source
103090
+ ? positionEndingAtClosingTagInSource(node.position, closingTagStr, source)
103091
+ : positionEndingAtConsumed(node.position, value, leadingWhitespace + openingTagEnd + closingTagIndex + closingTagStr.length);
102925
103092
  }
102926
103093
  const componentNode = createComponentNode({
102927
103094
  tag,
102928
103095
  attributes,
102929
103096
  children: parsedChildren,
102930
103097
  startPosition: node.position,
102931
- // With trailing content, end precisely at the closing tag. Prefer source
102932
- // offsets when available (the node's value strips blockquote/list
102933
- // prefixes); otherwise fall back to the whole node position.
102934
- endPosition: contentAfterClose
102935
- ? source
102936
- ? positionEndingAtClosingTagInSource(node.position, closingTagStr, source)
102937
- : positionEndingAtConsumed(node.position, value, leadingWhitespace + openingTagEnd + closingTagIndex + closingTagStr.length)
102938
- : node.position,
103098
+ endPosition,
102939
103099
  });
102940
103100
  substituteNodeWithMdxNode(parent, index, componentNode);
102941
- // Re-queue whichever side may hold further components.
102942
- if (contentAfterClose) {
102943
- parseSibling(stack, parent, index, contentAfterClose, safeMode);
102944
- }
102945
- else if (componentNode.children.length > 0) {
103101
+ // The unwrap reparented the children out of their paragraph, so re-walk them
103102
+ // since the children HTML may contain promotable syntax (e.g. `{…}`-attr tags)
103103
+ if (unwrappedSoleParagraph) {
102946
103104
  stack.push(componentNode);
102947
103105
  }
103106
+ // Trailing content after the close becomes siblings; parseMdChildren has
103107
+ // already promoted any components nested inside both sides, so the promoted
103108
+ // subtree itself needs no re-queue.
103109
+ if (contentAfterClose) {
103110
+ parseSibling(parent, index, contentAfterClose, safeMode, promoted);
103111
+ }
102948
103112
  }
102949
103113
  };
102950
- // Depth-first so nodes keep their source order.
103114
+ // Depth-first so nodes keep their source order. Index-based (not forEach) and
103115
+ // re-reading length each step: parseSibling splices siblings in mid-iteration, and
103116
+ // those — plus the original children they shift down — must all stay eligible.
102951
103117
  while (stack.length) {
102952
103118
  const parent = stack.pop();
102953
103119
  if (parent?.children) {
102954
- parent.children.forEach((_child, index) => {
103120
+ for (let index = 0; index < parent.children.length; index += 1) {
102955
103121
  processChildNode(parent, index);
102956
- });
103122
+ }
102957
103123
  }
102958
103124
  }
102959
103125
  return tree;
103126
+ }
103127
+ const mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
103128
+ const source = file?.value ? String(file.value) : null;
103129
+ return promoteComponentBlocks(tree, !!opts.safeMode, source);
102960
103130
  };
102961
103131
  /* harmony default export */ const mdx_blocks = (mdxishMdxComponentBlocks);
102962
103132
 
@@ -106555,6 +106725,7 @@ function loadComponents() {
106555
106725
 
106556
106726
 
106557
106727
 
106728
+
106558
106729
 
106559
106730
 
106560
106731
  const defaultTransformers = [
@@ -106569,10 +106740,11 @@ const defaultTransformers = [
106569
106740
  * Runs a series of string-level transformations before micromark/remark parsing:
106570
106741
  * 1. Canonicalize closing tags with stray whitespace (e.g., `</ td >` → `</td>`)
106571
106742
  * 2. Normalize malformed table separator syntax (e.g., `|: ---` → `| :---`)
106572
- * 3. Terminate HTML flow blocks so subsequent content isn't swallowed
106573
- * 4. Close invalid "self-closing" HTML tags (e.g., `<i />` → `<i></i>`)
106574
- * 5. Normalize compact ATX headings (e.g., `#Heading``# Heading`)
106575
- * 6. Replace snake_case component names with parser-safe placeholders
106743
+ * 3. Collapse blank lines inside `<svg>`/`<math>` so their children aren't fragmented
106744
+ * 4. Terminate HTML flow blocks so subsequent content isn't swallowed
106745
+ * 5. Close invalid "self-closing" HTML tags (e.g., `<i />` `<i></i>`)
106746
+ * 6. Normalize compact ATX headings (e.g., `#Heading` → `# Heading`)
106747
+ * 7. Replace snake_case component names with parser-safe placeholders
106576
106748
  */
106577
106749
  function preprocessContent(content, opts) {
106578
106750
  const { knownComponents } = opts;
@@ -106580,6 +106752,10 @@ function preprocessContent(content, opts) {
106580
106752
  // classification in `terminateHtmlFlowBlocks` is accurate)
106581
106753
  let result = normalizeClosingTagWhitespace(content);
106582
106754
  result = normalizeTableSeparator(result);
106755
+ // Before terminateHtmlFlowBlocks: a blank line inside an <svg>/<math> island
106756
+ // would otherwise fragment it (children spill out as an indented code block once
106757
+ // a wrapper re-parses its deindented body — #1545).
106758
+ result = collapseForeignContentBlankLines(result);
106583
106759
  result = terminateHtmlFlowBlocks(result);
106584
106760
  result = closeSelfClosingHtmlTags(result);
106585
106761
  result = normalizeCompactHeadings(result);
@@ -107303,6 +107479,8 @@ function restoreMagicBlocks(replaced, blocks) {
107303
107479
 
107304
107480
 
107305
107481
 
107482
+
107483
+
107306
107484
  /**
107307
107485
  * Removes Markdown and MDX comments.
107308
107486
  */
@@ -107313,10 +107491,16 @@ async function stripComments(doc, { mdx, mdxish } = {}) {
107313
107491
  // 1. we can rely on remarkMdx to parse MDXish
107314
107492
  // 2. we need to parse JSX comments into mdxTextExpression nodes so that the transformers can pick them up
107315
107493
  // 3. we need to claim <HTMLBlock> before htmlFlow intercepts its inner HTML tags
107494
+ // 4. we need mdxComponent to parse custom components as one node, and prevent the tag from getting escaped
107316
107495
  if (mdxish) {
107317
107496
  processor
107318
- .data('micromarkExtensions', [htmlBlockComponent(), jsxTable(), mdxExpression({ allowEmpty: true })])
107319
- .data('fromMarkdownExtensions', [htmlBlockComponentFromMarkdown(), jsxTableFromMarkdown(), mdxExpressionFromMarkdown()])
107497
+ .data('micromarkExtensions', [htmlBlockComponent(), jsxTable(), mdxComponent(), mdxExpression({ allowEmpty: true })])
107498
+ .data('fromMarkdownExtensions', [
107499
+ htmlBlockComponentFromMarkdown(),
107500
+ jsxTableFromMarkdown(),
107501
+ mdxComponentFromMarkdown(),
107502
+ mdxExpressionFromMarkdown(),
107503
+ ])
107320
107504
  .data('toMarkdownExtensions', [mdxExpressionToMarkdown()]);
107321
107505
  }
107322
107506
  processor