@readme/markdown 14.11.4 → 14.12.0

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.
@@ -91765,17 +91765,12 @@ const extractScripts = (html = '') => {
91765
91765
  return [cleaned, () => scripts.map(js => window.eval(js))];
91766
91766
  };
91767
91767
  const HTMLBlock = ({ children = '', html: htmlProp, runScripts, safeMode: safeModeRaw = false }) => {
91768
- // Determine HTML source: MDXish uses html prop (from HAST), MDX uses children
91769
- let html = '';
91770
- if (htmlProp !== undefined) {
91771
- html = htmlProp;
91772
- }
91773
- else {
91774
- if (typeof children !== 'string') {
91775
- throw new TypeError('HTMLBlock: children must be a string');
91776
- }
91777
- html = children;
91778
- }
91768
+ // Determine HTML source: MDXish uses html prop (from HAST), MDX uses children.
91769
+ // A non-string child (no html prop) can't be injected as raw HTML — see the
91770
+ // fail-soft fallback below.
91771
+ const htmlSource = htmlProp !== undefined ? htmlProp : children;
91772
+ const nonStringChildren = typeof htmlSource !== 'string';
91773
+ const html = nonStringChildren ? '' : htmlSource;
91779
91774
  // eslint-disable-next-line no-param-reassign
91780
91775
  runScripts = typeof runScripts !== 'boolean' ? runScripts === 'true' : runScripts;
91781
91776
  // In MDX mode, safeMode is passed in as a boolean from JSX parsing
@@ -91786,6 +91781,11 @@ const HTMLBlock = ({ children = '', html: htmlProp, runScripts, safeMode: safeMo
91786
91781
  if (typeof window !== 'undefined' && typeof runScripts === 'boolean' && runScripts)
91787
91782
  exec();
91788
91783
  }, [runScripts, exec]);
91784
+ if (nonStringChildren) {
91785
+ // Fail soft: a non-string child (e.g. JSX that wasn't serialized back to a
91786
+ // raw string) should never throw, so render the child nodes directly
91787
+ return external_react_default().createElement("div", { className: "rdmd-html" }, children);
91788
+ }
91789
91789
  if (safeMode) {
91790
91790
  return (external_react_default().createElement("pre", { className: "html-unsafe" },
91791
91791
  external_react_default().createElement("code", null, html)));
@@ -92855,7 +92855,7 @@ function legacyVariableFromMarkdown() {
92855
92855
  *
92856
92856
  * Unicode basic latin block.
92857
92857
  */
92858
- const codes_codes = /** @type {const} */ ({
92858
+ const codes = /** @type {const} */ ({
92859
92859
  carriageReturn: -5,
92860
92860
  lineFeed: -4,
92861
92861
  carriageReturnLineFeed: -3,
@@ -93003,11 +93003,11 @@ const codes_codes = /** @type {const} */ ({
93003
93003
  function isNameChar(code) {
93004
93004
  if (code === null)
93005
93005
  return false;
93006
- return ((code >= codes_codes.lowercaseA && code <= codes_codes.lowercaseZ) ||
93007
- (code >= codes_codes.uppercaseA && code <= codes_codes.uppercaseZ) ||
93008
- (code >= codes_codes.digit0 && code <= codes_codes.digit9) ||
93009
- code === codes_codes.dash ||
93010
- code === codes_codes.underscore);
93006
+ return ((code >= codes.lowercaseA && code <= codes.lowercaseZ) ||
93007
+ (code >= codes.uppercaseA && code <= codes.uppercaseZ) ||
93008
+ (code >= codes.digit0 && code <= codes.digit9) ||
93009
+ code === codes.dash ||
93010
+ code === codes.underscore);
93011
93011
  }
93012
93012
  const gemojiConstruct = {
93013
93013
  name: 'gemoji',
@@ -93017,7 +93017,7 @@ function tokenize(effects, ok, nok) {
93017
93017
  let hasName = false;
93018
93018
  // Entry point — expect opening `:`
93019
93019
  const start = (code) => {
93020
- if (code !== codes_codes.colon)
93020
+ if (code !== codes.colon)
93021
93021
  return nok(code);
93022
93022
  effects.enter('gemoji');
93023
93023
  effects.enter('gemojiMarker');
@@ -93028,7 +93028,7 @@ function tokenize(effects, ok, nok) {
93028
93028
  };
93029
93029
  // First char after `:`, branch on `+` for :+1:, otherwise start normal name
93030
93030
  const nameStart = (code) => {
93031
- if (code === codes_codes.plusSign) {
93031
+ if (code === codes.plusSign) {
93032
93032
  effects.consume(code); // +
93033
93033
  return plusOne;
93034
93034
  }
@@ -93043,7 +93043,7 @@ function tokenize(effects, ok, nok) {
93043
93043
  // After `+`, only `1` is valid (for :+1:), anything else rejects
93044
93044
  // this is a special case for :+1: 👍 since + isnt a normal name character
93045
93045
  const plusOne = (code) => {
93046
- if (code === codes_codes.digit1) {
93046
+ if (code === codes.digit1) {
93047
93047
  hasName = true;
93048
93048
  effects.consume(code); // 1
93049
93049
  return nameEnd;
@@ -93052,7 +93052,7 @@ function tokenize(effects, ok, nok) {
93052
93052
  };
93053
93053
  // Consume name characters until we hit closing `:` or an invalid char
93054
93054
  const name = (code) => {
93055
- if (code === codes_codes.colon) {
93055
+ if (code === codes.colon) {
93056
93056
  if (!hasName)
93057
93057
  return nok(code);
93058
93058
  return nameEnd(code);
@@ -93066,7 +93066,7 @@ function tokenize(effects, ok, nok) {
93066
93066
  };
93067
93067
  // Expect closing `:`
93068
93068
  const nameEnd = (code) => {
93069
- if (code !== codes_codes.colon)
93069
+ if (code !== codes.colon)
93070
93070
  return nok(code);
93071
93071
  effects.exit('gemojiName');
93072
93072
  effects.enter('gemojiMarker');
@@ -93079,7 +93079,7 @@ function tokenize(effects, ok, nok) {
93079
93079
  }
93080
93080
  function syntax_gemoji() {
93081
93081
  return {
93082
- text: { [codes_codes.colon]: gemojiConstruct },
93082
+ text: { [codes.colon]: gemojiConstruct },
93083
93083
  };
93084
93084
  }
93085
93085
 
@@ -93094,8 +93094,8 @@ function syntax_gemoji() {
93094
93094
 
93095
93095
  function isAllowedValueChar(code) {
93096
93096
  return (code !== null &&
93097
- code !== codes_codes.lessThan &&
93098
- code !== codes_codes.greaterThan &&
93097
+ code !== codes.lessThan &&
93098
+ code !== codes.greaterThan &&
93099
93099
  !markdownLineEnding(code));
93100
93100
  }
93101
93101
  const legacyVariableConstruct = {
@@ -93105,7 +93105,7 @@ const legacyVariableConstruct = {
93105
93105
  function syntax_tokenize(effects, ok, nok) {
93106
93106
  let hasValue = false;
93107
93107
  const start = (code) => {
93108
- if (code !== codes_codes.lessThan)
93108
+ if (code !== codes.lessThan)
93109
93109
  return nok(code);
93110
93110
  effects.enter('legacyVariable');
93111
93111
  effects.enter('legacyVariableMarkerStart');
@@ -93113,7 +93113,7 @@ function syntax_tokenize(effects, ok, nok) {
93113
93113
  return open2;
93114
93114
  };
93115
93115
  const open2 = (code) => {
93116
- if (code !== codes_codes.lessThan)
93116
+ if (code !== codes.lessThan)
93117
93117
  return nok(code);
93118
93118
  effects.consume(code); // <<
93119
93119
  effects.exit('legacyVariableMarkerStart');
@@ -93121,7 +93121,7 @@ function syntax_tokenize(effects, ok, nok) {
93121
93121
  return value;
93122
93122
  };
93123
93123
  const value = (code) => {
93124
- if (code === codes_codes.greaterThan) {
93124
+ if (code === codes.greaterThan) {
93125
93125
  if (!hasValue)
93126
93126
  return nok(code);
93127
93127
  effects.exit('legacyVariableValue');
@@ -93136,7 +93136,7 @@ function syntax_tokenize(effects, ok, nok) {
93136
93136
  return value;
93137
93137
  };
93138
93138
  const close2 = (code) => {
93139
- if (code !== codes_codes.greaterThan)
93139
+ if (code !== codes.greaterThan)
93140
93140
  return nok(code);
93141
93141
  effects.consume(code); // >>
93142
93142
  effects.exit('legacyVariableMarkerEnd');
@@ -93147,7 +93147,7 @@ function syntax_tokenize(effects, ok, nok) {
93147
93147
  }
93148
93148
  function legacyVariable() {
93149
93149
  return {
93150
- text: { [codes_codes.lessThan]: legacyVariableConstruct },
93150
+ text: { [codes.lessThan]: legacyVariableConstruct },
93151
93151
  };
93152
93152
  }
93153
93153
 
@@ -96621,6 +96621,9 @@ const TOP_LEVEL_TABLE_TAG_RE = /^<(?:table|Table)(?=[\s/>])/;
96621
96621
  * Uses `walkTags` so `<table>`s inside code spans / fenced blocks (masked away)
96622
96622
  * are never matched.
96623
96623
  *
96624
+ * `<table>`s inside an `<HTMLBlock>` body are also ignored: that body is opaque
96625
+ * raw HTML, so lifting a table out of it would corrupt the block.
96626
+ *
96624
96627
  * Note: An implicitly-closed table (no `</table>`, so htmlparser2 synthesizes the
96625
96628
  * close at a later tag) is skipped: splitting there would swallow whatever
96626
96629
  * followed the table into the fragment and drop it, so we leave such a node
@@ -96628,21 +96631,35 @@ const TOP_LEVEL_TABLE_TAG_RE = /^<(?:table|Table)(?=[\s/>])/;
96628
96631
  */
96629
96632
  const findTableRanges = (html) => {
96630
96633
  const ranges = [];
96631
- let depth = 0;
96634
+ let tableDepth = 0;
96635
+ let htmlBlockDepth = 0;
96632
96636
  let start = 0;
96633
96637
  walkTags(html, {
96634
- onOpen: ({ name, start: openStart, isStrayCloser }) => {
96635
- if (name.toLowerCase() !== 'table' || isStrayCloser)
96638
+ onOpen: ({ name, start: openStart, isSelfClosing, isStrayCloser }) => {
96639
+ if (isStrayCloser)
96636
96640
  return;
96637
- if (depth === 0)
96641
+ // `<HTMLBlock/>` has no body to protect; only a real open enters one.
96642
+ if (name === 'HTMLBlock') {
96643
+ if (!isSelfClosing)
96644
+ htmlBlockDepth += 1;
96645
+ return;
96646
+ }
96647
+ if (htmlBlockDepth > 0 || name.toLowerCase() !== 'table')
96648
+ return;
96649
+ if (tableDepth === 0)
96638
96650
  start = openStart;
96639
- depth += 1;
96651
+ tableDepth += 1;
96640
96652
  },
96641
96653
  onClose: ({ name, end, implicit }) => {
96642
- if (implicit || name.toLowerCase() !== 'table' || depth === 0)
96654
+ if (name === 'HTMLBlock') {
96655
+ if (!implicit && htmlBlockDepth > 0)
96656
+ htmlBlockDepth -= 1;
96643
96657
  return;
96644
- depth -= 1;
96645
- if (depth === 0)
96658
+ }
96659
+ if (implicit || htmlBlockDepth > 0 || name.toLowerCase() !== 'table' || tableDepth === 0)
96660
+ return;
96661
+ tableDepth -= 1;
96662
+ if (tableDepth === 0)
96646
96663
  ranges.push({ start, end });
96647
96664
  },
96648
96665
  });
@@ -96662,7 +96679,9 @@ const splitHtmlWithNestedTables = (node) => {
96662
96679
  // This is a top-level table, so we don't need to split it
96663
96680
  if (TOP_LEVEL_TABLE_TAG_RE.test(value))
96664
96681
  return null;
96665
- // No table text anywhere in the value → skip the htmlparser2 walk entirely.
96682
+ // No table text anywhere → skip the htmlparser2 walk entirely. (A `<table>` that
96683
+ // only appears inside an `<HTMLBlock>` body still yields no ranges below, so it's
96684
+ // left whole for `mdxishHtmlBlocks` to convert to an html-block next.)
96666
96685
  if (!/<\/?table/i.test(value))
96667
96686
  return null;
96668
96687
  const ranges = findTableRanges(value);
@@ -117497,6 +117516,19 @@ const compile_list_item_listItem = (node, parent, state, info) => {
117497
117516
  const plain_plain = (node) => node.value;
117498
117517
  /* harmony default export */ const compile_plain = (plain_plain);
117499
117518
 
117519
+ ;// ./processor/compile/text.ts
117520
+
117521
+ // A `_` flanked by word characters can never open or close emphasis under
117522
+ // CommonMark's flanking rules, so the escape mdast-util-to-markdown adds to
117523
+ // intraword underscores is unnecessary and only produces noisy `\_` diffs.
117524
+ // Uses Unicode letter/number classes so non-ASCII words (e.g. `é_pay`) match.
117525
+ const INTRAWORD_UNDERSCORE_ESCAPE = /(?<=[\p{L}\p{N}_])\\_(?=[\p{L}\p{N}_]|\\_)/gu;
117526
+ const compile_text_text = (node, parent, state, info) => {
117527
+ const serialized = handle.text(node, parent, state, info);
117528
+ return serialized.replace(INTRAWORD_UNDERSCORE_ESCAPE, '_');
117529
+ };
117530
+ /* harmony default export */ const compile_text = (compile_text_text);
117531
+
117500
117532
  ;// ./processor/compile/index.ts
117501
117533
 
117502
117534
 
@@ -117509,11 +117541,11 @@ const plain_plain = (node) => node.value;
117509
117541
 
117510
117542
 
117511
117543
 
117544
+
117512
117545
  function compilers(mdxish = false) {
117513
117546
  const data = this.data();
117514
117547
  const toMarkdownExtensions = data.toMarkdownExtensions || (data.toMarkdownExtensions = []);
117515
117548
  const handlers = {
117516
- ...(mdxish && { [enums_NodeTypes.anchor]: compile_anchor }),
117517
117549
  [enums_NodeTypes.callout]: compile_callout,
117518
117550
  [enums_NodeTypes.codeTabs]: compile_code_tabs,
117519
117551
  [enums_NodeTypes.embedBlock]: compile_embed,
@@ -117521,15 +117553,18 @@ function compilers(mdxish = false) {
117521
117553
  [enums_NodeTypes.glossary]: compile_compatibility,
117522
117554
  [enums_NodeTypes.htmlBlock]: html_block,
117523
117555
  [enums_NodeTypes.reusableContent]: compile_compatibility,
117524
- ...(mdxish && { [enums_NodeTypes.variable]: compile_variable }),
117525
117556
  embed: compile_compatibility,
117526
117557
  escape: compile_compatibility,
117527
117558
  figure: compile_compatibility,
117528
117559
  html: compile_compatibility,
117529
117560
  i: compile_compatibility,
117530
- ...(mdxish && { listItem: list_item }),
117531
117561
  plain: compile_plain,
117532
117562
  yaml: compile_compatibility,
117563
+ // needed only for mdxish
117564
+ ...(mdxish && { [enums_NodeTypes.anchor]: compile_anchor }),
117565
+ ...(mdxish && { listItem: list_item }),
117566
+ ...(mdxish && { text: compile_text }),
117567
+ ...(mdxish && { [enums_NodeTypes.variable]: compile_variable }),
117533
117568
  };
117534
117569
  toMarkdownExtensions.push({ extensions: [{ handlers }] });
117535
117570
  }
@@ -118388,6 +118423,55 @@ function emptyTaskListItemFromMarkdown() {
118388
118423
  };
118389
118424
  }
118390
118425
 
118426
+ ;// ./lib/mdast-util/jsx-table/index.ts
118427
+ const jsx_table_contextMap = new WeakMap();
118428
+ function findJsxTableToken() {
118429
+ const events = this.tokenStack;
118430
+ for (let i = events.length - 1; i >= 0; i -= 1) {
118431
+ if (events[i][0].type === 'jsxTable')
118432
+ return events[i][0];
118433
+ }
118434
+ return undefined;
118435
+ }
118436
+ function enterJsxTable(token) {
118437
+ jsx_table_contextMap.set(token, { chunks: [], lastEndLine: token.start.line });
118438
+ this.enter({ type: 'html', value: '' }, token);
118439
+ }
118440
+ function exitJsxTableData(token) {
118441
+ const tableToken = findJsxTableToken.call(this);
118442
+ if (!tableToken)
118443
+ return;
118444
+ const ctx = jsx_table_contextMap.get(tableToken);
118445
+ if (ctx) {
118446
+ const gap = token.start.line - ctx.lastEndLine;
118447
+ if (ctx.chunks.length > 0 && gap > 0) {
118448
+ ctx.chunks.push('\n'.repeat(gap));
118449
+ }
118450
+ ctx.chunks.push(this.sliceSerialize(token));
118451
+ ctx.lastEndLine = token.end.line;
118452
+ }
118453
+ }
118454
+ function exitJsxTable(token) {
118455
+ const ctx = jsx_table_contextMap.get(token);
118456
+ const node = this.stack[this.stack.length - 1];
118457
+ if (ctx) {
118458
+ node.value = ctx.chunks.join('');
118459
+ jsx_table_contextMap.delete(token);
118460
+ }
118461
+ this.exit(token);
118462
+ }
118463
+ function jsx_table_jsxTableFromMarkdown() {
118464
+ return {
118465
+ enter: {
118466
+ jsxTable: enterJsxTable,
118467
+ },
118468
+ exit: {
118469
+ jsxTableData: exitJsxTableData,
118470
+ jsxTable: exitJsxTable,
118471
+ },
118472
+ };
118473
+ }
118474
+
118391
118475
  ;// ./lib/mdast-util/magic-block/index.ts
118392
118476
  const magic_block_contextMap = new WeakMap();
118393
118477
  /**
@@ -118577,867 +118661,16 @@ function mdx_component_mdxComponentFromMarkdown() {
118577
118661
  };
118578
118662
  }
118579
118663
 
118580
- ;// ./lib/micromark/magic-block/syntax.ts
118581
-
118582
-
118583
- /**
118584
- * Known magic block types that the tokenizer will recognize.
118585
- * Unknown types will not be tokenized as magic blocks.
118586
- */
118587
- const KNOWN_BLOCK_TYPES = new Set([
118588
- 'code',
118589
- 'api-header',
118590
- 'image',
118591
- 'callout',
118592
- 'parameters',
118593
- 'table',
118594
- 'embed',
118595
- 'html',
118596
- 'recipe',
118597
- 'tutorial-tile',
118598
- ]);
118599
- /**
118600
- * Check if a character is valid for a magic block type identifier.
118601
- * Types can contain alphanumeric characters and hyphens (e.g., "api-header", "tutorial-tile")
118602
- */
118603
- function isTypeChar(code) {
118604
- return asciiAlphanumeric(code) || code === codes_codes.dash;
118605
- }
118606
- /**
118607
- * Creates the opening marker state machine: [block:
118608
- * Returns the first state function to start parsing.
118609
- */
118610
- function createOpeningMarkerParser(effects, nok, onComplete) {
118611
- const expectB = (code) => {
118612
- if (code !== codes_codes.lowercaseB)
118613
- return nok(code);
118614
- effects.consume(code);
118615
- return expectL;
118616
- };
118617
- const expectL = (code) => {
118618
- if (code !== codes_codes.lowercaseL)
118619
- return nok(code);
118620
- effects.consume(code);
118621
- return expectO;
118622
- };
118623
- const expectO = (code) => {
118624
- if (code !== codes_codes.lowercaseO)
118625
- return nok(code);
118626
- effects.consume(code);
118627
- return expectC;
118628
- };
118629
- const expectC = (code) => {
118630
- if (code !== codes_codes.lowercaseC)
118631
- return nok(code);
118632
- effects.consume(code);
118633
- return expectK;
118634
- };
118635
- const expectK = (code) => {
118636
- if (code !== codes_codes.lowercaseK)
118637
- return nok(code);
118638
- effects.consume(code);
118639
- return expectColon;
118640
- };
118641
- const expectColon = (code) => {
118642
- if (code !== codes_codes.colon)
118643
- return nok(code);
118644
- effects.consume(code);
118645
- effects.exit('magicBlockMarkerStart');
118646
- effects.enter('magicBlockType');
118647
- return onComplete;
118648
- };
118649
- return expectB;
118650
- }
118651
- /**
118652
- * Creates the type capture state machine.
118653
- * Captures type characters until ] and validates against known types.
118654
- */
118655
- function createTypeCaptureParser(effects, nok, onComplete, blockTypeRef) {
118656
- const captureTypeFirst = (code) => {
118657
- // Reject empty type name [block:]
118658
- if (code === codes_codes.rightSquareBracket) {
118659
- return nok(code);
118660
- }
118661
- if (isTypeChar(code)) {
118662
- blockTypeRef.value += String.fromCharCode(code);
118663
- effects.consume(code);
118664
- return captureType;
118665
- }
118666
- return nok(code);
118667
- };
118668
- const captureType = (code) => {
118669
- if (code === codes_codes.rightSquareBracket) {
118670
- if (!KNOWN_BLOCK_TYPES.has(blockTypeRef.value)) {
118671
- return nok(code);
118672
- }
118673
- effects.exit('magicBlockType');
118674
- effects.enter('magicBlockMarkerTypeEnd');
118675
- effects.consume(code);
118676
- effects.exit('magicBlockMarkerTypeEnd');
118677
- return onComplete;
118678
- }
118679
- if (isTypeChar(code)) {
118680
- blockTypeRef.value += String.fromCharCode(code);
118681
- effects.consume(code);
118682
- return captureType;
118683
- }
118684
- return nok(code);
118685
- };
118686
- return { first: captureTypeFirst, remaining: captureType };
118687
- }
118688
- /**
118689
- * Creates the closing marker state machine: /block]
118690
- * Handles partial matches by calling onMismatch to fall back to data capture.
118691
- */
118692
- function createClosingMarkerParser(effects, onSuccess, onMismatch, onEof, jsonState) {
118693
- const handleMismatch = (code) => {
118694
- if (jsonState && code === codes_codes.quotationMark) {
118695
- jsonState.inString = true;
118696
- }
118697
- return onMismatch(code);
118698
- };
118699
- const expectSlash = (code) => {
118700
- if (code === null)
118701
- return onEof(code);
118702
- if (code !== codes_codes.slash)
118703
- return handleMismatch(code);
118704
- effects.consume(code);
118705
- return expectB;
118706
- };
118707
- const expectB = (code) => {
118708
- if (code === null)
118709
- return onEof(code);
118710
- if (code !== codes_codes.lowercaseB)
118711
- return handleMismatch(code);
118712
- effects.consume(code);
118713
- return expectL;
118714
- };
118715
- const expectL = (code) => {
118716
- if (code === null)
118717
- return onEof(code);
118718
- if (code !== codes_codes.lowercaseL)
118719
- return handleMismatch(code);
118720
- effects.consume(code);
118721
- return expectO;
118722
- };
118723
- const expectO = (code) => {
118724
- if (code === null)
118725
- return onEof(code);
118726
- if (code !== codes_codes.lowercaseO)
118727
- return handleMismatch(code);
118728
- effects.consume(code);
118729
- return expectC;
118730
- };
118731
- const expectC = (code) => {
118732
- if (code === null)
118733
- return onEof(code);
118734
- if (code !== codes_codes.lowercaseC)
118735
- return handleMismatch(code);
118736
- effects.consume(code);
118737
- return expectK;
118738
- };
118739
- const expectK = (code) => {
118740
- if (code === null)
118741
- return onEof(code);
118742
- if (code !== codes_codes.lowercaseK)
118743
- return handleMismatch(code);
118744
- effects.consume(code);
118745
- return expectBracket;
118746
- };
118747
- const expectBracket = (code) => {
118748
- if (code === null)
118749
- return onEof(code);
118750
- if (code !== codes_codes.rightSquareBracket)
118751
- return handleMismatch(code);
118752
- effects.consume(code);
118753
- return onSuccess;
118754
- };
118755
- return { expectSlash };
118756
- }
118757
- /**
118758
- * Partial construct for checking non-lazy continuation.
118759
- * This is used by the flow tokenizer to check if we can continue
118760
- * parsing on the next line.
118761
- */
118762
- const syntax_nonLazyContinuation = {
118763
- partial: true,
118764
- tokenize: syntax_tokenizeNonLazyContinuation,
118765
- };
118766
- /**
118767
- * Tokenizer for non-lazy continuation checking.
118768
- * Returns ok if the next line is non-lazy (can continue), nok if lazy.
118769
- */
118770
- function syntax_tokenizeNonLazyContinuation(effects, ok, nok) {
118771
- const lineStart = (code) => {
118772
- // `this` here refers to the micromark parser
118773
- // since we are just passing functions as references and not actually calling them
118774
- // micromarks's internal parser will call this automatically with appropriate arguments
118775
- return this.parser.lazy[this.now().line] ? nok(code) : ok(code);
118776
- };
118777
- const start = (code) => {
118778
- if (code === null) {
118779
- return nok(code);
118780
- }
118781
- if (!markdownLineEnding(code)) {
118782
- return nok(code);
118783
- }
118784
- effects.enter('magicBlockLineEnding');
118785
- effects.consume(code);
118786
- effects.exit('magicBlockLineEnding');
118787
- return lineStart;
118788
- };
118789
- return start;
118790
- }
118664
+ ;// ./node_modules/micromark-util-symbol/lib/types.js
118791
118665
  /**
118792
- * Create a micromark extension for magic block syntax.
118793
- *
118794
- * This extension handles both single-line and multiline magic blocks:
118795
- * - Flow construct (concrete): Handles block-level multiline magic blocks at document level
118796
- * - Text construct: Handles inline magic blocks in lists, paragraphs, etc.
118666
+ * This module is compiled away!
118797
118667
  *
118798
- * The flow construct is marked as "concrete" which prevents it from being
118799
- * interrupted by container markers (like `>` for blockquotes or `-` for lists).
118800
- */
118801
- function syntax_magicBlock() {
118802
- return {
118803
- // Flow construct - handles block-level magic blocks at document root
118804
- // Marked as concrete to prevent interruption by containers
118805
- flow: {
118806
- [codes_codes.leftSquareBracket]: {
118807
- name: 'magicBlock',
118808
- concrete: true,
118809
- tokenize: tokenizeMagicBlockFlow,
118810
- },
118811
- },
118812
- // Text construct - handles magic blocks in inline contexts (lists, paragraphs)
118813
- text: {
118814
- [codes_codes.leftSquareBracket]: {
118815
- name: 'magicBlock',
118816
- tokenize: tokenizeMagicBlockText,
118817
- },
118818
- },
118819
- };
118820
- }
118821
- /**
118822
- * Flow tokenizer for block-level magic blocks (multiline).
118823
- * Uses the continuation checking pattern from code fences.
118824
- */
118825
- function tokenizeMagicBlockFlow(effects, ok, nok) {
118826
- // State for tracking JSON content
118827
- const jsonState = { escapeNext: false, inString: false };
118828
- const blockTypeRef = { value: '' };
118829
- let seenOpenBrace = false;
118830
- // Create shared parsers for opening marker and type capture
118831
- const typeParser = createTypeCaptureParser(effects, nok, beforeData, blockTypeRef);
118832
- const openingMarkerParser = createOpeningMarkerParser(effects, nok, typeParser.first);
118833
- return start;
118834
- function start(code) {
118835
- if (code !== codes_codes.leftSquareBracket)
118836
- return nok(code);
118837
- effects.enter('magicBlock');
118838
- effects.enter('magicBlockMarkerStart');
118839
- effects.consume(code);
118840
- return openingMarkerParser;
118841
- }
118842
- /**
118843
- * State before data content - handles line endings or starts data capture.
118844
- */
118845
- function beforeData(code) {
118846
- // EOF - magic block must be closed
118847
- if (code === null) {
118848
- effects.exit('magicBlock');
118849
- return nok(code);
118850
- }
118851
- // Line ending before any data - check continuation
118852
- if (markdownLineEnding(code)) {
118853
- return effects.check(syntax_nonLazyContinuation, continuationOkBeforeData, after)(code);
118854
- }
118855
- // Check for closing marker directly (without entering data)
118856
- // This handles cases like [block:type]\n{}\n\n[/block] where there are
118857
- // newlines after the data object
118858
- if (code === codes_codes.leftSquareBracket) {
118859
- effects.enter('magicBlockMarkerEnd');
118860
- effects.consume(code);
118861
- return expectSlashFromContinuation;
118862
- }
118863
- // If we've already seen the opening brace, just continue capturing data
118864
- if (seenOpenBrace) {
118865
- effects.enter('magicBlockData');
118866
- return captureData(code);
118867
- }
118868
- // Skip whitespace (spaces/tabs) before the data - stay in beforeData
118869
- // Don't enter magicBlockData token yet until we confirm there's a '{'
118870
- if (code === codes_codes.space || code === codes_codes.horizontalTab) {
118871
- return beforeDataWhitespace(code);
118872
- }
118873
- // Data must start with '{' for valid JSON
118874
- if (code !== codes_codes.leftCurlyBrace) {
118875
- effects.exit('magicBlock');
118876
- return nok(code);
118877
- }
118878
- // We have '{' - enter data token and start capturing
118879
- seenOpenBrace = true;
118880
- effects.enter('magicBlockData');
118881
- return captureData(code);
118882
- }
118883
- /**
118884
- * Consume whitespace before the data without creating a token.
118885
- * Uses a temporary token to satisfy micromark's requirement.
118886
- */
118887
- function beforeDataWhitespace(code) {
118888
- if (code === null) {
118889
- effects.exit('magicBlock');
118890
- return nok(code);
118891
- }
118892
- if (markdownLineEnding(code)) {
118893
- return effects.check(syntax_nonLazyContinuation, continuationOkBeforeData, after)(code);
118894
- }
118895
- if (code === codes_codes.space || code === codes_codes.horizontalTab) {
118896
- // We need to consume this but can't without a token - use magicBlockData
118897
- // and track that we haven't seen '{' yet
118898
- effects.enter('magicBlockData');
118899
- effects.consume(code);
118900
- return beforeDataWhitespaceContinue;
118901
- }
118902
- if (code === codes_codes.leftCurlyBrace) {
118903
- seenOpenBrace = true;
118904
- effects.enter('magicBlockData');
118905
- return captureData(code);
118906
- }
118907
- effects.exit('magicBlock');
118908
- return nok(code);
118909
- }
118910
- /**
118911
- * Continue consuming whitespace or validate the opening brace.
118912
- */
118913
- function beforeDataWhitespaceContinue(code) {
118914
- if (code === null) {
118915
- effects.exit('magicBlockData');
118916
- effects.exit('magicBlock');
118917
- return nok(code);
118918
- }
118919
- if (markdownLineEnding(code)) {
118920
- effects.exit('magicBlockData');
118921
- return effects.check(syntax_nonLazyContinuation, continuationOk, after)(code);
118922
- }
118923
- if (code === codes_codes.space || code === codes_codes.horizontalTab) {
118924
- effects.consume(code);
118925
- return beforeDataWhitespaceContinue;
118926
- }
118927
- if (code === codes_codes.leftCurlyBrace) {
118928
- seenOpenBrace = true;
118929
- return captureData(code);
118930
- }
118931
- effects.exit('magicBlockData');
118932
- effects.exit('magicBlock');
118933
- return nok(code);
118934
- }
118935
- /**
118936
- * Continuation OK before we've entered data token.
118937
- */
118938
- function continuationOkBeforeData(code) {
118939
- effects.enter('magicBlockLineEnding');
118940
- effects.consume(code);
118941
- effects.exit('magicBlockLineEnding');
118942
- return beforeData; // Stay in beforeData state - don't enter magicBlockData yet
118943
- }
118944
- function captureData(code) {
118945
- // EOF - magic block must be closed
118946
- if (code === null) {
118947
- effects.exit('magicBlockData');
118948
- effects.exit('magicBlock');
118949
- return nok(code);
118950
- }
118951
- // At line ending, check if we can continue on the next line
118952
- if (markdownLineEnding(code)) {
118953
- effects.exit('magicBlockData');
118954
- return effects.check(syntax_nonLazyContinuation, continuationOk, after)(code);
118955
- }
118956
- if (jsonState.escapeNext) {
118957
- jsonState.escapeNext = false;
118958
- effects.consume(code);
118959
- return captureData;
118960
- }
118961
- if (jsonState.inString) {
118962
- if (code === codes_codes.backslash) {
118963
- jsonState.escapeNext = true;
118964
- effects.consume(code);
118965
- return captureData;
118966
- }
118967
- if (code === codes_codes.quotationMark) {
118968
- jsonState.inString = false;
118969
- }
118970
- effects.consume(code);
118971
- return captureData;
118972
- }
118973
- if (code === codes_codes.quotationMark) {
118974
- jsonState.inString = true;
118975
- effects.consume(code);
118976
- return captureData;
118977
- }
118978
- if (code === codes_codes.leftSquareBracket) {
118979
- effects.exit('magicBlockData');
118980
- effects.enter('magicBlockMarkerEnd');
118981
- effects.consume(code);
118982
- return expectSlash;
118983
- }
118984
- effects.consume(code);
118985
- return captureData;
118986
- }
118987
- /**
118988
- * Called when non-lazy continuation check passes - we can continue parsing.
118989
- */
118990
- function continuationOk(code) {
118991
- // Consume the line ending
118992
- effects.enter('magicBlockLineEnding');
118993
- effects.consume(code);
118994
- effects.exit('magicBlockLineEnding');
118995
- return continuationStart;
118996
- }
118997
- /**
118998
- * Start of continuation line - check for more line endings, closing marker, or start capturing data.
118999
- */
119000
- function continuationStart(code) {
119001
- // Handle consecutive line endings
119002
- if (code === null) {
119003
- effects.exit('magicBlock');
119004
- return nok(code);
119005
- }
119006
- if (markdownLineEnding(code)) {
119007
- return effects.check(syntax_nonLazyContinuation, continuationOkBeforeData, after)(code);
119008
- }
119009
- // Check if this is the start of the closing marker [/block]
119010
- // If so, handle it directly without entering magicBlockData
119011
- if (code === codes_codes.leftSquareBracket) {
119012
- effects.enter('magicBlockMarkerEnd');
119013
- effects.consume(code);
119014
- return expectSlashFromContinuation;
119015
- }
119016
- effects.enter('magicBlockData');
119017
- return captureData(code);
119018
- }
119019
- /**
119020
- * Check for closing marker slash when coming from continuation.
119021
- * If not a closing marker, create an empty data token and continue.
119022
- */
119023
- function expectSlashFromContinuation(code) {
119024
- if (code === null) {
119025
- effects.exit('magicBlockMarkerEnd');
119026
- effects.exit('magicBlock');
119027
- return nok(code);
119028
- }
119029
- if (markdownLineEnding(code)) {
119030
- effects.exit('magicBlockMarkerEnd');
119031
- return effects.check(syntax_nonLazyContinuation, continuationOkBeforeData, after)(code);
119032
- }
119033
- if (code === codes_codes.slash) {
119034
- effects.consume(code);
119035
- return expectClosingB;
119036
- }
119037
- // Not a closing marker - this is data content
119038
- // Exit marker and enter data
119039
- effects.exit('magicBlockMarkerEnd');
119040
- effects.enter('magicBlockData');
119041
- // The [ was consumed by the marker, so we need to conceptually "have it" in our data
119042
- // But since we already consumed it into the marker, we need a different approach
119043
- // Re-classify: consume this character as data and continue
119044
- if (code === codes_codes.quotationMark)
119045
- jsonState.inString = true;
119046
- effects.consume(code);
119047
- return captureData;
119048
- }
119049
- function expectSlash(code) {
119050
- if (code === null) {
119051
- effects.exit('magicBlockMarkerEnd');
119052
- effects.exit('magicBlock');
119053
- return nok(code);
119054
- }
119055
- // At line ending during marker parsing
119056
- if (markdownLineEnding(code)) {
119057
- effects.exit('magicBlockMarkerEnd');
119058
- return effects.check(syntax_nonLazyContinuation, continuationOk, after)(code);
119059
- }
119060
- if (code !== codes_codes.slash) {
119061
- effects.exit('magicBlockMarkerEnd');
119062
- effects.enter('magicBlockData');
119063
- if (code === codes_codes.quotationMark)
119064
- jsonState.inString = true;
119065
- effects.consume(code);
119066
- return captureData;
119067
- }
119068
- effects.consume(code);
119069
- return expectClosingB;
119070
- }
119071
- function expectClosingB(code) {
119072
- if (code === null) {
119073
- effects.exit('magicBlockMarkerEnd');
119074
- effects.exit('magicBlock');
119075
- return nok(code);
119076
- }
119077
- if (code !== codes_codes.lowercaseB) {
119078
- effects.exit('magicBlockMarkerEnd');
119079
- effects.enter('magicBlockData');
119080
- if (code === codes_codes.quotationMark)
119081
- jsonState.inString = true;
119082
- effects.consume(code);
119083
- return captureData;
119084
- }
119085
- effects.consume(code);
119086
- return expectClosingL;
119087
- }
119088
- function expectClosingL(code) {
119089
- if (code === null) {
119090
- effects.exit('magicBlockMarkerEnd');
119091
- effects.exit('magicBlock');
119092
- return nok(code);
119093
- }
119094
- if (code !== codes_codes.lowercaseL) {
119095
- effects.exit('magicBlockMarkerEnd');
119096
- effects.enter('magicBlockData');
119097
- if (code === codes_codes.quotationMark)
119098
- jsonState.inString = true;
119099
- effects.consume(code);
119100
- return captureData;
119101
- }
119102
- effects.consume(code);
119103
- return expectClosingO;
119104
- }
119105
- function expectClosingO(code) {
119106
- if (code === null) {
119107
- effects.exit('magicBlockMarkerEnd');
119108
- effects.exit('magicBlock');
119109
- return nok(code);
119110
- }
119111
- if (code !== codes_codes.lowercaseO) {
119112
- effects.exit('magicBlockMarkerEnd');
119113
- effects.enter('magicBlockData');
119114
- if (code === codes_codes.quotationMark)
119115
- jsonState.inString = true;
119116
- effects.consume(code);
119117
- return captureData;
119118
- }
119119
- effects.consume(code);
119120
- return expectClosingC;
119121
- }
119122
- function expectClosingC(code) {
119123
- if (code === null) {
119124
- effects.exit('magicBlockMarkerEnd');
119125
- effects.exit('magicBlock');
119126
- return nok(code);
119127
- }
119128
- if (code !== codes_codes.lowercaseC) {
119129
- effects.exit('magicBlockMarkerEnd');
119130
- effects.enter('magicBlockData');
119131
- if (code === codes_codes.quotationMark)
119132
- jsonState.inString = true;
119133
- effects.consume(code);
119134
- return captureData;
119135
- }
119136
- effects.consume(code);
119137
- return expectClosingK;
119138
- }
119139
- function expectClosingK(code) {
119140
- if (code === null) {
119141
- effects.exit('magicBlockMarkerEnd');
119142
- effects.exit('magicBlock');
119143
- return nok(code);
119144
- }
119145
- if (code !== codes_codes.lowercaseK) {
119146
- effects.exit('magicBlockMarkerEnd');
119147
- effects.enter('magicBlockData');
119148
- if (code === codes_codes.quotationMark)
119149
- jsonState.inString = true;
119150
- effects.consume(code);
119151
- return captureData;
119152
- }
119153
- effects.consume(code);
119154
- return expectClosingBracket;
119155
- }
119156
- function expectClosingBracket(code) {
119157
- if (code === null) {
119158
- effects.exit('magicBlockMarkerEnd');
119159
- effects.exit('magicBlock');
119160
- return nok(code);
119161
- }
119162
- if (code !== codes_codes.rightSquareBracket) {
119163
- effects.exit('magicBlockMarkerEnd');
119164
- effects.enter('magicBlockData');
119165
- if (code === codes_codes.quotationMark)
119166
- jsonState.inString = true;
119167
- effects.consume(code);
119168
- return captureData;
119169
- }
119170
- effects.consume(code);
119171
- effects.exit('magicBlockMarkerEnd');
119172
- // Check for trailing whitespace on the same line
119173
- return consumeTrailing;
119174
- }
119175
- /**
119176
- * Consume trailing whitespace (spaces/tabs) on the same line after [/block].
119177
- * For concrete flow constructs, we must end at eol/eof or fail.
119178
- * Trailing whitespace is consumed; other content causes nok (text tokenizer handles it).
119179
- */
119180
- function consumeTrailing(code) {
119181
- // End of file - done
119182
- if (code === null) {
119183
- effects.exit('magicBlock');
119184
- return ok(code);
119185
- }
119186
- // Line ending - done
119187
- if (markdownLineEnding(code)) {
119188
- effects.exit('magicBlock');
119189
- return ok(code);
119190
- }
119191
- // Space or tab - consume as trailing whitespace
119192
- if (code === codes_codes.space || code === codes_codes.horizontalTab) {
119193
- effects.enter('magicBlockTrailing');
119194
- effects.consume(code);
119195
- return consumeTrailingContinue;
119196
- }
119197
- // Any other character - fail flow tokenizer, let text tokenizer handle it
119198
- effects.exit('magicBlock');
119199
- return nok(code);
119200
- }
119201
- /**
119202
- * Continue consuming trailing whitespace.
119203
- */
119204
- function consumeTrailingContinue(code) {
119205
- // End of file - done
119206
- if (code === null) {
119207
- effects.exit('magicBlockTrailing');
119208
- effects.exit('magicBlock');
119209
- return ok(code);
119210
- }
119211
- // Line ending - done
119212
- if (markdownLineEnding(code)) {
119213
- effects.exit('magicBlockTrailing');
119214
- effects.exit('magicBlock');
119215
- return ok(code);
119216
- }
119217
- // More space or tab - keep consuming
119218
- if (code === codes_codes.space || code === codes_codes.horizontalTab) {
119219
- effects.consume(code);
119220
- return consumeTrailingContinue;
119221
- }
119222
- // Non-whitespace after whitespace - fail flow tokenizer
119223
- effects.exit('magicBlockTrailing');
119224
- effects.exit('magicBlock');
119225
- return nok(code);
119226
- }
119227
- /**
119228
- * Called when we can't continue (lazy line or EOF) - exit the construct.
119229
- */
119230
- function after(code) {
119231
- effects.exit('magicBlock');
119232
- return nok(code);
119233
- }
119234
- }
119235
- /**
119236
- * Text tokenizer for single-line magic blocks only.
119237
- * Used in inline contexts like list items and paragraphs.
119238
- * Multiline blocks are handled by the flow tokenizer.
119239
- */
119240
- function tokenizeMagicBlockText(effects, ok, nok) {
119241
- // State for tracking JSON content
119242
- const jsonState = { escapeNext: false, inString: false };
119243
- const blockTypeRef = { value: '' };
119244
- let seenOpenBrace = false;
119245
- // Create shared parsers for opening marker and type capture
119246
- const typeParser = createTypeCaptureParser(effects, nok, beforeData, blockTypeRef);
119247
- const openingMarkerParser = createOpeningMarkerParser(effects, nok, typeParser.first);
119248
- // Success handler for closing marker - exits tokens and returns ok
119249
- const closingSuccess = (code) => {
119250
- effects.exit('magicBlockMarkerEnd');
119251
- effects.exit('magicBlock');
119252
- return ok(code);
119253
- };
119254
- // Mismatch handler - falls back to data capture
119255
- const closingMismatch = (code) => {
119256
- effects.exit('magicBlockMarkerEnd');
119257
- effects.enter('magicBlockData');
119258
- if (code === codes_codes.quotationMark)
119259
- jsonState.inString = true;
119260
- effects.consume(code);
119261
- return captureData;
119262
- };
119263
- // EOF handler
119264
- const closingEof = (_code) => nok(_code);
119265
- // Create closing marker parsers
119266
- const closingFromBeforeData = createClosingMarkerParser(effects, closingSuccess, closingMismatch, closingEof, jsonState);
119267
- const closingFromData = createClosingMarkerParser(effects, closingSuccess, closingMismatch, closingEof, jsonState);
119268
- return start;
119269
- function start(code) {
119270
- if (code !== codes_codes.leftSquareBracket)
119271
- return nok(code);
119272
- effects.enter('magicBlock');
119273
- effects.enter('magicBlockMarkerStart');
119274
- effects.consume(code);
119275
- return openingMarkerParser;
119276
- }
119277
- /**
119278
- * State before data content - handles line endings before entering data token.
119279
- * Whitespace before '{' is allowed.
119280
- */
119281
- function beforeData(code) {
119282
- // Fail on EOF - magic block must be closed
119283
- if (code === null) {
119284
- return nok(code);
119285
- }
119286
- // Handle line endings before any data - consume them without entering data token
119287
- if (markdownLineEnding(code)) {
119288
- effects.enter('magicBlockLineEnding');
119289
- effects.consume(code);
119290
- effects.exit('magicBlockLineEnding');
119291
- return beforeData;
119292
- }
119293
- // Check for closing marker directly (without entering data)
119294
- if (code === codes_codes.leftSquareBracket) {
119295
- effects.enter('magicBlockMarkerEnd');
119296
- effects.consume(code);
119297
- return closingFromBeforeData.expectSlash;
119298
- }
119299
- // If we've already seen the opening brace, just continue capturing data
119300
- if (seenOpenBrace) {
119301
- effects.enter('magicBlockData');
119302
- return captureData(code);
119303
- }
119304
- // Skip whitespace (spaces/tabs) before the data
119305
- if (code === codes_codes.space || code === codes_codes.horizontalTab) {
119306
- return beforeDataWhitespace(code);
119307
- }
119308
- // Data must start with '{' for valid JSON
119309
- if (code !== codes_codes.leftCurlyBrace) {
119310
- return nok(code);
119311
- }
119312
- // We have '{' - enter data token and start capturing
119313
- seenOpenBrace = true;
119314
- effects.enter('magicBlockData');
119315
- return captureData(code);
119316
- }
119317
- /**
119318
- * Consume whitespace before the data.
119319
- */
119320
- function beforeDataWhitespace(code) {
119321
- if (code === null) {
119322
- return nok(code);
119323
- }
119324
- if (markdownLineEnding(code)) {
119325
- effects.enter('magicBlockLineEnding');
119326
- effects.consume(code);
119327
- effects.exit('magicBlockLineEnding');
119328
- return beforeData;
119329
- }
119330
- if (code === codes_codes.space || code === codes_codes.horizontalTab) {
119331
- effects.enter('magicBlockData');
119332
- effects.consume(code);
119333
- return beforeDataWhitespaceContinue;
119334
- }
119335
- if (code === codes_codes.leftCurlyBrace) {
119336
- seenOpenBrace = true;
119337
- effects.enter('magicBlockData');
119338
- return captureData(code);
119339
- }
119340
- return nok(code);
119341
- }
119342
- /**
119343
- * Continue consuming whitespace or validate the opening brace.
119344
- */
119345
- function beforeDataWhitespaceContinue(code) {
119346
- if (code === null) {
119347
- effects.exit('magicBlockData');
119348
- return nok(code);
119349
- }
119350
- if (markdownLineEnding(code)) {
119351
- effects.exit('magicBlockData');
119352
- effects.enter('magicBlockLineEnding');
119353
- effects.consume(code);
119354
- effects.exit('magicBlockLineEnding');
119355
- return beforeData;
119356
- }
119357
- if (code === codes_codes.space || code === codes_codes.horizontalTab) {
119358
- effects.consume(code);
119359
- return beforeDataWhitespaceContinue;
119360
- }
119361
- if (code === codes_codes.leftCurlyBrace) {
119362
- seenOpenBrace = true;
119363
- return captureData(code);
119364
- }
119365
- effects.exit('magicBlockData');
119366
- return nok(code);
119367
- }
119368
- function captureData(code) {
119369
- // Fail on EOF - magic block must be closed
119370
- if (code === null) {
119371
- effects.exit('magicBlockData');
119372
- return nok(code);
119373
- }
119374
- // Handle multiline magic blocks within text/paragraphs
119375
- // Exit data, consume line ending with proper token, then re-enter data
119376
- if (markdownLineEnding(code)) {
119377
- effects.exit('magicBlockData');
119378
- effects.enter('magicBlockLineEnding');
119379
- effects.consume(code);
119380
- effects.exit('magicBlockLineEnding');
119381
- return beforeData; // Go back to beforeData to handle potential empty lines
119382
- }
119383
- if (jsonState.escapeNext) {
119384
- jsonState.escapeNext = false;
119385
- effects.consume(code);
119386
- return captureData;
119387
- }
119388
- if (jsonState.inString) {
119389
- if (code === codes_codes.backslash) {
119390
- jsonState.escapeNext = true;
119391
- effects.consume(code);
119392
- return captureData;
119393
- }
119394
- if (code === codes_codes.quotationMark) {
119395
- jsonState.inString = false;
119396
- }
119397
- effects.consume(code);
119398
- return captureData;
119399
- }
119400
- if (code === codes_codes.quotationMark) {
119401
- jsonState.inString = true;
119402
- effects.consume(code);
119403
- return captureData;
119404
- }
119405
- if (code === codes_codes.leftSquareBracket) {
119406
- effects.exit('magicBlockData');
119407
- effects.enter('magicBlockMarkerEnd');
119408
- effects.consume(code);
119409
- return closingFromData.expectSlash;
119410
- }
119411
- effects.consume(code);
119412
- return captureData;
119413
- }
119414
- }
119415
- /* harmony default export */ const syntax = ((/* unused pure expression or super */ null && (syntax_magicBlock)));
119416
-
119417
- ;// ./lib/micromark/magic-block/index.ts
119418
- /**
119419
- * Micromark extension for magic block syntax.
119420
- *
119421
- * Usage:
119422
- * ```ts
119423
- * import { magicBlock } from './lib/micromark/magic-block';
119424
- *
119425
- * const processor = unified()
119426
- * .data('micromarkExtensions', [magicBlock()])
119427
- * ```
119428
- */
119429
-
119430
-
119431
- ;// ./node_modules/micromark-util-symbol/lib/types.js
119432
- /**
119433
- * This module is compiled away!
119434
- *
119435
- * Here is the list of all types of tokens exposed by micromark, with a short
119436
- * explanation of what they include and where they are found.
119437
- * In picking names, generally, the rule is to be as explicit as possible
119438
- * instead of reusing names.
119439
- * For example, there is a `definitionDestination` and a `resourceDestination`,
119440
- * instead of one shared name.
118668
+ * Here is the list of all types of tokens exposed by micromark, with a short
118669
+ * explanation of what they include and where they are found.
118670
+ * In picking names, generally, the rule is to be as explicit as possible
118671
+ * instead of reusing names.
118672
+ * For example, there is a `definitionDestination` and a `resourceDestination`,
118673
+ * instead of one shared name.
119441
118674
  */
119442
118675
 
119443
118676
  // Note: when changing the next record, you must also change `TokenTypeMap`
@@ -119883,36 +119116,18 @@ const types_types = /** @type {const} */ ({
119883
119116
  chunkString: 'chunkString'
119884
119117
  })
119885
119118
 
119886
- ;// ./lib/micromark/mdx-component/syntax.ts
119887
-
119888
-
119889
-
119119
+ ;// ./lib/micromark/jsx-table/syntax.ts
119890
119120
 
119891
119121
 
119892
- // Raw tags (type-1: pre/script/style/textarea) and block tags (type-6: div,
119893
- // section, …) always start a block, so they stay flow even with trailing
119894
- // content. Other lowercase tags (i, span, …) follow the type-7 rule and only
119895
- // stay flow when nothing trails the close tag.
119896
- const htmlFlowTagNames = new Set([...htmlRawNames, ...htmlBlockNames]);
119897
- // Lowercase type-6 block tags claimable in flow even without a `{…}` attribute, so
119898
- // blank lines between nested JSX siblings don't fragment the block. Excludes table
119899
- // tags (mdxishTables owns their blank lines) and voids (never close).
119900
- const plainBlockClaimTagNames = new Set([...htmlBlockNames].filter(tag => !HTML_TABLE_STRUCTURE_TAGS.has(tag) && !HTML_VOID_ELEMENTS.has(tag)));
119901
119122
  const syntax_nonLazyContinuationStart = {
119902
119123
  tokenize: syntax_tokenizeNonLazyContinuationStart,
119903
119124
  partial: true,
119904
119125
  };
119905
- // Lookahead for `plainClaimLineStart`: is this line markup-only, or a paragraph
119906
- // that merely starts with a tag? Run via `effects.check` so it never consumes.
119907
- const markupOnlyContinuation = {
119908
- tokenize: tokenizeMarkupOnlyContinuation,
119909
- partial: true,
119910
- };
119911
- function resolveToMdxComponent(events) {
119126
+ function resolveToJsxTable(events) {
119912
119127
  let index = events.length;
119913
119128
  while (index > 0) {
119914
119129
  index -= 1;
119915
- if (events[index][0] === 'enter' && events[index][1].type === 'mdxComponent') {
119130
+ if (events[index][0] === 'enter' && events[index][1].type === 'jsxTable') {
119916
119131
  break;
119917
119132
  }
119918
119133
  }
@@ -119923,123 +119138,1229 @@ function resolveToMdxComponent(events) {
119923
119138
  }
119924
119139
  return events;
119925
119140
  }
119926
- const mdxComponentFlowConstruct = {
119927
- name: 'mdxComponent',
119928
- tokenize: createTokenize('flow'),
119929
- resolveTo: resolveToMdxComponent,
119141
+ const jsxTableConstruct = {
119142
+ name: 'jsxTable',
119143
+ tokenize: tokenizeJsxTable,
119144
+ resolveTo: resolveToJsxTable,
119930
119145
  concrete: true,
119931
119146
  };
119932
- const mdxComponentTextConstruct = {
119933
- name: 'mdxComponentText',
119934
- tokenize: createTokenize('text'),
119935
- };
119936
- /**
119937
- * Factory for both flow (block) and text (inline) variants.
119938
- *
119939
- * **Flow** — the original behavior: claims PascalCase components (always) and
119940
- * lowercase HTML tags that carry at least one `{…}` attribute expression.
119941
- * Multi-line, concrete, `afterClose` consumes the rest of the line.
119942
- *
119943
- * **Text** — runs inside paragraphs / inline context. Claims lowercase tags and
119944
- * inline PascalCase components (`INLINE_COMPONENT_TAGS` — Anchor, Glossary), both
119945
- * gated on at least one `{…}` brace attribute. All other PascalCase stays
119946
- * flow-only, matching how ReadMe's custom components are authored. Aborts on line
119947
- * endings (inline constructs don't span lines) and exits immediately after
119948
- * `</tag>` so the paragraph's inline parser picks up the trailing text.
119949
- */
119950
- function createTokenize(mode) {
119951
- const isFlow = mode === 'flow';
119952
- return function tokenize(effects, ok, nok) {
119953
- // eslint-disable-next-line @typescript-eslint/no-this-alias
119954
- const self = this;
119955
- let tagName = '';
119956
- let depth = 0;
119957
- let closingTagName = '';
119958
- // For lowercase tags we only want to claim the block if it uses JSX
119959
- // attribute expression syntax (`attr={...}`). Plain HTML should fall
119960
- // through to CommonMark html-flow. Flow mode claims any PascalCase block
119961
- // component; text mode claims only inline PascalCase components
119962
- // (INLINE_COMPONENT_TAGS — Anchor, Glossary), also brace-gated.
119963
- let isLowercaseTag = false;
119964
- let sawBraceAttr = false;
119965
- // A plain lowercase block tag claimed without a `{…}` attribute, gated by
119966
- // `plainClaimLineStart`: after a blank line it may only continue on a tag line.
119967
- let isPlainBlockClaim = false;
119968
- let pendingBlankLine = false;
119969
- // Code span tracking
119970
- let codeSpanOpenSize = 0;
119971
- let codeSpanCloseSize = 0;
119972
- // Fenced code block tracking
119973
- let fenceChar = null;
119974
- let fenceLength = 0;
119975
- let fenceCloseLength = 0;
119976
- let atLineStart = false;
119977
- // True once this construct consumes any line ending; lets `afterClose`
119978
- // treat only single-line lowercase tags as inline candidates.
119979
- let sawLineEnding = false;
119980
- // Bail when the opener line has unmatched tag-like tokens in its body.
119981
- // `<Foo>_<Bar>.csv` leaves opens > closes; matched shapes like
119982
- // `<Callout>x <strong>y</strong>` balance to 0. Without this,
119983
- // `concrete: true` causes orphan openers to eat sibling blockquotes.
119984
- let onOpenerLine = false;
119985
- let openerLineHasContent = false;
119986
- let openerLineOpens = 0;
119987
- let openerLineCloses = 0;
119988
- // Attribute parsing state
119989
- let quoteChar = null;
119990
- let braceDepth = 0;
119991
- let inTemplateLit = false; // true when inside a template literal (for line continuation)
119992
- // Stack of braceDepth values at each ${...} interpolation entry point.
119993
- // When a } brings braceDepth back to a saved value, we return to the
119994
- // template literal instead of continuing in the brace expression.
119995
- const templateStack = [];
119996
- const isAlpha = (code) => (code >= codes_codes.uppercaseA && code <= codes_codes.uppercaseZ) ||
119997
- (code >= codes_codes.lowercaseA && code <= codes_codes.lowercaseZ);
119998
- const isSameCaseAsTag = (code) => isLowercaseTag
119999
- ? code >= codes_codes.lowercaseA && code <= codes_codes.lowercaseZ
120000
- : code >= codes_codes.uppercaseA && code <= codes_codes.uppercaseZ;
120001
- // Shared brace-expression state machine. The two call sites differ only in where
120002
- // to continue after a line ending and where to return when braceDepth reaches zero.
120003
- function createBraceExprStates(continuationStart, afterBraceClose) {
120004
- function braceExpr(code) {
120005
- if (code === null)
120006
- return nok(code);
120007
- if (markdownLineEnding(code)) {
120008
- if (!isFlow)
120009
- return nok(code);
120010
- effects.exit('mdxComponentData');
120011
- return continuationStart(code);
120012
- }
120013
- if (code === codes_codes.quotationMark || code === codes_codes.apostrophe) {
120014
- quoteChar = code;
120015
- effects.consume(code);
120016
- return braceString;
120017
- }
120018
- if (code === codes_codes.graveAccent) {
120019
- inTemplateLit = true;
120020
- effects.consume(code);
120021
- return braceTemplateLiteral;
120022
- }
120023
- if (code === codes_codes.leftCurlyBrace) {
120024
- braceDepth += 1;
120025
- effects.consume(code);
120026
- return braceExpr;
120027
- }
120028
- if (code === codes_codes.rightCurlyBrace) {
120029
- braceDepth -= 1;
120030
- effects.consume(code);
120031
- if (templateStack.length > 0 && braceDepth === templateStack[templateStack.length - 1]) {
120032
- templateStack.pop();
120033
- inTemplateLit = true;
120034
- return braceTemplateLiteral;
120035
- }
120036
- if (braceDepth === 0) {
120037
- return afterBraceClose;
120038
- }
120039
- return braceExpr;
120040
- }
119147
+ function tokenizeJsxTable(effects, ok, nok) {
119148
+ let codeSpanOpenSize = 0;
119149
+ let codeSpanCloseSize = 0;
119150
+ let depth = 1;
119151
+ const ABLE_SUFFIX = [codes.lowercaseA, codes.lowercaseB, codes.lowercaseL, codes.lowercaseE];
119152
+ /** Build a state chain that matches a sequence of character codes. */
119153
+ function matchChars(chars, onMatch, onFail) {
119154
+ if (chars.length === 0)
119155
+ return onMatch;
119156
+ return ((code) => {
119157
+ if (code === chars[0]) {
120041
119158
  effects.consume(code);
120042
- return braceExpr;
119159
+ return matchChars(chars.slice(1), onMatch, onFail);
119160
+ }
119161
+ return onFail(code);
119162
+ });
119163
+ }
119164
+ return start;
119165
+ function start(code) {
119166
+ if (code !== codes.lessThan)
119167
+ return nok(code);
119168
+ effects.enter('jsxTable');
119169
+ effects.enter('jsxTableData');
119170
+ effects.consume(code);
119171
+ return afterLessThan;
119172
+ }
119173
+ function afterLessThan(code) {
119174
+ if (code === codes.uppercaseT || code === codes.lowercaseT) {
119175
+ effects.consume(code);
119176
+ return matchChars(ABLE_SUFFIX, afterTagName, nok);
119177
+ }
119178
+ return nok(code);
119179
+ }
119180
+ function afterTagName(code) {
119181
+ if (code === codes.greaterThan || code === codes.slash || code === codes.space || code === codes.horizontalTab) {
119182
+ effects.consume(code);
119183
+ return body;
119184
+ }
119185
+ return nok(code);
119186
+ }
119187
+ function body(code) {
119188
+ // Reject unclosed <Table> so it falls back to normal HTML block parsing
119189
+ // instead of swallowing all subsequent content to EOF
119190
+ if (code === null) {
119191
+ return nok(code);
119192
+ }
119193
+ if (markdownLineEnding(code)) {
119194
+ effects.exit('jsxTableData');
119195
+ return continuationStart(code);
119196
+ }
119197
+ if (code === codes.backslash) {
119198
+ effects.consume(code);
119199
+ return escapedChar;
119200
+ }
119201
+ if (code === codes.lessThan) {
119202
+ effects.consume(code);
119203
+ return closeSlash;
119204
+ }
119205
+ // Skip over backtick code spans so `</Table>` in inline code isn't
119206
+ // treated as the closing tag
119207
+ if (code === codes.graveAccent) {
119208
+ codeSpanOpenSize = 0;
119209
+ return countOpenTicks(code);
119210
+ }
119211
+ effects.consume(code);
119212
+ return body;
119213
+ }
119214
+ function countOpenTicks(code) {
119215
+ if (code === codes.graveAccent) {
119216
+ codeSpanOpenSize += 1;
119217
+ effects.consume(code);
119218
+ return countOpenTicks;
119219
+ }
119220
+ return inCodeSpan(code);
119221
+ }
119222
+ function inCodeSpan(code) {
119223
+ if (code === null || markdownLineEnding(code))
119224
+ return body(code);
119225
+ if (code === codes.graveAccent) {
119226
+ codeSpanCloseSize = 0;
119227
+ return countCloseTicks(code);
119228
+ }
119229
+ effects.consume(code);
119230
+ return inCodeSpan;
119231
+ }
119232
+ function countCloseTicks(code) {
119233
+ if (code === codes.graveAccent) {
119234
+ codeSpanCloseSize += 1;
119235
+ effects.consume(code);
119236
+ return countCloseTicks;
119237
+ }
119238
+ return codeSpanCloseSize === codeSpanOpenSize ? body(code) : inCodeSpan(code);
119239
+ }
119240
+ function escapedChar(code) {
119241
+ if (code === null || markdownLineEnding(code)) {
119242
+ return body(code);
119243
+ }
119244
+ effects.consume(code);
119245
+ return body;
119246
+ }
119247
+ function closeSlash(code) {
119248
+ if (code === codes.slash) {
119249
+ effects.consume(code);
119250
+ return closeTagFirstChar;
119251
+ }
119252
+ if (code === codes.uppercaseT || code === codes.lowercaseT) {
119253
+ effects.consume(code);
119254
+ return matchChars(ABLE_SUFFIX, openAfterTagName, body);
119255
+ }
119256
+ return body(code);
119257
+ }
119258
+ function closeTagFirstChar(code) {
119259
+ if (code === codes.uppercaseT || code === codes.lowercaseT) {
119260
+ effects.consume(code);
119261
+ return matchChars(ABLE_SUFFIX, closeGt, body);
119262
+ }
119263
+ return body(code);
119264
+ }
119265
+ function openAfterTagName(code) {
119266
+ if (code === codes.greaterThan || code === codes.slash || code === codes.space || code === codes.horizontalTab) {
119267
+ depth += 1;
119268
+ effects.consume(code);
119269
+ return body;
119270
+ }
119271
+ return body(code);
119272
+ }
119273
+ function closeGt(code) {
119274
+ if (code === codes.greaterThan) {
119275
+ depth -= 1;
119276
+ effects.consume(code);
119277
+ if (depth === 0) {
119278
+ return afterClose;
119279
+ }
119280
+ return body;
119281
+ }
119282
+ return body(code);
119283
+ }
119284
+ function afterClose(code) {
119285
+ if (code === null || markdownLineEnding(code)) {
119286
+ effects.exit('jsxTableData');
119287
+ effects.exit('jsxTable');
119288
+ return ok(code);
119289
+ }
119290
+ effects.consume(code);
119291
+ return afterClose;
119292
+ }
119293
+ // Line ending handling — follows the htmlFlow pattern
119294
+ function continuationStart(code) {
119295
+ return effects.check(syntax_nonLazyContinuationStart, continuationStartNonLazy, continuationAfter)(code);
119296
+ }
119297
+ function continuationStartNonLazy(code) {
119298
+ effects.enter(types_types.lineEnding);
119299
+ effects.consume(code);
119300
+ effects.exit(types_types.lineEnding);
119301
+ return continuationBefore;
119302
+ }
119303
+ function continuationBefore(code) {
119304
+ if (code === null || markdownLineEnding(code)) {
119305
+ return continuationStart(code);
119306
+ }
119307
+ effects.enter('jsxTableData');
119308
+ return body(code);
119309
+ }
119310
+ function continuationAfter(code) {
119311
+ // At EOF without </Table>, reject so content isn't swallowed
119312
+ if (code === null) {
119313
+ return nok(code);
119314
+ }
119315
+ effects.exit('jsxTable');
119316
+ return ok(code);
119317
+ }
119318
+ }
119319
+ function syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
119320
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
119321
+ const self = this;
119322
+ return start;
119323
+ function start(code) {
119324
+ if (markdownLineEnding(code)) {
119325
+ effects.enter(types_types.lineEnding);
119326
+ effects.consume(code);
119327
+ effects.exit(types_types.lineEnding);
119328
+ return after;
119329
+ }
119330
+ return nok(code);
119331
+ }
119332
+ function after(code) {
119333
+ if (self.parser.lazy[self.now().line]) {
119334
+ return nok(code);
119335
+ }
119336
+ return ok(code);
119337
+ }
119338
+ }
119339
+ /**
119340
+ * Micromark extension that tokenizes `<Table>...</Table>` and `<table>...</table>`
119341
+ * as a single flow block.
119342
+ *
119343
+ * Prevents CommonMark HTML block type 6 from fragmenting table blocks at blank lines.
119344
+ */
119345
+ function syntax_jsxTable() {
119346
+ return {
119347
+ flow: {
119348
+ [codes.lessThan]: [jsxTableConstruct],
119349
+ },
119350
+ };
119351
+ }
119352
+
119353
+ ;// ./lib/micromark/jsx-table/index.ts
119354
+
119355
+
119356
+ ;// ./lib/micromark/magic-block/syntax.ts
119357
+
119358
+
119359
+ /**
119360
+ * Known magic block types that the tokenizer will recognize.
119361
+ * Unknown types will not be tokenized as magic blocks.
119362
+ */
119363
+ const KNOWN_BLOCK_TYPES = new Set([
119364
+ 'code',
119365
+ 'api-header',
119366
+ 'image',
119367
+ 'callout',
119368
+ 'parameters',
119369
+ 'table',
119370
+ 'embed',
119371
+ 'html',
119372
+ 'recipe',
119373
+ 'tutorial-tile',
119374
+ ]);
119375
+ /**
119376
+ * Check if a character is valid for a magic block type identifier.
119377
+ * Types can contain alphanumeric characters and hyphens (e.g., "api-header", "tutorial-tile")
119378
+ */
119379
+ function isTypeChar(code) {
119380
+ return asciiAlphanumeric(code) || code === codes.dash;
119381
+ }
119382
+ /**
119383
+ * Creates the opening marker state machine: [block:
119384
+ * Returns the first state function to start parsing.
119385
+ */
119386
+ function createOpeningMarkerParser(effects, nok, onComplete) {
119387
+ const expectB = (code) => {
119388
+ if (code !== codes.lowercaseB)
119389
+ return nok(code);
119390
+ effects.consume(code);
119391
+ return expectL;
119392
+ };
119393
+ const expectL = (code) => {
119394
+ if (code !== codes.lowercaseL)
119395
+ return nok(code);
119396
+ effects.consume(code);
119397
+ return expectO;
119398
+ };
119399
+ const expectO = (code) => {
119400
+ if (code !== codes.lowercaseO)
119401
+ return nok(code);
119402
+ effects.consume(code);
119403
+ return expectC;
119404
+ };
119405
+ const expectC = (code) => {
119406
+ if (code !== codes.lowercaseC)
119407
+ return nok(code);
119408
+ effects.consume(code);
119409
+ return expectK;
119410
+ };
119411
+ const expectK = (code) => {
119412
+ if (code !== codes.lowercaseK)
119413
+ return nok(code);
119414
+ effects.consume(code);
119415
+ return expectColon;
119416
+ };
119417
+ const expectColon = (code) => {
119418
+ if (code !== codes.colon)
119419
+ return nok(code);
119420
+ effects.consume(code);
119421
+ effects.exit('magicBlockMarkerStart');
119422
+ effects.enter('magicBlockType');
119423
+ return onComplete;
119424
+ };
119425
+ return expectB;
119426
+ }
119427
+ /**
119428
+ * Creates the type capture state machine.
119429
+ * Captures type characters until ] and validates against known types.
119430
+ */
119431
+ function createTypeCaptureParser(effects, nok, onComplete, blockTypeRef) {
119432
+ const captureTypeFirst = (code) => {
119433
+ // Reject empty type name [block:]
119434
+ if (code === codes.rightSquareBracket) {
119435
+ return nok(code);
119436
+ }
119437
+ if (isTypeChar(code)) {
119438
+ blockTypeRef.value += String.fromCharCode(code);
119439
+ effects.consume(code);
119440
+ return captureType;
119441
+ }
119442
+ return nok(code);
119443
+ };
119444
+ const captureType = (code) => {
119445
+ if (code === codes.rightSquareBracket) {
119446
+ if (!KNOWN_BLOCK_TYPES.has(blockTypeRef.value)) {
119447
+ return nok(code);
119448
+ }
119449
+ effects.exit('magicBlockType');
119450
+ effects.enter('magicBlockMarkerTypeEnd');
119451
+ effects.consume(code);
119452
+ effects.exit('magicBlockMarkerTypeEnd');
119453
+ return onComplete;
119454
+ }
119455
+ if (isTypeChar(code)) {
119456
+ blockTypeRef.value += String.fromCharCode(code);
119457
+ effects.consume(code);
119458
+ return captureType;
119459
+ }
119460
+ return nok(code);
119461
+ };
119462
+ return { first: captureTypeFirst, remaining: captureType };
119463
+ }
119464
+ /**
119465
+ * Creates the closing marker state machine: /block]
119466
+ * Handles partial matches by calling onMismatch to fall back to data capture.
119467
+ */
119468
+ function createClosingMarkerParser(effects, onSuccess, onMismatch, onEof, jsonState) {
119469
+ const handleMismatch = (code) => {
119470
+ if (jsonState && code === codes.quotationMark) {
119471
+ jsonState.inString = true;
119472
+ }
119473
+ return onMismatch(code);
119474
+ };
119475
+ const expectSlash = (code) => {
119476
+ if (code === null)
119477
+ return onEof(code);
119478
+ if (code !== codes.slash)
119479
+ return handleMismatch(code);
119480
+ effects.consume(code);
119481
+ return expectB;
119482
+ };
119483
+ const expectB = (code) => {
119484
+ if (code === null)
119485
+ return onEof(code);
119486
+ if (code !== codes.lowercaseB)
119487
+ return handleMismatch(code);
119488
+ effects.consume(code);
119489
+ return expectL;
119490
+ };
119491
+ const expectL = (code) => {
119492
+ if (code === null)
119493
+ return onEof(code);
119494
+ if (code !== codes.lowercaseL)
119495
+ return handleMismatch(code);
119496
+ effects.consume(code);
119497
+ return expectO;
119498
+ };
119499
+ const expectO = (code) => {
119500
+ if (code === null)
119501
+ return onEof(code);
119502
+ if (code !== codes.lowercaseO)
119503
+ return handleMismatch(code);
119504
+ effects.consume(code);
119505
+ return expectC;
119506
+ };
119507
+ const expectC = (code) => {
119508
+ if (code === null)
119509
+ return onEof(code);
119510
+ if (code !== codes.lowercaseC)
119511
+ return handleMismatch(code);
119512
+ effects.consume(code);
119513
+ return expectK;
119514
+ };
119515
+ const expectK = (code) => {
119516
+ if (code === null)
119517
+ return onEof(code);
119518
+ if (code !== codes.lowercaseK)
119519
+ return handleMismatch(code);
119520
+ effects.consume(code);
119521
+ return expectBracket;
119522
+ };
119523
+ const expectBracket = (code) => {
119524
+ if (code === null)
119525
+ return onEof(code);
119526
+ if (code !== codes.rightSquareBracket)
119527
+ return handleMismatch(code);
119528
+ effects.consume(code);
119529
+ return onSuccess;
119530
+ };
119531
+ return { expectSlash };
119532
+ }
119533
+ /**
119534
+ * Partial construct for checking non-lazy continuation.
119535
+ * This is used by the flow tokenizer to check if we can continue
119536
+ * parsing on the next line.
119537
+ */
119538
+ const syntax_nonLazyContinuation = {
119539
+ partial: true,
119540
+ tokenize: syntax_tokenizeNonLazyContinuation,
119541
+ };
119542
+ /**
119543
+ * Tokenizer for non-lazy continuation checking.
119544
+ * Returns ok if the next line is non-lazy (can continue), nok if lazy.
119545
+ */
119546
+ function syntax_tokenizeNonLazyContinuation(effects, ok, nok) {
119547
+ const lineStart = (code) => {
119548
+ // `this` here refers to the micromark parser
119549
+ // since we are just passing functions as references and not actually calling them
119550
+ // micromarks's internal parser will call this automatically with appropriate arguments
119551
+ return this.parser.lazy[this.now().line] ? nok(code) : ok(code);
119552
+ };
119553
+ const start = (code) => {
119554
+ if (code === null) {
119555
+ return nok(code);
119556
+ }
119557
+ if (!markdownLineEnding(code)) {
119558
+ return nok(code);
119559
+ }
119560
+ effects.enter('magicBlockLineEnding');
119561
+ effects.consume(code);
119562
+ effects.exit('magicBlockLineEnding');
119563
+ return lineStart;
119564
+ };
119565
+ return start;
119566
+ }
119567
+ /**
119568
+ * Create a micromark extension for magic block syntax.
119569
+ *
119570
+ * This extension handles both single-line and multiline magic blocks:
119571
+ * - Flow construct (concrete): Handles block-level multiline magic blocks at document level
119572
+ * - Text construct: Handles inline magic blocks in lists, paragraphs, etc.
119573
+ *
119574
+ * The flow construct is marked as "concrete" which prevents it from being
119575
+ * interrupted by container markers (like `>` for blockquotes or `-` for lists).
119576
+ */
119577
+ function syntax_magicBlock() {
119578
+ return {
119579
+ // Flow construct - handles block-level magic blocks at document root
119580
+ // Marked as concrete to prevent interruption by containers
119581
+ flow: {
119582
+ [codes.leftSquareBracket]: {
119583
+ name: 'magicBlock',
119584
+ concrete: true,
119585
+ tokenize: tokenizeMagicBlockFlow,
119586
+ },
119587
+ },
119588
+ // Text construct - handles magic blocks in inline contexts (lists, paragraphs)
119589
+ text: {
119590
+ [codes.leftSquareBracket]: {
119591
+ name: 'magicBlock',
119592
+ tokenize: tokenizeMagicBlockText,
119593
+ },
119594
+ },
119595
+ };
119596
+ }
119597
+ /**
119598
+ * Flow tokenizer for block-level magic blocks (multiline).
119599
+ * Uses the continuation checking pattern from code fences.
119600
+ */
119601
+ function tokenizeMagicBlockFlow(effects, ok, nok) {
119602
+ // State for tracking JSON content
119603
+ const jsonState = { escapeNext: false, inString: false };
119604
+ const blockTypeRef = { value: '' };
119605
+ let seenOpenBrace = false;
119606
+ // Create shared parsers for opening marker and type capture
119607
+ const typeParser = createTypeCaptureParser(effects, nok, beforeData, blockTypeRef);
119608
+ const openingMarkerParser = createOpeningMarkerParser(effects, nok, typeParser.first);
119609
+ return start;
119610
+ function start(code) {
119611
+ if (code !== codes.leftSquareBracket)
119612
+ return nok(code);
119613
+ effects.enter('magicBlock');
119614
+ effects.enter('magicBlockMarkerStart');
119615
+ effects.consume(code);
119616
+ return openingMarkerParser;
119617
+ }
119618
+ /**
119619
+ * State before data content - handles line endings or starts data capture.
119620
+ */
119621
+ function beforeData(code) {
119622
+ // EOF - magic block must be closed
119623
+ if (code === null) {
119624
+ effects.exit('magicBlock');
119625
+ return nok(code);
119626
+ }
119627
+ // Line ending before any data - check continuation
119628
+ if (markdownLineEnding(code)) {
119629
+ return effects.check(syntax_nonLazyContinuation, continuationOkBeforeData, after)(code);
119630
+ }
119631
+ // Check for closing marker directly (without entering data)
119632
+ // This handles cases like [block:type]\n{}\n\n[/block] where there are
119633
+ // newlines after the data object
119634
+ if (code === codes.leftSquareBracket) {
119635
+ effects.enter('magicBlockMarkerEnd');
119636
+ effects.consume(code);
119637
+ return expectSlashFromContinuation;
119638
+ }
119639
+ // If we've already seen the opening brace, just continue capturing data
119640
+ if (seenOpenBrace) {
119641
+ effects.enter('magicBlockData');
119642
+ return captureData(code);
119643
+ }
119644
+ // Skip whitespace (spaces/tabs) before the data - stay in beforeData
119645
+ // Don't enter magicBlockData token yet until we confirm there's a '{'
119646
+ if (code === codes.space || code === codes.horizontalTab) {
119647
+ return beforeDataWhitespace(code);
119648
+ }
119649
+ // Data must start with '{' for valid JSON
119650
+ if (code !== codes.leftCurlyBrace) {
119651
+ effects.exit('magicBlock');
119652
+ return nok(code);
119653
+ }
119654
+ // We have '{' - enter data token and start capturing
119655
+ seenOpenBrace = true;
119656
+ effects.enter('magicBlockData');
119657
+ return captureData(code);
119658
+ }
119659
+ /**
119660
+ * Consume whitespace before the data without creating a token.
119661
+ * Uses a temporary token to satisfy micromark's requirement.
119662
+ */
119663
+ function beforeDataWhitespace(code) {
119664
+ if (code === null) {
119665
+ effects.exit('magicBlock');
119666
+ return nok(code);
119667
+ }
119668
+ if (markdownLineEnding(code)) {
119669
+ return effects.check(syntax_nonLazyContinuation, continuationOkBeforeData, after)(code);
119670
+ }
119671
+ if (code === codes.space || code === codes.horizontalTab) {
119672
+ // We need to consume this but can't without a token - use magicBlockData
119673
+ // and track that we haven't seen '{' yet
119674
+ effects.enter('magicBlockData');
119675
+ effects.consume(code);
119676
+ return beforeDataWhitespaceContinue;
119677
+ }
119678
+ if (code === codes.leftCurlyBrace) {
119679
+ seenOpenBrace = true;
119680
+ effects.enter('magicBlockData');
119681
+ return captureData(code);
119682
+ }
119683
+ effects.exit('magicBlock');
119684
+ return nok(code);
119685
+ }
119686
+ /**
119687
+ * Continue consuming whitespace or validate the opening brace.
119688
+ */
119689
+ function beforeDataWhitespaceContinue(code) {
119690
+ if (code === null) {
119691
+ effects.exit('magicBlockData');
119692
+ effects.exit('magicBlock');
119693
+ return nok(code);
119694
+ }
119695
+ if (markdownLineEnding(code)) {
119696
+ effects.exit('magicBlockData');
119697
+ return effects.check(syntax_nonLazyContinuation, continuationOk, after)(code);
119698
+ }
119699
+ if (code === codes.space || code === codes.horizontalTab) {
119700
+ effects.consume(code);
119701
+ return beforeDataWhitespaceContinue;
119702
+ }
119703
+ if (code === codes.leftCurlyBrace) {
119704
+ seenOpenBrace = true;
119705
+ return captureData(code);
119706
+ }
119707
+ effects.exit('magicBlockData');
119708
+ effects.exit('magicBlock');
119709
+ return nok(code);
119710
+ }
119711
+ /**
119712
+ * Continuation OK before we've entered data token.
119713
+ */
119714
+ function continuationOkBeforeData(code) {
119715
+ effects.enter('magicBlockLineEnding');
119716
+ effects.consume(code);
119717
+ effects.exit('magicBlockLineEnding');
119718
+ return beforeData; // Stay in beforeData state - don't enter magicBlockData yet
119719
+ }
119720
+ function captureData(code) {
119721
+ // EOF - magic block must be closed
119722
+ if (code === null) {
119723
+ effects.exit('magicBlockData');
119724
+ effects.exit('magicBlock');
119725
+ return nok(code);
119726
+ }
119727
+ // At line ending, check if we can continue on the next line
119728
+ if (markdownLineEnding(code)) {
119729
+ effects.exit('magicBlockData');
119730
+ return effects.check(syntax_nonLazyContinuation, continuationOk, after)(code);
119731
+ }
119732
+ if (jsonState.escapeNext) {
119733
+ jsonState.escapeNext = false;
119734
+ effects.consume(code);
119735
+ return captureData;
119736
+ }
119737
+ if (jsonState.inString) {
119738
+ if (code === codes.backslash) {
119739
+ jsonState.escapeNext = true;
119740
+ effects.consume(code);
119741
+ return captureData;
119742
+ }
119743
+ if (code === codes.quotationMark) {
119744
+ jsonState.inString = false;
119745
+ }
119746
+ effects.consume(code);
119747
+ return captureData;
119748
+ }
119749
+ if (code === codes.quotationMark) {
119750
+ jsonState.inString = true;
119751
+ effects.consume(code);
119752
+ return captureData;
119753
+ }
119754
+ if (code === codes.leftSquareBracket) {
119755
+ effects.exit('magicBlockData');
119756
+ effects.enter('magicBlockMarkerEnd');
119757
+ effects.consume(code);
119758
+ return expectSlash;
119759
+ }
119760
+ effects.consume(code);
119761
+ return captureData;
119762
+ }
119763
+ /**
119764
+ * Called when non-lazy continuation check passes - we can continue parsing.
119765
+ */
119766
+ function continuationOk(code) {
119767
+ // Consume the line ending
119768
+ effects.enter('magicBlockLineEnding');
119769
+ effects.consume(code);
119770
+ effects.exit('magicBlockLineEnding');
119771
+ return continuationStart;
119772
+ }
119773
+ /**
119774
+ * Start of continuation line - check for more line endings, closing marker, or start capturing data.
119775
+ */
119776
+ function continuationStart(code) {
119777
+ // Handle consecutive line endings
119778
+ if (code === null) {
119779
+ effects.exit('magicBlock');
119780
+ return nok(code);
119781
+ }
119782
+ if (markdownLineEnding(code)) {
119783
+ return effects.check(syntax_nonLazyContinuation, continuationOkBeforeData, after)(code);
119784
+ }
119785
+ // Check if this is the start of the closing marker [/block]
119786
+ // If so, handle it directly without entering magicBlockData
119787
+ if (code === codes.leftSquareBracket) {
119788
+ effects.enter('magicBlockMarkerEnd');
119789
+ effects.consume(code);
119790
+ return expectSlashFromContinuation;
119791
+ }
119792
+ effects.enter('magicBlockData');
119793
+ return captureData(code);
119794
+ }
119795
+ /**
119796
+ * Check for closing marker slash when coming from continuation.
119797
+ * If not a closing marker, create an empty data token and continue.
119798
+ */
119799
+ function expectSlashFromContinuation(code) {
119800
+ if (code === null) {
119801
+ effects.exit('magicBlockMarkerEnd');
119802
+ effects.exit('magicBlock');
119803
+ return nok(code);
119804
+ }
119805
+ if (markdownLineEnding(code)) {
119806
+ effects.exit('magicBlockMarkerEnd');
119807
+ return effects.check(syntax_nonLazyContinuation, continuationOkBeforeData, after)(code);
119808
+ }
119809
+ if (code === codes.slash) {
119810
+ effects.consume(code);
119811
+ return expectClosingB;
119812
+ }
119813
+ // Not a closing marker - this is data content
119814
+ // Exit marker and enter data
119815
+ effects.exit('magicBlockMarkerEnd');
119816
+ effects.enter('magicBlockData');
119817
+ // The [ was consumed by the marker, so we need to conceptually "have it" in our data
119818
+ // But since we already consumed it into the marker, we need a different approach
119819
+ // Re-classify: consume this character as data and continue
119820
+ if (code === codes.quotationMark)
119821
+ jsonState.inString = true;
119822
+ effects.consume(code);
119823
+ return captureData;
119824
+ }
119825
+ function expectSlash(code) {
119826
+ if (code === null) {
119827
+ effects.exit('magicBlockMarkerEnd');
119828
+ effects.exit('magicBlock');
119829
+ return nok(code);
119830
+ }
119831
+ // At line ending during marker parsing
119832
+ if (markdownLineEnding(code)) {
119833
+ effects.exit('magicBlockMarkerEnd');
119834
+ return effects.check(syntax_nonLazyContinuation, continuationOk, after)(code);
119835
+ }
119836
+ if (code !== codes.slash) {
119837
+ effects.exit('magicBlockMarkerEnd');
119838
+ effects.enter('magicBlockData');
119839
+ if (code === codes.quotationMark)
119840
+ jsonState.inString = true;
119841
+ effects.consume(code);
119842
+ return captureData;
119843
+ }
119844
+ effects.consume(code);
119845
+ return expectClosingB;
119846
+ }
119847
+ function expectClosingB(code) {
119848
+ if (code === null) {
119849
+ effects.exit('magicBlockMarkerEnd');
119850
+ effects.exit('magicBlock');
119851
+ return nok(code);
119852
+ }
119853
+ if (code !== codes.lowercaseB) {
119854
+ effects.exit('magicBlockMarkerEnd');
119855
+ effects.enter('magicBlockData');
119856
+ if (code === codes.quotationMark)
119857
+ jsonState.inString = true;
119858
+ effects.consume(code);
119859
+ return captureData;
119860
+ }
119861
+ effects.consume(code);
119862
+ return expectClosingL;
119863
+ }
119864
+ function expectClosingL(code) {
119865
+ if (code === null) {
119866
+ effects.exit('magicBlockMarkerEnd');
119867
+ effects.exit('magicBlock');
119868
+ return nok(code);
119869
+ }
119870
+ if (code !== codes.lowercaseL) {
119871
+ effects.exit('magicBlockMarkerEnd');
119872
+ effects.enter('magicBlockData');
119873
+ if (code === codes.quotationMark)
119874
+ jsonState.inString = true;
119875
+ effects.consume(code);
119876
+ return captureData;
119877
+ }
119878
+ effects.consume(code);
119879
+ return expectClosingO;
119880
+ }
119881
+ function expectClosingO(code) {
119882
+ if (code === null) {
119883
+ effects.exit('magicBlockMarkerEnd');
119884
+ effects.exit('magicBlock');
119885
+ return nok(code);
119886
+ }
119887
+ if (code !== codes.lowercaseO) {
119888
+ effects.exit('magicBlockMarkerEnd');
119889
+ effects.enter('magicBlockData');
119890
+ if (code === codes.quotationMark)
119891
+ jsonState.inString = true;
119892
+ effects.consume(code);
119893
+ return captureData;
119894
+ }
119895
+ effects.consume(code);
119896
+ return expectClosingC;
119897
+ }
119898
+ function expectClosingC(code) {
119899
+ if (code === null) {
119900
+ effects.exit('magicBlockMarkerEnd');
119901
+ effects.exit('magicBlock');
119902
+ return nok(code);
119903
+ }
119904
+ if (code !== codes.lowercaseC) {
119905
+ effects.exit('magicBlockMarkerEnd');
119906
+ effects.enter('magicBlockData');
119907
+ if (code === codes.quotationMark)
119908
+ jsonState.inString = true;
119909
+ effects.consume(code);
119910
+ return captureData;
119911
+ }
119912
+ effects.consume(code);
119913
+ return expectClosingK;
119914
+ }
119915
+ function expectClosingK(code) {
119916
+ if (code === null) {
119917
+ effects.exit('magicBlockMarkerEnd');
119918
+ effects.exit('magicBlock');
119919
+ return nok(code);
119920
+ }
119921
+ if (code !== codes.lowercaseK) {
119922
+ effects.exit('magicBlockMarkerEnd');
119923
+ effects.enter('magicBlockData');
119924
+ if (code === codes.quotationMark)
119925
+ jsonState.inString = true;
119926
+ effects.consume(code);
119927
+ return captureData;
119928
+ }
119929
+ effects.consume(code);
119930
+ return expectClosingBracket;
119931
+ }
119932
+ function expectClosingBracket(code) {
119933
+ if (code === null) {
119934
+ effects.exit('magicBlockMarkerEnd');
119935
+ effects.exit('magicBlock');
119936
+ return nok(code);
119937
+ }
119938
+ if (code !== codes.rightSquareBracket) {
119939
+ effects.exit('magicBlockMarkerEnd');
119940
+ effects.enter('magicBlockData');
119941
+ if (code === codes.quotationMark)
119942
+ jsonState.inString = true;
119943
+ effects.consume(code);
119944
+ return captureData;
119945
+ }
119946
+ effects.consume(code);
119947
+ effects.exit('magicBlockMarkerEnd');
119948
+ // Check for trailing whitespace on the same line
119949
+ return consumeTrailing;
119950
+ }
119951
+ /**
119952
+ * Consume trailing whitespace (spaces/tabs) on the same line after [/block].
119953
+ * For concrete flow constructs, we must end at eol/eof or fail.
119954
+ * Trailing whitespace is consumed; other content causes nok (text tokenizer handles it).
119955
+ */
119956
+ function consumeTrailing(code) {
119957
+ // End of file - done
119958
+ if (code === null) {
119959
+ effects.exit('magicBlock');
119960
+ return ok(code);
119961
+ }
119962
+ // Line ending - done
119963
+ if (markdownLineEnding(code)) {
119964
+ effects.exit('magicBlock');
119965
+ return ok(code);
119966
+ }
119967
+ // Space or tab - consume as trailing whitespace
119968
+ if (code === codes.space || code === codes.horizontalTab) {
119969
+ effects.enter('magicBlockTrailing');
119970
+ effects.consume(code);
119971
+ return consumeTrailingContinue;
119972
+ }
119973
+ // Any other character - fail flow tokenizer, let text tokenizer handle it
119974
+ effects.exit('magicBlock');
119975
+ return nok(code);
119976
+ }
119977
+ /**
119978
+ * Continue consuming trailing whitespace.
119979
+ */
119980
+ function consumeTrailingContinue(code) {
119981
+ // End of file - done
119982
+ if (code === null) {
119983
+ effects.exit('magicBlockTrailing');
119984
+ effects.exit('magicBlock');
119985
+ return ok(code);
119986
+ }
119987
+ // Line ending - done
119988
+ if (markdownLineEnding(code)) {
119989
+ effects.exit('magicBlockTrailing');
119990
+ effects.exit('magicBlock');
119991
+ return ok(code);
119992
+ }
119993
+ // More space or tab - keep consuming
119994
+ if (code === codes.space || code === codes.horizontalTab) {
119995
+ effects.consume(code);
119996
+ return consumeTrailingContinue;
119997
+ }
119998
+ // Non-whitespace after whitespace - fail flow tokenizer
119999
+ effects.exit('magicBlockTrailing');
120000
+ effects.exit('magicBlock');
120001
+ return nok(code);
120002
+ }
120003
+ /**
120004
+ * Called when we can't continue (lazy line or EOF) - exit the construct.
120005
+ */
120006
+ function after(code) {
120007
+ effects.exit('magicBlock');
120008
+ return nok(code);
120009
+ }
120010
+ }
120011
+ /**
120012
+ * Text tokenizer for single-line magic blocks only.
120013
+ * Used in inline contexts like list items and paragraphs.
120014
+ * Multiline blocks are handled by the flow tokenizer.
120015
+ */
120016
+ function tokenizeMagicBlockText(effects, ok, nok) {
120017
+ // State for tracking JSON content
120018
+ const jsonState = { escapeNext: false, inString: false };
120019
+ const blockTypeRef = { value: '' };
120020
+ let seenOpenBrace = false;
120021
+ // Create shared parsers for opening marker and type capture
120022
+ const typeParser = createTypeCaptureParser(effects, nok, beforeData, blockTypeRef);
120023
+ const openingMarkerParser = createOpeningMarkerParser(effects, nok, typeParser.first);
120024
+ // Success handler for closing marker - exits tokens and returns ok
120025
+ const closingSuccess = (code) => {
120026
+ effects.exit('magicBlockMarkerEnd');
120027
+ effects.exit('magicBlock');
120028
+ return ok(code);
120029
+ };
120030
+ // Mismatch handler - falls back to data capture
120031
+ const closingMismatch = (code) => {
120032
+ effects.exit('magicBlockMarkerEnd');
120033
+ effects.enter('magicBlockData');
120034
+ if (code === codes.quotationMark)
120035
+ jsonState.inString = true;
120036
+ effects.consume(code);
120037
+ return captureData;
120038
+ };
120039
+ // EOF handler
120040
+ const closingEof = (_code) => nok(_code);
120041
+ // Create closing marker parsers
120042
+ const closingFromBeforeData = createClosingMarkerParser(effects, closingSuccess, closingMismatch, closingEof, jsonState);
120043
+ const closingFromData = createClosingMarkerParser(effects, closingSuccess, closingMismatch, closingEof, jsonState);
120044
+ return start;
120045
+ function start(code) {
120046
+ if (code !== codes.leftSquareBracket)
120047
+ return nok(code);
120048
+ effects.enter('magicBlock');
120049
+ effects.enter('magicBlockMarkerStart');
120050
+ effects.consume(code);
120051
+ return openingMarkerParser;
120052
+ }
120053
+ /**
120054
+ * State before data content - handles line endings before entering data token.
120055
+ * Whitespace before '{' is allowed.
120056
+ */
120057
+ function beforeData(code) {
120058
+ // Fail on EOF - magic block must be closed
120059
+ if (code === null) {
120060
+ return nok(code);
120061
+ }
120062
+ // Handle line endings before any data - consume them without entering data token
120063
+ if (markdownLineEnding(code)) {
120064
+ effects.enter('magicBlockLineEnding');
120065
+ effects.consume(code);
120066
+ effects.exit('magicBlockLineEnding');
120067
+ return beforeData;
120068
+ }
120069
+ // Check for closing marker directly (without entering data)
120070
+ if (code === codes.leftSquareBracket) {
120071
+ effects.enter('magicBlockMarkerEnd');
120072
+ effects.consume(code);
120073
+ return closingFromBeforeData.expectSlash;
120074
+ }
120075
+ // If we've already seen the opening brace, just continue capturing data
120076
+ if (seenOpenBrace) {
120077
+ effects.enter('magicBlockData');
120078
+ return captureData(code);
120079
+ }
120080
+ // Skip whitespace (spaces/tabs) before the data
120081
+ if (code === codes.space || code === codes.horizontalTab) {
120082
+ return beforeDataWhitespace(code);
120083
+ }
120084
+ // Data must start with '{' for valid JSON
120085
+ if (code !== codes.leftCurlyBrace) {
120086
+ return nok(code);
120087
+ }
120088
+ // We have '{' - enter data token and start capturing
120089
+ seenOpenBrace = true;
120090
+ effects.enter('magicBlockData');
120091
+ return captureData(code);
120092
+ }
120093
+ /**
120094
+ * Consume whitespace before the data.
120095
+ */
120096
+ function beforeDataWhitespace(code) {
120097
+ if (code === null) {
120098
+ return nok(code);
120099
+ }
120100
+ if (markdownLineEnding(code)) {
120101
+ effects.enter('magicBlockLineEnding');
120102
+ effects.consume(code);
120103
+ effects.exit('magicBlockLineEnding');
120104
+ return beforeData;
120105
+ }
120106
+ if (code === codes.space || code === codes.horizontalTab) {
120107
+ effects.enter('magicBlockData');
120108
+ effects.consume(code);
120109
+ return beforeDataWhitespaceContinue;
120110
+ }
120111
+ if (code === codes.leftCurlyBrace) {
120112
+ seenOpenBrace = true;
120113
+ effects.enter('magicBlockData');
120114
+ return captureData(code);
120115
+ }
120116
+ return nok(code);
120117
+ }
120118
+ /**
120119
+ * Continue consuming whitespace or validate the opening brace.
120120
+ */
120121
+ function beforeDataWhitespaceContinue(code) {
120122
+ if (code === null) {
120123
+ effects.exit('magicBlockData');
120124
+ return nok(code);
120125
+ }
120126
+ if (markdownLineEnding(code)) {
120127
+ effects.exit('magicBlockData');
120128
+ effects.enter('magicBlockLineEnding');
120129
+ effects.consume(code);
120130
+ effects.exit('magicBlockLineEnding');
120131
+ return beforeData;
120132
+ }
120133
+ if (code === codes.space || code === codes.horizontalTab) {
120134
+ effects.consume(code);
120135
+ return beforeDataWhitespaceContinue;
120136
+ }
120137
+ if (code === codes.leftCurlyBrace) {
120138
+ seenOpenBrace = true;
120139
+ return captureData(code);
120140
+ }
120141
+ effects.exit('magicBlockData');
120142
+ return nok(code);
120143
+ }
120144
+ function captureData(code) {
120145
+ // Fail on EOF - magic block must be closed
120146
+ if (code === null) {
120147
+ effects.exit('magicBlockData');
120148
+ return nok(code);
120149
+ }
120150
+ // Handle multiline magic blocks within text/paragraphs
120151
+ // Exit data, consume line ending with proper token, then re-enter data
120152
+ if (markdownLineEnding(code)) {
120153
+ effects.exit('magicBlockData');
120154
+ effects.enter('magicBlockLineEnding');
120155
+ effects.consume(code);
120156
+ effects.exit('magicBlockLineEnding');
120157
+ return beforeData; // Go back to beforeData to handle potential empty lines
120158
+ }
120159
+ if (jsonState.escapeNext) {
120160
+ jsonState.escapeNext = false;
120161
+ effects.consume(code);
120162
+ return captureData;
120163
+ }
120164
+ if (jsonState.inString) {
120165
+ if (code === codes.backslash) {
120166
+ jsonState.escapeNext = true;
120167
+ effects.consume(code);
120168
+ return captureData;
120169
+ }
120170
+ if (code === codes.quotationMark) {
120171
+ jsonState.inString = false;
120172
+ }
120173
+ effects.consume(code);
120174
+ return captureData;
120175
+ }
120176
+ if (code === codes.quotationMark) {
120177
+ jsonState.inString = true;
120178
+ effects.consume(code);
120179
+ return captureData;
120180
+ }
120181
+ if (code === codes.leftSquareBracket) {
120182
+ effects.exit('magicBlockData');
120183
+ effects.enter('magicBlockMarkerEnd');
120184
+ effects.consume(code);
120185
+ return closingFromData.expectSlash;
120186
+ }
120187
+ effects.consume(code);
120188
+ return captureData;
120189
+ }
120190
+ }
120191
+ /* harmony default export */ const syntax = ((/* unused pure expression or super */ null && (syntax_magicBlock)));
120192
+
120193
+ ;// ./lib/micromark/magic-block/index.ts
120194
+ /**
120195
+ * Micromark extension for magic block syntax.
120196
+ *
120197
+ * Usage:
120198
+ * ```ts
120199
+ * import { magicBlock } from './lib/micromark/magic-block';
120200
+ *
120201
+ * const processor = unified()
120202
+ * .data('micromarkExtensions', [magicBlock()])
120203
+ * ```
120204
+ */
120205
+
120206
+
120207
+ ;// ./lib/micromark/mdx-component/syntax.ts
120208
+
120209
+
120210
+
120211
+
120212
+
120213
+ // Raw tags (type-1: pre/script/style/textarea) and block tags (type-6: div,
120214
+ // section, …) always start a block, so they stay flow even with trailing
120215
+ // content. Other lowercase tags (i, span, …) follow the type-7 rule and only
120216
+ // stay flow when nothing trails the close tag.
120217
+ const htmlFlowTagNames = new Set([...htmlRawNames, ...htmlBlockNames]);
120218
+ // Lowercase type-6 block tags claimable in flow even without a `{…}` attribute, so
120219
+ // blank lines between nested JSX siblings don't fragment the block. Excludes table
120220
+ // tags (mdxishTables owns their blank lines) and voids (never close).
120221
+ const plainBlockClaimTagNames = new Set([...htmlBlockNames].filter(tag => !HTML_TABLE_STRUCTURE_TAGS.has(tag) && !HTML_VOID_ELEMENTS.has(tag)));
120222
+ const mdx_component_syntax_nonLazyContinuationStart = {
120223
+ tokenize: mdx_component_syntax_tokenizeNonLazyContinuationStart,
120224
+ partial: true,
120225
+ };
120226
+ // Lookahead for `plainClaimLineStart`: is this line markup-only, or a paragraph
120227
+ // that merely starts with a tag? Run via `effects.check` so it never consumes.
120228
+ const markupOnlyContinuation = {
120229
+ tokenize: tokenizeMarkupOnlyContinuation,
120230
+ partial: true,
120231
+ };
120232
+ function resolveToMdxComponent(events) {
120233
+ let index = events.length;
120234
+ while (index > 0) {
120235
+ index -= 1;
120236
+ if (events[index][0] === 'enter' && events[index][1].type === 'mdxComponent') {
120237
+ break;
120238
+ }
120239
+ }
120240
+ if (index > 1 && events[index - 2][1].type === types_types.linePrefix) {
120241
+ events[index][1].start = events[index - 2][1].start;
120242
+ events[index + 1][1].start = events[index - 2][1].start;
120243
+ events.splice(index - 2, 2);
120244
+ }
120245
+ return events;
120246
+ }
120247
+ const mdxComponentFlowConstruct = {
120248
+ name: 'mdxComponent',
120249
+ tokenize: createTokenize('flow'),
120250
+ resolveTo: resolveToMdxComponent,
120251
+ concrete: true,
120252
+ };
120253
+ const mdxComponentTextConstruct = {
120254
+ name: 'mdxComponentText',
120255
+ tokenize: createTokenize('text'),
120256
+ };
120257
+ /**
120258
+ * Factory for both flow (block) and text (inline) variants.
120259
+ *
120260
+ * **Flow** — the original behavior: claims PascalCase components (always) and
120261
+ * lowercase HTML tags that carry at least one `{…}` attribute expression.
120262
+ * Multi-line, concrete, `afterClose` consumes the rest of the line.
120263
+ *
120264
+ * **Text** — runs inside paragraphs / inline context. Claims lowercase tags and
120265
+ * inline PascalCase components (`INLINE_COMPONENT_TAGS` — Anchor, Glossary), both
120266
+ * gated on at least one `{…}` brace attribute. All other PascalCase stays
120267
+ * flow-only, matching how ReadMe's custom components are authored. Aborts on line
120268
+ * endings (inline constructs don't span lines) and exits immediately after
120269
+ * `</tag>` so the paragraph's inline parser picks up the trailing text.
120270
+ */
120271
+ function createTokenize(mode) {
120272
+ const isFlow = mode === 'flow';
120273
+ return function tokenize(effects, ok, nok) {
120274
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
120275
+ const self = this;
120276
+ let tagName = '';
120277
+ let depth = 0;
120278
+ let closingTagName = '';
120279
+ // For lowercase tags we only want to claim the block if it uses JSX
120280
+ // attribute expression syntax (`attr={...}`). Plain HTML should fall
120281
+ // through to CommonMark html-flow. Flow mode claims any PascalCase block
120282
+ // component; text mode claims only inline PascalCase components
120283
+ // (INLINE_COMPONENT_TAGS — Anchor, Glossary), also brace-gated.
120284
+ let isLowercaseTag = false;
120285
+ let sawBraceAttr = false;
120286
+ // A plain lowercase block tag claimed without a `{…}` attribute, gated by
120287
+ // `plainClaimLineStart`: after a blank line it may only continue on a tag line.
120288
+ let isPlainBlockClaim = false;
120289
+ let pendingBlankLine = false;
120290
+ // Code span tracking
120291
+ let codeSpanOpenSize = 0;
120292
+ let codeSpanCloseSize = 0;
120293
+ // Fenced code block tracking
120294
+ let fenceChar = null;
120295
+ let fenceLength = 0;
120296
+ let fenceCloseLength = 0;
120297
+ let atLineStart = false;
120298
+ // True once this construct consumes any line ending; lets `afterClose`
120299
+ // treat only single-line lowercase tags as inline candidates.
120300
+ let sawLineEnding = false;
120301
+ // Bail when the opener line has unmatched tag-like tokens in its body.
120302
+ // `<Foo>_<Bar>.csv` leaves opens > closes; matched shapes like
120303
+ // `<Callout>x <strong>y</strong>` balance to 0. Without this,
120304
+ // `concrete: true` causes orphan openers to eat sibling blockquotes.
120305
+ let onOpenerLine = false;
120306
+ let openerLineHasContent = false;
120307
+ let openerLineOpens = 0;
120308
+ let openerLineCloses = 0;
120309
+ // Attribute parsing state
120310
+ let quoteChar = null;
120311
+ let braceDepth = 0;
120312
+ let inTemplateLit = false; // true when inside a template literal (for line continuation)
120313
+ // Stack of braceDepth values at each ${...} interpolation entry point.
120314
+ // When a } brings braceDepth back to a saved value, we return to the
120315
+ // template literal instead of continuing in the brace expression.
120316
+ const templateStack = [];
120317
+ const isAlpha = (code) => (code >= codes.uppercaseA && code <= codes.uppercaseZ) ||
120318
+ (code >= codes.lowercaseA && code <= codes.lowercaseZ);
120319
+ const isSameCaseAsTag = (code) => isLowercaseTag
120320
+ ? code >= codes.lowercaseA && code <= codes.lowercaseZ
120321
+ : code >= codes.uppercaseA && code <= codes.uppercaseZ;
120322
+ // Shared brace-expression state machine. The two call sites differ only in where
120323
+ // to continue after a line ending and where to return when braceDepth reaches zero.
120324
+ function createBraceExprStates(continuationStart, afterBraceClose) {
120325
+ function braceExpr(code) {
120326
+ if (code === null)
120327
+ return nok(code);
120328
+ if (markdownLineEnding(code)) {
120329
+ if (!isFlow)
120330
+ return nok(code);
120331
+ effects.exit('mdxComponentData');
120332
+ return continuationStart(code);
120333
+ }
120334
+ if (code === codes.quotationMark || code === codes.apostrophe) {
120335
+ quoteChar = code;
120336
+ effects.consume(code);
120337
+ return braceString;
120338
+ }
120339
+ if (code === codes.graveAccent) {
120340
+ inTemplateLit = true;
120341
+ effects.consume(code);
120342
+ return braceTemplateLiteral;
120343
+ }
120344
+ if (code === codes.leftCurlyBrace) {
120345
+ braceDepth += 1;
120346
+ effects.consume(code);
120347
+ return braceExpr;
120348
+ }
120349
+ if (code === codes.rightCurlyBrace) {
120350
+ braceDepth -= 1;
120351
+ effects.consume(code);
120352
+ if (templateStack.length > 0 && braceDepth === templateStack[templateStack.length - 1]) {
120353
+ templateStack.pop();
120354
+ inTemplateLit = true;
120355
+ return braceTemplateLiteral;
120356
+ }
120357
+ if (braceDepth === 0) {
120358
+ return afterBraceClose;
120359
+ }
120360
+ return braceExpr;
120361
+ }
120362
+ effects.consume(code);
120363
+ return braceExpr;
120043
120364
  }
120044
120365
  function braceString(code) {
120045
120366
  if (code === null)
@@ -120050,7 +120371,7 @@ function createTokenize(mode) {
120050
120371
  effects.exit('mdxComponentData');
120051
120372
  return continuationStart(code);
120052
120373
  }
120053
- if (code === codes_codes.backslash) {
120374
+ if (code === codes.backslash) {
120054
120375
  effects.consume(code);
120055
120376
  return braceStringEscape;
120056
120377
  }
@@ -120078,16 +120399,16 @@ function createTokenize(mode) {
120078
120399
  effects.exit('mdxComponentData');
120079
120400
  return continuationStart(code);
120080
120401
  }
120081
- if (code === codes_codes.graveAccent) {
120402
+ if (code === codes.graveAccent) {
120082
120403
  inTemplateLit = false;
120083
120404
  effects.consume(code);
120084
120405
  return braceExpr;
120085
120406
  }
120086
- if (code === codes_codes.backslash) {
120407
+ if (code === codes.backslash) {
120087
120408
  effects.consume(code);
120088
120409
  return braceTemplateLiteralEscape;
120089
120410
  }
120090
- if (code === codes_codes.dollarSign) {
120411
+ if (code === codes.dollarSign) {
120091
120412
  effects.consume(code);
120092
120413
  return braceTemplateLiteralDollar;
120093
120414
  }
@@ -120102,7 +120423,7 @@ function createTokenize(mode) {
120102
120423
  return braceTemplateLiteral;
120103
120424
  }
120104
120425
  function braceTemplateLiteralDollar(code) {
120105
- if (code === codes_codes.leftCurlyBrace) {
120426
+ if (code === codes.leftCurlyBrace) {
120106
120427
  templateStack.push(braceDepth);
120107
120428
  braceDepth += 1;
120108
120429
  inTemplateLit = false;
@@ -120118,7 +120439,7 @@ function createTokenize(mode) {
120118
120439
  return start;
120119
120440
  // ── Start ──────────────────────────────────────────────────────────────
120120
120441
  function start(code) {
120121
- if (code !== codes_codes.lessThan)
120442
+ if (code !== codes.lessThan)
120122
120443
  return nok(code);
120123
120444
  effects.enter('mdxComponent');
120124
120445
  effects.enter('mdxComponentData');
@@ -120130,7 +120451,7 @@ function createTokenize(mode) {
120130
120451
  // Uppercase A-Z → PascalCase MDX component. Flow mode claims block
120131
120452
  // components; text mode only claims inline components (Anchor, Glossary),
120132
120453
  // which is enforced once the full name is known in `tagNameRest`.
120133
- if (code !== null && code >= codes_codes.uppercaseA && code <= codes_codes.uppercaseZ) {
120454
+ if (code !== null && code >= codes.uppercaseA && code <= codes.uppercaseZ) {
120134
120455
  tagName = String.fromCharCode(code);
120135
120456
  isLowercaseTag = false;
120136
120457
  sawBraceAttr = false;
@@ -120140,7 +120461,7 @@ function createTokenize(mode) {
120140
120461
  // Lowercase a-z → HTML tag (claim only if `{...}` attr appears). In
120141
120462
  // flow mode, refuse to interrupt a paragraph — same rule as html-flow
120142
120463
  // type-7. The text variant picks these up during inline parsing.
120143
- if (code !== null && code >= codes_codes.lowercaseA && code <= codes_codes.lowercaseZ) {
120464
+ if (code !== null && code >= codes.lowercaseA && code <= codes.lowercaseZ) {
120144
120465
  if (isFlow && self.interrupt)
120145
120466
  return nok(code);
120146
120467
  tagName = String.fromCharCode(code);
@@ -120153,10 +120474,10 @@ function createTokenize(mode) {
120153
120474
  }
120154
120475
  function tagNameRest(code) {
120155
120476
  if (code !== null &&
120156
- ((code >= codes_codes.uppercaseA && code <= codes_codes.uppercaseZ) ||
120157
- (code >= codes_codes.lowercaseA && code <= codes_codes.lowercaseZ) ||
120158
- (code >= codes_codes.digit0 && code <= codes_codes.digit9) ||
120159
- code === codes_codes.underscore)) {
120477
+ ((code >= codes.uppercaseA && code <= codes.uppercaseZ) ||
120478
+ (code >= codes.lowercaseA && code <= codes.lowercaseZ) ||
120479
+ (code >= codes.digit0 && code <= codes.digit9) ||
120480
+ code === codes.underscore)) {
120160
120481
  tagName += String.fromCharCode(code);
120161
120482
  effects.consume(code);
120162
120483
  return tagNameRest;
@@ -120191,14 +120512,14 @@ function createTokenize(mode) {
120191
120512
  return openTagContinuationStart(code);
120192
120513
  }
120193
120514
  // Self-closing />
120194
- if (code === codes_codes.slash) {
120515
+ if (code === codes.slash) {
120195
120516
  if (requiresBraceAttr && !sawBraceAttr)
120196
120517
  return nok(code);
120197
120518
  effects.consume(code);
120198
120519
  return selfCloseGt;
120199
120520
  }
120200
120521
  // End of opening tag
120201
- if (code === codes_codes.greaterThan) {
120522
+ if (code === codes.greaterThan) {
120202
120523
  if (requiresBraceAttr && !sawBraceAttr) {
120203
120524
  // Plain lowercase block tags stay claimable in flow, gated per line by
120204
120525
  // `plainClaimLineStart`; everything else falls through to CommonMark.
@@ -120211,13 +120532,13 @@ function createTokenize(mode) {
120211
120532
  return body;
120212
120533
  }
120213
120534
  // Quoted attribute value
120214
- if (code === codes_codes.quotationMark || code === codes_codes.apostrophe) {
120535
+ if (code === codes.quotationMark || code === codes.apostrophe) {
120215
120536
  quoteChar = code;
120216
120537
  effects.consume(code);
120217
120538
  return inQuotedAttr;
120218
120539
  }
120219
120540
  // JSX expression attribute
120220
- if (code === codes_codes.leftCurlyBrace) {
120541
+ if (code === codes.leftCurlyBrace) {
120221
120542
  braceDepth = 1;
120222
120543
  sawBraceAttr = true;
120223
120544
  effects.consume(code);
@@ -120235,7 +120556,7 @@ function createTokenize(mode) {
120235
120556
  effects.exit('mdxComponentData');
120236
120557
  return openTagContinuationStart(code);
120237
120558
  }
120238
- if (code === codes_codes.backslash) {
120559
+ if (code === codes.backslash) {
120239
120560
  effects.consume(code);
120240
120561
  return inQuotedAttrEscape;
120241
120562
  }
@@ -120255,7 +120576,7 @@ function createTokenize(mode) {
120255
120576
  return inQuotedAttr;
120256
120577
  }
120257
120578
  function selfCloseGt(code) {
120258
- if (code === codes_codes.greaterThan) {
120579
+ if (code === codes.greaterThan) {
120259
120580
  effects.consume(code);
120260
120581
  // Self-closing tag completes the token
120261
120582
  return afterClose;
@@ -120265,7 +120586,7 @@ function createTokenize(mode) {
120265
120586
  }
120266
120587
  // Continuation for multi-line opening tags
120267
120588
  function openTagContinuationStart(code) {
120268
- return effects.check(syntax_nonLazyContinuationStart, openTagContinuationNonLazy, continuationAfter)(code);
120589
+ return effects.check(mdx_component_syntax_nonLazyContinuationStart, openTagContinuationNonLazy, continuationAfter)(code);
120269
120590
  }
120270
120591
  function openTagContinuationNonLazy(code) {
120271
120592
  sawLineEnding = true;
@@ -120308,25 +120629,25 @@ function createTokenize(mode) {
120308
120629
  atLineStart = true;
120309
120630
  return bodyContinuationStart(code);
120310
120631
  }
120311
- if (code !== codes_codes.space && code !== codes_codes.horizontalTab) {
120632
+ if (code !== codes.space && code !== codes.horizontalTab) {
120312
120633
  openerLineHasContent = true;
120313
120634
  }
120314
- if (code === codes_codes.backslash) {
120635
+ if (code === codes.backslash) {
120315
120636
  effects.consume(code);
120316
120637
  return bodyEscapedChar;
120317
120638
  }
120318
- if (code === codes_codes.lessThan) {
120639
+ if (code === codes.lessThan) {
120319
120640
  effects.consume(code);
120320
120641
  return bodyLessThan;
120321
120642
  }
120322
120643
  // Code span tracking
120323
- if (code === codes_codes.graveAccent) {
120644
+ if (code === codes.graveAccent) {
120324
120645
  codeSpanOpenSize = 0;
120325
120646
  return countOpenTicks(code);
120326
120647
  }
120327
120648
  // JSX expression child — track braces/template literals so the closing
120328
120649
  // backtick of `{`...`}` is not misread as a code span opener
120329
- if (code === codes_codes.leftCurlyBrace) {
120650
+ if (code === codes.leftCurlyBrace) {
120330
120651
  braceDepth = 1;
120331
120652
  inTemplateLit = false;
120332
120653
  effects.consume(code);
@@ -120346,14 +120667,14 @@ function createTokenize(mode) {
120346
120667
  }
120347
120668
  // ── Code span handling ─────────────────────────────────────────────────
120348
120669
  function countOpenTicks(code) {
120349
- if (code === codes_codes.graveAccent) {
120670
+ if (code === codes.graveAccent) {
120350
120671
  codeSpanOpenSize += 1;
120351
120672
  effects.consume(code);
120352
120673
  return countOpenTicks;
120353
120674
  }
120354
120675
  // 3+ backticks at line start = fenced code block
120355
120676
  if (atLineStart && codeSpanOpenSize >= 3) {
120356
- fenceChar = codes_codes.graveAccent;
120677
+ fenceChar = codes.graveAccent;
120357
120678
  fenceLength = codeSpanOpenSize;
120358
120679
  atLineStart = false;
120359
120680
  return inFencedCode(code);
@@ -120363,7 +120684,7 @@ function createTokenize(mode) {
120363
120684
  function inCodeSpan(code) {
120364
120685
  if (code === null || markdownLineEnding(code))
120365
120686
  return body(code);
120366
- if (code === codes_codes.graveAccent) {
120687
+ if (code === codes.graveAccent) {
120367
120688
  codeSpanCloseSize = 0;
120368
120689
  return countCloseTicks(code);
120369
120690
  }
@@ -120371,7 +120692,7 @@ function createTokenize(mode) {
120371
120692
  return inCodeSpan;
120372
120693
  }
120373
120694
  function countCloseTicks(code) {
120374
- if (code === codes_codes.graveAccent) {
120695
+ if (code === codes.graveAccent) {
120375
120696
  codeSpanCloseSize += 1;
120376
120697
  effects.consume(code);
120377
120698
  return countCloseTicks;
@@ -120390,7 +120711,7 @@ function createTokenize(mode) {
120390
120711
  return inFencedCode;
120391
120712
  }
120392
120713
  function fencedCodeContinuationStart(code) {
120393
- return effects.check(syntax_nonLazyContinuationStart, fencedCodeContinuationNonLazy, continuationAfter)(code);
120714
+ return effects.check(mdx_component_syntax_nonLazyContinuationStart, fencedCodeContinuationNonLazy, continuationAfter)(code);
120394
120715
  }
120395
120716
  function fencedCodeContinuationNonLazy(code) {
120396
120717
  sawLineEnding = true;
@@ -120405,6 +120726,16 @@ function createTokenize(mode) {
120405
120726
  }
120406
120727
  effects.enter('mdxComponentData');
120407
120728
  fenceCloseLength = 0;
120729
+ return fencedCodeMaybeClose(code);
120730
+ }
120731
+ // Skip leading indentation before the closing-fence check: an indented fence
120732
+ // (the norm in a component body) closes on an equally-indented line, else the
120733
+ // closer is never matched and scanning runs to EOF (CX-3704).
120734
+ function fencedCodeMaybeClose(code) {
120735
+ if (markdownSpace(code)) {
120736
+ effects.consume(code);
120737
+ return fencedCodeMaybeClose;
120738
+ }
120408
120739
  // Check for closing fence
120409
120740
  if (code === fenceChar) {
120410
120741
  fenceCloseLength = 1;
@@ -120434,7 +120765,7 @@ function createTokenize(mode) {
120434
120765
  return body(code);
120435
120766
  }
120436
120767
  // Only spaces/tabs allowed after closing fence
120437
- if (code === codes_codes.space || code === codes_codes.horizontalTab) {
120768
+ if (code === codes.space || code === codes.horizontalTab) {
120438
120769
  effects.consume(code);
120439
120770
  return fenceCloseTrailing;
120440
120771
  }
@@ -120443,7 +120774,7 @@ function createTokenize(mode) {
120443
120774
  }
120444
120775
  // ── Tilde fenced code detection ────────────────────────────────────────
120445
120776
  function bodyAfterLineStart(code) {
120446
- if (code === codes_codes.tilde) {
120777
+ if (code === codes.tilde) {
120447
120778
  fenceCloseLength = 1;
120448
120779
  effects.consume(code);
120449
120780
  return countTildes;
@@ -120452,13 +120783,13 @@ function createTokenize(mode) {
120452
120783
  return body(code);
120453
120784
  }
120454
120785
  function countTildes(code) {
120455
- if (code === codes_codes.tilde) {
120786
+ if (code === codes.tilde) {
120456
120787
  fenceCloseLength += 1;
120457
120788
  effects.consume(code);
120458
120789
  return countTildes;
120459
120790
  }
120460
120791
  if (fenceCloseLength >= 3) {
120461
- fenceChar = codes_codes.tilde;
120792
+ fenceChar = codes.tilde;
120462
120793
  fenceLength = fenceCloseLength;
120463
120794
  return inFencedCode(code);
120464
120795
  }
@@ -120468,7 +120799,7 @@ function createTokenize(mode) {
120468
120799
  }
120469
120800
  // ── Tag detection inside body ──────────────────────────────────────────
120470
120801
  function bodyLessThan(code) {
120471
- if (code === codes_codes.slash) {
120802
+ if (code === codes.slash) {
120472
120803
  if (onOpenerLine)
120473
120804
  openerLineCloses += 1;
120474
120805
  effects.consume(code);
@@ -120495,10 +120826,10 @@ function createTokenize(mode) {
120495
120826
  // ── Nested opening tag ─────────────────────────────────────────────────
120496
120827
  function nestedOpenTagName(code) {
120497
120828
  if (code !== null &&
120498
- ((code >= codes_codes.uppercaseA && code <= codes_codes.uppercaseZ) ||
120499
- (code >= codes_codes.lowercaseA && code <= codes_codes.lowercaseZ) ||
120500
- (code >= codes_codes.digit0 && code <= codes_codes.digit9) ||
120501
- code === codes_codes.underscore)) {
120829
+ ((code >= codes.uppercaseA && code <= codes.uppercaseZ) ||
120830
+ (code >= codes.lowercaseA && code <= codes.lowercaseZ) ||
120831
+ (code >= codes.digit0 && code <= codes.digit9) ||
120832
+ code === codes.underscore)) {
120502
120833
  closingTagName += String.fromCharCode(code);
120503
120834
  effects.consume(code);
120504
120835
  return nestedOpenTagName;
@@ -120506,10 +120837,10 @@ function createTokenize(mode) {
120506
120837
  // Same-name opener followed by a tag-end char bumps depth. A line ending
120507
120838
  // counts too: Prettier puts a newline right after the name (`<div\n …\n>`).
120508
120839
  if (closingTagName === tagName &&
120509
- (code === codes_codes.greaterThan ||
120510
- code === codes_codes.slash ||
120511
- code === codes_codes.space ||
120512
- code === codes_codes.horizontalTab ||
120840
+ (code === codes.greaterThan ||
120841
+ code === codes.slash ||
120842
+ code === codes.space ||
120843
+ code === codes.horizontalTab ||
120513
120844
  markdownLineEnding(code))) {
120514
120845
  depth += 1;
120515
120846
  }
@@ -120528,15 +120859,15 @@ function createTokenize(mode) {
120528
120859
  }
120529
120860
  function closingTagNameRest(code) {
120530
120861
  if (code !== null &&
120531
- ((code >= codes_codes.uppercaseA && code <= codes_codes.uppercaseZ) ||
120532
- (code >= codes_codes.lowercaseA && code <= codes_codes.lowercaseZ) ||
120533
- (code >= codes_codes.digit0 && code <= codes_codes.digit9) ||
120534
- code === codes_codes.underscore)) {
120862
+ ((code >= codes.uppercaseA && code <= codes.uppercaseZ) ||
120863
+ (code >= codes.lowercaseA && code <= codes.lowercaseZ) ||
120864
+ (code >= codes.digit0 && code <= codes.digit9) ||
120865
+ code === codes.underscore)) {
120535
120866
  closingTagName += String.fromCharCode(code);
120536
120867
  effects.consume(code);
120537
120868
  return closingTagNameRest;
120538
120869
  }
120539
- if (closingTagName === tagName && code === codes_codes.greaterThan) {
120870
+ if (closingTagName === tagName && code === codes.greaterThan) {
120540
120871
  depth -= 1;
120541
120872
  effects.consume(code);
120542
120873
  if (depth === 0) {
@@ -120588,7 +120919,7 @@ function createTokenize(mode) {
120588
120919
  }
120589
120920
  // ── Body continuation (line endings) ───────────────────────────────────
120590
120921
  function bodyContinuationStart(code) {
120591
- return effects.check(syntax_nonLazyContinuationStart, bodyContinuationNonLazy, continuationAfter)(code);
120922
+ return effects.check(mdx_component_syntax_nonLazyContinuationStart, bodyContinuationNonLazy, continuationAfter)(code);
120592
120923
  }
120593
120924
  function bodyContinuationNonLazy(code) {
120594
120925
  sawLineEnding = true;
@@ -120620,9 +120951,16 @@ function createTokenize(mode) {
120620
120951
  }
120621
120952
  // Dispatch a non-blank continuation line: fenced code at line start, else body.
120622
120953
  function bodyLineStart(code) {
120623
- if (atLineStart && code === codes_codes.tilde)
120954
+ // Skip leading indentation while staying "at line start" so an indented
120955
+ // fence is still recognized. Otherwise the first space clears `atLineStart`
120956
+ // and its content — including any unbalanced `{` — stays live text (CX-3704).
120957
+ if (atLineStart && markdownSpace(code)) {
120958
+ effects.consume(code);
120959
+ return bodyLineStart;
120960
+ }
120961
+ if (atLineStart && code === codes.tilde)
120624
120962
  return bodyAfterLineStart(code);
120625
- if (atLineStart && code === codes_codes.graveAccent) {
120963
+ if (atLineStart && code === codes.graveAccent) {
120626
120964
  codeSpanOpenSize = 0;
120627
120965
  // Leave `atLineStart` set — `countOpenTicks` needs it to tell a fence from an
120628
120966
  // inline code span once the run of backticks is fully counted; it's cleared once
@@ -120637,7 +120975,7 @@ function createTokenize(mode) {
120637
120975
  // fence) refuses so CommonMark html-flow reparses it exactly as it does today.
120638
120976
  function plainClaimLineStart(code) {
120639
120977
  // Leading whitespace only → treat as a blank line, matching CommonMark.
120640
- if (code === codes_codes.space || code === codes_codes.horizontalTab) {
120978
+ if (code === codes.space || code === codes.horizontalTab) {
120641
120979
  effects.consume(code);
120642
120980
  return plainClaimLineStart;
120643
120981
  }
@@ -120650,7 +120988,7 @@ function createTokenize(mode) {
120650
120988
  // paragraph that merely starts with a tag must fall back so its markdown
120651
120989
  // parses and rehype-raw re-nests it into the wrapper.
120652
120990
  if (pendingBlankLine) {
120653
- if (code !== codes_codes.lessThan)
120991
+ if (code !== codes.lessThan)
120654
120992
  return nok(code);
120655
120993
  return effects.check(markupOnlyContinuation, plainClaimContinue, nok)(code);
120656
120994
  }
@@ -120670,7 +121008,7 @@ function createTokenize(mode) {
120670
121008
  }
120671
121009
  };
120672
121010
  }
120673
- function syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
121011
+ function mdx_component_syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
120674
121012
  // eslint-disable-next-line @typescript-eslint/no-this-alias
120675
121013
  const self = this;
120676
121014
  return start;
@@ -120703,7 +121041,7 @@ function tokenizeMarkupOnlyContinuation(effects, ok, nok) {
120703
121041
  return afterLessThan;
120704
121042
  }
120705
121043
  function afterLessThan(code) {
120706
- if (code === codes_codes.slash) {
121044
+ if (code === codes.slash) {
120707
121045
  effects.consume(code);
120708
121046
  return afterSlash;
120709
121047
  }
@@ -120722,7 +121060,7 @@ function tokenizeMarkupOnlyContinuation(effects, ok, nok) {
120722
121060
  function scanToLineEnd(code) {
120723
121061
  if (code === null || markdownLineEnding(code)) {
120724
121062
  effects.exit(types_types.data);
120725
- return lastNonSpace === codes_codes.greaterThan ? ok(code) : nok(code);
121063
+ return lastNonSpace === codes.greaterThan ? ok(code) : nok(code);
120726
121064
  }
120727
121065
  if (!markdownSpace(code))
120728
121066
  lastNonSpace = code;
@@ -120755,8 +121093,8 @@ function tokenizeMarkupOnlyContinuation(effects, ok, nok) {
120755
121093
  */
120756
121094
  function syntax_mdxComponent() {
120757
121095
  return {
120758
- flow: { [codes_codes.lessThan]: [mdxComponentFlowConstruct] },
120759
- text: { [codes_codes.lessThan]: [mdxComponentTextConstruct] },
121096
+ flow: { [codes.lessThan]: [mdxComponentFlowConstruct] },
121097
+ text: { [codes.lessThan]: [mdxComponentTextConstruct] },
120760
121098
  };
120761
121099
  }
120762
121100
 
@@ -120778,9 +121116,20 @@ function syntax_mdxComponent() {
120778
121116
 
120779
121117
 
120780
121118
 
121119
+
121120
+
121121
+
121122
+
121123
+
121124
+
120781
121125
  const buildInlineMdProcessor = (safeMode) => {
120782
- const micromarkExts = [syntax_mdxComponent(), syntax_gemoji(), legacyVariable(), syntax_magicBlock()];
121126
+ // `jsxTable` must be present so a `<Table>`/`<table>` nested in a component
121127
+ // body (e.g. a `<Callout>`) is captured as one html node. Without it, blank
121128
+ // lines between rows let CommonMark HTML block type 6 fragment the table and
121129
+ // its rows spill out as text / indented code blocks (CX-3705).
121130
+ const micromarkExts = [syntax_jsxTable(), syntax_mdxComponent(), syntax_gemoji(), legacyVariable(), syntax_magicBlock()];
120783
121131
  const fromMarkdownExts = [
121132
+ jsx_table_jsxTableFromMarkdown(),
120784
121133
  mdx_component_mdxComponentFromMarkdown(),
120785
121134
  gemojiFromMarkdown(),
120786
121135
  legacyVariableFromMarkdown(),
@@ -120840,6 +121189,65 @@ const toMdxJsxTextElement = (name, attributes, children, position) => ({
120840
121189
  children,
120841
121190
  ...(position ? { position } : {}),
120842
121191
  });
121192
+ // Raw-body tags (pre/script/style/textarea) must stay byte-exact; table
121193
+ // structure (`table` + `tableTags`) is owned by `mdxishTables` and figures by
121194
+ // `mdxishJsxToMdast`, both of which run later on raw html nodes.
121195
+ const NON_PROMOTABLE_PLAIN_TAGS = new Set([...htmlRawNames, ...tableTags, 'table', 'figure', 'figcaption']);
121196
+ const NESTED_TABLE_RE = /<table[\s>]/i;
121197
+ const isMarkdownPromotableHtmlTag = (tag) => !NON_PROMOTABLE_PLAIN_TAGS.has(tag);
121198
+ // Expression nodes count as plain so `<div>{1+1}</div>` keeps its current
121199
+ // literal-brace behavior; variables/glossary already resolve inside raw html.
121200
+ const PLAIN_CONTENT_TYPES = new Set([
121201
+ 'paragraph',
121202
+ 'text',
121203
+ 'html',
121204
+ 'mdxTextExpression',
121205
+ 'mdxFlowExpression',
121206
+ enums_NodeTypes.variable,
121207
+ enums_NodeTypes.glossary,
121208
+ ]);
121209
+ // Promoting plain HTML is only worth bypassing rehype-raw's parse5 pass when
121210
+ // the body parses into an actual markdown construct.
121211
+ const containsMarkdownConstruct = (nodes) => nodes.some(node => !PLAIN_CONTENT_TYPES.has(node.type) ||
121212
+ ('children' in node && Array.isArray(node.children) && containsMarkdownConstruct(node.children)));
121213
+ /**
121214
+ * Index of the `</tag>` that balances the already-consumed opening tag (the
121215
+ * caller starts us one level deep). `lastIndexOf` mis-slices sibling same-tag
121216
+ * pairs like `<div>**a**</div><div>**b**</div>`, so we depth-match instead —
121217
+ * delegating to `walkTags` (htmlparser2) so quoted attributes (`title="</div>"`),
121218
+ * code spans, and legacy `<<VARIABLE>>` are handled for free. Returns -1 when
121219
+ * the wrapper is left open.
121220
+ */
121221
+ function findBalancedClosingTagIndex(content, tag) {
121222
+ const target = tag.toLowerCase();
121223
+ const canonicalCloserLength = tag.length + 3; // `</tag>`
121224
+ // The caller already stripped the opening tag, so re-attach one: htmlparser2
121225
+ // drops an unmatched closer, and we want it balanced. Offsets shift by the
121226
+ // prefix length.
121227
+ const prefix = `<${tag}>`;
121228
+ let depth = 0;
121229
+ let closeIndex = -1;
121230
+ walkTags(prefix + content, {
121231
+ onOpen: ({ name, isSelfClosing, isStrayCloser }) => {
121232
+ if (closeIndex >= 0 || isSelfClosing || isStrayCloser)
121233
+ return;
121234
+ if (name.toLowerCase() === target)
121235
+ depth += 1;
121236
+ },
121237
+ onClose: ({ name, start, end, implicit }) => {
121238
+ if (closeIndex >= 0 || implicit || name.toLowerCase() !== target)
121239
+ return;
121240
+ // Only canonical `</tag>` closers — the caller slices by that length, so a
121241
+ // whitespaced `</tag >` would misalign; leaving it unmatched keeps it raw.
121242
+ if (end - start !== canonicalCloserLength)
121243
+ return;
121244
+ depth -= 1;
121245
+ if (depth === 0)
121246
+ closeIndex = start - prefix.length;
121247
+ },
121248
+ });
121249
+ return closeIndex;
121250
+ }
120843
121251
 
120844
121252
  ;// ./processor/transform/mdxish/components/inline-html.ts
120845
121253
 
@@ -120971,70 +121379,168 @@ const mdxishInlineMdxComponents = () => tree => {
120971
121379
  };
120972
121380
  /* harmony default export */ const inline_mdx_blocks = (mdxishInlineMdxComponents);
120973
121381
 
121382
+ ;// ./processor/transform/mdxish/terminate-html-flow-blocks.ts
121383
+
121384
+
121385
+
121386
+ const STANDALONE_HTML_LINE_REGEX = /^(<[a-z][^<>]*>|<\/[a-z][^<>]*>)+\s*$/;
121387
+ const HTML_LINE_WITH_CONTENT_REGEX = /^<[a-z][^<>]*>.*<\/[a-z][^<>]*>(?:[^<]*)$/;
121388
+ // A line that is exactly one lowercase opening (or self-closing) tag — the shape
121389
+ // that opens a CommonMark type-6/7 HTML block and swallows the lines below it.
121390
+ const SINGLE_OPENING_TAG_REGEX = /^<[a-z][^<>]*>$/;
121391
+ // Tags whose contents must be preserved as is, inserting a blank line after the
121392
+ // opener corrupts the payload.
121393
+ // htmlRawNames here refer to <pre>, <textarea>, <script>, <style>
121394
+ const RAW_CONTENT_TAGS = [...htmlRawNames, ...HTML_TABLE_STRUCTURE_TAGS];
121395
+ // The `(?=[\s/>])` lookahead avoids false matches on lookalike names like `<script-foo>`.
121396
+ const RAW_CONTENT_TAG_MATCHERS = RAW_CONTENT_TAGS.map(tag => ({
121397
+ open: new RegExp(`<${tag}(?=[\\s/>])[^>]*?(?<!/)>`, 'gi'),
121398
+ close: new RegExp(`</${tag}(?=[\\s>])[^>]*>`, 'gi'),
121399
+ }));
121400
+ function isLineHtml(line) {
121401
+ return STANDALONE_HTML_LINE_REGEX.test(line) || HTML_LINE_WITH_CONTENT_REGEX.test(line);
121402
+ }
121403
+ // Per-tag {opens, closes} counts of RAW_CONTENT_TAGS on one line — feeds both the
121404
+ // per-line net-open check and the cumulative still-open depth tracking.
121405
+ function countRawContentTags(line) {
121406
+ return RAW_CONTENT_TAG_MATCHERS.map(({ open, close }) => ({
121407
+ opens: (line.match(open) ?? []).length,
121408
+ closes: (line.match(close) ?? []).length,
121409
+ }));
121410
+ }
121411
+ // Indentation width in columns, counting a tab as 4 per CommonMark.
121412
+ function indentWidth(line) {
121413
+ const leading = line.match(/^[ \t]*/)?.[0] ?? '';
121414
+ return leading.replace(/\t/g, ' ').length;
121415
+ }
121416
+ /**
121417
+ * Decides whether a blank line belongs between `line` and `next` so the HTML
121418
+ * flow block opened on `line` terminates and `next` parses as markdown.
121419
+ */
121420
+ function shouldTerminateBetween(line, next, { insideRawContent, lineLeavesRawOpen }) {
121421
+ if (next.trim().length === 0)
121422
+ return false;
121423
+ const currentIndent = indentWidth(line);
121424
+ const nextIndent = indentWidth(next);
121425
+ // 4+ columns is CommonMark indented-code territory: an inserted blank line
121426
+ // would turn the next line into a code block instead of freeing it (#1344).
121427
+ if (currentIndent > 3 || nextIndent > 3)
121428
+ return false;
121429
+ const currentTrimmed = line.trim();
121430
+ const nextTrimmed = next.trim();
121431
+ if (!isLineHtml(currentTrimmed) || isLineHtml(nextTrimmed) || lineLeavesRawOpen) {
121432
+ return false;
121433
+ }
121434
+ // Column-0 pairs keep the original (pre-relaxation) rule, deliberately ignoring
121435
+ // `insideRawContent`: one unclosed <pre>/<table> typo would otherwise suppress
121436
+ // termination for the whole rest of the document.
121437
+ if (currentIndent === 0 && nextIndent === 0)
121438
+ return true;
121439
+ // Indented shapes (either line at 1–3 columns) are stricter: only a lone opening
121440
+ // tag followed by markdown. A next line opening a tag or expression must stay
121441
+ // glued for the mdxComponent tokenizer; raw-content payloads stay byte-exact.
121442
+ return (!insideRawContent &&
121443
+ SINGLE_OPENING_TAG_REGEX.test(currentTrimmed) &&
121444
+ !nextTrimmed.startsWith('<') &&
121445
+ !nextTrimmed.startsWith('{'));
121446
+ }
121447
+ /**
121448
+ * CommonMark HTML blocks (types 6/7) end only at a blank line, so markdown on the
121449
+ * next line is swallowed as HTML (`## heading` after `<div>` renders as literal text).
121450
+ * Inserts the missing blank line; the gating rules live in `shouldTerminateBetween`.
121451
+ *
121452
+ * @link https://spec.commonmark.org/0.29/#html-blocks
121453
+ */
121454
+ function terminateHtmlFlowBlocks(content) {
121455
+ const { protectedContent, protectedCode } = protectCodeBlocks(content);
121456
+ const lines = protectedContent.split('\n');
121457
+ const result = [];
121458
+ // Per-tag count of still-open raw-content elements at the current boundary.
121459
+ const rawContentDepths = RAW_CONTENT_TAG_MATCHERS.map(() => 0);
121460
+ for (let i = 0; i < lines.length; i += 1) {
121461
+ const line = lines[i];
121462
+ result.push(line);
121463
+ const tagCounts = countRawContentTags(line);
121464
+ tagCounts.forEach(({ opens, closes }, tagIndex) => {
121465
+ rawContentDepths[tagIndex] = Math.max(0, rawContentDepths[tagIndex] + opens - closes);
121466
+ });
121467
+ const next = lines[i + 1];
121468
+ const rawContentFacts = {
121469
+ insideRawContent: rawContentDepths.some(depth => depth > 0),
121470
+ lineLeavesRawOpen: tagCounts.some(({ opens, closes }) => opens > closes),
121471
+ };
121472
+ if (next !== undefined && shouldTerminateBetween(line, next, rawContentFacts)) {
121473
+ result.push('');
121474
+ }
121475
+ }
121476
+ return restoreCodeBlocks(result.join('\n'), protectedCode);
121477
+ }
121478
+
120974
121479
  ;// ./processor/transform/mdxish/components/mdx-blocks.ts
120975
121480
 
120976
121481
 
120977
121482
 
120978
121483
 
120979
121484
 
120980
- /** Matches a JSX attribute expression (e.g. `key={i}`) anywhere in a string. */
121485
+
121486
+
121487
+ // Matches a JSX attribute expression (e.g. `key={i}`) anywhere in a string. */
120981
121488
  const NESTED_ATTR_EXPRESSION_RE = /[\w-]+\s*=\s*\{/;
120982
- /**
120983
- * Reduce leading whitespace on all lines just enough to prevent
120984
- * remark from treating indented content as code blocks (4+ spaces).
120985
- * Preserves relative indentation so whitespace text nodes are
120986
- * maintained in the HAST output.
121489
+ // Name shape mirrors `componentTagPattern`; the lookbehind skips the inner tag
121490
+ // of a legacy `<<VARIABLE>>`.
121491
+ const NESTED_COMPONENT_TAG_RE = /(?<!<)<([A-Z][A-Za-z0-9_]*)[\s/>]/g;
121492
+ // Excludes tags with dedicated transformers (`Table`, `HTMLBlock`, inline
121493
+ // components), which expect their wrapper to stay raw.
121494
+ const hasNestedGenericComponentTag = (content) => [...content.matchAll(NESTED_COMPONENT_TAG_RE)].some(match => !GENERIC_MDX_COMPONENT_EXCLUDED_TAGS.has(match[1]));
121495
+ /**
121496
+ * Strip the shared leading indentation from a component body so readability indentation
121497
+ * isn't parsed as indented code (4+ spaces), e.g. ` <p>` / ` text` -> `<p>` / ` text`.
121498
+ * Relative indentation is kept, so content genuinely 4+ columns deeper stays code. We
121499
+ * only strip when a line actually reaches 4 columns; otherwise the body is left as-is so
121500
+ * its leading whitespace survives as text nodes (mixed component + HTML content needs it).
120987
121501
  */
120988
121502
  function safeDeindent(text) {
120989
121503
  const lines = text.split('\n');
120990
121504
  const nonEmptyLines = lines.filter(line => line.trim().length > 0);
120991
121505
  if (nonEmptyLines.length === 0)
120992
121506
  return text;
120993
- const minIndent = Math.min(...nonEmptyLines.map(line => {
120994
- const match = line.match(/^(\s*)/);
120995
- return match ? match[1].length : 0;
120996
- }));
120997
- // Only strip enough indent to keep all lines below the 4-space code threshold
120998
- const stripAmount = Math.max(0, minIndent - 3);
121507
+ // Indent counts characters (tab = 1), unlike indentWidth's CommonMark columns
121508
+ // (tab = 4) in terminate-html-flow-blocks.
121509
+ const indents = nonEmptyLines.map(line => line.match(/^(\s*)/)?.[1].length ?? 0);
121510
+ const minIndent = Math.min(...indents);
121511
+ const maxIndent = Math.max(...indents);
121512
+ const stripAmount = maxIndent > 3 ? minIndent : 0;
120999
121513
  if (stripAmount === 0)
121000
121514
  return text;
121001
121515
  return lines.map(line => line.slice(stripAmount)).join('\n');
121002
121516
  }
121003
121517
  /**
121004
- * Parse markdown content into mdast children nodes.
121005
- * Dedents the content first to prevent indented component content
121006
- * (from nested components) from being treated as code blocks.
121518
+ * Parse component-body markdown into mdast children. Dedenting shifts columns and
121519
+ * stales the top-level `terminateHtmlFlowBlocks` decisions, so that one preprocessor
121520
+ * re-runs here; other column-anchored fixups (compact headings, tables) do not.
121007
121521
  */
121008
121522
  const parseMdChildren = (value, safeMode) => {
121009
- const parsed = getInlineMdProcessor({ safeMode }).parse(safeDeindent(value).trim());
121523
+ const parsed = getInlineMdProcessor({ safeMode }).parse(terminateHtmlFlowBlocks(safeDeindent(value).trim()));
121010
121524
  return parsed.children || [];
121011
121525
  };
121012
- /**
121013
- * Parse substring content of a node and update the parent's children to include the new nodes.
121014
- */
121526
+ // Parses trailing content into sibling nodes and re-queues the parent so any
121527
+ // components among them get processed.
121015
121528
  const parseSibling = (stack, parent, index, sibling, safeMode) => {
121016
121529
  const siblingNodes = parseMdChildren(sibling, safeMode);
121017
- // The new sibling nodes might contain new components to be processed
121018
121530
  if (siblingNodes.length > 0) {
121019
121531
  parent.children.splice(index + 1, 0, ...siblingNodes);
121020
121532
  stack.push(parent);
121021
121533
  }
121022
121534
  };
121023
- /**
121024
- * Build a position ending at `consumedLength` into the html node's value, so the
121025
- * component doesn't claim trailing content the tokenizer swallowed into one node.
121026
- */
121535
+ // Ends the position at `consumedLength` so the component doesn't claim trailing
121536
+ // content the tokenizer swallowed into the same html node.
121027
121537
  const positionEndingAtConsumed = (nodePosition, value, consumedLength) => {
121028
121538
  if (!nodePosition?.start)
121029
121539
  return nodePosition;
121030
121540
  return { start: nodePosition.start, end: pointAfter(nodePosition.start, value.slice(0, consumedLength)) };
121031
121541
  };
121032
- /**
121033
- * Build a position ending right after the last occurrence of `closingTag` within
121034
- * this node's span in the original source. Used in the trailing-content path so
121035
- * the offset is computed against the real source bytes (including blockquote/list
121036
- * prefixes that were stripped from the html node's value).
121037
- */
121542
+ // Like `positionEndingAtConsumed`, but measures against the original source so
121543
+ // blockquote/list prefixes stripped from the html node's value are counted.
121038
121544
  const positionEndingAtClosingTagInSource = (nodePosition, closingTag, source) => {
121039
121545
  if (!nodePosition?.start || !nodePosition.end)
121040
121546
  return nodePosition;
@@ -121045,9 +121551,6 @@ const positionEndingAtClosingTagInSource = (nodePosition, closingTag, source) =>
121045
121551
  const consumed = nodeSource.slice(0, closingTagOffset + closingTag.length);
121046
121552
  return { start: nodePosition.start, end: pointAfter(nodePosition.start, consumed) };
121047
121553
  };
121048
- /**
121049
- * Create an MdxJsxFlowElement node from component data.
121050
- */
121051
121554
  const createComponentNode = ({ tag, attributes, children, startPosition, endPosition }) => ({
121052
121555
  type: 'mdxJsxFlowElement',
121053
121556
  name: tag,
@@ -121069,6 +121572,10 @@ const substituteNodeWithMdxNode = (parent, index, mdxNode) => {
121069
121572
  * This transformer identifies these patterns and converts them to proper MDX JSX elements so they
121070
121573
  * can be accurately recognized and rendered later with their component definition code.
121071
121574
  *
121575
+ * Note: The main goal is to promote PascalCase tags to MDX elements, but we want to promote
121576
+ * normal HTML to MDX elements in some cases so they get the full custom parsing behavior.
121577
+ * E.g. tags with JSX expressions, nested components, etc.
121578
+ *
121072
121579
  * The mdx-component micromark tokenizer ensures that multi-line components are captured
121073
121580
  * as single HTML nodes, so this transformer only needs to handle two cases:
121074
121581
  *
@@ -121100,8 +121607,7 @@ const mdx_blocks_mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
121100
121607
  if ('children' in node && Array.isArray(node.children)) {
121101
121608
  stack.push(node);
121102
121609
  }
121103
- // Only visit HTML nodes with an actual html tag,
121104
- // which means a potential unparsed MDX component
121610
+ // Only html nodes can be an unparsed MDX component.
121105
121611
  const value = node.value;
121106
121612
  if (node.type !== 'html' || typeof value !== 'string')
121107
121613
  return;
@@ -121110,32 +121616,34 @@ const mdx_blocks_mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
121110
121616
  if (!parsed)
121111
121617
  return;
121112
121618
  const { tag, attributes, selfClosing, contentAfterTag = '' } = parsed;
121113
- // Offset of `trimmed` within the (possibly whitespace-padded) html node value,
121114
- // so consumed-length math maps back onto the node's real source offsets.
121619
+ // Offsets so consumed-length math maps back onto the node's real source.
121115
121620
  const leadingWhitespace = value.length - value.trimStart().length;
121116
- // Index right after the opening tag's `>` within `trimmed`.
121117
121621
  const openingTagEnd = trimmed.length - contentAfterTag.length;
121118
- // Skip tags that have dedicated transformers
121119
121622
  if (GENERIC_MDX_COMPONENT_EXCLUDED_TAGS.has(tag))
121120
- return;
121623
+ return; // owned by dedicated transformers
121121
121624
  const isPascal = isPascalCase(tag);
121122
- // Lowercase inline tags (inside a paragraph) with `{…}` attributes are
121123
- // promoted to `mdxJsxTextElement` by mdxishInlineComponentBlocks. Skip
121124
- // them here so they stay as html for that pass; PascalCase components
121125
- // keep going through this transformer (they stay flow-level even when
121126
- // inline, which is how ReadMe's custom components are modeled).
121625
+ // ==== SPECIAL CASES TO PROMOTE NORMAL HTML TO MDX ELEMENTS ====
121626
+ // Lowercase inline tags with `{…}` attributes belong to
121627
+ // mdxishInlineComponentBlocks; leave them as html for that pass. PascalCase
121628
+ // components stay flow-level even when inline (ReadMe's component model).
121127
121629
  if (!isPascal && parent.type === 'paragraph')
121128
121630
  return;
121129
- // Lowercase HTML tags are eligible when they (or a descendant tag in their
121130
- // content, e.g. a `.map()` body returning JSX with `key={i}`) carry a
121131
- // JSX-expression attribute. Without this, a wrapper `<div>` with only plain
121132
- // attributes (or none) swallows its whole nested block including any
121133
- // `style={{...}}`/`.map()` JSX inside it as literal HTML text, which
121134
- // rehype-raw's parse5 pass then garbles (it has no notion of JS expressions).
121135
- // Plain HTML with no expressions anywhere stays as an html node so
121136
- // rehype-raw handles it as normal.
121137
- const hasNestedExpressionAttr = !selfClosing && NESTED_ATTR_EXPRESSION_RE.test(contentAfterTag);
121138
- if (!isPascal && !hasExpressionAttr(attributes) && !hasNestedExpressionAttr)
121631
+ // A lowercase wrapper is only promoted when it (or a descendant) carries a
121632
+ // JSX expression or nests a component; otherwise it would swallow that inner
121633
+ // JSX/component as literal text that rehype-raw's parse5 pass can't handle.
121634
+ // Table-structural wrappers are excluded from both`mdxishTables` re-parses
121635
+ // those, so a `{}` in a cell (e.g. `<code>--depth={n}</code>`) must not
121636
+ // accidentally promote the table to an MDX element prematurely.
121637
+ const isTableStructuralTag = tag === 'table' || tableTags.has(tag);
121638
+ const hasNestedExpressionAttr = !selfClosing && !isTableStructuralTag && NESTED_ATTR_EXPRESSION_RE.test(contentAfterTag);
121639
+ const hasNestedComponentTag = !selfClosing && !isTableStructuralTag && hasNestedGenericComponentTag(contentAfterTag);
121640
+ // Promotion: By default commonmark doesn't parse markdown in single line HTML tags (e.g. <div>**bold**</div>)
121641
+ // To support that, we try to promote them to MDX elements so the markdown gets parsed
121642
+ const isPlainLowercaseHtml = !isPascal && !hasExpressionAttr(attributes) && !hasNestedExpressionAttr && !hasNestedComponentTag;
121643
+ const plainClosingTagIndex = isPlainLowercaseHtml && !selfClosing && isMarkdownPromotableHtmlTag(tag) && !NESTED_TABLE_RE.test(contentAfterTag)
121644
+ ? findBalancedClosingTagIndex(contentAfterTag, tag)
121645
+ : -1;
121646
+ if (isPlainLowercaseHtml && plainClosingTagIndex < 0)
121139
121647
  return;
121140
121648
  const closingTagStr = `</${tag}>`;
121141
121649
  // Case 1: Self-closing tag
@@ -121149,7 +121657,6 @@ const mdx_blocks_mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
121149
121657
  endPosition: positionEndingAtConsumed(node.position, value, leadingWhitespace + openingTagEnd),
121150
121658
  });
121151
121659
  substituteNodeWithMdxNode(parent, index, componentNode);
121152
- // Check and parse if there's relevant content after the current closing tag
121153
121660
  const remainingContent = contentAfterTag.trim();
121154
121661
  if (remainingContent) {
121155
121662
  parseSibling(stack, parent, index, remainingContent, safeMode);
@@ -121157,18 +121664,27 @@ const mdx_blocks_mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
121157
121664
  return;
121158
121665
  }
121159
121666
  // Case 2: Self-contained block (closing tag in content)
121160
- if (contentAfterTag.includes(closingTagStr)) {
121161
- // Find the first closing tag
121162
- const closingTagIndex = contentAfterTag.lastIndexOf(closingTagStr);
121163
- // Pass raw (untrimmed) content so dedent in parseMdChildren can
121164
- // normalize indentation before trimming
121667
+ const closingTagIndex = isPlainLowercaseHtml ? plainClosingTagIndex : contentAfterTag.lastIndexOf(closingTagStr);
121668
+ if (closingTagIndex >= 0) {
121669
+ // Untrimmed so parseMdChildren can dedent before trimming.
121165
121670
  const componentInnerContent = contentAfterTag.substring(0, closingTagIndex);
121166
121671
  const contentAfterClose = contentAfterTag.substring(closingTagIndex + closingTagStr.length).trim();
121167
- let parsedChildren = componentInnerContent.trim()
121168
- ? parseMdChildren(componentInnerContent, safeMode)
121169
- : [];
121170
- // Lowercase HTML tags are usually inline (e.g. <a>, <span>). Remark wraps
121171
- // bare text in a paragraph; unwrap when there's exactly one paragraph so
121672
+ let parsedChildren = [];
121673
+ if (componentInnerContent.trim()) {
121674
+ try {
121675
+ parsedChildren = parseMdChildren(componentInnerContent, safeMode);
121676
+ }
121677
+ catch (error) {
121678
+ // Plain HTML bodies can hold anything (e.g. stray braces the strict
121679
+ // expression parser rejects) — keep the node raw instead of throwing.
121680
+ if (isPlainLowercaseHtml)
121681
+ return;
121682
+ throw error;
121683
+ }
121684
+ }
121685
+ if (isPlainLowercaseHtml && !containsMarkdownConstruct(parsedChildren))
121686
+ return;
121687
+ // Lowercase tags are usually inline; unwrap a sole paragraph so their
121172
121688
  // phrasing content isn't spuriously block-wrapped.
121173
121689
  if (!isPascal && parsedChildren.length === 1 && parsedChildren[0].type === 'paragraph') {
121174
121690
  parsedChildren = parsedChildren[0].children;
@@ -121178,12 +121694,9 @@ const mdx_blocks_mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
121178
121694
  attributes,
121179
121695
  children: parsedChildren,
121180
121696
  startPosition: node.position,
121181
- // When trailing content follows the closing tag, compute the end position precisely
121182
- // within the html node's value so the component doesn't claim that content.
121183
- // Prefer source-based positioning when the original source is available: the html
121184
- // node's value has '> '/space prefixes stripped for blockquotes/list items, so
121185
- // positionEndingAtConsumed would undercount source offsets. When the entire node
121186
- // is consumed, use the original node position directly.
121697
+ // With trailing content, end precisely at the closing tag. Prefer source
121698
+ // offsets when available (the node's value strips blockquote/list
121699
+ // prefixes); otherwise fall back to the whole node position.
121187
121700
  endPosition: contentAfterClose
121188
121701
  ? source
121189
121702
  ? positionEndingAtClosingTagInSource(node.position, closingTagStr, source)
@@ -121191,17 +121704,16 @@ const mdx_blocks_mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
121191
121704
  : node.position,
121192
121705
  });
121193
121706
  substituteNodeWithMdxNode(parent, index, componentNode);
121194
- // After the closing tag, there might be more content to be processed
121707
+ // Re-queue whichever side may hold further components.
121195
121708
  if (contentAfterClose) {
121196
121709
  parseSibling(stack, parent, index, contentAfterClose, safeMode);
121197
121710
  }
121198
121711
  else if (componentNode.children.length > 0) {
121199
- // The content inside the component block might contain new components to be processed
121200
121712
  stack.push(componentNode);
121201
121713
  }
121202
121714
  }
121203
121715
  };
121204
- // Process the nodes with the components depth-first to maintain the correct order of the nodes
121716
+ // Depth-first so nodes keep their source order.
121205
121717
  while (stack.length) {
121206
121718
  const parent = stack.pop();
121207
121719
  if (parent?.children) {
@@ -123372,21 +123884,21 @@ function resolveEntity(name) {
123372
123884
  function tokenizeLooseHtmlEntity(effects, ok, nok) {
123373
123885
  let length = 0;
123374
123886
  const start = (code) => {
123375
- if (code !== codes_codes.ampersand)
123887
+ if (code !== codes.ampersand)
123376
123888
  return nok(code);
123377
123889
  effects.enter('looseHtmlEntity');
123378
123890
  effects.consume(code);
123379
123891
  return afterAmpersand;
123380
123892
  };
123381
123893
  const afterAmpersand = (code) => {
123382
- if (code === codes_codes.numberSign) {
123894
+ if (code === codes.numberSign) {
123383
123895
  effects.consume(code);
123384
123896
  return afterHash;
123385
123897
  }
123386
123898
  return accumulateNamed(code);
123387
123899
  };
123388
123900
  const afterHash = (code) => {
123389
- if (code === codes_codes.lowercaseX || code === codes_codes.uppercaseX) {
123901
+ if (code === codes.lowercaseX || code === codes.uppercaseX) {
123390
123902
  effects.consume(code);
123391
123903
  return accumulateHex;
123392
123904
  }
@@ -123400,7 +123912,7 @@ function tokenizeLooseHtmlEntity(effects, ok, nok) {
123400
123912
  }
123401
123913
  if (length === 0)
123402
123914
  return nok(code);
123403
- if (code === codes_codes.semicolon)
123915
+ if (code === codes.semicolon)
123404
123916
  return nok(code);
123405
123917
  effects.exit('looseHtmlEntity');
123406
123918
  return ok(code);
@@ -123413,7 +123925,7 @@ function tokenizeLooseHtmlEntity(effects, ok, nok) {
123413
123925
  }
123414
123926
  if (length === 0)
123415
123927
  return nok(code);
123416
- if (code === codes_codes.semicolon)
123928
+ if (code === codes.semicolon)
123417
123929
  return nok(code);
123418
123930
  effects.exit('looseHtmlEntity');
123419
123931
  return ok(code);
@@ -123426,7 +123938,7 @@ function tokenizeLooseHtmlEntity(effects, ok, nok) {
123426
123938
  }
123427
123939
  if (length === 0)
123428
123940
  return nok(code);
123429
- if (code === codes_codes.semicolon)
123941
+ if (code === codes.semicolon)
123430
123942
  return nok(code);
123431
123943
  effects.exit('looseHtmlEntity');
123432
123944
  return ok(code);
@@ -123461,7 +123973,7 @@ function exitLooseHtmlEntity(token) {
123461
123973
  }
123462
123974
  function looseHtmlEntity() {
123463
123975
  return {
123464
- text: { [codes_codes.ampersand]: looseHtmlEntityConstruct },
123976
+ text: { [codes.ampersand]: looseHtmlEntityConstruct },
123465
123977
  };
123466
123978
  }
123467
123979
  function looseHtmlEntityFromMarkdown() {
@@ -124154,9 +124666,6 @@ const magicBlockTransformer = (options = {}) => tree => {
124154
124666
  // single-line `<div>…</div>`). CommonMark slurps the whole div as one `html`
124155
124667
  // node, so the tokenizer never sees the HTMLBlock — we recover it here.
124156
124668
  const RAW_HTML_BLOCK_RE = /<HTMLBlock\b([^>]*)>\s*\{\s*`((?:[^`\\]|\\.)*)`\s*\}\s*<\/HTMLBlock>/g;
124157
- // Opening `<HTMLBlock …>` as its own `html` node — produced inside a paragraph
124158
- // when an HTMLBlock appears inline alongside text.
124159
- const HTML_BLOCK_OPEN_RE = /^<HTMLBlock\b([^>]*)>$/;
124160
124669
  /**
124161
124670
  * Builds the canonical `html-block` MDAST node the renderer expects.
124162
124671
  */
@@ -124237,13 +124746,14 @@ const splitRawHtmlBlocks = (node) => {
124237
124746
  /**
124238
124747
  * Converts every `<HTMLBlock>` shape that survives parsing into the canonical
124239
124748
  * `html-block` MDAST node, reading the body from the tokenizer's template-literal
124240
- * expression. Three shapes occur:
124749
+ * expression. Two shapes occur:
124241
124750
  *
124242
- * 1. JSX element (`mdxJsxFlowElement`/`mdxJsxTextElement`) — multiline/block
124243
- * context and table cells (after their remarkMdx re-parse).
124244
- * 2. Raw `html` blob (`splitRawHtmlBlocks`) single-line top-level, or nested
124245
- * in raw HTML like an inline `<div>`.
124246
- * 3. Inline-in-paragraph split into `html` + expression + `html` siblings.
124751
+ * 1. JSX element (`mdxJsxFlowElement`/`mdxJsxTextElement`) — table cells, after
124752
+ * their remarkMdx re-parse (that re-parse runs without the htmlBlockComponent
124753
+ * tokenizer, so `<HTMLBlock>` arrives as JSX rather than an opaque `html` node).
124754
+ * 2. Raw `html` blob (`splitRawHtmlBlocks`) the htmlBlockComponent tokenizer's
124755
+ * opaque output (top-level and inline), or an `<HTMLBlock>` embedded in a
124756
+ * larger raw-HTML node like an inline `<div>` that the tokenizer never saw.
124247
124757
  *
124248
124758
  * Runs *after* `mdxishTables` so table cells are re-parsed first;
124249
124759
  * `mdxishTables` recognizes the still-JSX `<HTMLBlock>` element when deciding to
@@ -124268,36 +124778,6 @@ const mdxishHtmlBlocks = () => tree => {
124268
124778
  if (replacement)
124269
124779
  parent.children.splice(index, 1, ...replacement);
124270
124780
  });
124271
- // Shape 3: inline within a paragraph — `<HTMLBlock>` open/close arrive as
124272
- // separate `html` siblings with the template-literal expression between them.
124273
- lib_visit(tree, 'paragraph', (paragraph) => {
124274
- // An html-block is block content, so it isn't a valid PhrasingContent child;
124275
- // widen to RootContent (which HTMLBlock belongs to) for the in-place splice.
124276
- const children = paragraph.children;
124277
- for (let i = 0; i < children.length; i += 1) {
124278
- const open = children[i];
124279
- const openMatch = open.type === 'html' ? open.value.match(HTML_BLOCK_OPEN_RE) : null;
124280
- if (!openMatch)
124281
- continue; // eslint-disable-line no-continue
124282
- const closeIdx = children.findIndex((child, j) => j > i && child.type === 'html' && child.value === '</HTMLBlock>');
124283
- if (closeIdx === -1)
124284
- continue; // eslint-disable-line no-continue
124285
- const body = children
124286
- .slice(i + 1, closeIdx)
124287
- .map(child => {
124288
- if (child.type === 'mdxTextExpression' || child.type === 'mdxFlowExpression') {
124289
- return extractTemplateLiteral(child.value);
124290
- }
124291
- // Preserve raw text from any other phrasing sibling (e.g. stray
124292
- // whitespace or content the tokenizer didn't claim) so it isn't
124293
- // silently dropped from the html payload.
124294
- return 'value' in child && typeof child.value === 'string' ? child.value : '';
124295
- })
124296
- .join('');
124297
- const openingTagIndent = (open.position?.start.column ?? 1) - 1;
124298
- children.splice(i, closeIdx - i + 1, htmlBlockFromRaw(openMatch[1], body, open.position, openingTagIndent));
124299
- }
124300
- });
124301
124781
  };
124302
124782
  /* harmony default export */ const mdxish_html_blocks = (mdxishHtmlBlocks);
124303
124783
 
@@ -124997,6 +125477,29 @@ const mdxishMermaidTransformer = () => (tree) => {
124997
125477
  };
124998
125478
  /* harmony default export */ const mdxish_mermaid = (mdxishMermaidTransformer);
124999
125479
 
125480
+ ;// ./processor/transform/mdxish/normalize-closing-tag-whitespace.ts
125481
+
125482
+
125483
+ // Spaces/tabs only — newlines would let prose `<` / `>` across lines look like one tag.
125484
+ const SPACED_CLOSING_TAG_RE = /<\/[ \t]*([a-zA-Z][a-zA-Z0-9-]*)[ \t]*>/g;
125485
+ /**
125486
+ * Canonicalize spaced closing tags (`</ td >` → `</td>`) for known HTML names.
125487
+ *
125488
+ * In HTML, `</` + whitespace is a bogus comment, so `</ table >` never closes the
125489
+ * table (jsxTable misses it → empty table + pre; CX-3706). Only standard HTML tags;
125490
+ * custom components, prose (`a </ b`), and code blocks are left alone.
125491
+ *
125492
+ * @example
125493
+ * normalizeClosingTagWhitespace('</ td >') // '</td>'
125494
+ * normalizeClosingTagWhitespace('</table >') // '</table>'
125495
+ * normalizeClosingTagWhitespace('a </ b >') // unchanged
125496
+ */
125497
+ function normalizeClosingTagWhitespace(content) {
125498
+ const { protectedContent, protectedCode } = protectCodeBlocks(content);
125499
+ const result = protectedContent.replace(SPACED_CLOSING_TAG_RE, (match, tagName) => STANDARD_HTML_TAGS.has(tagName.toLowerCase()) ? `</${tagName}>` : match);
125500
+ return restoreCodeBlocks(result, protectedCode);
125501
+ }
125502
+
125000
125503
  ;// ./processor/transform/mdxish/normalize-compact-headings.ts
125001
125504
 
125002
125505
  /**
@@ -125450,74 +125953,7 @@ function normalizeTableSeparator(content) {
125450
125953
  });
125451
125954
  return normalizedLines.join('\n');
125452
125955
  }
125453
- /* harmony default export */ const normalize_table_separator = ((/* unused pure expression or super */ null && (normalizeTableSeparator)));
125454
-
125455
- ;// ./processor/transform/mdxish/terminate-html-flow-blocks.ts
125456
-
125457
-
125458
-
125459
- const STANDALONE_HTML_LINE_REGEX = /^(<[a-z][^<>]*>|<\/[a-z][^<>]*>)+\s*$/;
125460
- const HTML_LINE_WITH_CONTENT_REGEX = /^<[a-z][^<>]*>.*<\/[a-z][^<>]*>(?:[^<]*)$/;
125461
- // Tags whose contents must be preserved as is, inserting a blank line after the
125462
- // opener corrupts the payload.
125463
- // htmlRawNames here refer to <pre>, <textarea>, <script>, <style>
125464
- const RAW_CONTENT_TAGS = [...htmlRawNames, ...HTML_TABLE_STRUCTURE_TAGS];
125465
- // The `(?=[\s/>])` lookahead avoids false matches on lookalike names like `<script-foo>`.
125466
- const RAW_CONTENT_TAG_MATCHERS = RAW_CONTENT_TAGS.map(tag => ({
125467
- open: new RegExp(`<${tag}(?=[\\s/>])[^>]*?(?<!/)>`, 'gi'),
125468
- close: new RegExp(`</${tag}(?=[\\s>])[^>]*>`, 'gi'),
125469
- }));
125470
- function isLineHtml(line) {
125471
- return STANDALONE_HTML_LINE_REGEX.test(line) || HTML_LINE_WITH_CONTENT_REGEX.test(line);
125472
- }
125473
- // True if any RAW_CONTENT_TAGS opener on this line is not closed on the same line.
125474
- function hasUnclosedRawContentOpener(line) {
125475
- return RAW_CONTENT_TAG_MATCHERS.some(({ open, close }) => {
125476
- const opens = (line.match(open) ?? []).length;
125477
- const closes = (line.match(close) ?? []).length;
125478
- return opens > closes;
125479
- });
125480
- }
125481
- /**
125482
- * Preprocessor to terminate HTML flow blocks.
125483
- *
125484
- * In CommonMark, HTML blocks (types 6 and 7) only terminate on a blank line.
125485
- * Without one, any content on the next line is consumed as part of the HTML block
125486
- * and never parsed as its own construct. For example, a `[block:callout]` immediately
125487
- * following `<div><p></p></div>` gets swallowed into the HTML flow token.
125488
- *
125489
- * @link https://spec.commonmark.org/0.29/#html-blocks
125490
- *
125491
- * This preprocessor inserts a blank line after standalone HTML lines when the next
125492
- * line is non-blank and not an HTML construct, ensuring micromark's HTML flow
125493
- * tokenizer terminates and subsequent content is parsed independently.
125494
- *
125495
- * Conditions:
125496
- * 1. Only non-indented lines with lowercase tag names are considered. Uppercase tags
125497
- * (e.g. `<Table>`, `<MyComponent>`) are JSX custom components and don't trigger
125498
- * CommonMark HTML blocks.
125499
- * 2. Lines inside protected blocks (e.g. fenced code) are left untouched.
125500
- * 3. Lines with an unclosed RAW_CONTENT_TAGS opener are exempted.
125501
- */
125502
- function terminateHtmlFlowBlocks(content) {
125503
- const { protectedContent, protectedCode } = protectCodeBlocks(content);
125504
- const lines = protectedContent.split('\n');
125505
- const result = [];
125506
- for (let i = 0; i < lines.length; i += 1) {
125507
- result.push(lines[i]);
125508
- // Skip blank & indented lines
125509
- if (i >= lines.length - 1 || lines[i + 1].trim().length === 0 || lines[i + 1].startsWith(' ') || lines[i + 1].startsWith('\t')) {
125510
- // eslint-disable-next-line no-continue
125511
- continue;
125512
- }
125513
- const isCurrentLineHtml = isLineHtml(lines[i]);
125514
- const isNextLineHtml = isLineHtml(lines[i + 1]);
125515
- if (isCurrentLineHtml && !isNextLineHtml && !hasUnclosedRawContentOpener(lines[i])) {
125516
- result.push('');
125517
- }
125518
- }
125519
- return restoreCodeBlocks(result.join('\n'), protectedCode);
125520
- }
125956
+ /* harmony default export */ const normalize_table_separator = ((/* unused pure expression or super */ null && (normalizeTableSeparator)));
125521
125957
 
125522
125958
  ;// ./processor/transform/mdxish/variables-code.ts
125523
125959
 
@@ -125675,25 +126111,25 @@ const variablesTextTransformer = () => tree => {
125675
126111
  };
125676
126112
  /* harmony default export */ const variables_text = (variablesTextTransformer);
125677
126113
 
125678
- ;// ./lib/mdast-util/jsx-table/index.ts
125679
- const jsx_table_contextMap = new WeakMap();
125680
- function findJsxTableToken() {
126114
+ ;// ./lib/mdast-util/html-block-component/index.ts
126115
+ const html_block_component_contextMap = new WeakMap();
126116
+ function findHtmlBlockComponentToken() {
125681
126117
  const events = this.tokenStack;
125682
126118
  for (let i = events.length - 1; i >= 0; i -= 1) {
125683
- if (events[i][0].type === 'jsxTable')
126119
+ if (events[i][0].type === 'htmlBlockComponent')
125684
126120
  return events[i][0];
125685
126121
  }
125686
126122
  return undefined;
125687
126123
  }
125688
- function enterJsxTable(token) {
125689
- jsx_table_contextMap.set(token, { chunks: [], lastEndLine: token.start.line });
126124
+ function enterHtmlBlockComponent(token) {
126125
+ html_block_component_contextMap.set(token, { chunks: [], lastEndLine: token.start.line });
125690
126126
  this.enter({ type: 'html', value: '' }, token);
125691
126127
  }
125692
- function exitJsxTableData(token) {
125693
- const tableToken = findJsxTableToken.call(this);
125694
- if (!tableToken)
126128
+ function exitHtmlBlockComponentData(token) {
126129
+ const componentToken = findHtmlBlockComponentToken.call(this);
126130
+ if (!componentToken)
125695
126131
  return;
125696
- const ctx = jsx_table_contextMap.get(tableToken);
126132
+ const ctx = html_block_component_contextMap.get(componentToken);
125697
126133
  if (ctx) {
125698
126134
  const gap = token.start.line - ctx.lastEndLine;
125699
126135
  if (ctx.chunks.length > 0 && gap > 0) {
@@ -125703,27 +126139,304 @@ function exitJsxTableData(token) {
125703
126139
  ctx.lastEndLine = token.end.line;
125704
126140
  }
125705
126141
  }
125706
- function exitJsxTable(token) {
125707
- const ctx = jsx_table_contextMap.get(token);
126142
+ function exitHtmlBlockComponent(token) {
126143
+ const ctx = html_block_component_contextMap.get(token);
125708
126144
  const node = this.stack[this.stack.length - 1];
125709
126145
  if (ctx) {
125710
126146
  node.value = ctx.chunks.join('');
125711
- jsx_table_contextMap.delete(token);
126147
+ html_block_component_contextMap.delete(token);
125712
126148
  }
125713
126149
  this.exit(token);
125714
126150
  }
125715
- function jsx_table_jsxTableFromMarkdown() {
126151
+ function html_block_component_htmlBlockComponentFromMarkdown() {
125716
126152
  return {
125717
126153
  enter: {
125718
- jsxTable: enterJsxTable,
126154
+ htmlBlockComponent: enterHtmlBlockComponent,
125719
126155
  },
125720
126156
  exit: {
125721
- jsxTableData: exitJsxTableData,
125722
- jsxTable: exitJsxTable,
126157
+ htmlBlockComponentData: exitHtmlBlockComponentData,
126158
+ htmlBlockComponent: exitHtmlBlockComponent,
126159
+ },
126160
+ };
126161
+ }
126162
+
126163
+ ;// ./lib/micromark/html-block-component/syntax.ts
126164
+
126165
+
126166
+ const TAG_SUFFIX = [
126167
+ codes.uppercaseT,
126168
+ codes.uppercaseM,
126169
+ codes.uppercaseL,
126170
+ codes.uppercaseB,
126171
+ codes.lowercaseL,
126172
+ codes.lowercaseO,
126173
+ codes.lowercaseC,
126174
+ codes.lowercaseK,
126175
+ ];
126176
+ // ---------------------------------------------------------------------------
126177
+ // Shared tokenizer factory
126178
+ // ---------------------------------------------------------------------------
126179
+ /**
126180
+ * Creates a tokenize function for `<HTMLBlock>...</HTMLBlock>`.
126181
+ *
126182
+ * - **flow** (block-level): supports multiline content via line continuations,
126183
+ * consumes trailing whitespace after the closing tag.
126184
+ * - **text** (inline): single-line only, exits immediately after the closing tag.
126185
+ */
126186
+ function syntax_createTokenize(mode) {
126187
+ return function tokenize(effects, ok, nok) {
126188
+ let depth = 1;
126189
+ function matchChars(chars, onMatch, onFail) {
126190
+ if (chars.length === 0)
126191
+ return onMatch;
126192
+ const next = (code) => {
126193
+ if (code === chars[0]) {
126194
+ effects.consume(code);
126195
+ return matchChars(chars.slice(1), onMatch, onFail);
126196
+ }
126197
+ return onFail(code);
126198
+ };
126199
+ return next;
126200
+ }
126201
+ function matchTagName(onMatch, onFail) {
126202
+ const next = (code) => {
126203
+ if (code === codes.uppercaseH) {
126204
+ effects.consume(code);
126205
+ return matchChars(TAG_SUFFIX, onMatch, onFail);
126206
+ }
126207
+ return onFail(code);
126208
+ };
126209
+ return next;
126210
+ }
126211
+ return start;
126212
+ function start(code) {
126213
+ if (code !== codes.lessThan)
126214
+ return nok(code);
126215
+ effects.enter('htmlBlockComponent');
126216
+ effects.enter('htmlBlockComponentData');
126217
+ effects.consume(code);
126218
+ return matchTagName(afterTagName, nok);
126219
+ }
126220
+ function afterTagName(code) {
126221
+ if (code === codes.greaterThan) {
126222
+ effects.consume(code);
126223
+ return body;
126224
+ }
126225
+ if (code === codes.space || code === codes.horizontalTab) {
126226
+ effects.consume(code);
126227
+ return inAttributes;
126228
+ }
126229
+ if (mode === 'flow' && markdownLineEnding(code)) {
126230
+ effects.exit('htmlBlockComponentData');
126231
+ return attributeContinuationStart(code);
126232
+ }
126233
+ if (code === codes.slash) {
126234
+ effects.consume(code);
126235
+ return selfClose;
126236
+ }
126237
+ return nok(code);
126238
+ }
126239
+ function inAttributes(code) {
126240
+ if (code === codes.greaterThan) {
126241
+ effects.consume(code);
126242
+ return body;
126243
+ }
126244
+ if (code === null) {
126245
+ return nok(code);
126246
+ }
126247
+ if (markdownLineEnding(code)) {
126248
+ if (mode === 'text')
126249
+ return nok(code);
126250
+ effects.exit('htmlBlockComponentData');
126251
+ return attributeContinuationStart(code);
126252
+ }
126253
+ effects.consume(code);
126254
+ return inAttributes;
126255
+ }
126256
+ function attributeContinuationStart(code) {
126257
+ return effects.check(html_block_component_syntax_nonLazyContinuationStart, attributeContinuationNonLazy, continuationAfter)(code);
126258
+ }
126259
+ function attributeContinuationNonLazy(code) {
126260
+ effects.enter(types_types.lineEnding);
126261
+ effects.consume(code);
126262
+ effects.exit(types_types.lineEnding);
126263
+ return attributeContinuationBefore;
126264
+ }
126265
+ function attributeContinuationBefore(code) {
126266
+ if (code === null || markdownLineEnding(code)) {
126267
+ return attributeContinuationStart(code);
126268
+ }
126269
+ effects.enter('htmlBlockComponentData');
126270
+ return inAttributes(code);
126271
+ }
126272
+ function selfClose(code) {
126273
+ if (code === codes.greaterThan) {
126274
+ effects.consume(code);
126275
+ return mode === 'flow' ? afterClose : done(code);
126276
+ }
126277
+ return nok(code);
126278
+ }
126279
+ function body(code) {
126280
+ if (code === null)
126281
+ return nok(code);
126282
+ if (markdownLineEnding(code)) {
126283
+ if (mode === 'text') {
126284
+ // Text constructs operate on paragraph content which spans lines
126285
+ effects.consume(code);
126286
+ return body;
126287
+ }
126288
+ effects.exit('htmlBlockComponentData');
126289
+ return continuationStart(code);
126290
+ }
126291
+ if (code === codes.lessThan) {
126292
+ effects.consume(code);
126293
+ return closeSlash;
126294
+ }
126295
+ effects.consume(code);
126296
+ return body;
126297
+ }
126298
+ function closeSlash(code) {
126299
+ if (code === codes.slash) {
126300
+ effects.consume(code);
126301
+ return matchTagName(closeGt, body);
126302
+ }
126303
+ return matchTagName(openAfterTagName, body)(code);
126304
+ }
126305
+ function openAfterTagName(code) {
126306
+ if (code === codes.greaterThan || code === codes.space || code === codes.horizontalTab) {
126307
+ depth += 1;
126308
+ effects.consume(code);
126309
+ return body;
126310
+ }
126311
+ return body(code);
126312
+ }
126313
+ function closeGt(code) {
126314
+ if (code === codes.greaterThan) {
126315
+ depth -= 1;
126316
+ effects.consume(code);
126317
+ if (depth === 0) {
126318
+ return mode === 'flow' ? afterClose : done(code);
126319
+ }
126320
+ return body;
126321
+ }
126322
+ return body(code);
126323
+ }
126324
+ // -- flow-only states ---------------------------------------------------
126325
+ function afterClose(code) {
126326
+ if (code === null || markdownLineEnding(code)) {
126327
+ return done(code);
126328
+ }
126329
+ if (code === codes.space || code === codes.horizontalTab) {
126330
+ effects.consume(code);
126331
+ return afterClose;
126332
+ }
126333
+ // Reject so the block re-parses as a paragraph, deferring to the
126334
+ // text tokenizer which preserves trailing content in the same line.
126335
+ return nok(code);
126336
+ }
126337
+ // -- flow-only: line continuation ---------------------------------------
126338
+ function continuationStart(code) {
126339
+ return effects.check(html_block_component_syntax_nonLazyContinuationStart, continuationStartNonLazy, continuationAfter)(code);
126340
+ }
126341
+ function continuationStartNonLazy(code) {
126342
+ effects.enter(types_types.lineEnding);
126343
+ effects.consume(code);
126344
+ effects.exit(types_types.lineEnding);
126345
+ return continuationBefore;
126346
+ }
126347
+ function continuationBefore(code) {
126348
+ if (code === null || markdownLineEnding(code)) {
126349
+ return continuationStart(code);
126350
+ }
126351
+ effects.enter('htmlBlockComponentData');
126352
+ return body(code);
126353
+ }
126354
+ function continuationAfter(code) {
126355
+ if (code === null)
126356
+ return nok(code);
126357
+ effects.exit('htmlBlockComponent');
126358
+ return ok(code);
126359
+ }
126360
+ // -- shared exit --------------------------------------------------------
126361
+ function done(_code) {
126362
+ effects.exit('htmlBlockComponentData');
126363
+ effects.exit('htmlBlockComponent');
126364
+ return ok(_code);
126365
+ }
126366
+ };
126367
+ }
126368
+ // ---------------------------------------------------------------------------
126369
+ // Flow construct (block-level)
126370
+ // ---------------------------------------------------------------------------
126371
+ const html_block_component_syntax_nonLazyContinuationStart = {
126372
+ tokenize: html_block_component_syntax_tokenizeNonLazyContinuationStart,
126373
+ partial: true,
126374
+ };
126375
+ function resolveToHtmlBlockComponent(events) {
126376
+ let index = events.length;
126377
+ while (index > 0) {
126378
+ index -= 1;
126379
+ if (events[index][0] === 'enter' && events[index][1].type === 'htmlBlockComponent') {
126380
+ break;
126381
+ }
126382
+ }
126383
+ if (index > 1 && events[index - 2][1].type === types_types.linePrefix) {
126384
+ events[index][1].start = events[index - 2][1].start;
126385
+ events[index + 1][1].start = events[index - 2][1].start;
126386
+ events.splice(index - 2, 2);
126387
+ }
126388
+ return events;
126389
+ }
126390
+ const htmlBlockComponentFlowConstruct = {
126391
+ name: 'htmlBlockComponent',
126392
+ tokenize: syntax_createTokenize('flow'),
126393
+ resolveTo: resolveToHtmlBlockComponent,
126394
+ concrete: true,
126395
+ };
126396
+ function html_block_component_syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
126397
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
126398
+ const self = this;
126399
+ return start;
126400
+ function start(code) {
126401
+ if (markdownLineEnding(code)) {
126402
+ effects.enter(types_types.lineEnding);
126403
+ effects.consume(code);
126404
+ effects.exit(types_types.lineEnding);
126405
+ return after;
126406
+ }
126407
+ return nok(code);
126408
+ }
126409
+ function after(code) {
126410
+ if (self.parser.lazy[self.now().line]) {
126411
+ return nok(code);
126412
+ }
126413
+ return ok(code);
126414
+ }
126415
+ }
126416
+ // ---------------------------------------------------------------------------
126417
+ // Text construct (inline)
126418
+ // ---------------------------------------------------------------------------
126419
+ const htmlBlockComponentTextConstruct = {
126420
+ name: 'htmlBlockComponent',
126421
+ tokenize: syntax_createTokenize('text'),
126422
+ };
126423
+ // ---------------------------------------------------------------------------
126424
+ // Extension
126425
+ // ---------------------------------------------------------------------------
126426
+ function syntax_htmlBlockComponent() {
126427
+ return {
126428
+ flow: {
126429
+ [codes.lessThan]: [htmlBlockComponentFlowConstruct],
126430
+ },
126431
+ text: {
126432
+ [codes.lessThan]: [htmlBlockComponentTextConstruct],
125723
126433
  },
125724
126434
  };
125725
126435
  }
125726
126436
 
126437
+ ;// ./lib/micromark/html-block-component/index.ts
126438
+
126439
+
125727
126440
  ;// ./lib/micromark/jsx-comment/syntax.ts
125728
126441
 
125729
126442
 
@@ -125745,7 +126458,7 @@ function jsx_table_jsxTableFromMarkdown() {
125745
126458
  function tokenizeJsxComment(effects, ok, nok) {
125746
126459
  return start;
125747
126460
  function start(code) {
125748
- if (code !== codes_codes.leftCurlyBrace)
126461
+ if (code !== codes.leftCurlyBrace)
125749
126462
  return nok(code);
125750
126463
  effects.enter('mdxFlowExpression');
125751
126464
  effects.enter('mdxFlowExpressionMarker');
@@ -125754,7 +126467,7 @@ function tokenizeJsxComment(effects, ok, nok) {
125754
126467
  return expectSlash;
125755
126468
  }
125756
126469
  function expectSlash(code) {
125757
- if (code !== codes_codes.slash) {
126470
+ if (code !== codes.slash) {
125758
126471
  effects.exit('mdxFlowExpression');
125759
126472
  return nok(code);
125760
126473
  }
@@ -125763,7 +126476,7 @@ function tokenizeJsxComment(effects, ok, nok) {
125763
126476
  return expectStar;
125764
126477
  }
125765
126478
  function expectStar(code) {
125766
- if (code !== codes_codes.asterisk) {
126479
+ if (code !== codes.asterisk) {
125767
126480
  effects.exit('mdxFlowExpressionChunk');
125768
126481
  effects.exit('mdxFlowExpression');
125769
126482
  return nok(code);
@@ -125790,7 +126503,7 @@ function tokenizeJsxComment(effects, ok, nok) {
125790
126503
  effects.exit('mdxFlowExpressionChunk');
125791
126504
  return before(code);
125792
126505
  }
125793
- if (code === codes_codes.asterisk) {
126506
+ if (code === codes.asterisk) {
125794
126507
  effects.consume(code);
125795
126508
  return maybeClosed;
125796
126509
  }
@@ -125802,11 +126515,11 @@ function tokenizeJsxComment(effects, ok, nok) {
125802
126515
  effects.exit('mdxFlowExpressionChunk');
125803
126516
  return before(code);
125804
126517
  }
125805
- if (code === codes_codes.slash) {
126518
+ if (code === codes.slash) {
125806
126519
  effects.consume(code);
125807
126520
  return expectClosingBrace;
125808
126521
  }
125809
- if (code === codes_codes.asterisk) {
126522
+ if (code === codes.asterisk) {
125810
126523
  effects.consume(code);
125811
126524
  return maybeClosed;
125812
126525
  }
@@ -125818,7 +126531,7 @@ function tokenizeJsxComment(effects, ok, nok) {
125818
126531
  effects.exit('mdxFlowExpressionChunk');
125819
126532
  return before(code);
125820
126533
  }
125821
- if (code === codes_codes.rightCurlyBrace) {
126534
+ if (code === codes.rightCurlyBrace) {
125822
126535
  effects.exit('mdxFlowExpressionChunk');
125823
126536
  effects.enter('mdxFlowExpressionMarker');
125824
126537
  effects.consume(code);
@@ -125826,7 +126539,7 @@ function tokenizeJsxComment(effects, ok, nok) {
125826
126539
  effects.exit('mdxFlowExpression');
125827
126540
  return ok;
125828
126541
  }
125829
- if (code === codes_codes.asterisk) {
126542
+ if (code === codes.asterisk) {
125830
126543
  effects.consume(code);
125831
126544
  return maybeClosed;
125832
126545
  }
@@ -125837,7 +126550,7 @@ function tokenizeJsxComment(effects, ok, nok) {
125837
126550
  function jsxComment() {
125838
126551
  return {
125839
126552
  flow: {
125840
- [codes_codes.leftCurlyBrace]: {
126553
+ [codes.leftCurlyBrace]: {
125841
126554
  name: 'jsxComment',
125842
126555
  concrete: true,
125843
126556
  tokenize: tokenizeJsxComment,
@@ -125846,243 +126559,6 @@ function jsxComment() {
125846
126559
  };
125847
126560
  }
125848
126561
 
125849
- ;// ./lib/micromark/jsx-table/syntax.ts
125850
-
125851
-
125852
- const jsx_table_syntax_nonLazyContinuationStart = {
125853
- tokenize: jsx_table_syntax_tokenizeNonLazyContinuationStart,
125854
- partial: true,
125855
- };
125856
- function resolveToJsxTable(events) {
125857
- let index = events.length;
125858
- while (index > 0) {
125859
- index -= 1;
125860
- if (events[index][0] === 'enter' && events[index][1].type === 'jsxTable') {
125861
- break;
125862
- }
125863
- }
125864
- if (index > 1 && events[index - 2][1].type === types_types.linePrefix) {
125865
- events[index][1].start = events[index - 2][1].start;
125866
- events[index + 1][1].start = events[index - 2][1].start;
125867
- events.splice(index - 2, 2);
125868
- }
125869
- return events;
125870
- }
125871
- const jsxTableConstruct = {
125872
- name: 'jsxTable',
125873
- tokenize: tokenizeJsxTable,
125874
- resolveTo: resolveToJsxTable,
125875
- concrete: true,
125876
- };
125877
- function tokenizeJsxTable(effects, ok, nok) {
125878
- let codeSpanOpenSize = 0;
125879
- let codeSpanCloseSize = 0;
125880
- let depth = 1;
125881
- const ABLE_SUFFIX = [codes_codes.lowercaseA, codes_codes.lowercaseB, codes_codes.lowercaseL, codes_codes.lowercaseE];
125882
- /** Build a state chain that matches a sequence of character codes. */
125883
- function matchChars(chars, onMatch, onFail) {
125884
- if (chars.length === 0)
125885
- return onMatch;
125886
- return ((code) => {
125887
- if (code === chars[0]) {
125888
- effects.consume(code);
125889
- return matchChars(chars.slice(1), onMatch, onFail);
125890
- }
125891
- return onFail(code);
125892
- });
125893
- }
125894
- return start;
125895
- function start(code) {
125896
- if (code !== codes_codes.lessThan)
125897
- return nok(code);
125898
- effects.enter('jsxTable');
125899
- effects.enter('jsxTableData');
125900
- effects.consume(code);
125901
- return afterLessThan;
125902
- }
125903
- function afterLessThan(code) {
125904
- if (code === codes_codes.uppercaseT || code === codes_codes.lowercaseT) {
125905
- effects.consume(code);
125906
- return matchChars(ABLE_SUFFIX, afterTagName, nok);
125907
- }
125908
- return nok(code);
125909
- }
125910
- function afterTagName(code) {
125911
- if (code === codes_codes.greaterThan || code === codes_codes.slash || code === codes_codes.space || code === codes_codes.horizontalTab) {
125912
- effects.consume(code);
125913
- return body;
125914
- }
125915
- return nok(code);
125916
- }
125917
- function body(code) {
125918
- // Reject unclosed <Table> so it falls back to normal HTML block parsing
125919
- // instead of swallowing all subsequent content to EOF
125920
- if (code === null) {
125921
- return nok(code);
125922
- }
125923
- if (markdownLineEnding(code)) {
125924
- effects.exit('jsxTableData');
125925
- return continuationStart(code);
125926
- }
125927
- if (code === codes_codes.backslash) {
125928
- effects.consume(code);
125929
- return escapedChar;
125930
- }
125931
- if (code === codes_codes.lessThan) {
125932
- effects.consume(code);
125933
- return closeSlash;
125934
- }
125935
- // Skip over backtick code spans so `</Table>` in inline code isn't
125936
- // treated as the closing tag
125937
- if (code === codes_codes.graveAccent) {
125938
- codeSpanOpenSize = 0;
125939
- return countOpenTicks(code);
125940
- }
125941
- effects.consume(code);
125942
- return body;
125943
- }
125944
- function countOpenTicks(code) {
125945
- if (code === codes_codes.graveAccent) {
125946
- codeSpanOpenSize += 1;
125947
- effects.consume(code);
125948
- return countOpenTicks;
125949
- }
125950
- return inCodeSpan(code);
125951
- }
125952
- function inCodeSpan(code) {
125953
- if (code === null || markdownLineEnding(code))
125954
- return body(code);
125955
- if (code === codes_codes.graveAccent) {
125956
- codeSpanCloseSize = 0;
125957
- return countCloseTicks(code);
125958
- }
125959
- effects.consume(code);
125960
- return inCodeSpan;
125961
- }
125962
- function countCloseTicks(code) {
125963
- if (code === codes_codes.graveAccent) {
125964
- codeSpanCloseSize += 1;
125965
- effects.consume(code);
125966
- return countCloseTicks;
125967
- }
125968
- return codeSpanCloseSize === codeSpanOpenSize ? body(code) : inCodeSpan(code);
125969
- }
125970
- function escapedChar(code) {
125971
- if (code === null || markdownLineEnding(code)) {
125972
- return body(code);
125973
- }
125974
- effects.consume(code);
125975
- return body;
125976
- }
125977
- function closeSlash(code) {
125978
- if (code === codes_codes.slash) {
125979
- effects.consume(code);
125980
- return closeTagFirstChar;
125981
- }
125982
- if (code === codes_codes.uppercaseT || code === codes_codes.lowercaseT) {
125983
- effects.consume(code);
125984
- return matchChars(ABLE_SUFFIX, openAfterTagName, body);
125985
- }
125986
- return body(code);
125987
- }
125988
- function closeTagFirstChar(code) {
125989
- if (code === codes_codes.uppercaseT || code === codes_codes.lowercaseT) {
125990
- effects.consume(code);
125991
- return matchChars(ABLE_SUFFIX, closeGt, body);
125992
- }
125993
- return body(code);
125994
- }
125995
- function openAfterTagName(code) {
125996
- if (code === codes_codes.greaterThan || code === codes_codes.slash || code === codes_codes.space || code === codes_codes.horizontalTab) {
125997
- depth += 1;
125998
- effects.consume(code);
125999
- return body;
126000
- }
126001
- return body(code);
126002
- }
126003
- function closeGt(code) {
126004
- if (code === codes_codes.greaterThan) {
126005
- depth -= 1;
126006
- effects.consume(code);
126007
- if (depth === 0) {
126008
- return afterClose;
126009
- }
126010
- return body;
126011
- }
126012
- return body(code);
126013
- }
126014
- function afterClose(code) {
126015
- if (code === null || markdownLineEnding(code)) {
126016
- effects.exit('jsxTableData');
126017
- effects.exit('jsxTable');
126018
- return ok(code);
126019
- }
126020
- effects.consume(code);
126021
- return afterClose;
126022
- }
126023
- // Line ending handling — follows the htmlFlow pattern
126024
- function continuationStart(code) {
126025
- return effects.check(jsx_table_syntax_nonLazyContinuationStart, continuationStartNonLazy, continuationAfter)(code);
126026
- }
126027
- function continuationStartNonLazy(code) {
126028
- effects.enter(types_types.lineEnding);
126029
- effects.consume(code);
126030
- effects.exit(types_types.lineEnding);
126031
- return continuationBefore;
126032
- }
126033
- function continuationBefore(code) {
126034
- if (code === null || markdownLineEnding(code)) {
126035
- return continuationStart(code);
126036
- }
126037
- effects.enter('jsxTableData');
126038
- return body(code);
126039
- }
126040
- function continuationAfter(code) {
126041
- // At EOF without </Table>, reject so content isn't swallowed
126042
- if (code === null) {
126043
- return nok(code);
126044
- }
126045
- effects.exit('jsxTable');
126046
- return ok(code);
126047
- }
126048
- }
126049
- function jsx_table_syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
126050
- // eslint-disable-next-line @typescript-eslint/no-this-alias
126051
- const self = this;
126052
- return start;
126053
- function start(code) {
126054
- if (markdownLineEnding(code)) {
126055
- effects.enter(types_types.lineEnding);
126056
- effects.consume(code);
126057
- effects.exit(types_types.lineEnding);
126058
- return after;
126059
- }
126060
- return nok(code);
126061
- }
126062
- function after(code) {
126063
- if (self.parser.lazy[self.now().line]) {
126064
- return nok(code);
126065
- }
126066
- return ok(code);
126067
- }
126068
- }
126069
- /**
126070
- * Micromark extension that tokenizes `<Table>...</Table>` and `<table>...</table>`
126071
- * as a single flow block.
126072
- *
126073
- * Prevents CommonMark HTML block type 6 from fragmenting table blocks at blank lines.
126074
- */
126075
- function syntax_jsxTable() {
126076
- return {
126077
- flow: {
126078
- [codes_codes.lessThan]: [jsxTableConstruct],
126079
- },
126080
- };
126081
- }
126082
-
126083
- ;// ./lib/micromark/jsx-table/index.ts
126084
-
126085
-
126086
126562
  ;// ./lib/micromark/mdx-expression-lenient/syntax.ts
126087
126563
 
126088
126564
 
@@ -126102,7 +126578,7 @@ function tokenizeTextExpression(effects, ok, nok) {
126102
126578
  let depth = 0;
126103
126579
  return start;
126104
126580
  function start(code) {
126105
- if (code !== codes_codes.leftCurlyBrace)
126581
+ if (code !== codes.leftCurlyBrace)
126106
126582
  return nok(code);
126107
126583
  effects.enter('mdxTextExpression');
126108
126584
  effects.enter('mdxTextExpressionMarker');
@@ -126111,7 +126587,7 @@ function tokenizeTextExpression(effects, ok, nok) {
126111
126587
  return before;
126112
126588
  }
126113
126589
  function before(code) {
126114
- if (code === codes_codes.eof) {
126590
+ if (code === codes.eof) {
126115
126591
  effects.exit('mdxTextExpression');
126116
126592
  return nok(code);
126117
126593
  }
@@ -126121,24 +126597,24 @@ function tokenizeTextExpression(effects, ok, nok) {
126121
126597
  effects.exit('lineEnding');
126122
126598
  return before;
126123
126599
  }
126124
- if (code === codes_codes.rightCurlyBrace && depth === 0) {
126600
+ if (code === codes.rightCurlyBrace && depth === 0) {
126125
126601
  return close(code);
126126
126602
  }
126127
126603
  effects.enter('mdxTextExpressionChunk');
126128
126604
  return inside(code);
126129
126605
  }
126130
126606
  function inside(code) {
126131
- if (code === codes_codes.eof || markdownLineEnding(code)) {
126607
+ if (code === codes.eof || markdownLineEnding(code)) {
126132
126608
  effects.exit('mdxTextExpressionChunk');
126133
126609
  return before(code);
126134
126610
  }
126135
- if (code === codes_codes.rightCurlyBrace && depth === 0) {
126611
+ if (code === codes.rightCurlyBrace && depth === 0) {
126136
126612
  effects.exit('mdxTextExpressionChunk');
126137
126613
  return close(code);
126138
126614
  }
126139
- if (code === codes_codes.leftCurlyBrace)
126615
+ if (code === codes.leftCurlyBrace)
126140
126616
  depth += 1;
126141
- else if (code === codes_codes.rightCurlyBrace)
126617
+ else if (code === codes.rightCurlyBrace)
126142
126618
  depth -= 1;
126143
126619
  effects.consume(code);
126144
126620
  return inside;
@@ -126154,7 +126630,7 @@ function tokenizeTextExpression(effects, ok, nok) {
126154
126630
  function mdxExpressionLenient() {
126155
126631
  return {
126156
126632
  text: {
126157
- [codes_codes.leftCurlyBrace]: {
126633
+ [codes.leftCurlyBrace]: {
126158
126634
  name: 'mdxTextExpression',
126159
126635
  tokenize: tokenizeTextExpression,
126160
126636
  },
@@ -126258,6 +126734,9 @@ function loadComponents() {
126258
126734
 
126259
126735
 
126260
126736
 
126737
+
126738
+
126739
+
126261
126740
 
126262
126741
 
126263
126742
 
@@ -126272,15 +126751,19 @@ const defaultTransformers = [
126272
126751
  * CommonMark/remark limitations and reach parity with legacy (rdmd) rendering.
126273
126752
  *
126274
126753
  * Runs a series of string-level transformations before micromark/remark parsing:
126275
- * 1. Normalize malformed table separator syntax (e.g., `|: ---``| :---`)
126276
- * 2. Terminate HTML flow blocks so subsequent content isn't swallowed
126277
- * 3. Close invalid "self-closing" HTML tags (e.g., `<i />` → `<i></i>`)
126278
- * 4. Normalize compact ATX headings (e.g., `#Heading``# Heading`)
126279
- * 5. Replace snake_case component names with parser-safe placeholders
126754
+ * 1. Canonicalize closing tags with stray whitespace (e.g., `</ td >` `</td>`)
126755
+ * 2. Normalize malformed table separator syntax (e.g., `|: ---` → `| :---`)
126756
+ * 3. Terminate HTML flow blocks so subsequent content isn't swallowed
126757
+ * 4. Close invalid "self-closing" HTML tags (e.g., `<i />` `<i></i>`)
126758
+ * 5. Normalize compact ATX headings (e.g., `#Heading` → `# Heading`)
126759
+ * 6. Replace snake_case component names with parser-safe placeholders
126280
126760
  */
126281
126761
  function preprocessContent(content, opts) {
126282
126762
  const { knownComponents } = opts;
126283
- let result = normalizeTableSeparator(content);
126763
+ // Runs first so `jsxTable` sees a literal `</table>` (and the HTML-line
126764
+ // classification in `terminateHtmlFlowBlocks` is accurate)
126765
+ let result = normalizeClosingTagWhitespace(content);
126766
+ result = normalizeTableSeparator(result);
126284
126767
  result = terminateHtmlFlowBlocks(result);
126285
126768
  result = closeSelfClosingHtmlTags(result);
126286
126769
  result = normalizeCompactHeadings(result);
@@ -126309,6 +126792,7 @@ function mdxishAstProcessor(mdContent, opts = {}) {
126309
126792
  syntax_gemoji(),
126310
126793
  legacyVariable(),
126311
126794
  looseHtmlEntity(),
126795
+ syntax_htmlBlockComponent(),
126312
126796
  ];
126313
126797
  const fromMarkdownExts = [
126314
126798
  jsx_table_jsxTableFromMarkdown(),
@@ -126318,6 +126802,7 @@ function mdxishAstProcessor(mdContent, opts = {}) {
126318
126802
  legacyVariableFromMarkdown(),
126319
126803
  emptyTaskListItemFromMarkdown(),
126320
126804
  looseHtmlEntityFromMarkdown(),
126805
+ html_block_component_htmlBlockComponentFromMarkdown(),
126321
126806
  ];
126322
126807
  if (!safeMode) {
126323
126808
  // Insert mdx expression (text-only, no flow) after gemoji at index 3
@@ -126331,6 +126816,10 @@ function mdxishAstProcessor(mdContent, opts = {}) {
126331
126816
  // JSX comment tokenizer must come before magicBlock so it claims `{/* ... */}` first
126332
126817
  micromarkExts.unshift(jsxComment());
126333
126818
  }
126819
+ // Claim `<HTMLBlock>` as one opaque token so broad tokenizers can't fragment its body
126820
+ // We put this last as micromark tries the last-registered extension first, so push (not unshift) to win the `<` race.
126821
+ // micromarkExts.push(htmlBlockComponent());
126822
+ // fromMarkdownExts.push(htmlBlockComponentFromMarkdown());
126334
126823
  const processor = lib_unified()
126335
126824
  .data('micromarkExtensions', micromarkExts)
126336
126825
  .data('fromMarkdownExtensions', fromMarkdownExts)
@@ -126386,6 +126875,12 @@ function mdxishMdastToMd(mdast) {
126386
126875
  .use(remarkStringify, {
126387
126876
  bullet: '-',
126388
126877
  emphasis: '_',
126878
+ // Escape literal braces in text so they don't parse as (often
126879
+ // unterminated) MDX expressions on the next round trip.
126880
+ unsafe: [
126881
+ { character: '{', inConstruct: 'phrasing' },
126882
+ { character: '}', inConstruct: 'phrasing' },
126883
+ ],
126389
126884
  });
126390
126885
  return processor.stringify(processor.runSync(mdast));
126391
126886
  }
@@ -126868,332 +127363,6 @@ const mdxishTags_tags = (doc) => {
126868
127363
  };
126869
127364
  /* harmony default export */ const mdxishTags = ((/* unused pure expression or super */ null && (mdxishTags_tags)));
126870
127365
 
126871
- ;// ./lib/mdast-util/html-block-component/index.ts
126872
- const html_block_component_contextMap = new WeakMap();
126873
- function findHtmlBlockComponentToken() {
126874
- const events = this.tokenStack;
126875
- for (let i = events.length - 1; i >= 0; i -= 1) {
126876
- if (events[i][0].type === 'htmlBlockComponent')
126877
- return events[i][0];
126878
- }
126879
- return undefined;
126880
- }
126881
- function enterHtmlBlockComponent(token) {
126882
- html_block_component_contextMap.set(token, { chunks: [], lastEndLine: token.start.line });
126883
- this.enter({ type: 'html', value: '' }, token);
126884
- }
126885
- function exitHtmlBlockComponentData(token) {
126886
- const componentToken = findHtmlBlockComponentToken.call(this);
126887
- if (!componentToken)
126888
- return;
126889
- const ctx = html_block_component_contextMap.get(componentToken);
126890
- if (ctx) {
126891
- const gap = token.start.line - ctx.lastEndLine;
126892
- if (ctx.chunks.length > 0 && gap > 0) {
126893
- ctx.chunks.push('\n'.repeat(gap));
126894
- }
126895
- ctx.chunks.push(this.sliceSerialize(token));
126896
- ctx.lastEndLine = token.end.line;
126897
- }
126898
- }
126899
- function exitHtmlBlockComponent(token) {
126900
- const ctx = html_block_component_contextMap.get(token);
126901
- const node = this.stack[this.stack.length - 1];
126902
- if (ctx) {
126903
- node.value = ctx.chunks.join('');
126904
- html_block_component_contextMap.delete(token);
126905
- }
126906
- this.exit(token);
126907
- }
126908
- function html_block_component_htmlBlockComponentFromMarkdown() {
126909
- return {
126910
- enter: {
126911
- htmlBlockComponent: enterHtmlBlockComponent,
126912
- },
126913
- exit: {
126914
- htmlBlockComponentData: exitHtmlBlockComponentData,
126915
- htmlBlockComponent: exitHtmlBlockComponent,
126916
- },
126917
- };
126918
- }
126919
-
126920
- ;// ./lib/micromark/html-block-component/syntax.ts
126921
-
126922
-
126923
- const TAG_SUFFIX = [
126924
- codes_codes.uppercaseT,
126925
- codes_codes.uppercaseM,
126926
- codes_codes.uppercaseL,
126927
- codes_codes.uppercaseB,
126928
- codes_codes.lowercaseL,
126929
- codes_codes.lowercaseO,
126930
- codes_codes.lowercaseC,
126931
- codes_codes.lowercaseK,
126932
- ];
126933
- // ---------------------------------------------------------------------------
126934
- // Shared tokenizer factory
126935
- // ---------------------------------------------------------------------------
126936
- /**
126937
- * Creates a tokenize function for `<HTMLBlock>...</HTMLBlock>`.
126938
- *
126939
- * - **flow** (block-level): supports multiline content via line continuations,
126940
- * consumes trailing whitespace after the closing tag.
126941
- * - **text** (inline): single-line only, exits immediately after the closing tag.
126942
- */
126943
- function syntax_createTokenize(mode) {
126944
- return function tokenize(effects, ok, nok) {
126945
- let depth = 1;
126946
- function matchChars(chars, onMatch, onFail) {
126947
- if (chars.length === 0)
126948
- return onMatch;
126949
- const next = (code) => {
126950
- if (code === chars[0]) {
126951
- effects.consume(code);
126952
- return matchChars(chars.slice(1), onMatch, onFail);
126953
- }
126954
- return onFail(code);
126955
- };
126956
- return next;
126957
- }
126958
- function matchTagName(onMatch, onFail) {
126959
- const next = (code) => {
126960
- if (code === codes_codes.uppercaseH) {
126961
- effects.consume(code);
126962
- return matchChars(TAG_SUFFIX, onMatch, onFail);
126963
- }
126964
- return onFail(code);
126965
- };
126966
- return next;
126967
- }
126968
- return start;
126969
- function start(code) {
126970
- if (code !== codes_codes.lessThan)
126971
- return nok(code);
126972
- effects.enter('htmlBlockComponent');
126973
- effects.enter('htmlBlockComponentData');
126974
- effects.consume(code);
126975
- return matchTagName(afterTagName, nok);
126976
- }
126977
- function afterTagName(code) {
126978
- if (code === codes_codes.greaterThan) {
126979
- effects.consume(code);
126980
- return body;
126981
- }
126982
- if (code === codes_codes.space || code === codes_codes.horizontalTab) {
126983
- effects.consume(code);
126984
- return inAttributes;
126985
- }
126986
- if (mode === 'flow' && markdownLineEnding(code)) {
126987
- effects.exit('htmlBlockComponentData');
126988
- return attributeContinuationStart(code);
126989
- }
126990
- if (code === codes_codes.slash) {
126991
- effects.consume(code);
126992
- return selfClose;
126993
- }
126994
- return nok(code);
126995
- }
126996
- function inAttributes(code) {
126997
- if (code === codes_codes.greaterThan) {
126998
- effects.consume(code);
126999
- return body;
127000
- }
127001
- if (code === null) {
127002
- return nok(code);
127003
- }
127004
- if (markdownLineEnding(code)) {
127005
- if (mode === 'text')
127006
- return nok(code);
127007
- effects.exit('htmlBlockComponentData');
127008
- return attributeContinuationStart(code);
127009
- }
127010
- effects.consume(code);
127011
- return inAttributes;
127012
- }
127013
- function attributeContinuationStart(code) {
127014
- return effects.check(html_block_component_syntax_nonLazyContinuationStart, attributeContinuationNonLazy, continuationAfter)(code);
127015
- }
127016
- function attributeContinuationNonLazy(code) {
127017
- effects.enter(types_types.lineEnding);
127018
- effects.consume(code);
127019
- effects.exit(types_types.lineEnding);
127020
- return attributeContinuationBefore;
127021
- }
127022
- function attributeContinuationBefore(code) {
127023
- if (code === null || markdownLineEnding(code)) {
127024
- return attributeContinuationStart(code);
127025
- }
127026
- effects.enter('htmlBlockComponentData');
127027
- return inAttributes(code);
127028
- }
127029
- function selfClose(code) {
127030
- if (code === codes_codes.greaterThan) {
127031
- effects.consume(code);
127032
- return mode === 'flow' ? afterClose : done(code);
127033
- }
127034
- return nok(code);
127035
- }
127036
- function body(code) {
127037
- if (code === null)
127038
- return nok(code);
127039
- if (markdownLineEnding(code)) {
127040
- if (mode === 'text') {
127041
- // Text constructs operate on paragraph content which spans lines
127042
- effects.consume(code);
127043
- return body;
127044
- }
127045
- effects.exit('htmlBlockComponentData');
127046
- return continuationStart(code);
127047
- }
127048
- if (code === codes_codes.lessThan) {
127049
- effects.consume(code);
127050
- return closeSlash;
127051
- }
127052
- effects.consume(code);
127053
- return body;
127054
- }
127055
- function closeSlash(code) {
127056
- if (code === codes_codes.slash) {
127057
- effects.consume(code);
127058
- return matchTagName(closeGt, body);
127059
- }
127060
- return matchTagName(openAfterTagName, body)(code);
127061
- }
127062
- function openAfterTagName(code) {
127063
- if (code === codes_codes.greaterThan || code === codes_codes.space || code === codes_codes.horizontalTab) {
127064
- depth += 1;
127065
- effects.consume(code);
127066
- return body;
127067
- }
127068
- return body(code);
127069
- }
127070
- function closeGt(code) {
127071
- if (code === codes_codes.greaterThan) {
127072
- depth -= 1;
127073
- effects.consume(code);
127074
- if (depth === 0) {
127075
- return mode === 'flow' ? afterClose : done(code);
127076
- }
127077
- return body;
127078
- }
127079
- return body(code);
127080
- }
127081
- // -- flow-only states ---------------------------------------------------
127082
- function afterClose(code) {
127083
- if (code === null || markdownLineEnding(code)) {
127084
- return done(code);
127085
- }
127086
- if (code === codes_codes.space || code === codes_codes.horizontalTab) {
127087
- effects.consume(code);
127088
- return afterClose;
127089
- }
127090
- // Reject so the block re-parses as a paragraph, deferring to the
127091
- // text tokenizer which preserves trailing content in the same line.
127092
- return nok(code);
127093
- }
127094
- // -- flow-only: line continuation ---------------------------------------
127095
- function continuationStart(code) {
127096
- return effects.check(html_block_component_syntax_nonLazyContinuationStart, continuationStartNonLazy, continuationAfter)(code);
127097
- }
127098
- function continuationStartNonLazy(code) {
127099
- effects.enter(types_types.lineEnding);
127100
- effects.consume(code);
127101
- effects.exit(types_types.lineEnding);
127102
- return continuationBefore;
127103
- }
127104
- function continuationBefore(code) {
127105
- if (code === null || markdownLineEnding(code)) {
127106
- return continuationStart(code);
127107
- }
127108
- effects.enter('htmlBlockComponentData');
127109
- return body(code);
127110
- }
127111
- function continuationAfter(code) {
127112
- if (code === null)
127113
- return nok(code);
127114
- effects.exit('htmlBlockComponent');
127115
- return ok(code);
127116
- }
127117
- // -- shared exit --------------------------------------------------------
127118
- function done(_code) {
127119
- effects.exit('htmlBlockComponentData');
127120
- effects.exit('htmlBlockComponent');
127121
- return ok(_code);
127122
- }
127123
- };
127124
- }
127125
- // ---------------------------------------------------------------------------
127126
- // Flow construct (block-level)
127127
- // ---------------------------------------------------------------------------
127128
- const html_block_component_syntax_nonLazyContinuationStart = {
127129
- tokenize: html_block_component_syntax_tokenizeNonLazyContinuationStart,
127130
- partial: true,
127131
- };
127132
- function resolveToHtmlBlockComponent(events) {
127133
- let index = events.length;
127134
- while (index > 0) {
127135
- index -= 1;
127136
- if (events[index][0] === 'enter' && events[index][1].type === 'htmlBlockComponent') {
127137
- break;
127138
- }
127139
- }
127140
- if (index > 1 && events[index - 2][1].type === types_types.linePrefix) {
127141
- events[index][1].start = events[index - 2][1].start;
127142
- events[index + 1][1].start = events[index - 2][1].start;
127143
- events.splice(index - 2, 2);
127144
- }
127145
- return events;
127146
- }
127147
- const htmlBlockComponentFlowConstruct = {
127148
- name: 'htmlBlockComponent',
127149
- tokenize: syntax_createTokenize('flow'),
127150
- resolveTo: resolveToHtmlBlockComponent,
127151
- concrete: true,
127152
- };
127153
- function html_block_component_syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
127154
- // eslint-disable-next-line @typescript-eslint/no-this-alias
127155
- const self = this;
127156
- return start;
127157
- function start(code) {
127158
- if (markdownLineEnding(code)) {
127159
- effects.enter(types_types.lineEnding);
127160
- effects.consume(code);
127161
- effects.exit(types_types.lineEnding);
127162
- return after;
127163
- }
127164
- return nok(code);
127165
- }
127166
- function after(code) {
127167
- if (self.parser.lazy[self.now().line]) {
127168
- return nok(code);
127169
- }
127170
- return ok(code);
127171
- }
127172
- }
127173
- // ---------------------------------------------------------------------------
127174
- // Text construct (inline)
127175
- // ---------------------------------------------------------------------------
127176
- const htmlBlockComponentTextConstruct = {
127177
- name: 'htmlBlockComponent',
127178
- tokenize: syntax_createTokenize('text'),
127179
- };
127180
- // ---------------------------------------------------------------------------
127181
- // Extension
127182
- // ---------------------------------------------------------------------------
127183
- function syntax_htmlBlockComponent() {
127184
- return {
127185
- flow: {
127186
- [codes.lessThan]: [htmlBlockComponentFlowConstruct],
127187
- },
127188
- text: {
127189
- [codes.lessThan]: [htmlBlockComponentTextConstruct],
127190
- },
127191
- };
127192
- }
127193
-
127194
- ;// ./lib/micromark/html-block-component/index.ts
127195
-
127196
-
127197
127366
  ;// ./lib/stripComments.ts
127198
127367
 
127199
127368