@readme/markdown 15.6.0 → 15.7.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.
@@ -8,5 +8,6 @@ declare const components: {
8
8
  Snake_case_component: string;
9
9
  Card: string;
10
10
  Grid: string;
11
+ ExpressionPropCodeBlock: string;
11
12
  };
12
13
  export default components;
@@ -1,3 +1,2 @@
1
1
  import type { Construct } from 'micromark-util-types';
2
- export declare const nonLazyContinuationStart: Construct;
3
2
  export declare const markupOnlyContinuation: Construct;
package/dist/main.js CHANGED
@@ -76043,31 +76043,11 @@ const HTML_VOID_ELEMENTS = new Set([
76043
76043
 
76044
76044
 
76045
76045
  /**
76046
- * Partial constructs the `mdxComponent` tokenizer runs via `effects.check` to
76047
- * decide whether the next line continues the block. They live here (not in
76048
- * `syntax.ts`) because they hold none of `createTokenize`'s closure state — each
76046
+ * Partial construct the `mdxComponent` tokenizer runs via `effects.check` to
76047
+ * decide whether the next line continues the block. It lives here (not in
76048
+ * `syntax.ts`) because it holds none of `createTokenize`'s closure state — it
76049
76049
  * is a self-contained, single-line lookahead.
76050
76050
  */
76051
- function continuation_checks_tokenizeNonLazyContinuationStart(effects, ok, nok) {
76052
- // eslint-disable-next-line @typescript-eslint/no-this-alias
76053
- const self = this;
76054
- return start;
76055
- function start(code) {
76056
- if (markdownLineEnding(code)) {
76057
- effects.enter(types.lineEnding);
76058
- effects.consume(code);
76059
- effects.exit(types.lineEnding);
76060
- return after;
76061
- }
76062
- return nok(code);
76063
- }
76064
- function after(code) {
76065
- if (self.parser.lazy[self.now().line]) {
76066
- return nok(code);
76067
- }
76068
- return ok(code);
76069
- }
76070
- }
76071
76051
  // A markup-only line opens with a tag (`<x`/`</x`) and ends (ignoring trailing
76072
76052
  // spaces) at a `>`. That distinguishes a structural continuation like
76073
76053
  // `<span>b</span></div>` from a paragraph like `<b>Note:</b> read *this*`.
@@ -76108,12 +76088,6 @@ function tokenizeMarkupOnlyContinuation(effects, ok, nok) {
76108
76088
  return scanToLineEnd;
76109
76089
  }
76110
76090
  }
76111
- // A line ending whose next line isn't a lazy paragraph continuation. Checked so a
76112
- // component body's blank/continuation lines aren't stolen by an interrupted paragraph.
76113
- const continuation_checks_nonLazyContinuationStart = {
76114
- tokenize: continuation_checks_tokenizeNonLazyContinuationStart,
76115
- partial: true,
76116
- };
76117
76091
  // Lookahead for `plainClaimLineStart`: is this line markup-only, or a paragraph
76118
76092
  // that merely starts with a tag? Run via `effects.check` so it never consumes.
76119
76093
  const markupOnlyContinuation = {
@@ -76529,14 +76503,7 @@ function syntax_createTokenize(mode) {
76529
76503
  }
76530
76504
  // Continuation for multi-line opening tags
76531
76505
  function openTagContinuationStart(code) {
76532
- return effects.check(continuation_checks_nonLazyContinuationStart, openTagContinuationNonLazy, continuationAfter)(code);
76533
- }
76534
- function openTagContinuationNonLazy(code) {
76535
- sawLineEnding = true;
76536
- effects.enter(types.lineEnding);
76537
- effects.consume(code);
76538
- effects.exit(types.lineEnding);
76539
- return openTagContinuationBefore;
76506
+ return continueOnNextLine(code, openTagContinuationBefore);
76540
76507
  }
76541
76508
  function openTagContinuationBefore(code) {
76542
76509
  if (code === null || markdownLineEnding(code)) {
@@ -76654,14 +76621,7 @@ function syntax_createTokenize(mode) {
76654
76621
  return inFencedCode;
76655
76622
  }
76656
76623
  function fencedCodeContinuationStart(code) {
76657
- return effects.check(continuation_checks_nonLazyContinuationStart, fencedCodeContinuationNonLazy, continuationAfter)(code);
76658
- }
76659
- function fencedCodeContinuationNonLazy(code) {
76660
- sawLineEnding = true;
76661
- effects.enter(types.lineEnding);
76662
- effects.consume(code);
76663
- effects.exit(types.lineEnding);
76664
- return fencedCodeContinuationBefore;
76624
+ return continueOnNextLine(code, fencedCodeContinuationBefore);
76665
76625
  }
76666
76626
  function fencedCodeContinuationBefore(code) {
76667
76627
  if (code === null || markdownLineEnding(code)) {
@@ -76878,14 +76838,7 @@ function syntax_createTokenize(mode) {
76878
76838
  }
76879
76839
  // ── Body continuation (line endings) ───────────────────────────────────
76880
76840
  function bodyContinuationStart(code) {
76881
- return effects.check(continuation_checks_nonLazyContinuationStart, bodyContinuationNonLazy, continuationAfter)(code);
76882
- }
76883
- function bodyContinuationNonLazy(code) {
76884
- sawLineEnding = true;
76885
- effects.enter(types.lineEnding);
76886
- effects.consume(code);
76887
- effects.exit(types.lineEnding);
76888
- return bodyContinuationBefore;
76841
+ return continueOnNextLine(code, bodyContinuationBefore);
76889
76842
  }
76890
76843
  function bodyContinuationBefore(code) {
76891
76844
  if (code === null || markdownLineEnding(code)) {
@@ -76954,13 +76907,18 @@ function syntax_createTokenize(mode) {
76954
76907
  pendingBlankLine = false;
76955
76908
  return bodyLineStart(code);
76956
76909
  }
76957
- // ── Shared lazy continuation failure ───────────────────────────────────
76958
- function continuationAfter(code) {
76959
- if (code === null) {
76910
+ // ── Shared line-ending continuation ────────────────────────────────────
76911
+ // Consumes one line ending and resumes at `nextLine`. Lazy lines (under-indented
76912
+ // under a list item or blockquote) continue too: a claim only ends at its closing
76913
+ // tag, and an unclosed one fails whole at EOF instead of leaving a truncated opener (CX-3940).
76914
+ function continueOnNextLine(code, nextLine) {
76915
+ if (!markdownLineEnding(code))
76960
76916
  return nok(code);
76961
- }
76962
- effects.exit('mdxComponent');
76963
- return ok(code);
76917
+ sawLineEnding = true;
76918
+ effects.enter(types.lineEnding);
76919
+ effects.consume(code);
76920
+ effects.exit(types.lineEnding);
76921
+ return nextLine;
76964
76922
  }
76965
76923
  };
76966
76924
  }
@@ -81088,6 +81046,8 @@ const processTableNode = (node, index, parent, documentPosition) => {
81088
81046
  type: 'table',
81089
81047
  position,
81090
81048
  children,
81049
+ // Remember the author's spelling so the serializer can write `<table>` back instead of `<Table>`
81050
+ ...(node.name === 'table' && { data: { lowercaseTable: true } }),
81091
81051
  };
81092
81052
  parent.children[index] = mdNode;
81093
81053
  };
@@ -96690,7 +96650,7 @@ const rehypeToc = ({ components = {} }) => {
96690
96650
  });
96691
96651
  };
96692
96652
  };
96693
- const MAX_DEPTH = 2;
96653
+ const MAX_DEPTH = 3;
96694
96654
  /**
96695
96655
  * Get the depth of a heading element based on its tag name.
96696
96656
  *
@@ -104798,7 +104758,7 @@ const parseMdChildren = (value, safeMode) => {
104798
104758
  // Promote nested wrappers bottom-up so an outer wrapper sees markdown buried in a
104799
104759
  // child claimed whole (e.g. `<li>` in `<ol>`) before its containsMarkdownConstruct check (RM-17560).
104800
104760
  // eslint-disable-next-line @typescript-eslint/no-use-before-define -- mutually recursive; hoisted decl, safe at runtime
104801
- promoteComponentBlocks(parsed, safeMode, null);
104761
+ promoteComponentBlocks(parsed, safeMode, reparseSource);
104802
104762
  const children = parsed.children || [];
104803
104763
  // These children root a new coordinate space: their offsets index into `reparseSource`.
104804
104764
  stampReparseSource(children, reparseSource);
@@ -104817,23 +104777,26 @@ const parseSibling = (parent, index, sibling, safeMode, promoted) => {
104817
104777
  }
104818
104778
  };
104819
104779
  // Ends the position at `consumedLength` so the component doesn't claim trailing
104820
- // content the tokenizer swallowed into the same html node.
104821
- const positionEndingAtConsumed = (nodePosition, value, consumedLength) => {
104780
+ // content the tokenizer swallowed into the same html node. Measured against the source
104781
+ // when available: each value line is its source line minus the container prefix
104782
+ // (list indent, `> `) micromark stripped, so those prefixes are counted back in.
104783
+ const positionEndingAtConsumed = (nodePosition, value, consumedLength, source) => {
104822
104784
  if (!nodePosition?.start)
104823
104785
  return nodePosition;
104824
- return { start: nodePosition.start, end: pointAfter(nodePosition.start, value.slice(0, consumedLength)) };
104825
- };
104826
- // Like `positionEndingAtConsumed`, but measures against the original source so
104827
- // blockquote/list prefixes stripped from the html node's value are counted.
104828
- const positionEndingAtClosingTagInSource = (nodePosition, closingTag, source) => {
104829
- if (!nodePosition?.start || !nodePosition.end)
104830
- return nodePosition;
104831
- const nodeSource = source.slice(nodePosition.start.offset, nodePosition.end.offset);
104832
- const closingTagOffset = nodeSource.lastIndexOf(closingTag);
104833
- if (closingTagOffset === -1)
104834
- return nodePosition;
104835
- const consumed = nodeSource.slice(0, closingTagOffset + closingTag.length);
104836
- return { start: nodePosition.start, end: pointAfter(nodePosition.start, consumed) };
104786
+ const consumedValue = value.slice(0, consumedLength);
104787
+ const sourceLines = source?.slice(nodePosition.start.offset, nodePosition.end?.offset).split('\n');
104788
+ const valueLines = value.split('\n');
104789
+ if (!sourceLines || sourceLines.length !== valueLines.length) {
104790
+ return { start: nodePosition.start, end: pointAfter(nodePosition.start, consumedValue) };
104791
+ }
104792
+ const consumedLines = consumedValue.split('\n');
104793
+ const lastLineIndex = consumedLines.length - 1;
104794
+ const prefixWidth = sourceLines[lastLineIndex].length - valueLines[lastLineIndex].length;
104795
+ const consumedSource = [
104796
+ ...sourceLines.slice(0, lastLineIndex),
104797
+ sourceLines[lastLineIndex].slice(0, prefixWidth + consumedLines[lastLineIndex].length),
104798
+ ].join('\n');
104799
+ return { start: nodePosition.start, end: pointAfter(nodePosition.start, consumedSource) };
104837
104800
  };
104838
104801
  const createComponentNode = ({ tag, attributes, children, startPosition, endPosition, }) => ({
104839
104802
  type: 'mdxJsxFlowElement',
@@ -104940,16 +104903,18 @@ function promoteComponentBlocks(tree, safeMode, source) {
104940
104903
  const closingTagStr = `</${tag}>`;
104941
104904
  // Case 1: Self-closing tag
104942
104905
  if (selfClosing) {
104906
+ const remainingContent = contentAfterTag.trim();
104943
104907
  const componentNode = createComponentNode({
104944
104908
  tag,
104945
104909
  attributes,
104946
104910
  children: [],
104947
104911
  startPosition: node.position,
104948
- // End at the self-closing tag, not at any trailing content.
104949
- endPosition: positionEndingAtConsumed(node.position, value, leadingWhitespace + openingTagEnd),
104912
+ // Without trailing content the whole node position is correct; with it, end at the tag.
104913
+ endPosition: remainingContent
104914
+ ? positionEndingAtConsumed(node.position, value, leadingWhitespace + openingTagEnd, source)
104915
+ : node.position,
104950
104916
  });
104951
104917
  substituteNodeWithMdxNode(parent, index, componentNode);
104952
- const remainingContent = contentAfterTag.trim();
104953
104918
  if (remainingContent) {
104954
104919
  parseSibling(parent, index, remainingContent, safeMode, promoted);
104955
104920
  }
@@ -104988,14 +104953,10 @@ function promoteComponentBlocks(tree, safeMode, source) {
104988
104953
  stampReparseSource(parsedChildren, soleParagraph.data.reparseSource);
104989
104954
  unwrappedSoleParagraph = true;
104990
104955
  }
104991
- // Without trailing content the whole node position is correct. With it, end
104992
- // precisely at the closing tag — preferring source offsets when available (the
104993
- // node's value strips blockquote/list prefixes), else the consumed span.
104956
+ // Without trailing content the whole node position is correct; with it, end at the closing tag.
104994
104957
  let endPosition = node.position;
104995
104958
  if (contentAfterClose) {
104996
- endPosition = source
104997
- ? positionEndingAtClosingTagInSource(node.position, closingTagStr, source)
104998
- : positionEndingAtConsumed(node.position, value, leadingWhitespace + openingTagEnd + closingTagIndex + closingTagStr.length);
104959
+ endPosition = positionEndingAtConsumed(node.position, value, leadingWhitespace + openingTagEnd + closingTagIndex + closingTagStr.length, source);
104999
104960
  }
105000
104961
  const componentNode = createComponentNode({
105001
104962
  tag,
@@ -107666,13 +107627,22 @@ const mdxishTablesToJsx = () => tree => {
107666
107627
  gfmCells.push([cell, normalized]);
107667
107628
  return undefined;
107668
107629
  });
107669
- if (!requiresJsxTable) {
107630
+ const stayLowercase = table.data?.lowercaseTable === true;
107631
+ // We transform to GFM tables if:
107632
+ // 1. If it doesn't contain complex elements that the syntax can't represent
107633
+ // 2. The original table is not lowercase HTML <table>, because we want to
107634
+ // preserve original tables as much as possible
107635
+ if (!requiresJsxTable && !stayLowercase) {
107670
107636
  gfmCells.forEach(([cell, children]) => {
107671
107637
  cell.children = children;
107672
107638
  });
107673
107639
  table.type = 'table';
107674
107640
  return;
107675
107641
  }
107642
+ // Nothing to build a JSX table from; leave the empty node to the GFM stringifier.
107643
+ const [headerRow, ...bodyRows] = table.children;
107644
+ if (!headerRow)
107645
+ return;
107676
107646
  visit(table, mdxish_tables_to_jsx_isTableCell, flattenBreaksToNewlines);
107677
107647
  const styles = table.align.map(mdxish_tables_to_jsx_alignToStyle);
107678
107648
  const head = {
@@ -107684,7 +107654,7 @@ const mdxishTablesToJsx = () => tree => {
107684
107654
  attributes: [],
107685
107655
  type: 'mdxJsxFlowElement',
107686
107656
  name: 'tr',
107687
- children: table.children[0].children.map((cell, cellIndex) => {
107657
+ children: headerRow.children.map((cell, cellIndex) => {
107688
107658
  return {
107689
107659
  attributes: [],
107690
107660
  type: 'mdxJsxFlowElement',
@@ -107700,7 +107670,7 @@ const mdxishTablesToJsx = () => tree => {
107700
107670
  attributes: [],
107701
107671
  type: 'mdxJsxFlowElement',
107702
107672
  name: 'tbody',
107703
- children: table.children.splice(1).map(row => {
107673
+ children: bodyRows.map(row => {
107704
107674
  return {
107705
107675
  attributes: [],
107706
107676
  type: 'mdxJsxFlowElement',
@@ -107728,8 +107698,8 @@ const mdxishTablesToJsx = () => tree => {
107728
107698
  ];
107729
107699
  const jsx = {
107730
107700
  type: 'mdxJsxFlowElement',
107731
- name: 'Table',
107732
- attributes: table.align.find(a => a) ? attributes : [],
107701
+ name: stayLowercase ? 'table' : 'Table',
107702
+ attributes: !stayLowercase && table.align.find(a => a) ? attributes : [],
107733
107703
  children: [head, body],
107734
107704
  };
107735
107705
  parent.children[index] = jsx;
package/dist/main.node.js CHANGED
@@ -96226,31 +96226,11 @@ const HTML_VOID_ELEMENTS = new Set([
96226
96226
 
96227
96227
 
96228
96228
  /**
96229
- * Partial constructs the `mdxComponent` tokenizer runs via `effects.check` to
96230
- * decide whether the next line continues the block. They live here (not in
96231
- * `syntax.ts`) because they hold none of `createTokenize`'s closure state — each
96229
+ * Partial construct the `mdxComponent` tokenizer runs via `effects.check` to
96230
+ * decide whether the next line continues the block. It lives here (not in
96231
+ * `syntax.ts`) because it holds none of `createTokenize`'s closure state — it
96232
96232
  * is a self-contained, single-line lookahead.
96233
96233
  */
96234
- function continuation_checks_tokenizeNonLazyContinuationStart(effects, ok, nok) {
96235
- // eslint-disable-next-line @typescript-eslint/no-this-alias
96236
- const self = this;
96237
- return start;
96238
- function start(code) {
96239
- if (markdownLineEnding(code)) {
96240
- effects.enter(types_types.lineEnding);
96241
- effects.consume(code);
96242
- effects.exit(types_types.lineEnding);
96243
- return after;
96244
- }
96245
- return nok(code);
96246
- }
96247
- function after(code) {
96248
- if (self.parser.lazy[self.now().line]) {
96249
- return nok(code);
96250
- }
96251
- return ok(code);
96252
- }
96253
- }
96254
96234
  // A markup-only line opens with a tag (`<x`/`</x`) and ends (ignoring trailing
96255
96235
  // spaces) at a `>`. That distinguishes a structural continuation like
96256
96236
  // `<span>b</span></div>` from a paragraph like `<b>Note:</b> read *this*`.
@@ -96291,12 +96271,6 @@ function tokenizeMarkupOnlyContinuation(effects, ok, nok) {
96291
96271
  return scanToLineEnd;
96292
96272
  }
96293
96273
  }
96294
- // A line ending whose next line isn't a lazy paragraph continuation. Checked so a
96295
- // component body's blank/continuation lines aren't stolen by an interrupted paragraph.
96296
- const continuation_checks_nonLazyContinuationStart = {
96297
- tokenize: continuation_checks_tokenizeNonLazyContinuationStart,
96298
- partial: true,
96299
- };
96300
96274
  // Lookahead for `plainClaimLineStart`: is this line markup-only, or a paragraph
96301
96275
  // that merely starts with a tag? Run via `effects.check` so it never consumes.
96302
96276
  const markupOnlyContinuation = {
@@ -96712,14 +96686,7 @@ function syntax_createTokenize(mode) {
96712
96686
  }
96713
96687
  // Continuation for multi-line opening tags
96714
96688
  function openTagContinuationStart(code) {
96715
- return effects.check(continuation_checks_nonLazyContinuationStart, openTagContinuationNonLazy, continuationAfter)(code);
96716
- }
96717
- function openTagContinuationNonLazy(code) {
96718
- sawLineEnding = true;
96719
- effects.enter(types_types.lineEnding);
96720
- effects.consume(code);
96721
- effects.exit(types_types.lineEnding);
96722
- return openTagContinuationBefore;
96689
+ return continueOnNextLine(code, openTagContinuationBefore);
96723
96690
  }
96724
96691
  function openTagContinuationBefore(code) {
96725
96692
  if (code === null || markdownLineEnding(code)) {
@@ -96837,14 +96804,7 @@ function syntax_createTokenize(mode) {
96837
96804
  return inFencedCode;
96838
96805
  }
96839
96806
  function fencedCodeContinuationStart(code) {
96840
- return effects.check(continuation_checks_nonLazyContinuationStart, fencedCodeContinuationNonLazy, continuationAfter)(code);
96841
- }
96842
- function fencedCodeContinuationNonLazy(code) {
96843
- sawLineEnding = true;
96844
- effects.enter(types_types.lineEnding);
96845
- effects.consume(code);
96846
- effects.exit(types_types.lineEnding);
96847
- return fencedCodeContinuationBefore;
96807
+ return continueOnNextLine(code, fencedCodeContinuationBefore);
96848
96808
  }
96849
96809
  function fencedCodeContinuationBefore(code) {
96850
96810
  if (code === null || markdownLineEnding(code)) {
@@ -97061,14 +97021,7 @@ function syntax_createTokenize(mode) {
97061
97021
  }
97062
97022
  // ── Body continuation (line endings) ───────────────────────────────────
97063
97023
  function bodyContinuationStart(code) {
97064
- return effects.check(continuation_checks_nonLazyContinuationStart, bodyContinuationNonLazy, continuationAfter)(code);
97065
- }
97066
- function bodyContinuationNonLazy(code) {
97067
- sawLineEnding = true;
97068
- effects.enter(types_types.lineEnding);
97069
- effects.consume(code);
97070
- effects.exit(types_types.lineEnding);
97071
- return bodyContinuationBefore;
97024
+ return continueOnNextLine(code, bodyContinuationBefore);
97072
97025
  }
97073
97026
  function bodyContinuationBefore(code) {
97074
97027
  if (code === null || markdownLineEnding(code)) {
@@ -97137,13 +97090,18 @@ function syntax_createTokenize(mode) {
97137
97090
  pendingBlankLine = false;
97138
97091
  return bodyLineStart(code);
97139
97092
  }
97140
- // ── Shared lazy continuation failure ───────────────────────────────────
97141
- function continuationAfter(code) {
97142
- if (code === null) {
97093
+ // ── Shared line-ending continuation ────────────────────────────────────
97094
+ // Consumes one line ending and resumes at `nextLine`. Lazy lines (under-indented
97095
+ // under a list item or blockquote) continue too: a claim only ends at its closing
97096
+ // tag, and an unclosed one fails whole at EOF instead of leaving a truncated opener (CX-3940).
97097
+ function continueOnNextLine(code, nextLine) {
97098
+ if (!markdownLineEnding(code))
97143
97099
  return nok(code);
97144
- }
97145
- effects.exit('mdxComponent');
97146
- return ok(code);
97100
+ sawLineEnding = true;
97101
+ effects.enter(types_types.lineEnding);
97102
+ effects.consume(code);
97103
+ effects.exit(types_types.lineEnding);
97104
+ return nextLine;
97147
97105
  }
97148
97106
  };
97149
97107
  }
@@ -101271,6 +101229,8 @@ const processTableNode = (node, index, parent, documentPosition) => {
101271
101229
  type: 'table',
101272
101230
  position,
101273
101231
  children,
101232
+ // Remember the author's spelling so the serializer can write `<table>` back instead of `<Table>`
101233
+ ...(node.name === 'table' && { data: { lowercaseTable: true } }),
101274
101234
  };
101275
101235
  parent.children[index] = mdNode;
101276
101236
  };
@@ -116873,7 +116833,7 @@ const rehypeToc = ({ components = {} }) => {
116873
116833
  });
116874
116834
  };
116875
116835
  };
116876
- const MAX_DEPTH = 2;
116836
+ const MAX_DEPTH = 3;
116877
116837
  /**
116878
116838
  * Get the depth of a heading element based on its tag name.
116879
116839
  *
@@ -124981,7 +124941,7 @@ const parseMdChildren = (value, safeMode) => {
124981
124941
  // Promote nested wrappers bottom-up so an outer wrapper sees markdown buried in a
124982
124942
  // child claimed whole (e.g. `<li>` in `<ol>`) before its containsMarkdownConstruct check (RM-17560).
124983
124943
  // eslint-disable-next-line @typescript-eslint/no-use-before-define -- mutually recursive; hoisted decl, safe at runtime
124984
- promoteComponentBlocks(parsed, safeMode, null);
124944
+ promoteComponentBlocks(parsed, safeMode, reparseSource);
124985
124945
  const children = parsed.children || [];
124986
124946
  // These children root a new coordinate space: their offsets index into `reparseSource`.
124987
124947
  stampReparseSource(children, reparseSource);
@@ -125000,23 +124960,26 @@ const parseSibling = (parent, index, sibling, safeMode, promoted) => {
125000
124960
  }
125001
124961
  };
125002
124962
  // Ends the position at `consumedLength` so the component doesn't claim trailing
125003
- // content the tokenizer swallowed into the same html node.
125004
- const positionEndingAtConsumed = (nodePosition, value, consumedLength) => {
124963
+ // content the tokenizer swallowed into the same html node. Measured against the source
124964
+ // when available: each value line is its source line minus the container prefix
124965
+ // (list indent, `> `) micromark stripped, so those prefixes are counted back in.
124966
+ const positionEndingAtConsumed = (nodePosition, value, consumedLength, source) => {
125005
124967
  if (!nodePosition?.start)
125006
124968
  return nodePosition;
125007
- return { start: nodePosition.start, end: pointAfter(nodePosition.start, value.slice(0, consumedLength)) };
125008
- };
125009
- // Like `positionEndingAtConsumed`, but measures against the original source so
125010
- // blockquote/list prefixes stripped from the html node's value are counted.
125011
- const positionEndingAtClosingTagInSource = (nodePosition, closingTag, source) => {
125012
- if (!nodePosition?.start || !nodePosition.end)
125013
- return nodePosition;
125014
- const nodeSource = source.slice(nodePosition.start.offset, nodePosition.end.offset);
125015
- const closingTagOffset = nodeSource.lastIndexOf(closingTag);
125016
- if (closingTagOffset === -1)
125017
- return nodePosition;
125018
- const consumed = nodeSource.slice(0, closingTagOffset + closingTag.length);
125019
- return { start: nodePosition.start, end: pointAfter(nodePosition.start, consumed) };
124969
+ const consumedValue = value.slice(0, consumedLength);
124970
+ const sourceLines = source?.slice(nodePosition.start.offset, nodePosition.end?.offset).split('\n');
124971
+ const valueLines = value.split('\n');
124972
+ if (!sourceLines || sourceLines.length !== valueLines.length) {
124973
+ return { start: nodePosition.start, end: pointAfter(nodePosition.start, consumedValue) };
124974
+ }
124975
+ const consumedLines = consumedValue.split('\n');
124976
+ const lastLineIndex = consumedLines.length - 1;
124977
+ const prefixWidth = sourceLines[lastLineIndex].length - valueLines[lastLineIndex].length;
124978
+ const consumedSource = [
124979
+ ...sourceLines.slice(0, lastLineIndex),
124980
+ sourceLines[lastLineIndex].slice(0, prefixWidth + consumedLines[lastLineIndex].length),
124981
+ ].join('\n');
124982
+ return { start: nodePosition.start, end: pointAfter(nodePosition.start, consumedSource) };
125020
124983
  };
125021
124984
  const createComponentNode = ({ tag, attributes, children, startPosition, endPosition, }) => ({
125022
124985
  type: 'mdxJsxFlowElement',
@@ -125123,16 +125086,18 @@ function promoteComponentBlocks(tree, safeMode, source) {
125123
125086
  const closingTagStr = `</${tag}>`;
125124
125087
  // Case 1: Self-closing tag
125125
125088
  if (selfClosing) {
125089
+ const remainingContent = contentAfterTag.trim();
125126
125090
  const componentNode = createComponentNode({
125127
125091
  tag,
125128
125092
  attributes,
125129
125093
  children: [],
125130
125094
  startPosition: node.position,
125131
- // End at the self-closing tag, not at any trailing content.
125132
- endPosition: positionEndingAtConsumed(node.position, value, leadingWhitespace + openingTagEnd),
125095
+ // Without trailing content the whole node position is correct; with it, end at the tag.
125096
+ endPosition: remainingContent
125097
+ ? positionEndingAtConsumed(node.position, value, leadingWhitespace + openingTagEnd, source)
125098
+ : node.position,
125133
125099
  });
125134
125100
  substituteNodeWithMdxNode(parent, index, componentNode);
125135
- const remainingContent = contentAfterTag.trim();
125136
125101
  if (remainingContent) {
125137
125102
  parseSibling(parent, index, remainingContent, safeMode, promoted);
125138
125103
  }
@@ -125171,14 +125136,10 @@ function promoteComponentBlocks(tree, safeMode, source) {
125171
125136
  stampReparseSource(parsedChildren, soleParagraph.data.reparseSource);
125172
125137
  unwrappedSoleParagraph = true;
125173
125138
  }
125174
- // Without trailing content the whole node position is correct. With it, end
125175
- // precisely at the closing tag — preferring source offsets when available (the
125176
- // node's value strips blockquote/list prefixes), else the consumed span.
125139
+ // Without trailing content the whole node position is correct; with it, end at the closing tag.
125177
125140
  let endPosition = node.position;
125178
125141
  if (contentAfterClose) {
125179
- endPosition = source
125180
- ? positionEndingAtClosingTagInSource(node.position, closingTagStr, source)
125181
- : positionEndingAtConsumed(node.position, value, leadingWhitespace + openingTagEnd + closingTagIndex + closingTagStr.length);
125142
+ endPosition = positionEndingAtConsumed(node.position, value, leadingWhitespace + openingTagEnd + closingTagIndex + closingTagStr.length, source);
125182
125143
  }
125183
125144
  const componentNode = createComponentNode({
125184
125145
  tag,
@@ -127849,13 +127810,22 @@ const mdxishTablesToJsx = () => tree => {
127849
127810
  gfmCells.push([cell, normalized]);
127850
127811
  return undefined;
127851
127812
  });
127852
- if (!requiresJsxTable) {
127813
+ const stayLowercase = table.data?.lowercaseTable === true;
127814
+ // We transform to GFM tables if:
127815
+ // 1. If it doesn't contain complex elements that the syntax can't represent
127816
+ // 2. The original table is not lowercase HTML <table>, because we want to
127817
+ // preserve original tables as much as possible
127818
+ if (!requiresJsxTable && !stayLowercase) {
127853
127819
  gfmCells.forEach(([cell, children]) => {
127854
127820
  cell.children = children;
127855
127821
  });
127856
127822
  table.type = 'table';
127857
127823
  return;
127858
127824
  }
127825
+ // Nothing to build a JSX table from; leave the empty node to the GFM stringifier.
127826
+ const [headerRow, ...bodyRows] = table.children;
127827
+ if (!headerRow)
127828
+ return;
127859
127829
  visit(table, mdxish_tables_to_jsx_isTableCell, flattenBreaksToNewlines);
127860
127830
  const styles = table.align.map(mdxish_tables_to_jsx_alignToStyle);
127861
127831
  const head = {
@@ -127867,7 +127837,7 @@ const mdxishTablesToJsx = () => tree => {
127867
127837
  attributes: [],
127868
127838
  type: 'mdxJsxFlowElement',
127869
127839
  name: 'tr',
127870
- children: table.children[0].children.map((cell, cellIndex) => {
127840
+ children: headerRow.children.map((cell, cellIndex) => {
127871
127841
  return {
127872
127842
  attributes: [],
127873
127843
  type: 'mdxJsxFlowElement',
@@ -127883,7 +127853,7 @@ const mdxishTablesToJsx = () => tree => {
127883
127853
  attributes: [],
127884
127854
  type: 'mdxJsxFlowElement',
127885
127855
  name: 'tbody',
127886
- children: table.children.splice(1).map(row => {
127856
+ children: bodyRows.map(row => {
127887
127857
  return {
127888
127858
  attributes: [],
127889
127859
  type: 'mdxJsxFlowElement',
@@ -127911,8 +127881,8 @@ const mdxishTablesToJsx = () => tree => {
127911
127881
  ];
127912
127882
  const jsx = {
127913
127883
  type: 'mdxJsxFlowElement',
127914
- name: 'Table',
127915
- attributes: table.align.find(a => a) ? attributes : [],
127884
+ name: stayLowercase ? 'table' : 'Table',
127885
+ attributes: !stayLowercase && table.align.find(a => a) ? attributes : [],
127916
127886
  children: [head, body],
127917
127887
  };
127918
127888
  parent.children[index] = jsx;