@readme/markdown 13.7.3 → 13.7.4

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
@@ -11873,6 +11873,8 @@ const GlossaryContext = (0,external_amd_react_commonjs_react_commonjs2_react_roo
11873
11873
 
11874
11874
  const Glossary = ({ children, term: termProp, terms }) => {
11875
11875
  const term = (Array.isArray(children) ? children[0] : children) || termProp;
11876
+ if (!term)
11877
+ return null;
11876
11878
  const foundTerm = terms.find(i => term.toLowerCase() === i?.term?.toLowerCase());
11877
11879
  if (!foundTerm)
11878
11880
  return external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("span", null, term);
@@ -12342,19 +12344,10 @@ const TailwindStyle = ({ children, darkModeDataAttribute }) => {
12342
12344
  records.forEach(record => {
12343
12345
  if (record.type === 'childList') {
12344
12346
  record.addedNodes.forEach(node => {
12345
- if (!(node instanceof HTMLElement))
12347
+ if (!(node instanceof HTMLElement) || !node.classList.contains(tailwindPrefix))
12346
12348
  return;
12347
- // Check the added node itself
12348
- if (node.classList.contains(tailwindPrefix)) {
12349
- traverse(node, addClasses);
12350
- shouldUpdate = true;
12351
- }
12352
- // Also check descendants — React may insert a parent node
12353
- // whose children contain TailwindRoot elements
12354
- node.querySelectorAll(`.${tailwindPrefix}`).forEach(child => {
12355
- traverse(child, addClasses);
12356
- shouldUpdate = true;
12357
- });
12349
+ traverse(node, addClasses);
12350
+ shouldUpdate = true;
12358
12351
  });
12359
12352
  }
12360
12353
  else if (record.type === 'attributes') {
@@ -52989,6 +52982,10 @@ const plain = (node, opts = {}) => {
52989
52982
  };
52990
52983
  /* harmony default export */ const lib_plain = (plain);
52991
52984
 
52985
+ ;// ./processor/compile/gemoji.ts
52986
+ const gemoji = (node) => `:${node.name}:`;
52987
+ /* harmony default export */ const compile_gemoji = (gemoji);
52988
+
52992
52989
  ;// ./processor/compile/variable.ts
52993
52990
  const variable = (node) => `{user.${node.data?.hProperties?.name || ''}}`;
52994
52991
  /* harmony default export */ const compile_variable = (variable);
@@ -53039,6 +53036,7 @@ const extractText = (node) => {
53039
53036
 
53040
53037
 
53041
53038
 
53039
+
53042
53040
  const titleParser = unified().use(remarkParse).use(remarkGfm);
53043
53041
  // The title paragraph may contain custom AST nodes that `toMarkdown` doesn't
53044
53042
  // natively understand
@@ -53046,8 +53044,8 @@ const toMarkdownExtensions = [
53046
53044
  gfmToMarkdown(),
53047
53045
  // For mdx variable syntaxes (e.g., {user.name})
53048
53046
  mdxExpressionToMarkdown(),
53049
- // Important: This is required and would crash the parser if there's no variable node handler
53050
- { handlers: { [NodeTypes.variable]: compile_variable } },
53047
+ // Important: This is required and would crash the parser if there's no variable and gemoji node handler
53048
+ { handlers: { [NodeTypes.variable]: compile_variable, [NodeTypes.emoji]: compile_gemoji } },
53051
53049
  ];
53052
53050
  const callouts_regex = `^(${emoji_regex().source}|⚠)(\\s+|$)`;
53053
53051
  const findFirst = (node) => {
@@ -53442,7 +53440,7 @@ const embedTransformer = () => {
53442
53440
  *
53443
53441
  * @type {Array<Gemoji>}
53444
53442
  */
53445
- const gemoji = [
53443
+ const gemoji_gemoji = [
53446
53444
  {
53447
53445
  emoji: '😀',
53448
53446
  names: ['grinning'],
@@ -70385,7 +70383,7 @@ class Owlmoji {
70385
70383
  return null;
70386
70384
  };
70387
70385
  static nameToEmoji = nameToEmoji;
70388
- static owlmoji = gemoji.concat(owlmoji);
70386
+ static owlmoji = gemoji_gemoji.concat(owlmoji);
70389
70387
  }
70390
70388
 
70391
70389
  ;// ./processor/transform/gemoji+.ts
@@ -71295,6 +71293,316 @@ const mdxToHast = () => tree => {
71295
71293
  };
71296
71294
  /* harmony default export */ const mdx_to_hast = (mdxToHast);
71297
71295
 
71296
+ ;// ./lib/mdast-util/gemoji/index.ts
71297
+
71298
+
71299
+ function exitGemoji(token) {
71300
+ const name = this.sliceSerialize(token).slice(1, -1); // strip surrounding colons
71301
+ switch (Owlmoji.kind(name)) {
71302
+ case 'gemoji': {
71303
+ this.enter({ type: NodeTypes.emoji, value: Owlmoji.nameToEmoji[name], name }, token);
71304
+ this.exit(token);
71305
+ break;
71306
+ }
71307
+ case 'fontawesome': {
71308
+ this.enter({
71309
+ type: NodeTypes.i,
71310
+ value: name,
71311
+ data: { hName: 'i', hProperties: { className: ['fa-regular', name] } },
71312
+ }, token);
71313
+ this.exit(token);
71314
+ break;
71315
+ }
71316
+ case 'owlmoji': {
71317
+ this.enter({
71318
+ type: NodeTypes.emoji,
71319
+ value: `:${name}:`,
71320
+ name,
71321
+ data: {
71322
+ hName: 'img',
71323
+ hProperties: {
71324
+ src: `/public/img/emojis/${name}.png`,
71325
+ alt: `:${name}:`,
71326
+ title: `:${name}:`,
71327
+ className: 'emoji',
71328
+ align: 'absmiddle',
71329
+ height: '20',
71330
+ width: '20',
71331
+ },
71332
+ },
71333
+ }, token);
71334
+ this.exit(token);
71335
+ break;
71336
+ }
71337
+ default: {
71338
+ // Unknown shortcode, emit as literal text `:name:`
71339
+ this.enter({ type: 'text', value: `:${name}:` }, token);
71340
+ this.exit(token);
71341
+ break;
71342
+ }
71343
+ }
71344
+ }
71345
+ function gemojiFromMarkdown() {
71346
+ return {
71347
+ exit: {
71348
+ gemoji: exitGemoji,
71349
+ },
71350
+ };
71351
+ }
71352
+
71353
+ ;// ./node_modules/micromark-util-symbol/lib/codes.js
71354
+ /**
71355
+ * Character codes.
71356
+ *
71357
+ * This module is compiled away!
71358
+ *
71359
+ * micromark works based on character codes.
71360
+ * This module contains constants for the ASCII block and the replacement
71361
+ * character.
71362
+ * A couple of them are handled in a special way, such as the line endings
71363
+ * (CR, LF, and CR+LF, commonly known as end-of-line: EOLs), the tab (horizontal
71364
+ * tab) and its expansion based on what column it’s at (virtual space),
71365
+ * and the end-of-file (eof) character.
71366
+ * As values are preprocessed before handling them, the actual characters LF,
71367
+ * CR, HT, and NUL (which is present as the replacement character), are
71368
+ * guaranteed to not exist.
71369
+ *
71370
+ * Unicode basic latin block.
71371
+ */
71372
+ const codes = /** @type {const} */ ({
71373
+ carriageReturn: -5,
71374
+ lineFeed: -4,
71375
+ carriageReturnLineFeed: -3,
71376
+ horizontalTab: -2,
71377
+ virtualSpace: -1,
71378
+ eof: null,
71379
+ nul: 0,
71380
+ soh: 1,
71381
+ stx: 2,
71382
+ etx: 3,
71383
+ eot: 4,
71384
+ enq: 5,
71385
+ ack: 6,
71386
+ bel: 7,
71387
+ bs: 8,
71388
+ ht: 9, // `\t`
71389
+ lf: 10, // `\n`
71390
+ vt: 11, // `\v`
71391
+ ff: 12, // `\f`
71392
+ cr: 13, // `\r`
71393
+ so: 14,
71394
+ si: 15,
71395
+ dle: 16,
71396
+ dc1: 17,
71397
+ dc2: 18,
71398
+ dc3: 19,
71399
+ dc4: 20,
71400
+ nak: 21,
71401
+ syn: 22,
71402
+ etb: 23,
71403
+ can: 24,
71404
+ em: 25,
71405
+ sub: 26,
71406
+ esc: 27,
71407
+ fs: 28,
71408
+ gs: 29,
71409
+ rs: 30,
71410
+ us: 31,
71411
+ space: 32,
71412
+ exclamationMark: 33, // `!`
71413
+ quotationMark: 34, // `"`
71414
+ numberSign: 35, // `#`
71415
+ dollarSign: 36, // `$`
71416
+ percentSign: 37, // `%`
71417
+ ampersand: 38, // `&`
71418
+ apostrophe: 39, // `'`
71419
+ leftParenthesis: 40, // `(`
71420
+ rightParenthesis: 41, // `)`
71421
+ asterisk: 42, // `*`
71422
+ plusSign: 43, // `+`
71423
+ comma: 44, // `,`
71424
+ dash: 45, // `-`
71425
+ dot: 46, // `.`
71426
+ slash: 47, // `/`
71427
+ digit0: 48, // `0`
71428
+ digit1: 49, // `1`
71429
+ digit2: 50, // `2`
71430
+ digit3: 51, // `3`
71431
+ digit4: 52, // `4`
71432
+ digit5: 53, // `5`
71433
+ digit6: 54, // `6`
71434
+ digit7: 55, // `7`
71435
+ digit8: 56, // `8`
71436
+ digit9: 57, // `9`
71437
+ colon: 58, // `:`
71438
+ semicolon: 59, // `;`
71439
+ lessThan: 60, // `<`
71440
+ equalsTo: 61, // `=`
71441
+ greaterThan: 62, // `>`
71442
+ questionMark: 63, // `?`
71443
+ atSign: 64, // `@`
71444
+ uppercaseA: 65, // `A`
71445
+ uppercaseB: 66, // `B`
71446
+ uppercaseC: 67, // `C`
71447
+ uppercaseD: 68, // `D`
71448
+ uppercaseE: 69, // `E`
71449
+ uppercaseF: 70, // `F`
71450
+ uppercaseG: 71, // `G`
71451
+ uppercaseH: 72, // `H`
71452
+ uppercaseI: 73, // `I`
71453
+ uppercaseJ: 74, // `J`
71454
+ uppercaseK: 75, // `K`
71455
+ uppercaseL: 76, // `L`
71456
+ uppercaseM: 77, // `M`
71457
+ uppercaseN: 78, // `N`
71458
+ uppercaseO: 79, // `O`
71459
+ uppercaseP: 80, // `P`
71460
+ uppercaseQ: 81, // `Q`
71461
+ uppercaseR: 82, // `R`
71462
+ uppercaseS: 83, // `S`
71463
+ uppercaseT: 84, // `T`
71464
+ uppercaseU: 85, // `U`
71465
+ uppercaseV: 86, // `V`
71466
+ uppercaseW: 87, // `W`
71467
+ uppercaseX: 88, // `X`
71468
+ uppercaseY: 89, // `Y`
71469
+ uppercaseZ: 90, // `Z`
71470
+ leftSquareBracket: 91, // `[`
71471
+ backslash: 92, // `\`
71472
+ rightSquareBracket: 93, // `]`
71473
+ caret: 94, // `^`
71474
+ underscore: 95, // `_`
71475
+ graveAccent: 96, // `` ` ``
71476
+ lowercaseA: 97, // `a`
71477
+ lowercaseB: 98, // `b`
71478
+ lowercaseC: 99, // `c`
71479
+ lowercaseD: 100, // `d`
71480
+ lowercaseE: 101, // `e`
71481
+ lowercaseF: 102, // `f`
71482
+ lowercaseG: 103, // `g`
71483
+ lowercaseH: 104, // `h`
71484
+ lowercaseI: 105, // `i`
71485
+ lowercaseJ: 106, // `j`
71486
+ lowercaseK: 107, // `k`
71487
+ lowercaseL: 108, // `l`
71488
+ lowercaseM: 109, // `m`
71489
+ lowercaseN: 110, // `n`
71490
+ lowercaseO: 111, // `o`
71491
+ lowercaseP: 112, // `p`
71492
+ lowercaseQ: 113, // `q`
71493
+ lowercaseR: 114, // `r`
71494
+ lowercaseS: 115, // `s`
71495
+ lowercaseT: 116, // `t`
71496
+ lowercaseU: 117, // `u`
71497
+ lowercaseV: 118, // `v`
71498
+ lowercaseW: 119, // `w`
71499
+ lowercaseX: 120, // `x`
71500
+ lowercaseY: 121, // `y`
71501
+ lowercaseZ: 122, // `z`
71502
+ leftCurlyBrace: 123, // `{`
71503
+ verticalBar: 124, // `|`
71504
+ rightCurlyBrace: 125, // `}`
71505
+ tilde: 126, // `~`
71506
+ del: 127,
71507
+ // Unicode Specials block.
71508
+ byteOrderMarker: 65_279,
71509
+ // Unicode Specials block.
71510
+ replacementCharacter: 65_533 // `�`
71511
+ })
71512
+
71513
+ ;// ./lib/micromark/gemoji/syntax.ts
71514
+
71515
+ // Matches the name pattern from the original regex: \+1 or [-\w]+
71516
+ // see https://github.com/readmeio/markdown/blob/489a71e19b34f640595ce81e988dad631045186f/processor/transform/gemoji%2B.ts#L9
71517
+ function isNameChar(code) {
71518
+ if (code === null)
71519
+ return false;
71520
+ return ((code >= codes.lowercaseA && code <= codes.lowercaseZ) ||
71521
+ (code >= codes.uppercaseA && code <= codes.uppercaseZ) ||
71522
+ (code >= codes.digit0 && code <= codes.digit9) ||
71523
+ code === codes.dash ||
71524
+ code === codes.underscore);
71525
+ }
71526
+ const gemojiConstruct = {
71527
+ name: 'gemoji',
71528
+ tokenize,
71529
+ };
71530
+ function tokenize(effects, ok, nok) {
71531
+ let hasName = false;
71532
+ // Entry point — expect opening `:`
71533
+ const start = (code) => {
71534
+ if (code !== codes.colon)
71535
+ return nok(code);
71536
+ effects.enter('gemoji');
71537
+ effects.enter('gemojiMarker');
71538
+ effects.consume(code); // :
71539
+ effects.exit('gemojiMarker');
71540
+ effects.enter('gemojiName');
71541
+ return nameStart;
71542
+ };
71543
+ // First char after `:`, branch on `+` for :+1:, otherwise start normal name
71544
+ const nameStart = (code) => {
71545
+ if (code === codes.plusSign) {
71546
+ effects.consume(code); // +
71547
+ return plusOne;
71548
+ }
71549
+ if (isNameChar(code)) {
71550
+ hasName = true;
71551
+ effects.consume(code);
71552
+ return name;
71553
+ }
71554
+ // Not a valid shortcode start (e.g. `::`, `: `, `:<`)
71555
+ return nok(code);
71556
+ };
71557
+ // After `+`, only `1` is valid (for :+1:), anything else rejects
71558
+ // this is a special case for :+1: 👍 since + isnt a normal name character
71559
+ const plusOne = (code) => {
71560
+ if (code === codes.digit1) {
71561
+ hasName = true;
71562
+ effects.consume(code); // 1
71563
+ return nameEnd;
71564
+ }
71565
+ return nok(code);
71566
+ };
71567
+ // Consume name characters until we hit closing `:` or an invalid char
71568
+ const name = (code) => {
71569
+ if (code === codes.colon) {
71570
+ if (!hasName)
71571
+ return nok(code);
71572
+ return nameEnd(code);
71573
+ }
71574
+ if (isNameChar(code)) {
71575
+ effects.consume(code);
71576
+ return name;
71577
+ }
71578
+ // Invalid character in name (space, newline, special char) — reject
71579
+ return nok(code);
71580
+ };
71581
+ // Expect closing `:`
71582
+ const nameEnd = (code) => {
71583
+ if (code !== codes.colon)
71584
+ return nok(code);
71585
+ effects.exit('gemojiName');
71586
+ effects.enter('gemojiMarker');
71587
+ effects.consume(code); // :
71588
+ effects.exit('gemojiMarker');
71589
+ effects.exit('gemoji');
71590
+ return ok;
71591
+ };
71592
+ return start;
71593
+ }
71594
+ function syntax_gemoji() {
71595
+ return {
71596
+ text: { [codes.colon]: gemojiConstruct },
71597
+ };
71598
+ }
71599
+
71600
+ ;// ./lib/micromark/gemoji/index.ts
71601
+ /**
71602
+ * Micromark extension for :emoji: inline syntax.
71603
+ */
71604
+
71605
+
71298
71606
  ;// ./processor/transform/mdxish/normalize-malformed-md-syntax.ts
71299
71607
 
71300
71608
  // Marker patterns for multi-node emphasis detection
@@ -71651,6 +71959,7 @@ const normalizeEmphasisAST = () => (tree) => {
71651
71959
 
71652
71960
 
71653
71961
 
71962
+
71654
71963
  const isTableCell = (node) => isMDXElement(node) && ['th', 'td'].includes(node.name);
71655
71964
  const tableTypes = {
71656
71965
  tr: 'tableRow',
@@ -71658,10 +71967,12 @@ const tableTypes = {
71658
71967
  td: 'tableCell',
71659
71968
  };
71660
71969
  const tableNodeProcessor = unified()
71970
+ .data('micromarkExtensions', [syntax_gemoji()])
71971
+ .data('fromMarkdownExtensions', [gemojiFromMarkdown()])
71661
71972
  .use(remarkParse)
71662
71973
  .use(remarkMdx)
71663
71974
  .use(normalize_malformed_md_syntax)
71664
- .use([[callouts, { isMdxish: true }], gemoji_, code_tabs])
71975
+ .use([[callouts, { isMdxish: true }], code_tabs])
71665
71976
  .use(remarkGfm);
71666
71977
  /**
71667
71978
  * Check if children are only text nodes that might contain markdown
@@ -72534,7 +72845,6 @@ const mdxishTransformers = [
72534
72845
  [callouts, { isMdxish: true }],
72535
72846
  code_tabs,
72536
72847
  transform_images,
72537
- gemoji_,
72538
72848
  ];
72539
72849
  /* harmony default export */ const transform = (Object.values(defaultTransforms));
72540
72850
 
@@ -92316,10 +92626,6 @@ const embed_embed = (node) => {
92316
92626
  };
92317
92627
  /* harmony default export */ const compile_embed = (embed_embed);
92318
92628
 
92319
- ;// ./processor/compile/gemoji.ts
92320
- const gemoji_gemoji = (node) => `:${node.name}:`;
92321
- /* harmony default export */ const compile_gemoji = (gemoji_gemoji);
92322
-
92323
92629
  ;// ./processor/compile/html-block.ts
92324
92630
 
92325
92631
  const htmlBlock = (node) => {
@@ -94302,6 +94608,86 @@ const mdxComponentHandlers = {
94302
94608
  [NodeTypes.htmlBlock]: htmlBlockHandler,
94303
94609
  };
94304
94610
 
94611
+ ;// ./processor/transform/mdxish/close-self-closing-html-tags.ts
94612
+
94613
+ /**
94614
+ * HTML void elements that are legitimately self-closing per the HTML spec.
94615
+ * These should NOT be transformed.
94616
+ *
94617
+ * @see https://html.spec.whatwg.org/multipage/syntax.html#void-elements
94618
+ */
94619
+ const HTML_VOID_ELEMENTS = new Set([
94620
+ 'area',
94621
+ 'base',
94622
+ 'br',
94623
+ 'col',
94624
+ 'embed',
94625
+ 'hr',
94626
+ 'img',
94627
+ 'input',
94628
+ 'link',
94629
+ 'meta',
94630
+ 'param',
94631
+ 'source',
94632
+ 'track',
94633
+ 'wbr',
94634
+ ]);
94635
+ /**
94636
+ * Matches self-closing HTML tags: `<tagname/>` or `<tagname attr="val" />`
94637
+ *
94638
+ * Captures:
94639
+ * 1 - tag name (lowercase letters, digits, hyphens)
94640
+ * 2 - attributes (everything between tag name and `/>`)
94641
+ *
94642
+ * The attribute portion skips over quoted strings (`"..."` and `'...'`) so that
94643
+ * a `/>` inside an attribute value (e.g. `title="use /> here"`) does not cause
94644
+ * a premature match.
94645
+ *
94646
+ * Only matches lowercase tag names to avoid interfering with PascalCase
94647
+ * JSX custom components (e.g. `<MyComponent />`), which are handled
94648
+ * separately by mdxish-component-blocks.
94649
+ */
94650
+ const SELF_CLOSING_TAG_RE = /<([a-z][a-z0-9-]*)((?:\s+(?:[^>"']*(?:"[^"]*"|'[^']*'))*[^>"']*)?)?\s*\/>/g;
94651
+ /**
94652
+ * String-level preprocessor that converts self-closing non-void HTML tags
94653
+ * into explicitly closed tags.
94654
+ *
94655
+ * Problem: `rehype-raw` (via parse5) follows the HTML spec where the `/` in
94656
+ * `<i />` is ignored for non-void elements. This causes `<i />` to be parsed
94657
+ * as an opening `<i>` tag, which then wraps all subsequent content.
94658
+ *
94659
+ * Solution: Transform `<i />` → `<i></i>` before parsing, so rehype-raw
94660
+ * sees a properly closed element.
94661
+ *
94662
+ * This preprocessor:
94663
+ * - Skips void elements (`<br />`, `<hr />`, `<img />`, etc.)
94664
+ * - Skips PascalCase tags (custom components handled elsewhere)
94665
+ * - Protects code blocks from transformation
94666
+ *
94667
+ * @example
94668
+ * closeSelfClosingHtmlTags('<i/> text') // '<i></i> text'
94669
+ * closeSelfClosingHtmlTags('<br />') // '<br />' (void, untouched)
94670
+ * closeSelfClosingHtmlTags('<MyComp />') // '<MyComp />' (PascalCase, untouched)
94671
+ * closeSelfClosingHtmlTags('<i class="icon" />') // '<i class="icon"></i>'
94672
+ */
94673
+ function closeSelfClosingHtmlTags(content) {
94674
+ const { protectedContent, protectedCode } = protectCodeBlocks(content);
94675
+ const result = protectedContent.replace(SELF_CLOSING_TAG_RE, (match, tagName, attrs) => {
94676
+ // Skip void elements (legitimately self-closing)
94677
+ if (HTML_VOID_ELEMENTS.has(tagName)) {
94678
+ return match;
94679
+ }
94680
+ // Skip tags with hyphens — these are custom elements (web components)
94681
+ // and should not be rewritten (e.g. <my-component />)
94682
+ if (tagName.includes('-')) {
94683
+ return match;
94684
+ }
94685
+ const attributes = attrs?.trim() ? ` ${attrs.trim()}` : '';
94686
+ return `<${tagName}${attributes}></${tagName}>`;
94687
+ });
94688
+ return restoreCodeBlocks(result, protectedCode);
94689
+ }
94690
+
94305
94691
  ;// ./processor/transform/mdxish/evaluate-expressions.ts
94306
94692
 
94307
94693
 
@@ -94591,166 +94977,6 @@ function legacyVariableFromMarkdown() {
94591
94977
  };
94592
94978
  }
94593
94979
 
94594
- ;// ./node_modules/micromark-util-symbol/lib/codes.js
94595
- /**
94596
- * Character codes.
94597
- *
94598
- * This module is compiled away!
94599
- *
94600
- * micromark works based on character codes.
94601
- * This module contains constants for the ASCII block and the replacement
94602
- * character.
94603
- * A couple of them are handled in a special way, such as the line endings
94604
- * (CR, LF, and CR+LF, commonly known as end-of-line: EOLs), the tab (horizontal
94605
- * tab) and its expansion based on what column it’s at (virtual space),
94606
- * and the end-of-file (eof) character.
94607
- * As values are preprocessed before handling them, the actual characters LF,
94608
- * CR, HT, and NUL (which is present as the replacement character), are
94609
- * guaranteed to not exist.
94610
- *
94611
- * Unicode basic latin block.
94612
- */
94613
- const codes = /** @type {const} */ ({
94614
- carriageReturn: -5,
94615
- lineFeed: -4,
94616
- carriageReturnLineFeed: -3,
94617
- horizontalTab: -2,
94618
- virtualSpace: -1,
94619
- eof: null,
94620
- nul: 0,
94621
- soh: 1,
94622
- stx: 2,
94623
- etx: 3,
94624
- eot: 4,
94625
- enq: 5,
94626
- ack: 6,
94627
- bel: 7,
94628
- bs: 8,
94629
- ht: 9, // `\t`
94630
- lf: 10, // `\n`
94631
- vt: 11, // `\v`
94632
- ff: 12, // `\f`
94633
- cr: 13, // `\r`
94634
- so: 14,
94635
- si: 15,
94636
- dle: 16,
94637
- dc1: 17,
94638
- dc2: 18,
94639
- dc3: 19,
94640
- dc4: 20,
94641
- nak: 21,
94642
- syn: 22,
94643
- etb: 23,
94644
- can: 24,
94645
- em: 25,
94646
- sub: 26,
94647
- esc: 27,
94648
- fs: 28,
94649
- gs: 29,
94650
- rs: 30,
94651
- us: 31,
94652
- space: 32,
94653
- exclamationMark: 33, // `!`
94654
- quotationMark: 34, // `"`
94655
- numberSign: 35, // `#`
94656
- dollarSign: 36, // `$`
94657
- percentSign: 37, // `%`
94658
- ampersand: 38, // `&`
94659
- apostrophe: 39, // `'`
94660
- leftParenthesis: 40, // `(`
94661
- rightParenthesis: 41, // `)`
94662
- asterisk: 42, // `*`
94663
- plusSign: 43, // `+`
94664
- comma: 44, // `,`
94665
- dash: 45, // `-`
94666
- dot: 46, // `.`
94667
- slash: 47, // `/`
94668
- digit0: 48, // `0`
94669
- digit1: 49, // `1`
94670
- digit2: 50, // `2`
94671
- digit3: 51, // `3`
94672
- digit4: 52, // `4`
94673
- digit5: 53, // `5`
94674
- digit6: 54, // `6`
94675
- digit7: 55, // `7`
94676
- digit8: 56, // `8`
94677
- digit9: 57, // `9`
94678
- colon: 58, // `:`
94679
- semicolon: 59, // `;`
94680
- lessThan: 60, // `<`
94681
- equalsTo: 61, // `=`
94682
- greaterThan: 62, // `>`
94683
- questionMark: 63, // `?`
94684
- atSign: 64, // `@`
94685
- uppercaseA: 65, // `A`
94686
- uppercaseB: 66, // `B`
94687
- uppercaseC: 67, // `C`
94688
- uppercaseD: 68, // `D`
94689
- uppercaseE: 69, // `E`
94690
- uppercaseF: 70, // `F`
94691
- uppercaseG: 71, // `G`
94692
- uppercaseH: 72, // `H`
94693
- uppercaseI: 73, // `I`
94694
- uppercaseJ: 74, // `J`
94695
- uppercaseK: 75, // `K`
94696
- uppercaseL: 76, // `L`
94697
- uppercaseM: 77, // `M`
94698
- uppercaseN: 78, // `N`
94699
- uppercaseO: 79, // `O`
94700
- uppercaseP: 80, // `P`
94701
- uppercaseQ: 81, // `Q`
94702
- uppercaseR: 82, // `R`
94703
- uppercaseS: 83, // `S`
94704
- uppercaseT: 84, // `T`
94705
- uppercaseU: 85, // `U`
94706
- uppercaseV: 86, // `V`
94707
- uppercaseW: 87, // `W`
94708
- uppercaseX: 88, // `X`
94709
- uppercaseY: 89, // `Y`
94710
- uppercaseZ: 90, // `Z`
94711
- leftSquareBracket: 91, // `[`
94712
- backslash: 92, // `\`
94713
- rightSquareBracket: 93, // `]`
94714
- caret: 94, // `^`
94715
- underscore: 95, // `_`
94716
- graveAccent: 96, // `` ` ``
94717
- lowercaseA: 97, // `a`
94718
- lowercaseB: 98, // `b`
94719
- lowercaseC: 99, // `c`
94720
- lowercaseD: 100, // `d`
94721
- lowercaseE: 101, // `e`
94722
- lowercaseF: 102, // `f`
94723
- lowercaseG: 103, // `g`
94724
- lowercaseH: 104, // `h`
94725
- lowercaseI: 105, // `i`
94726
- lowercaseJ: 106, // `j`
94727
- lowercaseK: 107, // `k`
94728
- lowercaseL: 108, // `l`
94729
- lowercaseM: 109, // `m`
94730
- lowercaseN: 110, // `n`
94731
- lowercaseO: 111, // `o`
94732
- lowercaseP: 112, // `p`
94733
- lowercaseQ: 113, // `q`
94734
- lowercaseR: 114, // `r`
94735
- lowercaseS: 115, // `s`
94736
- lowercaseT: 116, // `t`
94737
- lowercaseU: 117, // `u`
94738
- lowercaseV: 118, // `v`
94739
- lowercaseW: 119, // `w`
94740
- lowercaseX: 120, // `x`
94741
- lowercaseY: 121, // `y`
94742
- lowercaseZ: 122, // `z`
94743
- leftCurlyBrace: 123, // `{`
94744
- verticalBar: 124, // `|`
94745
- rightCurlyBrace: 125, // `}`
94746
- tilde: 126, // `~`
94747
- del: 127,
94748
- // Unicode Specials block.
94749
- byteOrderMarker: 65_279,
94750
- // Unicode Specials block.
94751
- replacementCharacter: 65_533 // `�`
94752
- })
94753
-
94754
94980
  ;// ./lib/micromark/legacy-variable/syntax.ts
94755
94981
 
94756
94982
 
@@ -94762,9 +94988,9 @@ function isAllowedValueChar(code) {
94762
94988
  }
94763
94989
  const legacyVariableConstruct = {
94764
94990
  name: 'legacyVariable',
94765
- tokenize,
94991
+ tokenize: syntax_tokenize,
94766
94992
  };
94767
- function tokenize(effects, ok, nok) {
94993
+ function syntax_tokenize(effects, ok, nok) {
94768
94994
  let hasValue = false;
94769
94995
  const start = (code) => {
94770
94996
  if (code !== codes.lessThan)
@@ -95903,6 +96129,8 @@ const EMPTY_CODE_PLACEHOLDER = {
95903
96129
 
95904
96130
 
95905
96131
 
96132
+
96133
+
95906
96134
 
95907
96135
 
95908
96136
 
@@ -95945,8 +96173,8 @@ const preprocessBody = (text) => {
95945
96173
  };
95946
96174
  /** Markdown parser */
95947
96175
  const contentParser = unified()
95948
- .data('micromarkExtensions', [legacyVariable(), looseHtmlEntity()])
95949
- .data('fromMarkdownExtensions', [legacyVariableFromMarkdown(), emptyTaskListItemFromMarkdown(), looseHtmlEntityFromMarkdown()])
96176
+ .data('micromarkExtensions', [syntax_gemoji(), legacyVariable(), looseHtmlEntity()])
96177
+ .data('fromMarkdownExtensions', [gemojiFromMarkdown(), legacyVariableFromMarkdown(), emptyTaskListItemFromMarkdown(), looseHtmlEntityFromMarkdown()])
95950
96178
  .use(remarkParse)
95951
96179
  .use(remarkBreaks)
95952
96180
  .use(remarkGfm)
@@ -95959,8 +96187,8 @@ const contentParser = unified()
95959
96187
  * such as `<ul><li>https://a</li>\n</ul>` due to subtokenizing recursion for URLs
95960
96188
  */
95961
96189
  const markdownToHtml = unified()
95962
- .data('micromarkExtensions', [gfmStrikethrough(), legacyVariable(), looseHtmlEntity()])
95963
- .data('fromMarkdownExtensions', [gfmStrikethroughFromMarkdown(), legacyVariableFromMarkdown(), emptyTaskListItemFromMarkdown(), looseHtmlEntityFromMarkdown()])
96190
+ .data('micromarkExtensions', [gfmStrikethrough(), syntax_gemoji(), legacyVariable(), looseHtmlEntity()])
96191
+ .data('fromMarkdownExtensions', [gfmStrikethroughFromMarkdown(), gemojiFromMarkdown(), legacyVariableFromMarkdown(), emptyTaskListItemFromMarkdown(), looseHtmlEntityFromMarkdown()])
95964
96192
  .use(remarkParse)
95965
96193
  .use(normalize_malformed_md_syntax)
95966
96194
  .use(remarkRehype)
@@ -96101,6 +96329,7 @@ const parseBlock = (text) => {
96101
96329
  */
96102
96330
  const apiHeaderTitleParser = unified()
96103
96331
  .data('micromarkExtensions', [
96332
+ syntax_gemoji(),
96104
96333
  legacyVariable(),
96105
96334
  looseHtmlEntity(),
96106
96335
  {
@@ -96114,7 +96343,7 @@ const apiHeaderTitleParser = unified()
96114
96343
  },
96115
96344
  },
96116
96345
  ])
96117
- .data('fromMarkdownExtensions', [legacyVariableFromMarkdown(), looseHtmlEntityFromMarkdown()])
96346
+ .data('fromMarkdownExtensions', [gemojiFromMarkdown(), legacyVariableFromMarkdown(), looseHtmlEntityFromMarkdown()])
96118
96347
  .use(remarkParse)
96119
96348
  .use(remarkGfm);
96120
96349
  const parseApiHeaderTitle = (text) => {
@@ -97228,6 +97457,179 @@ function mdxish_jsx_to_mdast_extractText(nodes) {
97228
97457
  })
97229
97458
  .join('');
97230
97459
  }
97460
+ const FIGURE_OPEN_REGEX = /^<figure(\s[^>]*)?>$/;
97461
+ const FIGURE_CLOSE_REGEX = /^\s*<\/figure>\s*$/;
97462
+ const FIGURE_COMPLETE_REGEX = /^<figure(\s[^>]*)?>[\s\S]*<\/figure>\s*$/;
97463
+ const FIGCAPTION_REGEX = /<figcaption>(.*?)<\/figcaption>/s;
97464
+ const FIGCAPTION_OPEN_REGEX = /^<figcaption>$/;
97465
+ const FIGCAPTION_CLOSE_REGEX = /^<\/figcaption>$/;
97466
+ /**
97467
+ * Extracts an image or image-block from a node. If the node itself is an image/image-block,
97468
+ * it is returned directly. If the node is a paragraph, its children are searched for one.
97469
+ * This is needed because standalone markdown images (`![](url)`) may be wrapped in a
97470
+ * paragraph node by the parser, or already transformed to image-block by imageTransformer.
97471
+ */
97472
+ function findImageInNode(node) {
97473
+ if (node.type === 'image' || node.type === NodeTypes.imageBlock)
97474
+ return node;
97475
+ if (node.type === 'paragraph') {
97476
+ return node.children.find(child => child.type === 'image' || child.type === NodeTypes.imageBlock);
97477
+ }
97478
+ return undefined;
97479
+ }
97480
+ /**
97481
+ * Parses a complete `<figure>` HTML string into image URL, alt text, and optional caption.
97482
+ * Returns undefined if the HTML doesn't contain a recognizable image.
97483
+ */
97484
+ function parseCompleteFigure(html) {
97485
+ const imageMatch = /!\[([^\]]*)\]\(([^)]+)\)/.exec(html);
97486
+ if (!imageMatch)
97487
+ return undefined;
97488
+ const captionMatch = FIGCAPTION_REGEX.exec(html);
97489
+ return {
97490
+ alt: imageMatch[1],
97491
+ caption: captionMatch?.[1],
97492
+ url: imageMatch[2],
97493
+ };
97494
+ }
97495
+ /**
97496
+ * Builds a FigureNode containing an image and optional figcaption from parsed figure data.
97497
+ */
97498
+ function buildFigureNode(imageNode, captionText, position) {
97499
+ const figureChildren = [imageNode];
97500
+ if (captionText) {
97501
+ figureChildren.push({
97502
+ children: [{ type: 'text', value: captionText }],
97503
+ data: { hName: 'figcaption' },
97504
+ type: 'figcaption',
97505
+ });
97506
+ }
97507
+ return {
97508
+ children: figureChildren,
97509
+ data: { hName: 'figure' },
97510
+ position,
97511
+ type: 'figure',
97512
+ };
97513
+ }
97514
+ /**
97515
+ * Scans siblings starting at `startIndex` within a parent's children looking for the
97516
+ * figcaption text and </figure> closing tag. Handles three fragmentation patterns:
97517
+ *
97518
+ * 1. Combined: `<figcaption>Hello</figcaption>\n</figure>` in one html node
97519
+ * 2. Separate: `<figcaption>Hello</figcaption>` then `</figure>` as sibling html nodes
97520
+ * 3. Split (table cells): `<figcaption>` + text(Hello) + `</figcaption>` + `</figure>` as siblings
97521
+ */
97522
+ function scanForFigcaptionAndClose(children, startIndex) {
97523
+ let captionText;
97524
+ let endIndex = startIndex - 1;
97525
+ let foundClose = false;
97526
+ for (let j = startIndex; j < children.length; j += 1) {
97527
+ const sibling = children[j];
97528
+ const htmlValue = sibling.type === 'html' ? sibling.value : undefined;
97529
+ if (htmlValue === undefined && sibling.type !== 'text')
97530
+ break;
97531
+ // Standalone </figure>
97532
+ if (htmlValue && FIGURE_CLOSE_REGEX.test(htmlValue)) {
97533
+ endIndex = j;
97534
+ foundClose = true;
97535
+ break;
97536
+ }
97537
+ // Combined <figcaption>...</figcaption> in one node (possibly with </figure>)
97538
+ if (htmlValue) {
97539
+ const figcaptionMatch = FIGCAPTION_REGEX.exec(htmlValue);
97540
+ if (figcaptionMatch) {
97541
+ captionText = figcaptionMatch[1];
97542
+ if (FIGURE_CLOSE_REGEX.test(htmlValue.replace(FIGCAPTION_REGEX, ''))) {
97543
+ endIndex = j;
97544
+ foundClose = true;
97545
+ break;
97546
+ }
97547
+ const nextSibling = children[j + 1];
97548
+ if (nextSibling?.type === 'html' && FIGURE_CLOSE_REGEX.test(nextSibling.value)) {
97549
+ endIndex = j + 1;
97550
+ foundClose = true;
97551
+ break;
97552
+ }
97553
+ }
97554
+ }
97555
+ // Split figcaption: <figcaption> + text + </figcaption> as separate nodes (table cells)
97556
+ if (htmlValue && FIGCAPTION_OPEN_REGEX.test(htmlValue)) {
97557
+ const textNode = children[j + 1];
97558
+ const closeCaption = children[j + 2];
97559
+ if (textNode?.type === 'text' &&
97560
+ closeCaption?.type === 'html' &&
97561
+ FIGCAPTION_CLOSE_REGEX.test(closeCaption.value)) {
97562
+ captionText = textNode.value;
97563
+ const closeFigure = children[j + 3];
97564
+ if (closeFigure?.type === 'html' && FIGURE_CLOSE_REGEX.test(closeFigure.value)) {
97565
+ endIndex = j + 3;
97566
+ foundClose = true;
97567
+ break;
97568
+ }
97569
+ }
97570
+ }
97571
+ }
97572
+ return { captionText, endIndex, foundClose };
97573
+ }
97574
+ /**
97575
+ * Reconstruct fragmented or complete HTML <figure> elements into figure MDAST nodes.
97576
+ *
97577
+ * Handles three html-based cases (the JSX case is handled by transformFigure in COMPONENT_MAP):
97578
+ * 1. Complete: A single html node containing the full `<figure>...<figcaption>...</figure>` block
97579
+ * (e.g. inside callouts where blockquote parsing keeps it together).
97580
+ * 2. Fragmented siblings: `terminateHtmlFlowBlocks` splits `<figure>` into separate sibling
97581
+ * nodes (open tag, image, figcaption, close tag).
97582
+ * 3. Split tags (GFM table cells): Each tag becomes its own html node with text nodes between them.
97583
+ *
97584
+ * Runs on all parent nodes so it works inside callouts, tables, and at root level.
97585
+ */
97586
+ function reassembleHtmlFigures(tree) {
97587
+ // Case 1: Handle complete <figure> blocks in a single html node (e.g. inside callouts)
97588
+ visit(tree, 'html', (node, index, parent) => {
97589
+ if (!parent || index === undefined)
97590
+ return;
97591
+ if (!FIGURE_COMPLETE_REGEX.test(node.value.trim()))
97592
+ return;
97593
+ const parsed = parseCompleteFigure(node.value);
97594
+ if (!parsed)
97595
+ return;
97596
+ const imageNode = {
97597
+ type: 'image',
97598
+ url: parsed.url,
97599
+ alt: parsed.alt,
97600
+ };
97601
+ const figureNode = buildFigureNode(imageNode, parsed.caption, node.position);
97602
+ parent.children.splice(index, 1, figureNode);
97603
+ });
97604
+ // Case 2 & 3: Handle fragmented <figure> blocks split across sibling nodes
97605
+ const processChildren = (parent) => {
97606
+ const children = parent.children;
97607
+ let i = 0;
97608
+ while (i < children.length) {
97609
+ const node = children[i];
97610
+ const nextNode = children[i + 1];
97611
+ const imageNode = nextNode ? findImageInNode(nextNode) : undefined;
97612
+ if (node.type === 'html' &&
97613
+ FIGURE_OPEN_REGEX.test(node.value.trim()) &&
97614
+ imageNode) {
97615
+ const { captionText, endIndex, foundClose } = scanForFigcaptionAndClose(children, i + 2);
97616
+ if (foundClose) {
97617
+ const figureNode = buildFigureNode(imageNode, captionText, node.position);
97618
+ parent.children.splice(i, endIndex - i + 1, figureNode);
97619
+ }
97620
+ }
97621
+ i += 1;
97622
+ }
97623
+ };
97624
+ // Process all parent nodes (root, callouts, blockquotes, table cells, list items)
97625
+ visit(tree, (node) => {
97626
+ if ('children' in node)
97627
+ processChildren(node);
97628
+ });
97629
+ }
97630
+ /**
97631
+ * Transforms an inline `<Anchor>` JSX element into a readme-anchor MDAST node.
97632
+ */
97231
97633
  const transformAnchor = (jsx) => {
97232
97634
  const attrs = getAttrs(jsx);
97233
97635
  const { href = '', label, target, title } = attrs;
@@ -97246,6 +97648,10 @@ const transformAnchor = (jsx) => {
97246
97648
  position: jsx.position,
97247
97649
  };
97248
97650
  };
97651
+ /**
97652
+ * Transforms an `<Image />` JSX element into an image-block MDAST node.
97653
+ * Normalizes attributes (align, border, width→sizing) and parses caption markdown into children.
97654
+ */
97249
97655
  const transformImage = (jsx) => {
97250
97656
  const attrs = getAttrs(jsx);
97251
97657
  const { align, alt = '', border, caption, className, height, lazy, src = '', title = '', width } = attrs;
@@ -97285,6 +97691,9 @@ const transformImage = (jsx) => {
97285
97691
  position: jsx.position,
97286
97692
  };
97287
97693
  };
97694
+ /**
97695
+ * Transforms a `<Callout>` JSX element into an rdme-callout MDAST node.
97696
+ */
97288
97697
  const transformCallout = (jsx) => {
97289
97698
  const attrs = getAttrs(jsx);
97290
97699
  const { empty = false, icon = '', theme = '' } = attrs;
@@ -97302,6 +97711,9 @@ const transformCallout = (jsx) => {
97302
97711
  position: jsx.position,
97303
97712
  };
97304
97713
  };
97714
+ /**
97715
+ * Transforms an `<Embed />` JSX element into an embed-block MDAST node.
97716
+ */
97305
97717
  const transformEmbed = (jsx) => {
97306
97718
  const attrs = getAttrs(jsx);
97307
97719
  const { favicon, height, href, html, iframe, image, providerName, providerUrl, provider, title = '', typeOfEmbed, url = '', width, } = attrs;
@@ -97330,6 +97742,9 @@ const transformEmbed = (jsx) => {
97330
97742
  position: jsx.position,
97331
97743
  };
97332
97744
  };
97745
+ /**
97746
+ * Transforms a `<Recipe />` JSX element into a recipe MDAST node.
97747
+ */
97333
97748
  const transformRecipe = (jsx) => {
97334
97749
  const attrs = getAttrs(jsx);
97335
97750
  const { backgroundColor = '', emoji = '', id = '', link = '', slug = '', title = '' } = attrs;
@@ -97466,21 +97881,44 @@ const transformTable = (jsx) => {
97466
97881
  children: rows,
97467
97882
  };
97468
97883
  };
97884
+ /**
97885
+ * Transforms a `<figure>` JSX element into a FigureNode.
97886
+ * Inside JSX tables with blank lines, the parser treats `<figure>` as an mdxJsxFlowElement
97887
+ * containing a paragraph with the image and a `<figcaption>` mdxJsxTextElement as children.
97888
+ */
97889
+ const transformFigure = (jsx) => {
97890
+ let imageNode;
97891
+ let captionText;
97892
+ visit(jsx, (child) => {
97893
+ if (!imageNode && (child.type === 'image' || child.type === NodeTypes.imageBlock)) {
97894
+ imageNode = child;
97895
+ }
97896
+ if (!captionText && child.type === 'mdxJsxTextElement' && child.name === 'figcaption') {
97897
+ captionText = mdxish_jsx_to_mdast_extractText(child.children);
97898
+ }
97899
+ });
97900
+ if (!imageNode)
97901
+ return null;
97902
+ return buildFigureNode(imageNode, captionText, jsx.position);
97903
+ };
97469
97904
  const COMPONENT_MAP = {
97470
97905
  Callout: transformCallout,
97471
97906
  Embed: transformEmbed,
97472
97907
  Image: transformImage,
97908
+ figure: transformFigure,
97473
97909
  Recipe: transformRecipe,
97474
97910
  Table: transformTable,
97475
97911
  };
97476
97912
  /**
97477
- * Transform mdxJsxFlowElement nodes and magic block nodes into proper MDAST node types.
97913
+ * Transform mdxJsxFlowElement nodes, magic block nodes, and HTML figure elements
97914
+ * into proper MDAST node types.
97478
97915
  *
97479
97916
  * This transformer runs after mdxishComponentBlocks and converts:
97480
- * - JSX component elements (Image, Callout, Embed, Recipe) into their corresponding MDAST types
97917
+ * - JSX component elements (Image, Callout, Embed, Recipe, figure) into their corresponding MDAST types
97481
97918
  * - Magic block image nodes (type: 'image') into image-block
97482
97919
  * - Magic block embed nodes (type: 'embed') into embed-block
97483
- * - Figure nodes (magic blocks with captions) into flat image-block with caption string
97920
+ * - Fragmented HTML <figure> blocks (from terminateHtmlFlowBlocks) back into figure nodes
97921
+ * - Figure nodes (from magic blocks, HTML, or JSX) into flat image-block with caption string
97484
97922
  * - Normalizes all image-block attrs (border, align, sizing, caption) to a consistent shape
97485
97923
  *
97486
97924
  * This is controlled by the `newEditorTypes` flag to maintain backwards compatibility.
@@ -97527,6 +97965,9 @@ const mdxishJsxToMdast = () => tree => {
97527
97965
  parent.children[index] = newNode;
97528
97966
  return SKIP;
97529
97967
  });
97968
+ // Reassembling fragmented HTML <figure> blocks into proper figure/figcaption nodes
97969
+ // this will then later be transformed into image-block nodes by imageTransformer
97970
+ reassembleHtmlFigures(tree);
97530
97971
  // Flatten figure nodes (magic blocks with captions) into image-block nodes
97531
97972
  const isFigure = (node) => node.type === 'figure';
97532
97973
  visit(tree, isFigure, (node, index, parent) => {
@@ -97779,6 +98220,7 @@ function restoreSnakeCase(placeholderName, mapping) {
97779
98220
  ;// ./processor/transform/mdxish/mdxish-tables-to-jsx.ts
97780
98221
 
97781
98222
 
98223
+ const SELF_CLOSING_JSX_REGEX = /^\s*<[A-Z][^>]*\/>\s*$/;
97782
98224
  const mdxish_tables_to_jsx_alignToStyle = (align) => {
97783
98225
  if (!align || align === 'left')
97784
98226
  return null;
@@ -97805,7 +98247,7 @@ const mdxishTablesToJsx = () => tree => {
97805
98247
  visit(tree, (node) => ['table', 'tableau'].includes(node.type), (table, index, parent) => {
97806
98248
  let hasFlowContent = false;
97807
98249
  visit(table, mdxish_tables_to_jsx_isTableCell, (cell) => {
97808
- if (cell.children.length === 0)
98250
+ if (hasFlowContent || cell.children.length === 0)
97809
98251
  return;
97810
98252
  const content = cell.children.length === 1 && cell.children[0].type === 'paragraph'
97811
98253
  ? cell.children[0].children[0]
@@ -97816,17 +98258,21 @@ const mdxishTablesToJsx = () => tree => {
97816
98258
  breakParent.children.splice(breakIndex, 1, { type: 'text', value: '\n' });
97817
98259
  });
97818
98260
  if (!(phrasing(content) || content.type === 'plain') && content.type !== 'escape') {
97819
- if (content.type === 'html')
97820
- return;
97821
- hasFlowContent = true;
97822
- return EXIT;
97823
- }
97824
- visit(cell, mdxish_tables_to_jsx_isLiteral, (node) => {
97825
- if (node.value.match(/\n/)) {
98261
+ // Plain HTML (e.g. <div>Hello</div>) is skipped here — it stays in GFM cells fine.
98262
+ // But self-closing JSX components (e.g. <Image src="..." caption="..." />) serialize
98263
+ // with newlines that break GFM cells, so they must trigger JSX <Table> serialization.
98264
+ const isPlainHtml = content.type === 'html' && !SELF_CLOSING_JSX_REGEX.test(content.value);
98265
+ if (!isPlainHtml) {
97826
98266
  hasFlowContent = true;
97827
- return EXIT;
97828
98267
  }
97829
- });
98268
+ }
98269
+ if (!hasFlowContent) {
98270
+ visit(cell, mdxish_tables_to_jsx_isLiteral, (node) => {
98271
+ if (node.value.match(/\n/)) {
98272
+ hasFlowContent = true;
98273
+ }
98274
+ });
98275
+ }
97830
98276
  });
97831
98277
  if (!hasFlowContent) {
97832
98278
  table.type = 'table';
@@ -100066,13 +100512,14 @@ function loadComponents() {
100066
100512
 
100067
100513
 
100068
100514
 
100515
+
100516
+
100069
100517
 
100070
100518
 
100071
100519
 
100072
100520
  const defaultTransformers = [
100073
100521
  [callouts, { isMdxish: true }],
100074
100522
  code_tabs,
100075
- gemoji_,
100076
100523
  transform_embeds,
100077
100524
  ];
100078
100525
  /**
@@ -100082,13 +100529,15 @@ const defaultTransformers = [
100082
100529
  * Runs a series of string-level transformations before micromark/remark parsing:
100083
100530
  * 1. Normalize malformed table separator syntax (e.g., `|: ---` → `| :---`)
100084
100531
  * 2. Terminate HTML flow blocks so subsequent content isn't swallowed
100085
- * 3. Evaluate JSX expressions in attributes (unless safeMode)
100086
- * 4. Replace snake_case component names with parser-safe placeholders
100532
+ * 3. Close invalid "self-closing" HTML tags (e.g., `<i />` → `<i></i>`)
100533
+ * 4. Evaluate JSX expressions in attributes (unless safeMode)
100534
+ * 5. Replace snake_case component names with parser-safe placeholders
100087
100535
  */
100088
100536
  function preprocessContent(content, opts) {
100089
100537
  const { safeMode, jsxContext, knownComponents } = opts;
100090
100538
  let result = normalizeTableSeparator(content);
100091
100539
  result = terminateHtmlFlowBlocks(result);
100540
+ result = closeSelfClosingHtmlTags(result);
100092
100541
  result = safeMode ? result : preprocessJSXExpressions(result, jsxContext);
100093
100542
  return processSnakeCaseComponent(result, { knownComponents });
100094
100543
  }
@@ -100118,12 +100567,13 @@ function mdxishAstProcessor(mdContent, opts = {}) {
100118
100567
  };
100119
100568
  const processor = unified()
100120
100569
  .data('micromarkExtensions', safeMode
100121
- ? [jsxTable(), magicBlock(), legacyVariable(), looseHtmlEntity()]
100122
- : [jsxTable(), magicBlock(), mdxExprTextOnly, legacyVariable(), looseHtmlEntity()])
100570
+ ? [jsxTable(), magicBlock(), syntax_gemoji(), legacyVariable(), looseHtmlEntity()]
100571
+ : [jsxTable(), magicBlock(), syntax_gemoji(), mdxExprTextOnly, legacyVariable(), looseHtmlEntity()])
100123
100572
  .data('fromMarkdownExtensions', safeMode
100124
100573
  ? [
100125
100574
  jsxTableFromMarkdown(),
100126
100575
  magicBlockFromMarkdown(),
100576
+ gemojiFromMarkdown(),
100127
100577
  legacyVariableFromMarkdown(),
100128
100578
  emptyTaskListItemFromMarkdown(),
100129
100579
  looseHtmlEntityFromMarkdown(),
@@ -100131,6 +100581,7 @@ function mdxishAstProcessor(mdContent, opts = {}) {
100131
100581
  : [
100132
100582
  jsxTableFromMarkdown(),
100133
100583
  magicBlockFromMarkdown(),
100584
+ gemojiFromMarkdown(),
100134
100585
  mdxExpressionFromMarkdown(),
100135
100586
  legacyVariableFromMarkdown(),
100136
100587
  emptyTaskListItemFromMarkdown(),