@readme/markdown 15.0.0 → 15.0.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
@@ -14677,72 +14677,319 @@ function push(list, items) {
14677
14677
  return items
14678
14678
  }
14679
14679
 
14680
+ ;// ./node_modules/micromark-util-subtokenize/lib/splice-buffer.js
14681
+ /**
14682
+ * Some of the internal operations of micromark do lots of editing
14683
+ * operations on very large arrays. This runs into problems with two
14684
+ * properties of most circa-2020 JavaScript interpreters:
14685
+ *
14686
+ * - Array-length modifications at the high end of an array (push/pop) are
14687
+ * expected to be common and are implemented in (amortized) time
14688
+ * proportional to the number of elements added or removed, whereas
14689
+ * other operations (shift/unshift and splice) are much less efficient.
14690
+ * - Function arguments are passed on the stack, so adding tens of thousands
14691
+ * of elements to an array with `arr.push(...newElements)` will frequently
14692
+ * cause stack overflows. (see <https://stackoverflow.com/questions/22123769/rangeerror-maximum-call-stack-size-exceeded-why>)
14693
+ *
14694
+ * SpliceBuffers are an implementation of gap buffers, which are a
14695
+ * generalization of the "queue made of two stacks" idea. The splice buffer
14696
+ * maintains a cursor, and moving the cursor has cost proportional to the
14697
+ * distance the cursor moves, but inserting, deleting, or splicing in
14698
+ * new information at the cursor is as efficient as the push/pop operation.
14699
+ * This allows for an efficient sequence of splices (or pushes, pops, shifts,
14700
+ * or unshifts) as long such edits happen at the same part of the array or
14701
+ * generally sweep through the array from the beginning to the end.
14702
+ *
14703
+ * The interface for splice buffers also supports large numbers of inputs by
14704
+ * passing a single array argument rather passing multiple arguments on the
14705
+ * function call stack.
14706
+ *
14707
+ * @template T
14708
+ * Item type.
14709
+ */
14710
+ class SpliceBuffer {
14711
+ /**
14712
+ * @param {ReadonlyArray<T> | null | undefined} [initial]
14713
+ * Initial items (optional).
14714
+ * @returns
14715
+ * Splice buffer.
14716
+ */
14717
+ constructor(initial) {
14718
+ /** @type {Array<T>} */
14719
+ this.left = initial ? [...initial] : [];
14720
+ /** @type {Array<T>} */
14721
+ this.right = [];
14722
+ }
14723
+
14724
+ /**
14725
+ * Array access;
14726
+ * does not move the cursor.
14727
+ *
14728
+ * @param {number} index
14729
+ * Index.
14730
+ * @return {T}
14731
+ * Item.
14732
+ */
14733
+ get(index) {
14734
+ if (index < 0 || index >= this.left.length + this.right.length) {
14735
+ throw new RangeError('Cannot access index `' + index + '` in a splice buffer of size `' + (this.left.length + this.right.length) + '`');
14736
+ }
14737
+ if (index < this.left.length) return this.left[index];
14738
+ return this.right[this.right.length - index + this.left.length - 1];
14739
+ }
14740
+
14741
+ /**
14742
+ * The length of the splice buffer, one greater than the largest index in the
14743
+ * array.
14744
+ */
14745
+ get length() {
14746
+ return this.left.length + this.right.length;
14747
+ }
14748
+
14749
+ /**
14750
+ * Remove and return `list[0]`;
14751
+ * moves the cursor to `0`.
14752
+ *
14753
+ * @returns {T | undefined}
14754
+ * Item, optional.
14755
+ */
14756
+ shift() {
14757
+ this.setCursor(0);
14758
+ return this.right.pop();
14759
+ }
14760
+
14761
+ /**
14762
+ * Slice the buffer to get an array;
14763
+ * does not move the cursor.
14764
+ *
14765
+ * @param {number} start
14766
+ * Start.
14767
+ * @param {number | null | undefined} [end]
14768
+ * End (optional).
14769
+ * @returns {Array<T>}
14770
+ * Array of items.
14771
+ */
14772
+ slice(start, end) {
14773
+ /** @type {number} */
14774
+ const stop = end === null || end === undefined ? Number.POSITIVE_INFINITY : end;
14775
+ if (stop < this.left.length) {
14776
+ return this.left.slice(start, stop);
14777
+ }
14778
+ if (start > this.left.length) {
14779
+ return this.right.slice(this.right.length - stop + this.left.length, this.right.length - start + this.left.length).reverse();
14780
+ }
14781
+ return this.left.slice(start).concat(this.right.slice(this.right.length - stop + this.left.length).reverse());
14782
+ }
14783
+
14784
+ /**
14785
+ * Mimics the behavior of Array.prototype.splice() except for the change of
14786
+ * interface necessary to avoid segfaults when patching in very large arrays.
14787
+ *
14788
+ * This operation moves cursor is moved to `start` and results in the cursor
14789
+ * placed after any inserted items.
14790
+ *
14791
+ * @param {number} start
14792
+ * Start;
14793
+ * zero-based index at which to start changing the array;
14794
+ * negative numbers count backwards from the end of the array and values
14795
+ * that are out-of bounds are clamped to the appropriate end of the array.
14796
+ * @param {number | null | undefined} [deleteCount=0]
14797
+ * Delete count (default: `0`);
14798
+ * maximum number of elements to delete, starting from start.
14799
+ * @param {Array<T> | null | undefined} [items=[]]
14800
+ * Items to include in place of the deleted items (default: `[]`).
14801
+ * @return {Array<T>}
14802
+ * Any removed items.
14803
+ */
14804
+ splice(start, deleteCount, items) {
14805
+ /** @type {number} */
14806
+ const count = deleteCount || 0;
14807
+ this.setCursor(Math.trunc(start));
14808
+ const removed = this.right.splice(this.right.length - count, Number.POSITIVE_INFINITY);
14809
+ if (items) chunkedPush(this.left, items);
14810
+ return removed.reverse();
14811
+ }
14812
+
14813
+ /**
14814
+ * Remove and return the highest-numbered item in the array, so
14815
+ * `list[list.length - 1]`;
14816
+ * Moves the cursor to `length`.
14817
+ *
14818
+ * @returns {T | undefined}
14819
+ * Item, optional.
14820
+ */
14821
+ pop() {
14822
+ this.setCursor(Number.POSITIVE_INFINITY);
14823
+ return this.left.pop();
14824
+ }
14825
+
14826
+ /**
14827
+ * Inserts a single item to the high-numbered side of the array;
14828
+ * moves the cursor to `length`.
14829
+ *
14830
+ * @param {T} item
14831
+ * Item.
14832
+ * @returns {undefined}
14833
+ * Nothing.
14834
+ */
14835
+ push(item) {
14836
+ this.setCursor(Number.POSITIVE_INFINITY);
14837
+ this.left.push(item);
14838
+ }
14839
+
14840
+ /**
14841
+ * Inserts many items to the high-numbered side of the array.
14842
+ * Moves the cursor to `length`.
14843
+ *
14844
+ * @param {Array<T>} items
14845
+ * Items.
14846
+ * @returns {undefined}
14847
+ * Nothing.
14848
+ */
14849
+ pushMany(items) {
14850
+ this.setCursor(Number.POSITIVE_INFINITY);
14851
+ chunkedPush(this.left, items);
14852
+ }
14853
+
14854
+ /**
14855
+ * Inserts a single item to the low-numbered side of the array;
14856
+ * Moves the cursor to `0`.
14857
+ *
14858
+ * @param {T} item
14859
+ * Item.
14860
+ * @returns {undefined}
14861
+ * Nothing.
14862
+ */
14863
+ unshift(item) {
14864
+ this.setCursor(0);
14865
+ this.right.push(item);
14866
+ }
14867
+
14868
+ /**
14869
+ * Inserts many items to the low-numbered side of the array;
14870
+ * moves the cursor to `0`.
14871
+ *
14872
+ * @param {Array<T>} items
14873
+ * Items.
14874
+ * @returns {undefined}
14875
+ * Nothing.
14876
+ */
14877
+ unshiftMany(items) {
14878
+ this.setCursor(0);
14879
+ chunkedPush(this.right, items.reverse());
14880
+ }
14881
+
14882
+ /**
14883
+ * Move the cursor to a specific position in the array. Requires
14884
+ * time proportional to the distance moved.
14885
+ *
14886
+ * If `n < 0`, the cursor will end up at the beginning.
14887
+ * If `n > length`, the cursor will end up at the end.
14888
+ *
14889
+ * @param {number} n
14890
+ * Position.
14891
+ * @return {undefined}
14892
+ * Nothing.
14893
+ */
14894
+ setCursor(n) {
14895
+ if (n === this.left.length || n > this.left.length && this.right.length === 0 || n < 0 && this.left.length === 0) return;
14896
+ if (n < this.left.length) {
14897
+ // Move cursor to the this.left
14898
+ const removed = this.left.splice(n, Number.POSITIVE_INFINITY);
14899
+ chunkedPush(this.right, removed.reverse());
14900
+ } else {
14901
+ // Move cursor to the this.right
14902
+ const removed = this.right.splice(this.left.length + this.right.length - n, Number.POSITIVE_INFINITY);
14903
+ chunkedPush(this.left, removed.reverse());
14904
+ }
14905
+ }
14906
+ }
14907
+
14908
+ /**
14909
+ * Avoid stack overflow by pushing items onto the stack in segments
14910
+ *
14911
+ * @template T
14912
+ * Item type.
14913
+ * @param {Array<T>} list
14914
+ * List to inject into.
14915
+ * @param {ReadonlyArray<T>} right
14916
+ * Items to inject.
14917
+ * @return {undefined}
14918
+ * Nothing.
14919
+ */
14920
+ function chunkedPush(list, right) {
14921
+ /** @type {number} */
14922
+ let chunkStart = 0;
14923
+ if (right.length < 10000) {
14924
+ list.push(...right);
14925
+ } else {
14926
+ while (chunkStart < right.length) {
14927
+ list.push(...right.slice(chunkStart, chunkStart + 10000));
14928
+ chunkStart += 10000;
14929
+ }
14930
+ }
14931
+ }
14680
14932
  ;// ./node_modules/micromark-util-subtokenize/index.js
14681
14933
  /**
14682
- * @typedef {import('micromark-util-types').Chunk} Chunk
14683
- * @typedef {import('micromark-util-types').Event} Event
14684
- * @typedef {import('micromark-util-types').Token} Token
14934
+ * @import {Chunk, Event, Token} from 'micromark-util-types'
14685
14935
  */
14686
14936
 
14687
14937
 
14938
+
14939
+
14940
+ // Hidden API exposed for testing.
14941
+
14942
+
14688
14943
  /**
14689
14944
  * Tokenize subcontent.
14690
14945
  *
14691
- * @param {Array<Event>} events
14946
+ * @param {Array<Event>} eventsArray
14692
14947
  * List of events.
14693
14948
  * @returns {boolean}
14694
14949
  * Whether subtokens were found.
14695
- */ // eslint-disable-next-line complexity
14696
- function subtokenize(events) {
14950
+ */
14951
+ // eslint-disable-next-line complexity
14952
+ function subtokenize(eventsArray) {
14697
14953
  /** @type {Record<string, number>} */
14698
- const jumps = {}
14699
- let index = -1
14954
+ const jumps = {};
14955
+ let index = -1;
14700
14956
  /** @type {Event} */
14701
- let event
14957
+ let event;
14702
14958
  /** @type {number | undefined} */
14703
- let lineIndex
14959
+ let lineIndex;
14704
14960
  /** @type {number} */
14705
- let otherIndex
14961
+ let otherIndex;
14706
14962
  /** @type {Event} */
14707
- let otherEvent
14963
+ let otherEvent;
14708
14964
  /** @type {Array<Event>} */
14709
- let parameters
14965
+ let parameters;
14710
14966
  /** @type {Array<Event>} */
14711
- let subevents
14967
+ let subevents;
14712
14968
  /** @type {boolean | undefined} */
14713
- let more
14969
+ let more;
14970
+ const events = new SpliceBuffer(eventsArray);
14714
14971
  while (++index < events.length) {
14715
14972
  while (index in jumps) {
14716
- index = jumps[index]
14973
+ index = jumps[index];
14717
14974
  }
14718
- event = events[index]
14975
+ event = events.get(index);
14719
14976
 
14720
14977
  // Add a hook for the GFM tasklist extension, which needs to know if text
14721
14978
  // is in the first content of a list item.
14722
- if (
14723
- index &&
14724
- event[1].type === 'chunkFlow' &&
14725
- events[index - 1][1].type === 'listItemPrefix'
14726
- ) {
14727
- subevents = event[1]._tokenizer.events
14728
- otherIndex = 0
14729
- if (
14730
- otherIndex < subevents.length &&
14731
- subevents[otherIndex][1].type === 'lineEndingBlank'
14732
- ) {
14733
- otherIndex += 2
14979
+ if (index && event[1].type === "chunkFlow" && events.get(index - 1)[1].type === "listItemPrefix") {
14980
+ subevents = event[1]._tokenizer.events;
14981
+ otherIndex = 0;
14982
+ if (otherIndex < subevents.length && subevents[otherIndex][1].type === "lineEndingBlank") {
14983
+ otherIndex += 2;
14734
14984
  }
14735
- if (
14736
- otherIndex < subevents.length &&
14737
- subevents[otherIndex][1].type === 'content'
14738
- ) {
14985
+ if (otherIndex < subevents.length && subevents[otherIndex][1].type === "content") {
14739
14986
  while (++otherIndex < subevents.length) {
14740
- if (subevents[otherIndex][1].type === 'content') {
14741
- break
14987
+ if (subevents[otherIndex][1].type === "content") {
14988
+ break;
14742
14989
  }
14743
- if (subevents[otherIndex][1].type === 'chunkText') {
14744
- subevents[otherIndex][1]._isInFirstContentOfListItem = true
14745
- otherIndex++
14990
+ if (subevents[otherIndex][1].type === "chunkText") {
14991
+ subevents[otherIndex][1]._isInFirstContentOfListItem = true;
14992
+ otherIndex++;
14746
14993
  }
14747
14994
  }
14748
14995
  }
@@ -14751,158 +14998,160 @@ function subtokenize(events) {
14751
14998
  // Enter.
14752
14999
  if (event[0] === 'enter') {
14753
15000
  if (event[1].contentType) {
14754
- Object.assign(jumps, subcontent(events, index))
14755
- index = jumps[index]
14756
- more = true
15001
+ Object.assign(jumps, subcontent(events, index));
15002
+ index = jumps[index];
15003
+ more = true;
14757
15004
  }
14758
15005
  }
14759
15006
  // Exit.
14760
15007
  else if (event[1]._container) {
14761
- otherIndex = index
14762
- lineIndex = undefined
15008
+ otherIndex = index;
15009
+ lineIndex = undefined;
14763
15010
  while (otherIndex--) {
14764
- otherEvent = events[otherIndex]
14765
- if (
14766
- otherEvent[1].type === 'lineEnding' ||
14767
- otherEvent[1].type === 'lineEndingBlank'
14768
- ) {
15011
+ otherEvent = events.get(otherIndex);
15012
+ if (otherEvent[1].type === "lineEnding" || otherEvent[1].type === "lineEndingBlank") {
14769
15013
  if (otherEvent[0] === 'enter') {
14770
15014
  if (lineIndex) {
14771
- events[lineIndex][1].type = 'lineEndingBlank'
15015
+ events.get(lineIndex)[1].type = "lineEndingBlank";
14772
15016
  }
14773
- otherEvent[1].type = 'lineEnding'
14774
- lineIndex = otherIndex
15017
+ otherEvent[1].type = "lineEnding";
15018
+ lineIndex = otherIndex;
14775
15019
  }
15020
+ } else if (otherEvent[1].type === "linePrefix") {
15021
+ // Move past.
14776
15022
  } else {
14777
- break
15023
+ break;
14778
15024
  }
14779
15025
  }
14780
15026
  if (lineIndex) {
14781
15027
  // Fix position.
14782
- event[1].end = Object.assign({}, events[lineIndex][1].start)
15028
+ event[1].end = {
15029
+ ...events.get(lineIndex)[1].start
15030
+ };
14783
15031
 
14784
15032
  // Switch container exit w/ line endings.
14785
- parameters = events.slice(lineIndex, index)
14786
- parameters.unshift(event)
14787
- splice(events, lineIndex, index - lineIndex + 1, parameters)
15033
+ parameters = events.slice(lineIndex, index);
15034
+ parameters.unshift(event);
15035
+ events.splice(lineIndex, index - lineIndex + 1, parameters);
14788
15036
  }
14789
15037
  }
14790
15038
  }
14791
- return !more
15039
+
15040
+ // The changes to the `events` buffer must be copied back into the eventsArray
15041
+ splice(eventsArray, 0, Number.POSITIVE_INFINITY, events.slice(0));
15042
+ return !more;
14792
15043
  }
14793
15044
 
14794
15045
  /**
14795
15046
  * Tokenize embedded tokens.
14796
15047
  *
14797
- * @param {Array<Event>} events
15048
+ * @param {SpliceBuffer<Event>} events
15049
+ * Events.
14798
15050
  * @param {number} eventIndex
15051
+ * Index.
14799
15052
  * @returns {Record<string, number>}
15053
+ * Gaps.
14800
15054
  */
14801
15055
  function subcontent(events, eventIndex) {
14802
- const token = events[eventIndex][1]
14803
- const context = events[eventIndex][2]
14804
- let startPosition = eventIndex - 1
15056
+ const token = events.get(eventIndex)[1];
15057
+ const context = events.get(eventIndex)[2];
15058
+ let startPosition = eventIndex - 1;
14805
15059
  /** @type {Array<number>} */
14806
- const startPositions = []
14807
- const tokenizer =
14808
- token._tokenizer || context.parser[token.contentType](token.start)
14809
- const childEvents = tokenizer.events
15060
+ const startPositions = [];
15061
+ const tokenizer = token._tokenizer || context.parser[token.contentType](token.start);
15062
+ const childEvents = tokenizer.events;
14810
15063
  /** @type {Array<[number, number]>} */
14811
- const jumps = []
15064
+ const jumps = [];
14812
15065
  /** @type {Record<string, number>} */
14813
- const gaps = {}
15066
+ const gaps = {};
14814
15067
  /** @type {Array<Chunk>} */
14815
- let stream
15068
+ let stream;
14816
15069
  /** @type {Token | undefined} */
14817
- let previous
14818
- let index = -1
15070
+ let previous;
15071
+ let index = -1;
14819
15072
  /** @type {Token | undefined} */
14820
- let current = token
14821
- let adjust = 0
14822
- let start = 0
14823
- const breaks = [start]
15073
+ let current = token;
15074
+ let adjust = 0;
15075
+ let start = 0;
15076
+ const breaks = [start];
14824
15077
 
14825
15078
  // Loop forward through the linked tokens to pass them in order to the
14826
15079
  // subtokenizer.
14827
15080
  while (current) {
14828
15081
  // Find the position of the event for this token.
14829
- while (events[++startPosition][1] !== current) {
15082
+ while (events.get(++startPosition)[1] !== current) {
14830
15083
  // Empty.
14831
15084
  }
14832
- startPositions.push(startPosition)
15085
+ startPositions.push(startPosition);
14833
15086
  if (!current._tokenizer) {
14834
- stream = context.sliceStream(current)
15087
+ stream = context.sliceStream(current);
14835
15088
  if (!current.next) {
14836
- stream.push(null)
15089
+ stream.push(null);
14837
15090
  }
14838
15091
  if (previous) {
14839
- tokenizer.defineSkip(current.start)
15092
+ tokenizer.defineSkip(current.start);
14840
15093
  }
14841
15094
  if (current._isInFirstContentOfListItem) {
14842
- tokenizer._gfmTasklistFirstContentOfListItem = true
15095
+ tokenizer._gfmTasklistFirstContentOfListItem = true;
14843
15096
  }
14844
- tokenizer.write(stream)
15097
+ tokenizer.write(stream);
14845
15098
  if (current._isInFirstContentOfListItem) {
14846
- tokenizer._gfmTasklistFirstContentOfListItem = undefined
15099
+ tokenizer._gfmTasklistFirstContentOfListItem = undefined;
14847
15100
  }
14848
15101
  }
14849
15102
 
14850
15103
  // Unravel the next token.
14851
- previous = current
14852
- current = current.next
15104
+ previous = current;
15105
+ current = current.next;
14853
15106
  }
14854
15107
 
14855
15108
  // Now, loop back through all events (and linked tokens), to figure out which
14856
15109
  // parts belong where.
14857
- current = token
15110
+ current = token;
14858
15111
  while (++index < childEvents.length) {
14859
15112
  if (
14860
- // Find a void token that includes a break.
14861
- childEvents[index][0] === 'exit' &&
14862
- childEvents[index - 1][0] === 'enter' &&
14863
- childEvents[index][1].type === childEvents[index - 1][1].type &&
14864
- childEvents[index][1].start.line !== childEvents[index][1].end.line
14865
- ) {
14866
- start = index + 1
14867
- breaks.push(start)
15113
+ // Find a void token that includes a break.
15114
+ childEvents[index][0] === 'exit' && childEvents[index - 1][0] === 'enter' && childEvents[index][1].type === childEvents[index - 1][1].type && childEvents[index][1].start.line !== childEvents[index][1].end.line) {
15115
+ start = index + 1;
15116
+ breaks.push(start);
14868
15117
  // Help GC.
14869
- current._tokenizer = undefined
14870
- current.previous = undefined
14871
- current = current.next
15118
+ current._tokenizer = undefined;
15119
+ current.previous = undefined;
15120
+ current = current.next;
14872
15121
  }
14873
15122
  }
14874
15123
 
14875
15124
  // Help GC.
14876
- tokenizer.events = []
15125
+ tokenizer.events = [];
14877
15126
 
14878
15127
  // If there’s one more token (which is the cases for lines that end in an
14879
15128
  // EOF), that’s perfect: the last point we found starts it.
14880
15129
  // If there isn’t then make sure any remaining content is added to it.
14881
15130
  if (current) {
14882
15131
  // Help GC.
14883
- current._tokenizer = undefined
14884
- current.previous = undefined
15132
+ current._tokenizer = undefined;
15133
+ current.previous = undefined;
14885
15134
  } else {
14886
- breaks.pop()
15135
+ breaks.pop();
14887
15136
  }
14888
15137
 
14889
15138
  // Now splice the events from the subtokenizer into the current events,
14890
15139
  // moving back to front so that splice indices aren’t affected.
14891
- index = breaks.length
15140
+ index = breaks.length;
14892
15141
  while (index--) {
14893
- const slice = childEvents.slice(breaks[index], breaks[index + 1])
14894
- const start = startPositions.pop()
14895
- jumps.unshift([start, start + slice.length - 1])
14896
- splice(events, start, 2, slice)
15142
+ const slice = childEvents.slice(breaks[index], breaks[index + 1]);
15143
+ const start = startPositions.pop();
15144
+ jumps.push([start, start + slice.length - 1]);
15145
+ events.splice(start, 2, slice);
14897
15146
  }
14898
- index = -1
15147
+ jumps.reverse();
15148
+ index = -1;
14899
15149
  while (++index < jumps.length) {
14900
- gaps[adjust + jumps[index][0]] = adjust + jumps[index][1]
14901
- adjust += jumps[index][1] - jumps[index][0] - 1
15150
+ gaps[adjust + jumps[index][0]] = adjust + jumps[index][1];
15151
+ adjust += jumps[index][1] - jumps[index][0] - 1;
14902
15152
  }
14903
- return gaps
15153
+ return gaps;
14904
15154
  }
14905
-
14906
15155
  ;// ./node_modules/micromark/lib/postprocess.js
14907
15156
  /**
14908
15157
  * @typedef {import('micromark-util-types').Event} Event
@@ -93267,7 +93516,9 @@ class MdxSyntaxError extends SyntaxError {
93267
93516
  * as `\r<br>`. Treating both characters as hard breaks doubles the spacing.
93268
93517
  */
93269
93518
  const hardBreaks = () => tree => {
93270
- findAndReplace(tree, [/\r?\n/g, () => ({ type: 'break' })]);
93519
+ // Skip `html-block`: its opaque payload is rendered verbatim, so turning its newlines
93520
+ // into `break` nodes is unnecessary and costly on large blocks.
93521
+ findAndReplace(tree, [/\r?\n/g, () => ({ type: 'break' })], { ignore: ['html-block'] });
93271
93522
  };
93272
93523
  /* harmony default export */ const hard_breaks = (hardBreaks);
93273
93524
 
@@ -103736,6 +103987,10 @@ const NESTED_ATTR_EXPRESSION_RE = /[\w-]+\s*=\s*\{/;
103736
103987
  // Name shape mirrors `componentTagPattern`; the lookbehind skips the inner tag
103737
103988
  // of a legacy `<<VARIABLE>>`.
103738
103989
  const NESTED_COMPONENT_TAG_RE = /(?<!<)<([A-Z][A-Za-z0-9_]*)[\s/>]/g;
103990
+ // Whole blank lines at a component body's edges. `\n` sits inside each group so a
103991
+ // match can only ever span complete lines, never part of a content line.
103992
+ const LEADING_BLANK_LINES_RE = /^(?:[ \t]*\n)+/;
103993
+ const TRAILING_BLANK_LINES_RE = /(?:\n[ \t]*)+$/;
103739
103994
  // Excludes tags with dedicated transformers (`Table`, `HTMLBlock`, inline
103740
103995
  // components), which expect their wrapper to stay raw.
103741
103996
  const hasNestedGenericComponentTag = (content) => [...content.matchAll(NESTED_COMPONENT_TAG_RE)].some(match => !GENERIC_MDX_COMPONENT_EXCLUDED_TAGS.has(match[1]));
@@ -103769,13 +104024,21 @@ function safeDeindent(text) {
103769
104024
  })
103770
104025
  .join('\n');
103771
104026
  }
104027
+ /**
104028
+ * Drop the blank lines at a component body's edges, keeping the first content line's
104029
+ * indent: `.trim()` stripped that line alone, so a uniformly indented body reparsed
104030
+ * lopsided and every list item after the first nested. The trailing pattern
104031
+ * takes the last content line's newline but leaves its spaces, which are code content
104032
+ * when a fence runs into the end tag.
104033
+ */
104034
+ const trimBlankEdges = (text) => text.replace(LEADING_BLANK_LINES_RE, '').replace(TRAILING_BLANK_LINES_RE, '');
103772
104035
  /**
103773
104036
  * Parse component-body markdown into mdast children. Dedenting shifts columns and
103774
104037
  * stales the top-level `terminateHtmlFlowBlocks` decisions, so that one preprocessor
103775
104038
  * re-runs here; other column-anchored fixups (compact headings, tables) do not.
103776
104039
  */
103777
104040
  const parseMdChildren = (value, safeMode) => {
103778
- const reparseSource = terminateHtmlFlowBlocks(safeDeindent(value).trim());
104041
+ const reparseSource = terminateHtmlFlowBlocks(trimBlankEdges(safeDeindent(value)));
103779
104042
  const parsed = getInlineMdProcessor({ safeMode }).parse(reparseSource);
103780
104043
  // Promote nested wrappers bottom-up so an outer wrapper sees markdown buried in a
103781
104044
  // child claimed whole (e.g. `<li>` in `<ol>`) before its containsMarkdownConstruct check (RM-17560).
@@ -103940,7 +104203,8 @@ function promoteComponentBlocks(tree, safeMode, source) {
103940
104203
  // Case 2: Self-contained block (closing tag in content)
103941
104204
  const closingTagIndex = isPlainLowercaseHtml ? plainClosingTagIndex : contentAfterTag.lastIndexOf(closingTagStr);
103942
104205
  if (closingTagIndex >= 0) {
103943
- // Untrimmed so parseMdChildren can dedent before trimming.
104206
+ // Left as authored: parseMdChildren needs the original columns to dedent by, and
104207
+ // it clears the blank edges itself.
103944
104208
  const componentInnerContent = contentAfterTag.substring(0, closingTagIndex);
103945
104209
  const contentAfterClose = contentAfterTag.substring(closingTagIndex + closingTagStr.length).trim();
103946
104210
  let parsedChildren = [];