@readme/markdown 14.11.5 → 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.
package/dist/main.js CHANGED
@@ -1,13 +1,13 @@
1
1
  (function webpackUniversalModuleDefinition(root, factory) {
2
2
  if(typeof exports === 'object' && typeof module === 'object')
3
- module.exports = factory(require("@readme/syntax-highlighter"), require("@readme/variable"), require("@tippyjs/react"), require("acorn"), require("mermaid"), require("react"), require("react-dom"));
3
+ module.exports = factory(require("@readme/syntax-highlighter"), require("@readme/variable"), require("@tippyjs/react"), require("acorn"), require("react"), require("react-dom"));
4
4
  else if(typeof define === 'function' && define.amd)
5
- define(["@readme/syntax-highlighter", "@readme/variable", "@tippyjs/react", "acorn", "mermaid", "react", "react-dom"], factory);
5
+ define(["@readme/syntax-highlighter", "@readme/variable", "@tippyjs/react", "acorn", "react", "react-dom"], factory);
6
6
  else {
7
- var a = typeof exports === 'object' ? factory(require("@readme/syntax-highlighter"), require("@readme/variable"), require("@tippyjs/react"), require("acorn"), require("mermaid"), require("react"), require("react-dom")) : factory(root["@readme/syntax-highlighter"], root["@readme/variable"], root["@tippyjs/react"], root["acorn"], root["mermaid"], root["React"], root["ReactDOM"]);
7
+ var a = typeof exports === 'object' ? factory(require("@readme/syntax-highlighter"), require("@readme/variable"), require("@tippyjs/react"), require("acorn"), require("react"), require("react-dom")) : factory(root["@readme/syntax-highlighter"], root["@readme/variable"], root["@tippyjs/react"], root["acorn"], root["React"], root["ReactDOM"]);
8
8
  for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
9
9
  }
10
- })(self, (__WEBPACK_EXTERNAL_MODULE__3966__, __WEBPACK_EXTERNAL_MODULE__8167__, __WEBPACK_EXTERNAL_MODULE__4189__, __WEBPACK_EXTERNAL_MODULE__6473__, __WEBPACK_EXTERNAL_MODULE__1387__, __WEBPACK_EXTERNAL_MODULE__1307__, __WEBPACK_EXTERNAL_MODULE__8759__) => {
10
+ })(self, (__WEBPACK_EXTERNAL_MODULE__3966__, __WEBPACK_EXTERNAL_MODULE__8167__, __WEBPACK_EXTERNAL_MODULE__4189__, __WEBPACK_EXTERNAL_MODULE__6473__, __WEBPACK_EXTERNAL_MODULE__1307__, __WEBPACK_EXTERNAL_MODULE__8759__) => {
11
11
  return /******/ (() => { // webpackBootstrap
12
12
  /******/ var __webpack_modules__ = ({
13
13
 
@@ -11327,6 +11327,14 @@ module.exports = function () {
11327
11327
  };
11328
11328
 
11329
11329
 
11330
+ /***/ }),
11331
+
11332
+ /***/ 9446:
11333
+ /***/ ((module) => {
11334
+
11335
+ "use strict";
11336
+ module.exports = import("mermaid");;
11337
+
11330
11338
  /***/ }),
11331
11339
 
11332
11340
  /***/ 3966:
@@ -11361,14 +11369,6 @@ module.exports = __WEBPACK_EXTERNAL_MODULE__6473__;
11361
11369
 
11362
11370
  /***/ }),
11363
11371
 
11364
- /***/ 1387:
11365
- /***/ ((module) => {
11366
-
11367
- "use strict";
11368
- module.exports = __WEBPACK_EXTERNAL_MODULE__1387__;
11369
-
11370
- /***/ }),
11371
-
11372
11372
  /***/ 1307:
11373
11373
  /***/ ((module) => {
11374
11374
 
@@ -11975,7 +11975,7 @@ function queueMermaidNode(node, theme) {
11975
11975
  const nodes = [...mermaidQueue];
11976
11976
  mermaidQueue = [];
11977
11977
  mermaidFlushTimer = null;
11978
- const module = await Promise.resolve(/* import() */).then(__webpack_require__.t.bind(__webpack_require__, 1387, 23));
11978
+ const module = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 9446));
11979
11979
  mermaid = module.default;
11980
11980
  mermaid.initialize({
11981
11981
  startOnLoad: false,
@@ -12211,17 +12211,12 @@ const extractScripts = (html = '') => {
12211
12211
  return [cleaned, () => scripts.map(js => window.eval(js))];
12212
12212
  };
12213
12213
  const HTMLBlock = ({ children = '', html: htmlProp, runScripts, safeMode: safeModeRaw = false }) => {
12214
- // Determine HTML source: MDXish uses html prop (from HAST), MDX uses children
12215
- let html = '';
12216
- if (htmlProp !== undefined) {
12217
- html = htmlProp;
12218
- }
12219
- else {
12220
- if (typeof children !== 'string') {
12221
- throw new TypeError('HTMLBlock: children must be a string');
12222
- }
12223
- html = children;
12224
- }
12214
+ // Determine HTML source: MDXish uses html prop (from HAST), MDX uses children.
12215
+ // A non-string child (no html prop) can't be injected as raw HTML — see the
12216
+ // fail-soft fallback below.
12217
+ const htmlSource = htmlProp !== undefined ? htmlProp : children;
12218
+ const nonStringChildren = typeof htmlSource !== 'string';
12219
+ const html = nonStringChildren ? '' : htmlSource;
12225
12220
  // eslint-disable-next-line no-param-reassign
12226
12221
  runScripts = typeof runScripts !== 'boolean' ? runScripts === 'true' : runScripts;
12227
12222
  // In MDX mode, safeMode is passed in as a boolean from JSX parsing
@@ -12232,6 +12227,11 @@ const HTMLBlock = ({ children = '', html: htmlProp, runScripts, safeMode: safeMo
12232
12227
  if (typeof window !== 'undefined' && typeof runScripts === 'boolean' && runScripts)
12233
12228
  exec();
12234
12229
  }, [runScripts, exec]);
12230
+ if (nonStringChildren) {
12231
+ // Fail soft: a non-string child (e.g. JSX that wasn't serialized back to a
12232
+ // raw string) should never throw, so render the child nodes directly
12233
+ return external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("div", { className: "rdmd-html" }, children);
12234
+ }
12235
12235
  if (safeMode) {
12236
12236
  return (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("pre", { className: "html-unsafe" },
12237
12237
  external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("code", null, html)));
@@ -76446,6 +76446,9 @@ const TOP_LEVEL_TABLE_TAG_RE = /^<(?:table|Table)(?=[\s/>])/;
76446
76446
  * Uses `walkTags` so `<table>`s inside code spans / fenced blocks (masked away)
76447
76447
  * are never matched.
76448
76448
  *
76449
+ * `<table>`s inside an `<HTMLBlock>` body are also ignored: that body is opaque
76450
+ * raw HTML, so lifting a table out of it would corrupt the block.
76451
+ *
76449
76452
  * Note: An implicitly-closed table (no `</table>`, so htmlparser2 synthesizes the
76450
76453
  * close at a later tag) is skipped: splitting there would swallow whatever
76451
76454
  * followed the table into the fragment and drop it, so we leave such a node
@@ -76453,21 +76456,35 @@ const TOP_LEVEL_TABLE_TAG_RE = /^<(?:table|Table)(?=[\s/>])/;
76453
76456
  */
76454
76457
  const findTableRanges = (html) => {
76455
76458
  const ranges = [];
76456
- let depth = 0;
76459
+ let tableDepth = 0;
76460
+ let htmlBlockDepth = 0;
76457
76461
  let start = 0;
76458
76462
  walkTags(html, {
76459
- onOpen: ({ name, start: openStart, isStrayCloser }) => {
76460
- if (name.toLowerCase() !== 'table' || isStrayCloser)
76463
+ onOpen: ({ name, start: openStart, isSelfClosing, isStrayCloser }) => {
76464
+ if (isStrayCloser)
76461
76465
  return;
76462
- if (depth === 0)
76466
+ // `<HTMLBlock/>` has no body to protect; only a real open enters one.
76467
+ if (name === 'HTMLBlock') {
76468
+ if (!isSelfClosing)
76469
+ htmlBlockDepth += 1;
76470
+ return;
76471
+ }
76472
+ if (htmlBlockDepth > 0 || name.toLowerCase() !== 'table')
76473
+ return;
76474
+ if (tableDepth === 0)
76463
76475
  start = openStart;
76464
- depth += 1;
76476
+ tableDepth += 1;
76465
76477
  },
76466
76478
  onClose: ({ name, end, implicit }) => {
76467
- if (implicit || name.toLowerCase() !== 'table' || depth === 0)
76479
+ if (name === 'HTMLBlock') {
76480
+ if (!implicit && htmlBlockDepth > 0)
76481
+ htmlBlockDepth -= 1;
76468
76482
  return;
76469
- depth -= 1;
76470
- if (depth === 0)
76483
+ }
76484
+ if (implicit || htmlBlockDepth > 0 || name.toLowerCase() !== 'table' || tableDepth === 0)
76485
+ return;
76486
+ tableDepth -= 1;
76487
+ if (tableDepth === 0)
76471
76488
  ranges.push({ start, end });
76472
76489
  },
76473
76490
  });
@@ -76487,7 +76504,9 @@ const splitHtmlWithNestedTables = (node) => {
76487
76504
  // This is a top-level table, so we don't need to split it
76488
76505
  if (TOP_LEVEL_TABLE_TAG_RE.test(value))
76489
76506
  return null;
76490
- // No table text anywhere in the value → skip the htmlparser2 walk entirely.
76507
+ // No table text anywhere → skip the htmlparser2 walk entirely. (A `<table>` that
76508
+ // only appears inside an `<HTMLBlock>` body still yields no ranges below, so it's
76509
+ // left whole for `mdxishHtmlBlocks` to convert to an html-block next.)
76491
76510
  if (!/<\/?table/i.test(value))
76492
76511
  return null;
76493
76512
  const ranges = findTableRanges(value);
@@ -99649,6 +99668,55 @@ function emptyTaskListItemFromMarkdown() {
99649
99668
  };
99650
99669
  }
99651
99670
 
99671
+ ;// ./lib/mdast-util/jsx-table/index.ts
99672
+ const jsx_table_contextMap = new WeakMap();
99673
+ function findJsxTableToken() {
99674
+ const events = this.tokenStack;
99675
+ for (let i = events.length - 1; i >= 0; i -= 1) {
99676
+ if (events[i][0].type === 'jsxTable')
99677
+ return events[i][0];
99678
+ }
99679
+ return undefined;
99680
+ }
99681
+ function enterJsxTable(token) {
99682
+ jsx_table_contextMap.set(token, { chunks: [], lastEndLine: token.start.line });
99683
+ this.enter({ type: 'html', value: '' }, token);
99684
+ }
99685
+ function exitJsxTableData(token) {
99686
+ const tableToken = findJsxTableToken.call(this);
99687
+ if (!tableToken)
99688
+ return;
99689
+ const ctx = jsx_table_contextMap.get(tableToken);
99690
+ if (ctx) {
99691
+ const gap = token.start.line - ctx.lastEndLine;
99692
+ if (ctx.chunks.length > 0 && gap > 0) {
99693
+ ctx.chunks.push('\n'.repeat(gap));
99694
+ }
99695
+ ctx.chunks.push(this.sliceSerialize(token));
99696
+ ctx.lastEndLine = token.end.line;
99697
+ }
99698
+ }
99699
+ function exitJsxTable(token) {
99700
+ const ctx = jsx_table_contextMap.get(token);
99701
+ const node = this.stack[this.stack.length - 1];
99702
+ if (ctx) {
99703
+ node.value = ctx.chunks.join('');
99704
+ jsx_table_contextMap.delete(token);
99705
+ }
99706
+ this.exit(token);
99707
+ }
99708
+ function jsxTableFromMarkdown() {
99709
+ return {
99710
+ enter: {
99711
+ jsxTable: enterJsxTable,
99712
+ },
99713
+ exit: {
99714
+ jsxTableData: exitJsxTableData,
99715
+ jsxTable: exitJsxTable,
99716
+ },
99717
+ };
99718
+ }
99719
+
99652
99720
  ;// ./lib/mdast-util/magic-block/index.ts
99653
99721
  const magic_block_contextMap = new WeakMap();
99654
99722
  /**
@@ -99838,867 +99906,16 @@ function mdxComponentFromMarkdown() {
99838
99906
  };
99839
99907
  }
99840
99908
 
99841
- ;// ./lib/micromark/magic-block/syntax.ts
99842
-
99843
-
99844
- /**
99845
- * Known magic block types that the tokenizer will recognize.
99846
- * Unknown types will not be tokenized as magic blocks.
99847
- */
99848
- const KNOWN_BLOCK_TYPES = new Set([
99849
- 'code',
99850
- 'api-header',
99851
- 'image',
99852
- 'callout',
99853
- 'parameters',
99854
- 'table',
99855
- 'embed',
99856
- 'html',
99857
- 'recipe',
99858
- 'tutorial-tile',
99859
- ]);
99860
- /**
99861
- * Check if a character is valid for a magic block type identifier.
99862
- * Types can contain alphanumeric characters and hyphens (e.g., "api-header", "tutorial-tile")
99863
- */
99864
- function isTypeChar(code) {
99865
- return asciiAlphanumeric(code) || code === codes.dash;
99866
- }
99867
- /**
99868
- * Creates the opening marker state machine: [block:
99869
- * Returns the first state function to start parsing.
99870
- */
99871
- function createOpeningMarkerParser(effects, nok, onComplete) {
99872
- const expectB = (code) => {
99873
- if (code !== codes.lowercaseB)
99874
- return nok(code);
99875
- effects.consume(code);
99876
- return expectL;
99877
- };
99878
- const expectL = (code) => {
99879
- if (code !== codes.lowercaseL)
99880
- return nok(code);
99881
- effects.consume(code);
99882
- return expectO;
99883
- };
99884
- const expectO = (code) => {
99885
- if (code !== codes.lowercaseO)
99886
- return nok(code);
99887
- effects.consume(code);
99888
- return expectC;
99889
- };
99890
- const expectC = (code) => {
99891
- if (code !== codes.lowercaseC)
99892
- return nok(code);
99893
- effects.consume(code);
99894
- return expectK;
99895
- };
99896
- const expectK = (code) => {
99897
- if (code !== codes.lowercaseK)
99898
- return nok(code);
99899
- effects.consume(code);
99900
- return expectColon;
99901
- };
99902
- const expectColon = (code) => {
99903
- if (code !== codes.colon)
99904
- return nok(code);
99905
- effects.consume(code);
99906
- effects.exit('magicBlockMarkerStart');
99907
- effects.enter('magicBlockType');
99908
- return onComplete;
99909
- };
99910
- return expectB;
99911
- }
99912
- /**
99913
- * Creates the type capture state machine.
99914
- * Captures type characters until ] and validates against known types.
99915
- */
99916
- function createTypeCaptureParser(effects, nok, onComplete, blockTypeRef) {
99917
- const captureTypeFirst = (code) => {
99918
- // Reject empty type name [block:]
99919
- if (code === codes.rightSquareBracket) {
99920
- return nok(code);
99921
- }
99922
- if (isTypeChar(code)) {
99923
- blockTypeRef.value += String.fromCharCode(code);
99924
- effects.consume(code);
99925
- return captureType;
99926
- }
99927
- return nok(code);
99928
- };
99929
- const captureType = (code) => {
99930
- if (code === codes.rightSquareBracket) {
99931
- if (!KNOWN_BLOCK_TYPES.has(blockTypeRef.value)) {
99932
- return nok(code);
99933
- }
99934
- effects.exit('magicBlockType');
99935
- effects.enter('magicBlockMarkerTypeEnd');
99936
- effects.consume(code);
99937
- effects.exit('magicBlockMarkerTypeEnd');
99938
- return onComplete;
99939
- }
99940
- if (isTypeChar(code)) {
99941
- blockTypeRef.value += String.fromCharCode(code);
99942
- effects.consume(code);
99943
- return captureType;
99944
- }
99945
- return nok(code);
99946
- };
99947
- return { first: captureTypeFirst, remaining: captureType };
99948
- }
99949
- /**
99950
- * Creates the closing marker state machine: /block]
99951
- * Handles partial matches by calling onMismatch to fall back to data capture.
99952
- */
99953
- function createClosingMarkerParser(effects, onSuccess, onMismatch, onEof, jsonState) {
99954
- const handleMismatch = (code) => {
99955
- if (jsonState && code === codes.quotationMark) {
99956
- jsonState.inString = true;
99957
- }
99958
- return onMismatch(code);
99959
- };
99960
- const expectSlash = (code) => {
99961
- if (code === null)
99962
- return onEof(code);
99963
- if (code !== codes.slash)
99964
- return handleMismatch(code);
99965
- effects.consume(code);
99966
- return expectB;
99967
- };
99968
- const expectB = (code) => {
99969
- if (code === null)
99970
- return onEof(code);
99971
- if (code !== codes.lowercaseB)
99972
- return handleMismatch(code);
99973
- effects.consume(code);
99974
- return expectL;
99975
- };
99976
- const expectL = (code) => {
99977
- if (code === null)
99978
- return onEof(code);
99979
- if (code !== codes.lowercaseL)
99980
- return handleMismatch(code);
99981
- effects.consume(code);
99982
- return expectO;
99983
- };
99984
- const expectO = (code) => {
99985
- if (code === null)
99986
- return onEof(code);
99987
- if (code !== codes.lowercaseO)
99988
- return handleMismatch(code);
99989
- effects.consume(code);
99990
- return expectC;
99991
- };
99992
- const expectC = (code) => {
99993
- if (code === null)
99994
- return onEof(code);
99995
- if (code !== codes.lowercaseC)
99996
- return handleMismatch(code);
99997
- effects.consume(code);
99998
- return expectK;
99999
- };
100000
- const expectK = (code) => {
100001
- if (code === null)
100002
- return onEof(code);
100003
- if (code !== codes.lowercaseK)
100004
- return handleMismatch(code);
100005
- effects.consume(code);
100006
- return expectBracket;
100007
- };
100008
- const expectBracket = (code) => {
100009
- if (code === null)
100010
- return onEof(code);
100011
- if (code !== codes.rightSquareBracket)
100012
- return handleMismatch(code);
100013
- effects.consume(code);
100014
- return onSuccess;
100015
- };
100016
- return { expectSlash };
100017
- }
100018
- /**
100019
- * Partial construct for checking non-lazy continuation.
100020
- * This is used by the flow tokenizer to check if we can continue
100021
- * parsing on the next line.
100022
- */
100023
- const syntax_nonLazyContinuation = {
100024
- partial: true,
100025
- tokenize: syntax_tokenizeNonLazyContinuation,
100026
- };
100027
- /**
100028
- * Tokenizer for non-lazy continuation checking.
100029
- * Returns ok if the next line is non-lazy (can continue), nok if lazy.
100030
- */
100031
- function syntax_tokenizeNonLazyContinuation(effects, ok, nok) {
100032
- const lineStart = (code) => {
100033
- // `this` here refers to the micromark parser
100034
- // since we are just passing functions as references and not actually calling them
100035
- // micromarks's internal parser will call this automatically with appropriate arguments
100036
- return this.parser.lazy[this.now().line] ? nok(code) : ok(code);
100037
- };
100038
- const start = (code) => {
100039
- if (code === null) {
100040
- return nok(code);
100041
- }
100042
- if (!markdownLineEnding(code)) {
100043
- return nok(code);
100044
- }
100045
- effects.enter('magicBlockLineEnding');
100046
- effects.consume(code);
100047
- effects.exit('magicBlockLineEnding');
100048
- return lineStart;
100049
- };
100050
- return start;
100051
- }
99909
+ ;// ./node_modules/micromark-util-symbol/lib/types.js
100052
99910
  /**
100053
- * Create a micromark extension for magic block syntax.
100054
- *
100055
- * This extension handles both single-line and multiline magic blocks:
100056
- * - Flow construct (concrete): Handles block-level multiline magic blocks at document level
100057
- * - Text construct: Handles inline magic blocks in lists, paragraphs, etc.
99911
+ * This module is compiled away!
100058
99912
  *
100059
- * The flow construct is marked as "concrete" which prevents it from being
100060
- * interrupted by container markers (like `>` for blockquotes or `-` for lists).
100061
- */
100062
- function magicBlock() {
100063
- return {
100064
- // Flow construct - handles block-level magic blocks at document root
100065
- // Marked as concrete to prevent interruption by containers
100066
- flow: {
100067
- [codes.leftSquareBracket]: {
100068
- name: 'magicBlock',
100069
- concrete: true,
100070
- tokenize: tokenizeMagicBlockFlow,
100071
- },
100072
- },
100073
- // Text construct - handles magic blocks in inline contexts (lists, paragraphs)
100074
- text: {
100075
- [codes.leftSquareBracket]: {
100076
- name: 'magicBlock',
100077
- tokenize: tokenizeMagicBlockText,
100078
- },
100079
- },
100080
- };
100081
- }
100082
- /**
100083
- * Flow tokenizer for block-level magic blocks (multiline).
100084
- * Uses the continuation checking pattern from code fences.
100085
- */
100086
- function tokenizeMagicBlockFlow(effects, ok, nok) {
100087
- // State for tracking JSON content
100088
- const jsonState = { escapeNext: false, inString: false };
100089
- const blockTypeRef = { value: '' };
100090
- let seenOpenBrace = false;
100091
- // Create shared parsers for opening marker and type capture
100092
- const typeParser = createTypeCaptureParser(effects, nok, beforeData, blockTypeRef);
100093
- const openingMarkerParser = createOpeningMarkerParser(effects, nok, typeParser.first);
100094
- return start;
100095
- function start(code) {
100096
- if (code !== codes.leftSquareBracket)
100097
- return nok(code);
100098
- effects.enter('magicBlock');
100099
- effects.enter('magicBlockMarkerStart');
100100
- effects.consume(code);
100101
- return openingMarkerParser;
100102
- }
100103
- /**
100104
- * State before data content - handles line endings or starts data capture.
100105
- */
100106
- function beforeData(code) {
100107
- // EOF - magic block must be closed
100108
- if (code === null) {
100109
- effects.exit('magicBlock');
100110
- return nok(code);
100111
- }
100112
- // Line ending before any data - check continuation
100113
- if (markdownLineEnding(code)) {
100114
- return effects.check(syntax_nonLazyContinuation, continuationOkBeforeData, after)(code);
100115
- }
100116
- // Check for closing marker directly (without entering data)
100117
- // This handles cases like [block:type]\n{}\n\n[/block] where there are
100118
- // newlines after the data object
100119
- if (code === codes.leftSquareBracket) {
100120
- effects.enter('magicBlockMarkerEnd');
100121
- effects.consume(code);
100122
- return expectSlashFromContinuation;
100123
- }
100124
- // If we've already seen the opening brace, just continue capturing data
100125
- if (seenOpenBrace) {
100126
- effects.enter('magicBlockData');
100127
- return captureData(code);
100128
- }
100129
- // Skip whitespace (spaces/tabs) before the data - stay in beforeData
100130
- // Don't enter magicBlockData token yet until we confirm there's a '{'
100131
- if (code === codes.space || code === codes.horizontalTab) {
100132
- return beforeDataWhitespace(code);
100133
- }
100134
- // Data must start with '{' for valid JSON
100135
- if (code !== codes.leftCurlyBrace) {
100136
- effects.exit('magicBlock');
100137
- return nok(code);
100138
- }
100139
- // We have '{' - enter data token and start capturing
100140
- seenOpenBrace = true;
100141
- effects.enter('magicBlockData');
100142
- return captureData(code);
100143
- }
100144
- /**
100145
- * Consume whitespace before the data without creating a token.
100146
- * Uses a temporary token to satisfy micromark's requirement.
100147
- */
100148
- function beforeDataWhitespace(code) {
100149
- if (code === null) {
100150
- effects.exit('magicBlock');
100151
- return nok(code);
100152
- }
100153
- if (markdownLineEnding(code)) {
100154
- return effects.check(syntax_nonLazyContinuation, continuationOkBeforeData, after)(code);
100155
- }
100156
- if (code === codes.space || code === codes.horizontalTab) {
100157
- // We need to consume this but can't without a token - use magicBlockData
100158
- // and track that we haven't seen '{' yet
100159
- effects.enter('magicBlockData');
100160
- effects.consume(code);
100161
- return beforeDataWhitespaceContinue;
100162
- }
100163
- if (code === codes.leftCurlyBrace) {
100164
- seenOpenBrace = true;
100165
- effects.enter('magicBlockData');
100166
- return captureData(code);
100167
- }
100168
- effects.exit('magicBlock');
100169
- return nok(code);
100170
- }
100171
- /**
100172
- * Continue consuming whitespace or validate the opening brace.
100173
- */
100174
- function beforeDataWhitespaceContinue(code) {
100175
- if (code === null) {
100176
- effects.exit('magicBlockData');
100177
- effects.exit('magicBlock');
100178
- return nok(code);
100179
- }
100180
- if (markdownLineEnding(code)) {
100181
- effects.exit('magicBlockData');
100182
- return effects.check(syntax_nonLazyContinuation, continuationOk, after)(code);
100183
- }
100184
- if (code === codes.space || code === codes.horizontalTab) {
100185
- effects.consume(code);
100186
- return beforeDataWhitespaceContinue;
100187
- }
100188
- if (code === codes.leftCurlyBrace) {
100189
- seenOpenBrace = true;
100190
- return captureData(code);
100191
- }
100192
- effects.exit('magicBlockData');
100193
- effects.exit('magicBlock');
100194
- return nok(code);
100195
- }
100196
- /**
100197
- * Continuation OK before we've entered data token.
100198
- */
100199
- function continuationOkBeforeData(code) {
100200
- effects.enter('magicBlockLineEnding');
100201
- effects.consume(code);
100202
- effects.exit('magicBlockLineEnding');
100203
- return beforeData; // Stay in beforeData state - don't enter magicBlockData yet
100204
- }
100205
- function captureData(code) {
100206
- // EOF - magic block must be closed
100207
- if (code === null) {
100208
- effects.exit('magicBlockData');
100209
- effects.exit('magicBlock');
100210
- return nok(code);
100211
- }
100212
- // At line ending, check if we can continue on the next line
100213
- if (markdownLineEnding(code)) {
100214
- effects.exit('magicBlockData');
100215
- return effects.check(syntax_nonLazyContinuation, continuationOk, after)(code);
100216
- }
100217
- if (jsonState.escapeNext) {
100218
- jsonState.escapeNext = false;
100219
- effects.consume(code);
100220
- return captureData;
100221
- }
100222
- if (jsonState.inString) {
100223
- if (code === codes.backslash) {
100224
- jsonState.escapeNext = true;
100225
- effects.consume(code);
100226
- return captureData;
100227
- }
100228
- if (code === codes.quotationMark) {
100229
- jsonState.inString = false;
100230
- }
100231
- effects.consume(code);
100232
- return captureData;
100233
- }
100234
- if (code === codes.quotationMark) {
100235
- jsonState.inString = true;
100236
- effects.consume(code);
100237
- return captureData;
100238
- }
100239
- if (code === codes.leftSquareBracket) {
100240
- effects.exit('magicBlockData');
100241
- effects.enter('magicBlockMarkerEnd');
100242
- effects.consume(code);
100243
- return expectSlash;
100244
- }
100245
- effects.consume(code);
100246
- return captureData;
100247
- }
100248
- /**
100249
- * Called when non-lazy continuation check passes - we can continue parsing.
100250
- */
100251
- function continuationOk(code) {
100252
- // Consume the line ending
100253
- effects.enter('magicBlockLineEnding');
100254
- effects.consume(code);
100255
- effects.exit('magicBlockLineEnding');
100256
- return continuationStart;
100257
- }
100258
- /**
100259
- * Start of continuation line - check for more line endings, closing marker, or start capturing data.
100260
- */
100261
- function continuationStart(code) {
100262
- // Handle consecutive line endings
100263
- if (code === null) {
100264
- effects.exit('magicBlock');
100265
- return nok(code);
100266
- }
100267
- if (markdownLineEnding(code)) {
100268
- return effects.check(syntax_nonLazyContinuation, continuationOkBeforeData, after)(code);
100269
- }
100270
- // Check if this is the start of the closing marker [/block]
100271
- // If so, handle it directly without entering magicBlockData
100272
- if (code === codes.leftSquareBracket) {
100273
- effects.enter('magicBlockMarkerEnd');
100274
- effects.consume(code);
100275
- return expectSlashFromContinuation;
100276
- }
100277
- effects.enter('magicBlockData');
100278
- return captureData(code);
100279
- }
100280
- /**
100281
- * Check for closing marker slash when coming from continuation.
100282
- * If not a closing marker, create an empty data token and continue.
100283
- */
100284
- function expectSlashFromContinuation(code) {
100285
- if (code === null) {
100286
- effects.exit('magicBlockMarkerEnd');
100287
- effects.exit('magicBlock');
100288
- return nok(code);
100289
- }
100290
- if (markdownLineEnding(code)) {
100291
- effects.exit('magicBlockMarkerEnd');
100292
- return effects.check(syntax_nonLazyContinuation, continuationOkBeforeData, after)(code);
100293
- }
100294
- if (code === codes.slash) {
100295
- effects.consume(code);
100296
- return expectClosingB;
100297
- }
100298
- // Not a closing marker - this is data content
100299
- // Exit marker and enter data
100300
- effects.exit('magicBlockMarkerEnd');
100301
- effects.enter('magicBlockData');
100302
- // The [ was consumed by the marker, so we need to conceptually "have it" in our data
100303
- // But since we already consumed it into the marker, we need a different approach
100304
- // Re-classify: consume this character as data and continue
100305
- if (code === codes.quotationMark)
100306
- jsonState.inString = true;
100307
- effects.consume(code);
100308
- return captureData;
100309
- }
100310
- function expectSlash(code) {
100311
- if (code === null) {
100312
- effects.exit('magicBlockMarkerEnd');
100313
- effects.exit('magicBlock');
100314
- return nok(code);
100315
- }
100316
- // At line ending during marker parsing
100317
- if (markdownLineEnding(code)) {
100318
- effects.exit('magicBlockMarkerEnd');
100319
- return effects.check(syntax_nonLazyContinuation, continuationOk, after)(code);
100320
- }
100321
- if (code !== codes.slash) {
100322
- effects.exit('magicBlockMarkerEnd');
100323
- effects.enter('magicBlockData');
100324
- if (code === codes.quotationMark)
100325
- jsonState.inString = true;
100326
- effects.consume(code);
100327
- return captureData;
100328
- }
100329
- effects.consume(code);
100330
- return expectClosingB;
100331
- }
100332
- function expectClosingB(code) {
100333
- if (code === null) {
100334
- effects.exit('magicBlockMarkerEnd');
100335
- effects.exit('magicBlock');
100336
- return nok(code);
100337
- }
100338
- if (code !== codes.lowercaseB) {
100339
- effects.exit('magicBlockMarkerEnd');
100340
- effects.enter('magicBlockData');
100341
- if (code === codes.quotationMark)
100342
- jsonState.inString = true;
100343
- effects.consume(code);
100344
- return captureData;
100345
- }
100346
- effects.consume(code);
100347
- return expectClosingL;
100348
- }
100349
- function expectClosingL(code) {
100350
- if (code === null) {
100351
- effects.exit('magicBlockMarkerEnd');
100352
- effects.exit('magicBlock');
100353
- return nok(code);
100354
- }
100355
- if (code !== codes.lowercaseL) {
100356
- effects.exit('magicBlockMarkerEnd');
100357
- effects.enter('magicBlockData');
100358
- if (code === codes.quotationMark)
100359
- jsonState.inString = true;
100360
- effects.consume(code);
100361
- return captureData;
100362
- }
100363
- effects.consume(code);
100364
- return expectClosingO;
100365
- }
100366
- function expectClosingO(code) {
100367
- if (code === null) {
100368
- effects.exit('magicBlockMarkerEnd');
100369
- effects.exit('magicBlock');
100370
- return nok(code);
100371
- }
100372
- if (code !== codes.lowercaseO) {
100373
- effects.exit('magicBlockMarkerEnd');
100374
- effects.enter('magicBlockData');
100375
- if (code === codes.quotationMark)
100376
- jsonState.inString = true;
100377
- effects.consume(code);
100378
- return captureData;
100379
- }
100380
- effects.consume(code);
100381
- return expectClosingC;
100382
- }
100383
- function expectClosingC(code) {
100384
- if (code === null) {
100385
- effects.exit('magicBlockMarkerEnd');
100386
- effects.exit('magicBlock');
100387
- return nok(code);
100388
- }
100389
- if (code !== codes.lowercaseC) {
100390
- effects.exit('magicBlockMarkerEnd');
100391
- effects.enter('magicBlockData');
100392
- if (code === codes.quotationMark)
100393
- jsonState.inString = true;
100394
- effects.consume(code);
100395
- return captureData;
100396
- }
100397
- effects.consume(code);
100398
- return expectClosingK;
100399
- }
100400
- function expectClosingK(code) {
100401
- if (code === null) {
100402
- effects.exit('magicBlockMarkerEnd');
100403
- effects.exit('magicBlock');
100404
- return nok(code);
100405
- }
100406
- if (code !== codes.lowercaseK) {
100407
- effects.exit('magicBlockMarkerEnd');
100408
- effects.enter('magicBlockData');
100409
- if (code === codes.quotationMark)
100410
- jsonState.inString = true;
100411
- effects.consume(code);
100412
- return captureData;
100413
- }
100414
- effects.consume(code);
100415
- return expectClosingBracket;
100416
- }
100417
- function expectClosingBracket(code) {
100418
- if (code === null) {
100419
- effects.exit('magicBlockMarkerEnd');
100420
- effects.exit('magicBlock');
100421
- return nok(code);
100422
- }
100423
- if (code !== codes.rightSquareBracket) {
100424
- effects.exit('magicBlockMarkerEnd');
100425
- effects.enter('magicBlockData');
100426
- if (code === codes.quotationMark)
100427
- jsonState.inString = true;
100428
- effects.consume(code);
100429
- return captureData;
100430
- }
100431
- effects.consume(code);
100432
- effects.exit('magicBlockMarkerEnd');
100433
- // Check for trailing whitespace on the same line
100434
- return consumeTrailing;
100435
- }
100436
- /**
100437
- * Consume trailing whitespace (spaces/tabs) on the same line after [/block].
100438
- * For concrete flow constructs, we must end at eol/eof or fail.
100439
- * Trailing whitespace is consumed; other content causes nok (text tokenizer handles it).
100440
- */
100441
- function consumeTrailing(code) {
100442
- // End of file - done
100443
- if (code === null) {
100444
- effects.exit('magicBlock');
100445
- return ok(code);
100446
- }
100447
- // Line ending - done
100448
- if (markdownLineEnding(code)) {
100449
- effects.exit('magicBlock');
100450
- return ok(code);
100451
- }
100452
- // Space or tab - consume as trailing whitespace
100453
- if (code === codes.space || code === codes.horizontalTab) {
100454
- effects.enter('magicBlockTrailing');
100455
- effects.consume(code);
100456
- return consumeTrailingContinue;
100457
- }
100458
- // Any other character - fail flow tokenizer, let text tokenizer handle it
100459
- effects.exit('magicBlock');
100460
- return nok(code);
100461
- }
100462
- /**
100463
- * Continue consuming trailing whitespace.
100464
- */
100465
- function consumeTrailingContinue(code) {
100466
- // End of file - done
100467
- if (code === null) {
100468
- effects.exit('magicBlockTrailing');
100469
- effects.exit('magicBlock');
100470
- return ok(code);
100471
- }
100472
- // Line ending - done
100473
- if (markdownLineEnding(code)) {
100474
- effects.exit('magicBlockTrailing');
100475
- effects.exit('magicBlock');
100476
- return ok(code);
100477
- }
100478
- // More space or tab - keep consuming
100479
- if (code === codes.space || code === codes.horizontalTab) {
100480
- effects.consume(code);
100481
- return consumeTrailingContinue;
100482
- }
100483
- // Non-whitespace after whitespace - fail flow tokenizer
100484
- effects.exit('magicBlockTrailing');
100485
- effects.exit('magicBlock');
100486
- return nok(code);
100487
- }
100488
- /**
100489
- * Called when we can't continue (lazy line or EOF) - exit the construct.
100490
- */
100491
- function after(code) {
100492
- effects.exit('magicBlock');
100493
- return nok(code);
100494
- }
100495
- }
100496
- /**
100497
- * Text tokenizer for single-line magic blocks only.
100498
- * Used in inline contexts like list items and paragraphs.
100499
- * Multiline blocks are handled by the flow tokenizer.
100500
- */
100501
- function tokenizeMagicBlockText(effects, ok, nok) {
100502
- // State for tracking JSON content
100503
- const jsonState = { escapeNext: false, inString: false };
100504
- const blockTypeRef = { value: '' };
100505
- let seenOpenBrace = false;
100506
- // Create shared parsers for opening marker and type capture
100507
- const typeParser = createTypeCaptureParser(effects, nok, beforeData, blockTypeRef);
100508
- const openingMarkerParser = createOpeningMarkerParser(effects, nok, typeParser.first);
100509
- // Success handler for closing marker - exits tokens and returns ok
100510
- const closingSuccess = (code) => {
100511
- effects.exit('magicBlockMarkerEnd');
100512
- effects.exit('magicBlock');
100513
- return ok(code);
100514
- };
100515
- // Mismatch handler - falls back to data capture
100516
- const closingMismatch = (code) => {
100517
- effects.exit('magicBlockMarkerEnd');
100518
- effects.enter('magicBlockData');
100519
- if (code === codes.quotationMark)
100520
- jsonState.inString = true;
100521
- effects.consume(code);
100522
- return captureData;
100523
- };
100524
- // EOF handler
100525
- const closingEof = (_code) => nok(_code);
100526
- // Create closing marker parsers
100527
- const closingFromBeforeData = createClosingMarkerParser(effects, closingSuccess, closingMismatch, closingEof, jsonState);
100528
- const closingFromData = createClosingMarkerParser(effects, closingSuccess, closingMismatch, closingEof, jsonState);
100529
- return start;
100530
- function start(code) {
100531
- if (code !== codes.leftSquareBracket)
100532
- return nok(code);
100533
- effects.enter('magicBlock');
100534
- effects.enter('magicBlockMarkerStart');
100535
- effects.consume(code);
100536
- return openingMarkerParser;
100537
- }
100538
- /**
100539
- * State before data content - handles line endings before entering data token.
100540
- * Whitespace before '{' is allowed.
100541
- */
100542
- function beforeData(code) {
100543
- // Fail on EOF - magic block must be closed
100544
- if (code === null) {
100545
- return nok(code);
100546
- }
100547
- // Handle line endings before any data - consume them without entering data token
100548
- if (markdownLineEnding(code)) {
100549
- effects.enter('magicBlockLineEnding');
100550
- effects.consume(code);
100551
- effects.exit('magicBlockLineEnding');
100552
- return beforeData;
100553
- }
100554
- // Check for closing marker directly (without entering data)
100555
- if (code === codes.leftSquareBracket) {
100556
- effects.enter('magicBlockMarkerEnd');
100557
- effects.consume(code);
100558
- return closingFromBeforeData.expectSlash;
100559
- }
100560
- // If we've already seen the opening brace, just continue capturing data
100561
- if (seenOpenBrace) {
100562
- effects.enter('magicBlockData');
100563
- return captureData(code);
100564
- }
100565
- // Skip whitespace (spaces/tabs) before the data
100566
- if (code === codes.space || code === codes.horizontalTab) {
100567
- return beforeDataWhitespace(code);
100568
- }
100569
- // Data must start with '{' for valid JSON
100570
- if (code !== codes.leftCurlyBrace) {
100571
- return nok(code);
100572
- }
100573
- // We have '{' - enter data token and start capturing
100574
- seenOpenBrace = true;
100575
- effects.enter('magicBlockData');
100576
- return captureData(code);
100577
- }
100578
- /**
100579
- * Consume whitespace before the data.
100580
- */
100581
- function beforeDataWhitespace(code) {
100582
- if (code === null) {
100583
- return nok(code);
100584
- }
100585
- if (markdownLineEnding(code)) {
100586
- effects.enter('magicBlockLineEnding');
100587
- effects.consume(code);
100588
- effects.exit('magicBlockLineEnding');
100589
- return beforeData;
100590
- }
100591
- if (code === codes.space || code === codes.horizontalTab) {
100592
- effects.enter('magicBlockData');
100593
- effects.consume(code);
100594
- return beforeDataWhitespaceContinue;
100595
- }
100596
- if (code === codes.leftCurlyBrace) {
100597
- seenOpenBrace = true;
100598
- effects.enter('magicBlockData');
100599
- return captureData(code);
100600
- }
100601
- return nok(code);
100602
- }
100603
- /**
100604
- * Continue consuming whitespace or validate the opening brace.
100605
- */
100606
- function beforeDataWhitespaceContinue(code) {
100607
- if (code === null) {
100608
- effects.exit('magicBlockData');
100609
- return nok(code);
100610
- }
100611
- if (markdownLineEnding(code)) {
100612
- effects.exit('magicBlockData');
100613
- effects.enter('magicBlockLineEnding');
100614
- effects.consume(code);
100615
- effects.exit('magicBlockLineEnding');
100616
- return beforeData;
100617
- }
100618
- if (code === codes.space || code === codes.horizontalTab) {
100619
- effects.consume(code);
100620
- return beforeDataWhitespaceContinue;
100621
- }
100622
- if (code === codes.leftCurlyBrace) {
100623
- seenOpenBrace = true;
100624
- return captureData(code);
100625
- }
100626
- effects.exit('magicBlockData');
100627
- return nok(code);
100628
- }
100629
- function captureData(code) {
100630
- // Fail on EOF - magic block must be closed
100631
- if (code === null) {
100632
- effects.exit('magicBlockData');
100633
- return nok(code);
100634
- }
100635
- // Handle multiline magic blocks within text/paragraphs
100636
- // Exit data, consume line ending with proper token, then re-enter data
100637
- if (markdownLineEnding(code)) {
100638
- effects.exit('magicBlockData');
100639
- effects.enter('magicBlockLineEnding');
100640
- effects.consume(code);
100641
- effects.exit('magicBlockLineEnding');
100642
- return beforeData; // Go back to beforeData to handle potential empty lines
100643
- }
100644
- if (jsonState.escapeNext) {
100645
- jsonState.escapeNext = false;
100646
- effects.consume(code);
100647
- return captureData;
100648
- }
100649
- if (jsonState.inString) {
100650
- if (code === codes.backslash) {
100651
- jsonState.escapeNext = true;
100652
- effects.consume(code);
100653
- return captureData;
100654
- }
100655
- if (code === codes.quotationMark) {
100656
- jsonState.inString = false;
100657
- }
100658
- effects.consume(code);
100659
- return captureData;
100660
- }
100661
- if (code === codes.quotationMark) {
100662
- jsonState.inString = true;
100663
- effects.consume(code);
100664
- return captureData;
100665
- }
100666
- if (code === codes.leftSquareBracket) {
100667
- effects.exit('magicBlockData');
100668
- effects.enter('magicBlockMarkerEnd');
100669
- effects.consume(code);
100670
- return closingFromData.expectSlash;
100671
- }
100672
- effects.consume(code);
100673
- return captureData;
100674
- }
100675
- }
100676
- /* harmony default export */ const syntax = ((/* unused pure expression or super */ null && (magicBlock)));
100677
-
100678
- ;// ./lib/micromark/magic-block/index.ts
100679
- /**
100680
- * Micromark extension for magic block syntax.
100681
- *
100682
- * Usage:
100683
- * ```ts
100684
- * import { magicBlock } from './lib/micromark/magic-block';
100685
- *
100686
- * const processor = unified()
100687
- * .data('micromarkExtensions', [magicBlock()])
100688
- * ```
100689
- */
100690
-
100691
-
100692
- ;// ./node_modules/micromark-util-symbol/lib/types.js
100693
- /**
100694
- * This module is compiled away!
100695
- *
100696
- * Here is the list of all types of tokens exposed by micromark, with a short
100697
- * explanation of what they include and where they are found.
100698
- * In picking names, generally, the rule is to be as explicit as possible
100699
- * instead of reusing names.
100700
- * For example, there is a `definitionDestination` and a `resourceDestination`,
100701
- * instead of one shared name.
99913
+ * Here is the list of all types of tokens exposed by micromark, with a short
99914
+ * explanation of what they include and where they are found.
99915
+ * In picking names, generally, the rule is to be as explicit as possible
99916
+ * instead of reusing names.
99917
+ * For example, there is a `definitionDestination` and a `resourceDestination`,
99918
+ * instead of one shared name.
100702
99919
  */
100703
99920
 
100704
99921
  // Note: when changing the next record, you must also change `TokenTypeMap`
@@ -101144,36 +100361,18 @@ const types_types = /** @type {const} */ ({
101144
100361
  chunkString: 'chunkString'
101145
100362
  })
101146
100363
 
101147
- ;// ./lib/micromark/mdx-component/syntax.ts
101148
-
101149
-
101150
-
100364
+ ;// ./lib/micromark/jsx-table/syntax.ts
101151
100365
 
101152
100366
 
101153
- // Raw tags (type-1: pre/script/style/textarea) and block tags (type-6: div,
101154
- // section, …) always start a block, so they stay flow even with trailing
101155
- // content. Other lowercase tags (i, span, …) follow the type-7 rule and only
101156
- // stay flow when nothing trails the close tag.
101157
- const htmlFlowTagNames = new Set([...htmlRawNames, ...htmlBlockNames]);
101158
- // Lowercase type-6 block tags claimable in flow even without a `{…}` attribute, so
101159
- // blank lines between nested JSX siblings don't fragment the block. Excludes table
101160
- // tags (mdxishTables owns their blank lines) and voids (never close).
101161
- const plainBlockClaimTagNames = new Set([...htmlBlockNames].filter(tag => !HTML_TABLE_STRUCTURE_TAGS.has(tag) && !HTML_VOID_ELEMENTS.has(tag)));
101162
100367
  const syntax_nonLazyContinuationStart = {
101163
100368
  tokenize: syntax_tokenizeNonLazyContinuationStart,
101164
100369
  partial: true,
101165
100370
  };
101166
- // Lookahead for `plainClaimLineStart`: is this line markup-only, or a paragraph
101167
- // that merely starts with a tag? Run via `effects.check` so it never consumes.
101168
- const markupOnlyContinuation = {
101169
- tokenize: tokenizeMarkupOnlyContinuation,
101170
- partial: true,
101171
- };
101172
- function resolveToMdxComponent(events) {
100371
+ function resolveToJsxTable(events) {
101173
100372
  let index = events.length;
101174
100373
  while (index > 0) {
101175
100374
  index -= 1;
101176
- if (events[index][0] === 'enter' && events[index][1].type === 'mdxComponent') {
100375
+ if (events[index][0] === 'enter' && events[index][1].type === 'jsxTable') {
101177
100376
  break;
101178
100377
  }
101179
100378
  }
@@ -101184,59 +100383,1165 @@ function resolveToMdxComponent(events) {
101184
100383
  }
101185
100384
  return events;
101186
100385
  }
101187
- const mdxComponentFlowConstruct = {
101188
- name: 'mdxComponent',
101189
- tokenize: createTokenize('flow'),
101190
- resolveTo: resolveToMdxComponent,
100386
+ const jsxTableConstruct = {
100387
+ name: 'jsxTable',
100388
+ tokenize: tokenizeJsxTable,
100389
+ resolveTo: resolveToJsxTable,
101191
100390
  concrete: true,
101192
100391
  };
101193
- const mdxComponentTextConstruct = {
101194
- name: 'mdxComponentText',
101195
- tokenize: createTokenize('text'),
101196
- };
101197
- /**
101198
- * Factory for both flow (block) and text (inline) variants.
101199
- *
101200
- * **Flow** — the original behavior: claims PascalCase components (always) and
101201
- * lowercase HTML tags that carry at least one `{…}` attribute expression.
101202
- * Multi-line, concrete, `afterClose` consumes the rest of the line.
101203
- *
101204
- * **Text** — runs inside paragraphs / inline context. Claims lowercase tags and
101205
- * inline PascalCase components (`INLINE_COMPONENT_TAGS` — Anchor, Glossary), both
101206
- * gated on at least one `{…}` brace attribute. All other PascalCase stays
101207
- * flow-only, matching how ReadMe's custom components are authored. Aborts on line
101208
- * endings (inline constructs don't span lines) and exits immediately after
101209
- * `</tag>` so the paragraph's inline parser picks up the trailing text.
101210
- */
101211
- function createTokenize(mode) {
101212
- const isFlow = mode === 'flow';
101213
- return function tokenize(effects, ok, nok) {
101214
- // eslint-disable-next-line @typescript-eslint/no-this-alias
101215
- const self = this;
101216
- let tagName = '';
101217
- let depth = 0;
101218
- let closingTagName = '';
101219
- // For lowercase tags we only want to claim the block if it uses JSX
101220
- // attribute expression syntax (`attr={...}`). Plain HTML should fall
101221
- // through to CommonMark html-flow. Flow mode claims any PascalCase block
101222
- // component; text mode claims only inline PascalCase components
101223
- // (INLINE_COMPONENT_TAGS — Anchor, Glossary), also brace-gated.
101224
- let isLowercaseTag = false;
101225
- let sawBraceAttr = false;
101226
- // A plain lowercase block tag claimed without a `{…}` attribute, gated by
101227
- // `plainClaimLineStart`: after a blank line it may only continue on a tag line.
101228
- let isPlainBlockClaim = false;
101229
- let pendingBlankLine = false;
101230
- // Code span tracking
101231
- let codeSpanOpenSize = 0;
101232
- let codeSpanCloseSize = 0;
101233
- // Fenced code block tracking
101234
- let fenceChar = null;
101235
- let fenceLength = 0;
101236
- let fenceCloseLength = 0;
101237
- let atLineStart = false;
101238
- // True once this construct consumes any line ending; lets `afterClose`
101239
- // treat only single-line lowercase tags as inline candidates.
100392
+ function tokenizeJsxTable(effects, ok, nok) {
100393
+ let codeSpanOpenSize = 0;
100394
+ let codeSpanCloseSize = 0;
100395
+ let depth = 1;
100396
+ const ABLE_SUFFIX = [codes.lowercaseA, codes.lowercaseB, codes.lowercaseL, codes.lowercaseE];
100397
+ /** Build a state chain that matches a sequence of character codes. */
100398
+ function matchChars(chars, onMatch, onFail) {
100399
+ if (chars.length === 0)
100400
+ return onMatch;
100401
+ return ((code) => {
100402
+ if (code === chars[0]) {
100403
+ effects.consume(code);
100404
+ return matchChars(chars.slice(1), onMatch, onFail);
100405
+ }
100406
+ return onFail(code);
100407
+ });
100408
+ }
100409
+ return start;
100410
+ function start(code) {
100411
+ if (code !== codes.lessThan)
100412
+ return nok(code);
100413
+ effects.enter('jsxTable');
100414
+ effects.enter('jsxTableData');
100415
+ effects.consume(code);
100416
+ return afterLessThan;
100417
+ }
100418
+ function afterLessThan(code) {
100419
+ if (code === codes.uppercaseT || code === codes.lowercaseT) {
100420
+ effects.consume(code);
100421
+ return matchChars(ABLE_SUFFIX, afterTagName, nok);
100422
+ }
100423
+ return nok(code);
100424
+ }
100425
+ function afterTagName(code) {
100426
+ if (code === codes.greaterThan || code === codes.slash || code === codes.space || code === codes.horizontalTab) {
100427
+ effects.consume(code);
100428
+ return body;
100429
+ }
100430
+ return nok(code);
100431
+ }
100432
+ function body(code) {
100433
+ // Reject unclosed <Table> so it falls back to normal HTML block parsing
100434
+ // instead of swallowing all subsequent content to EOF
100435
+ if (code === null) {
100436
+ return nok(code);
100437
+ }
100438
+ if (markdownLineEnding(code)) {
100439
+ effects.exit('jsxTableData');
100440
+ return continuationStart(code);
100441
+ }
100442
+ if (code === codes.backslash) {
100443
+ effects.consume(code);
100444
+ return escapedChar;
100445
+ }
100446
+ if (code === codes.lessThan) {
100447
+ effects.consume(code);
100448
+ return closeSlash;
100449
+ }
100450
+ // Skip over backtick code spans so `</Table>` in inline code isn't
100451
+ // treated as the closing tag
100452
+ if (code === codes.graveAccent) {
100453
+ codeSpanOpenSize = 0;
100454
+ return countOpenTicks(code);
100455
+ }
100456
+ effects.consume(code);
100457
+ return body;
100458
+ }
100459
+ function countOpenTicks(code) {
100460
+ if (code === codes.graveAccent) {
100461
+ codeSpanOpenSize += 1;
100462
+ effects.consume(code);
100463
+ return countOpenTicks;
100464
+ }
100465
+ return inCodeSpan(code);
100466
+ }
100467
+ function inCodeSpan(code) {
100468
+ if (code === null || markdownLineEnding(code))
100469
+ return body(code);
100470
+ if (code === codes.graveAccent) {
100471
+ codeSpanCloseSize = 0;
100472
+ return countCloseTicks(code);
100473
+ }
100474
+ effects.consume(code);
100475
+ return inCodeSpan;
100476
+ }
100477
+ function countCloseTicks(code) {
100478
+ if (code === codes.graveAccent) {
100479
+ codeSpanCloseSize += 1;
100480
+ effects.consume(code);
100481
+ return countCloseTicks;
100482
+ }
100483
+ return codeSpanCloseSize === codeSpanOpenSize ? body(code) : inCodeSpan(code);
100484
+ }
100485
+ function escapedChar(code) {
100486
+ if (code === null || markdownLineEnding(code)) {
100487
+ return body(code);
100488
+ }
100489
+ effects.consume(code);
100490
+ return body;
100491
+ }
100492
+ function closeSlash(code) {
100493
+ if (code === codes.slash) {
100494
+ effects.consume(code);
100495
+ return closeTagFirstChar;
100496
+ }
100497
+ if (code === codes.uppercaseT || code === codes.lowercaseT) {
100498
+ effects.consume(code);
100499
+ return matchChars(ABLE_SUFFIX, openAfterTagName, body);
100500
+ }
100501
+ return body(code);
100502
+ }
100503
+ function closeTagFirstChar(code) {
100504
+ if (code === codes.uppercaseT || code === codes.lowercaseT) {
100505
+ effects.consume(code);
100506
+ return matchChars(ABLE_SUFFIX, closeGt, body);
100507
+ }
100508
+ return body(code);
100509
+ }
100510
+ function openAfterTagName(code) {
100511
+ if (code === codes.greaterThan || code === codes.slash || code === codes.space || code === codes.horizontalTab) {
100512
+ depth += 1;
100513
+ effects.consume(code);
100514
+ return body;
100515
+ }
100516
+ return body(code);
100517
+ }
100518
+ function closeGt(code) {
100519
+ if (code === codes.greaterThan) {
100520
+ depth -= 1;
100521
+ effects.consume(code);
100522
+ if (depth === 0) {
100523
+ return afterClose;
100524
+ }
100525
+ return body;
100526
+ }
100527
+ return body(code);
100528
+ }
100529
+ function afterClose(code) {
100530
+ if (code === null || markdownLineEnding(code)) {
100531
+ effects.exit('jsxTableData');
100532
+ effects.exit('jsxTable');
100533
+ return ok(code);
100534
+ }
100535
+ effects.consume(code);
100536
+ return afterClose;
100537
+ }
100538
+ // Line ending handling — follows the htmlFlow pattern
100539
+ function continuationStart(code) {
100540
+ return effects.check(syntax_nonLazyContinuationStart, continuationStartNonLazy, continuationAfter)(code);
100541
+ }
100542
+ function continuationStartNonLazy(code) {
100543
+ effects.enter(types_types.lineEnding);
100544
+ effects.consume(code);
100545
+ effects.exit(types_types.lineEnding);
100546
+ return continuationBefore;
100547
+ }
100548
+ function continuationBefore(code) {
100549
+ if (code === null || markdownLineEnding(code)) {
100550
+ return continuationStart(code);
100551
+ }
100552
+ effects.enter('jsxTableData');
100553
+ return body(code);
100554
+ }
100555
+ function continuationAfter(code) {
100556
+ // At EOF without </Table>, reject so content isn't swallowed
100557
+ if (code === null) {
100558
+ return nok(code);
100559
+ }
100560
+ effects.exit('jsxTable');
100561
+ return ok(code);
100562
+ }
100563
+ }
100564
+ function syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
100565
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
100566
+ const self = this;
100567
+ return start;
100568
+ function start(code) {
100569
+ if (markdownLineEnding(code)) {
100570
+ effects.enter(types_types.lineEnding);
100571
+ effects.consume(code);
100572
+ effects.exit(types_types.lineEnding);
100573
+ return after;
100574
+ }
100575
+ return nok(code);
100576
+ }
100577
+ function after(code) {
100578
+ if (self.parser.lazy[self.now().line]) {
100579
+ return nok(code);
100580
+ }
100581
+ return ok(code);
100582
+ }
100583
+ }
100584
+ /**
100585
+ * Micromark extension that tokenizes `<Table>...</Table>` and `<table>...</table>`
100586
+ * as a single flow block.
100587
+ *
100588
+ * Prevents CommonMark HTML block type 6 from fragmenting table blocks at blank lines.
100589
+ */
100590
+ function jsxTable() {
100591
+ return {
100592
+ flow: {
100593
+ [codes.lessThan]: [jsxTableConstruct],
100594
+ },
100595
+ };
100596
+ }
100597
+
100598
+ ;// ./lib/micromark/jsx-table/index.ts
100599
+
100600
+
100601
+ ;// ./lib/micromark/magic-block/syntax.ts
100602
+
100603
+
100604
+ /**
100605
+ * Known magic block types that the tokenizer will recognize.
100606
+ * Unknown types will not be tokenized as magic blocks.
100607
+ */
100608
+ const KNOWN_BLOCK_TYPES = new Set([
100609
+ 'code',
100610
+ 'api-header',
100611
+ 'image',
100612
+ 'callout',
100613
+ 'parameters',
100614
+ 'table',
100615
+ 'embed',
100616
+ 'html',
100617
+ 'recipe',
100618
+ 'tutorial-tile',
100619
+ ]);
100620
+ /**
100621
+ * Check if a character is valid for a magic block type identifier.
100622
+ * Types can contain alphanumeric characters and hyphens (e.g., "api-header", "tutorial-tile")
100623
+ */
100624
+ function isTypeChar(code) {
100625
+ return asciiAlphanumeric(code) || code === codes.dash;
100626
+ }
100627
+ /**
100628
+ * Creates the opening marker state machine: [block:
100629
+ * Returns the first state function to start parsing.
100630
+ */
100631
+ function createOpeningMarkerParser(effects, nok, onComplete) {
100632
+ const expectB = (code) => {
100633
+ if (code !== codes.lowercaseB)
100634
+ return nok(code);
100635
+ effects.consume(code);
100636
+ return expectL;
100637
+ };
100638
+ const expectL = (code) => {
100639
+ if (code !== codes.lowercaseL)
100640
+ return nok(code);
100641
+ effects.consume(code);
100642
+ return expectO;
100643
+ };
100644
+ const expectO = (code) => {
100645
+ if (code !== codes.lowercaseO)
100646
+ return nok(code);
100647
+ effects.consume(code);
100648
+ return expectC;
100649
+ };
100650
+ const expectC = (code) => {
100651
+ if (code !== codes.lowercaseC)
100652
+ return nok(code);
100653
+ effects.consume(code);
100654
+ return expectK;
100655
+ };
100656
+ const expectK = (code) => {
100657
+ if (code !== codes.lowercaseK)
100658
+ return nok(code);
100659
+ effects.consume(code);
100660
+ return expectColon;
100661
+ };
100662
+ const expectColon = (code) => {
100663
+ if (code !== codes.colon)
100664
+ return nok(code);
100665
+ effects.consume(code);
100666
+ effects.exit('magicBlockMarkerStart');
100667
+ effects.enter('magicBlockType');
100668
+ return onComplete;
100669
+ };
100670
+ return expectB;
100671
+ }
100672
+ /**
100673
+ * Creates the type capture state machine.
100674
+ * Captures type characters until ] and validates against known types.
100675
+ */
100676
+ function createTypeCaptureParser(effects, nok, onComplete, blockTypeRef) {
100677
+ const captureTypeFirst = (code) => {
100678
+ // Reject empty type name [block:]
100679
+ if (code === codes.rightSquareBracket) {
100680
+ return nok(code);
100681
+ }
100682
+ if (isTypeChar(code)) {
100683
+ blockTypeRef.value += String.fromCharCode(code);
100684
+ effects.consume(code);
100685
+ return captureType;
100686
+ }
100687
+ return nok(code);
100688
+ };
100689
+ const captureType = (code) => {
100690
+ if (code === codes.rightSquareBracket) {
100691
+ if (!KNOWN_BLOCK_TYPES.has(blockTypeRef.value)) {
100692
+ return nok(code);
100693
+ }
100694
+ effects.exit('magicBlockType');
100695
+ effects.enter('magicBlockMarkerTypeEnd');
100696
+ effects.consume(code);
100697
+ effects.exit('magicBlockMarkerTypeEnd');
100698
+ return onComplete;
100699
+ }
100700
+ if (isTypeChar(code)) {
100701
+ blockTypeRef.value += String.fromCharCode(code);
100702
+ effects.consume(code);
100703
+ return captureType;
100704
+ }
100705
+ return nok(code);
100706
+ };
100707
+ return { first: captureTypeFirst, remaining: captureType };
100708
+ }
100709
+ /**
100710
+ * Creates the closing marker state machine: /block]
100711
+ * Handles partial matches by calling onMismatch to fall back to data capture.
100712
+ */
100713
+ function createClosingMarkerParser(effects, onSuccess, onMismatch, onEof, jsonState) {
100714
+ const handleMismatch = (code) => {
100715
+ if (jsonState && code === codes.quotationMark) {
100716
+ jsonState.inString = true;
100717
+ }
100718
+ return onMismatch(code);
100719
+ };
100720
+ const expectSlash = (code) => {
100721
+ if (code === null)
100722
+ return onEof(code);
100723
+ if (code !== codes.slash)
100724
+ return handleMismatch(code);
100725
+ effects.consume(code);
100726
+ return expectB;
100727
+ };
100728
+ const expectB = (code) => {
100729
+ if (code === null)
100730
+ return onEof(code);
100731
+ if (code !== codes.lowercaseB)
100732
+ return handleMismatch(code);
100733
+ effects.consume(code);
100734
+ return expectL;
100735
+ };
100736
+ const expectL = (code) => {
100737
+ if (code === null)
100738
+ return onEof(code);
100739
+ if (code !== codes.lowercaseL)
100740
+ return handleMismatch(code);
100741
+ effects.consume(code);
100742
+ return expectO;
100743
+ };
100744
+ const expectO = (code) => {
100745
+ if (code === null)
100746
+ return onEof(code);
100747
+ if (code !== codes.lowercaseO)
100748
+ return handleMismatch(code);
100749
+ effects.consume(code);
100750
+ return expectC;
100751
+ };
100752
+ const expectC = (code) => {
100753
+ if (code === null)
100754
+ return onEof(code);
100755
+ if (code !== codes.lowercaseC)
100756
+ return handleMismatch(code);
100757
+ effects.consume(code);
100758
+ return expectK;
100759
+ };
100760
+ const expectK = (code) => {
100761
+ if (code === null)
100762
+ return onEof(code);
100763
+ if (code !== codes.lowercaseK)
100764
+ return handleMismatch(code);
100765
+ effects.consume(code);
100766
+ return expectBracket;
100767
+ };
100768
+ const expectBracket = (code) => {
100769
+ if (code === null)
100770
+ return onEof(code);
100771
+ if (code !== codes.rightSquareBracket)
100772
+ return handleMismatch(code);
100773
+ effects.consume(code);
100774
+ return onSuccess;
100775
+ };
100776
+ return { expectSlash };
100777
+ }
100778
+ /**
100779
+ * Partial construct for checking non-lazy continuation.
100780
+ * This is used by the flow tokenizer to check if we can continue
100781
+ * parsing on the next line.
100782
+ */
100783
+ const syntax_nonLazyContinuation = {
100784
+ partial: true,
100785
+ tokenize: syntax_tokenizeNonLazyContinuation,
100786
+ };
100787
+ /**
100788
+ * Tokenizer for non-lazy continuation checking.
100789
+ * Returns ok if the next line is non-lazy (can continue), nok if lazy.
100790
+ */
100791
+ function syntax_tokenizeNonLazyContinuation(effects, ok, nok) {
100792
+ const lineStart = (code) => {
100793
+ // `this` here refers to the micromark parser
100794
+ // since we are just passing functions as references and not actually calling them
100795
+ // micromarks's internal parser will call this automatically with appropriate arguments
100796
+ return this.parser.lazy[this.now().line] ? nok(code) : ok(code);
100797
+ };
100798
+ const start = (code) => {
100799
+ if (code === null) {
100800
+ return nok(code);
100801
+ }
100802
+ if (!markdownLineEnding(code)) {
100803
+ return nok(code);
100804
+ }
100805
+ effects.enter('magicBlockLineEnding');
100806
+ effects.consume(code);
100807
+ effects.exit('magicBlockLineEnding');
100808
+ return lineStart;
100809
+ };
100810
+ return start;
100811
+ }
100812
+ /**
100813
+ * Create a micromark extension for magic block syntax.
100814
+ *
100815
+ * This extension handles both single-line and multiline magic blocks:
100816
+ * - Flow construct (concrete): Handles block-level multiline magic blocks at document level
100817
+ * - Text construct: Handles inline magic blocks in lists, paragraphs, etc.
100818
+ *
100819
+ * The flow construct is marked as "concrete" which prevents it from being
100820
+ * interrupted by container markers (like `>` for blockquotes or `-` for lists).
100821
+ */
100822
+ function magicBlock() {
100823
+ return {
100824
+ // Flow construct - handles block-level magic blocks at document root
100825
+ // Marked as concrete to prevent interruption by containers
100826
+ flow: {
100827
+ [codes.leftSquareBracket]: {
100828
+ name: 'magicBlock',
100829
+ concrete: true,
100830
+ tokenize: tokenizeMagicBlockFlow,
100831
+ },
100832
+ },
100833
+ // Text construct - handles magic blocks in inline contexts (lists, paragraphs)
100834
+ text: {
100835
+ [codes.leftSquareBracket]: {
100836
+ name: 'magicBlock',
100837
+ tokenize: tokenizeMagicBlockText,
100838
+ },
100839
+ },
100840
+ };
100841
+ }
100842
+ /**
100843
+ * Flow tokenizer for block-level magic blocks (multiline).
100844
+ * Uses the continuation checking pattern from code fences.
100845
+ */
100846
+ function tokenizeMagicBlockFlow(effects, ok, nok) {
100847
+ // State for tracking JSON content
100848
+ const jsonState = { escapeNext: false, inString: false };
100849
+ const blockTypeRef = { value: '' };
100850
+ let seenOpenBrace = false;
100851
+ // Create shared parsers for opening marker and type capture
100852
+ const typeParser = createTypeCaptureParser(effects, nok, beforeData, blockTypeRef);
100853
+ const openingMarkerParser = createOpeningMarkerParser(effects, nok, typeParser.first);
100854
+ return start;
100855
+ function start(code) {
100856
+ if (code !== codes.leftSquareBracket)
100857
+ return nok(code);
100858
+ effects.enter('magicBlock');
100859
+ effects.enter('magicBlockMarkerStart');
100860
+ effects.consume(code);
100861
+ return openingMarkerParser;
100862
+ }
100863
+ /**
100864
+ * State before data content - handles line endings or starts data capture.
100865
+ */
100866
+ function beforeData(code) {
100867
+ // EOF - magic block must be closed
100868
+ if (code === null) {
100869
+ effects.exit('magicBlock');
100870
+ return nok(code);
100871
+ }
100872
+ // Line ending before any data - check continuation
100873
+ if (markdownLineEnding(code)) {
100874
+ return effects.check(syntax_nonLazyContinuation, continuationOkBeforeData, after)(code);
100875
+ }
100876
+ // Check for closing marker directly (without entering data)
100877
+ // This handles cases like [block:type]\n{}\n\n[/block] where there are
100878
+ // newlines after the data object
100879
+ if (code === codes.leftSquareBracket) {
100880
+ effects.enter('magicBlockMarkerEnd');
100881
+ effects.consume(code);
100882
+ return expectSlashFromContinuation;
100883
+ }
100884
+ // If we've already seen the opening brace, just continue capturing data
100885
+ if (seenOpenBrace) {
100886
+ effects.enter('magicBlockData');
100887
+ return captureData(code);
100888
+ }
100889
+ // Skip whitespace (spaces/tabs) before the data - stay in beforeData
100890
+ // Don't enter magicBlockData token yet until we confirm there's a '{'
100891
+ if (code === codes.space || code === codes.horizontalTab) {
100892
+ return beforeDataWhitespace(code);
100893
+ }
100894
+ // Data must start with '{' for valid JSON
100895
+ if (code !== codes.leftCurlyBrace) {
100896
+ effects.exit('magicBlock');
100897
+ return nok(code);
100898
+ }
100899
+ // We have '{' - enter data token and start capturing
100900
+ seenOpenBrace = true;
100901
+ effects.enter('magicBlockData');
100902
+ return captureData(code);
100903
+ }
100904
+ /**
100905
+ * Consume whitespace before the data without creating a token.
100906
+ * Uses a temporary token to satisfy micromark's requirement.
100907
+ */
100908
+ function beforeDataWhitespace(code) {
100909
+ if (code === null) {
100910
+ effects.exit('magicBlock');
100911
+ return nok(code);
100912
+ }
100913
+ if (markdownLineEnding(code)) {
100914
+ return effects.check(syntax_nonLazyContinuation, continuationOkBeforeData, after)(code);
100915
+ }
100916
+ if (code === codes.space || code === codes.horizontalTab) {
100917
+ // We need to consume this but can't without a token - use magicBlockData
100918
+ // and track that we haven't seen '{' yet
100919
+ effects.enter('magicBlockData');
100920
+ effects.consume(code);
100921
+ return beforeDataWhitespaceContinue;
100922
+ }
100923
+ if (code === codes.leftCurlyBrace) {
100924
+ seenOpenBrace = true;
100925
+ effects.enter('magicBlockData');
100926
+ return captureData(code);
100927
+ }
100928
+ effects.exit('magicBlock');
100929
+ return nok(code);
100930
+ }
100931
+ /**
100932
+ * Continue consuming whitespace or validate the opening brace.
100933
+ */
100934
+ function beforeDataWhitespaceContinue(code) {
100935
+ if (code === null) {
100936
+ effects.exit('magicBlockData');
100937
+ effects.exit('magicBlock');
100938
+ return nok(code);
100939
+ }
100940
+ if (markdownLineEnding(code)) {
100941
+ effects.exit('magicBlockData');
100942
+ return effects.check(syntax_nonLazyContinuation, continuationOk, after)(code);
100943
+ }
100944
+ if (code === codes.space || code === codes.horizontalTab) {
100945
+ effects.consume(code);
100946
+ return beforeDataWhitespaceContinue;
100947
+ }
100948
+ if (code === codes.leftCurlyBrace) {
100949
+ seenOpenBrace = true;
100950
+ return captureData(code);
100951
+ }
100952
+ effects.exit('magicBlockData');
100953
+ effects.exit('magicBlock');
100954
+ return nok(code);
100955
+ }
100956
+ /**
100957
+ * Continuation OK before we've entered data token.
100958
+ */
100959
+ function continuationOkBeforeData(code) {
100960
+ effects.enter('magicBlockLineEnding');
100961
+ effects.consume(code);
100962
+ effects.exit('magicBlockLineEnding');
100963
+ return beforeData; // Stay in beforeData state - don't enter magicBlockData yet
100964
+ }
100965
+ function captureData(code) {
100966
+ // EOF - magic block must be closed
100967
+ if (code === null) {
100968
+ effects.exit('magicBlockData');
100969
+ effects.exit('magicBlock');
100970
+ return nok(code);
100971
+ }
100972
+ // At line ending, check if we can continue on the next line
100973
+ if (markdownLineEnding(code)) {
100974
+ effects.exit('magicBlockData');
100975
+ return effects.check(syntax_nonLazyContinuation, continuationOk, after)(code);
100976
+ }
100977
+ if (jsonState.escapeNext) {
100978
+ jsonState.escapeNext = false;
100979
+ effects.consume(code);
100980
+ return captureData;
100981
+ }
100982
+ if (jsonState.inString) {
100983
+ if (code === codes.backslash) {
100984
+ jsonState.escapeNext = true;
100985
+ effects.consume(code);
100986
+ return captureData;
100987
+ }
100988
+ if (code === codes.quotationMark) {
100989
+ jsonState.inString = false;
100990
+ }
100991
+ effects.consume(code);
100992
+ return captureData;
100993
+ }
100994
+ if (code === codes.quotationMark) {
100995
+ jsonState.inString = true;
100996
+ effects.consume(code);
100997
+ return captureData;
100998
+ }
100999
+ if (code === codes.leftSquareBracket) {
101000
+ effects.exit('magicBlockData');
101001
+ effects.enter('magicBlockMarkerEnd');
101002
+ effects.consume(code);
101003
+ return expectSlash;
101004
+ }
101005
+ effects.consume(code);
101006
+ return captureData;
101007
+ }
101008
+ /**
101009
+ * Called when non-lazy continuation check passes - we can continue parsing.
101010
+ */
101011
+ function continuationOk(code) {
101012
+ // Consume the line ending
101013
+ effects.enter('magicBlockLineEnding');
101014
+ effects.consume(code);
101015
+ effects.exit('magicBlockLineEnding');
101016
+ return continuationStart;
101017
+ }
101018
+ /**
101019
+ * Start of continuation line - check for more line endings, closing marker, or start capturing data.
101020
+ */
101021
+ function continuationStart(code) {
101022
+ // Handle consecutive line endings
101023
+ if (code === null) {
101024
+ effects.exit('magicBlock');
101025
+ return nok(code);
101026
+ }
101027
+ if (markdownLineEnding(code)) {
101028
+ return effects.check(syntax_nonLazyContinuation, continuationOkBeforeData, after)(code);
101029
+ }
101030
+ // Check if this is the start of the closing marker [/block]
101031
+ // If so, handle it directly without entering magicBlockData
101032
+ if (code === codes.leftSquareBracket) {
101033
+ effects.enter('magicBlockMarkerEnd');
101034
+ effects.consume(code);
101035
+ return expectSlashFromContinuation;
101036
+ }
101037
+ effects.enter('magicBlockData');
101038
+ return captureData(code);
101039
+ }
101040
+ /**
101041
+ * Check for closing marker slash when coming from continuation.
101042
+ * If not a closing marker, create an empty data token and continue.
101043
+ */
101044
+ function expectSlashFromContinuation(code) {
101045
+ if (code === null) {
101046
+ effects.exit('magicBlockMarkerEnd');
101047
+ effects.exit('magicBlock');
101048
+ return nok(code);
101049
+ }
101050
+ if (markdownLineEnding(code)) {
101051
+ effects.exit('magicBlockMarkerEnd');
101052
+ return effects.check(syntax_nonLazyContinuation, continuationOkBeforeData, after)(code);
101053
+ }
101054
+ if (code === codes.slash) {
101055
+ effects.consume(code);
101056
+ return expectClosingB;
101057
+ }
101058
+ // Not a closing marker - this is data content
101059
+ // Exit marker and enter data
101060
+ effects.exit('magicBlockMarkerEnd');
101061
+ effects.enter('magicBlockData');
101062
+ // The [ was consumed by the marker, so we need to conceptually "have it" in our data
101063
+ // But since we already consumed it into the marker, we need a different approach
101064
+ // Re-classify: consume this character as data and continue
101065
+ if (code === codes.quotationMark)
101066
+ jsonState.inString = true;
101067
+ effects.consume(code);
101068
+ return captureData;
101069
+ }
101070
+ function expectSlash(code) {
101071
+ if (code === null) {
101072
+ effects.exit('magicBlockMarkerEnd');
101073
+ effects.exit('magicBlock');
101074
+ return nok(code);
101075
+ }
101076
+ // At line ending during marker parsing
101077
+ if (markdownLineEnding(code)) {
101078
+ effects.exit('magicBlockMarkerEnd');
101079
+ return effects.check(syntax_nonLazyContinuation, continuationOk, after)(code);
101080
+ }
101081
+ if (code !== codes.slash) {
101082
+ effects.exit('magicBlockMarkerEnd');
101083
+ effects.enter('magicBlockData');
101084
+ if (code === codes.quotationMark)
101085
+ jsonState.inString = true;
101086
+ effects.consume(code);
101087
+ return captureData;
101088
+ }
101089
+ effects.consume(code);
101090
+ return expectClosingB;
101091
+ }
101092
+ function expectClosingB(code) {
101093
+ if (code === null) {
101094
+ effects.exit('magicBlockMarkerEnd');
101095
+ effects.exit('magicBlock');
101096
+ return nok(code);
101097
+ }
101098
+ if (code !== codes.lowercaseB) {
101099
+ effects.exit('magicBlockMarkerEnd');
101100
+ effects.enter('magicBlockData');
101101
+ if (code === codes.quotationMark)
101102
+ jsonState.inString = true;
101103
+ effects.consume(code);
101104
+ return captureData;
101105
+ }
101106
+ effects.consume(code);
101107
+ return expectClosingL;
101108
+ }
101109
+ function expectClosingL(code) {
101110
+ if (code === null) {
101111
+ effects.exit('magicBlockMarkerEnd');
101112
+ effects.exit('magicBlock');
101113
+ return nok(code);
101114
+ }
101115
+ if (code !== codes.lowercaseL) {
101116
+ effects.exit('magicBlockMarkerEnd');
101117
+ effects.enter('magicBlockData');
101118
+ if (code === codes.quotationMark)
101119
+ jsonState.inString = true;
101120
+ effects.consume(code);
101121
+ return captureData;
101122
+ }
101123
+ effects.consume(code);
101124
+ return expectClosingO;
101125
+ }
101126
+ function expectClosingO(code) {
101127
+ if (code === null) {
101128
+ effects.exit('magicBlockMarkerEnd');
101129
+ effects.exit('magicBlock');
101130
+ return nok(code);
101131
+ }
101132
+ if (code !== codes.lowercaseO) {
101133
+ effects.exit('magicBlockMarkerEnd');
101134
+ effects.enter('magicBlockData');
101135
+ if (code === codes.quotationMark)
101136
+ jsonState.inString = true;
101137
+ effects.consume(code);
101138
+ return captureData;
101139
+ }
101140
+ effects.consume(code);
101141
+ return expectClosingC;
101142
+ }
101143
+ function expectClosingC(code) {
101144
+ if (code === null) {
101145
+ effects.exit('magicBlockMarkerEnd');
101146
+ effects.exit('magicBlock');
101147
+ return nok(code);
101148
+ }
101149
+ if (code !== codes.lowercaseC) {
101150
+ effects.exit('magicBlockMarkerEnd');
101151
+ effects.enter('magicBlockData');
101152
+ if (code === codes.quotationMark)
101153
+ jsonState.inString = true;
101154
+ effects.consume(code);
101155
+ return captureData;
101156
+ }
101157
+ effects.consume(code);
101158
+ return expectClosingK;
101159
+ }
101160
+ function expectClosingK(code) {
101161
+ if (code === null) {
101162
+ effects.exit('magicBlockMarkerEnd');
101163
+ effects.exit('magicBlock');
101164
+ return nok(code);
101165
+ }
101166
+ if (code !== codes.lowercaseK) {
101167
+ effects.exit('magicBlockMarkerEnd');
101168
+ effects.enter('magicBlockData');
101169
+ if (code === codes.quotationMark)
101170
+ jsonState.inString = true;
101171
+ effects.consume(code);
101172
+ return captureData;
101173
+ }
101174
+ effects.consume(code);
101175
+ return expectClosingBracket;
101176
+ }
101177
+ function expectClosingBracket(code) {
101178
+ if (code === null) {
101179
+ effects.exit('magicBlockMarkerEnd');
101180
+ effects.exit('magicBlock');
101181
+ return nok(code);
101182
+ }
101183
+ if (code !== codes.rightSquareBracket) {
101184
+ effects.exit('magicBlockMarkerEnd');
101185
+ effects.enter('magicBlockData');
101186
+ if (code === codes.quotationMark)
101187
+ jsonState.inString = true;
101188
+ effects.consume(code);
101189
+ return captureData;
101190
+ }
101191
+ effects.consume(code);
101192
+ effects.exit('magicBlockMarkerEnd');
101193
+ // Check for trailing whitespace on the same line
101194
+ return consumeTrailing;
101195
+ }
101196
+ /**
101197
+ * Consume trailing whitespace (spaces/tabs) on the same line after [/block].
101198
+ * For concrete flow constructs, we must end at eol/eof or fail.
101199
+ * Trailing whitespace is consumed; other content causes nok (text tokenizer handles it).
101200
+ */
101201
+ function consumeTrailing(code) {
101202
+ // End of file - done
101203
+ if (code === null) {
101204
+ effects.exit('magicBlock');
101205
+ return ok(code);
101206
+ }
101207
+ // Line ending - done
101208
+ if (markdownLineEnding(code)) {
101209
+ effects.exit('magicBlock');
101210
+ return ok(code);
101211
+ }
101212
+ // Space or tab - consume as trailing whitespace
101213
+ if (code === codes.space || code === codes.horizontalTab) {
101214
+ effects.enter('magicBlockTrailing');
101215
+ effects.consume(code);
101216
+ return consumeTrailingContinue;
101217
+ }
101218
+ // Any other character - fail flow tokenizer, let text tokenizer handle it
101219
+ effects.exit('magicBlock');
101220
+ return nok(code);
101221
+ }
101222
+ /**
101223
+ * Continue consuming trailing whitespace.
101224
+ */
101225
+ function consumeTrailingContinue(code) {
101226
+ // End of file - done
101227
+ if (code === null) {
101228
+ effects.exit('magicBlockTrailing');
101229
+ effects.exit('magicBlock');
101230
+ return ok(code);
101231
+ }
101232
+ // Line ending - done
101233
+ if (markdownLineEnding(code)) {
101234
+ effects.exit('magicBlockTrailing');
101235
+ effects.exit('magicBlock');
101236
+ return ok(code);
101237
+ }
101238
+ // More space or tab - keep consuming
101239
+ if (code === codes.space || code === codes.horizontalTab) {
101240
+ effects.consume(code);
101241
+ return consumeTrailingContinue;
101242
+ }
101243
+ // Non-whitespace after whitespace - fail flow tokenizer
101244
+ effects.exit('magicBlockTrailing');
101245
+ effects.exit('magicBlock');
101246
+ return nok(code);
101247
+ }
101248
+ /**
101249
+ * Called when we can't continue (lazy line or EOF) - exit the construct.
101250
+ */
101251
+ function after(code) {
101252
+ effects.exit('magicBlock');
101253
+ return nok(code);
101254
+ }
101255
+ }
101256
+ /**
101257
+ * Text tokenizer for single-line magic blocks only.
101258
+ * Used in inline contexts like list items and paragraphs.
101259
+ * Multiline blocks are handled by the flow tokenizer.
101260
+ */
101261
+ function tokenizeMagicBlockText(effects, ok, nok) {
101262
+ // State for tracking JSON content
101263
+ const jsonState = { escapeNext: false, inString: false };
101264
+ const blockTypeRef = { value: '' };
101265
+ let seenOpenBrace = false;
101266
+ // Create shared parsers for opening marker and type capture
101267
+ const typeParser = createTypeCaptureParser(effects, nok, beforeData, blockTypeRef);
101268
+ const openingMarkerParser = createOpeningMarkerParser(effects, nok, typeParser.first);
101269
+ // Success handler for closing marker - exits tokens and returns ok
101270
+ const closingSuccess = (code) => {
101271
+ effects.exit('magicBlockMarkerEnd');
101272
+ effects.exit('magicBlock');
101273
+ return ok(code);
101274
+ };
101275
+ // Mismatch handler - falls back to data capture
101276
+ const closingMismatch = (code) => {
101277
+ effects.exit('magicBlockMarkerEnd');
101278
+ effects.enter('magicBlockData');
101279
+ if (code === codes.quotationMark)
101280
+ jsonState.inString = true;
101281
+ effects.consume(code);
101282
+ return captureData;
101283
+ };
101284
+ // EOF handler
101285
+ const closingEof = (_code) => nok(_code);
101286
+ // Create closing marker parsers
101287
+ const closingFromBeforeData = createClosingMarkerParser(effects, closingSuccess, closingMismatch, closingEof, jsonState);
101288
+ const closingFromData = createClosingMarkerParser(effects, closingSuccess, closingMismatch, closingEof, jsonState);
101289
+ return start;
101290
+ function start(code) {
101291
+ if (code !== codes.leftSquareBracket)
101292
+ return nok(code);
101293
+ effects.enter('magicBlock');
101294
+ effects.enter('magicBlockMarkerStart');
101295
+ effects.consume(code);
101296
+ return openingMarkerParser;
101297
+ }
101298
+ /**
101299
+ * State before data content - handles line endings before entering data token.
101300
+ * Whitespace before '{' is allowed.
101301
+ */
101302
+ function beforeData(code) {
101303
+ // Fail on EOF - magic block must be closed
101304
+ if (code === null) {
101305
+ return nok(code);
101306
+ }
101307
+ // Handle line endings before any data - consume them without entering data token
101308
+ if (markdownLineEnding(code)) {
101309
+ effects.enter('magicBlockLineEnding');
101310
+ effects.consume(code);
101311
+ effects.exit('magicBlockLineEnding');
101312
+ return beforeData;
101313
+ }
101314
+ // Check for closing marker directly (without entering data)
101315
+ if (code === codes.leftSquareBracket) {
101316
+ effects.enter('magicBlockMarkerEnd');
101317
+ effects.consume(code);
101318
+ return closingFromBeforeData.expectSlash;
101319
+ }
101320
+ // If we've already seen the opening brace, just continue capturing data
101321
+ if (seenOpenBrace) {
101322
+ effects.enter('magicBlockData');
101323
+ return captureData(code);
101324
+ }
101325
+ // Skip whitespace (spaces/tabs) before the data
101326
+ if (code === codes.space || code === codes.horizontalTab) {
101327
+ return beforeDataWhitespace(code);
101328
+ }
101329
+ // Data must start with '{' for valid JSON
101330
+ if (code !== codes.leftCurlyBrace) {
101331
+ return nok(code);
101332
+ }
101333
+ // We have '{' - enter data token and start capturing
101334
+ seenOpenBrace = true;
101335
+ effects.enter('magicBlockData');
101336
+ return captureData(code);
101337
+ }
101338
+ /**
101339
+ * Consume whitespace before the data.
101340
+ */
101341
+ function beforeDataWhitespace(code) {
101342
+ if (code === null) {
101343
+ return nok(code);
101344
+ }
101345
+ if (markdownLineEnding(code)) {
101346
+ effects.enter('magicBlockLineEnding');
101347
+ effects.consume(code);
101348
+ effects.exit('magicBlockLineEnding');
101349
+ return beforeData;
101350
+ }
101351
+ if (code === codes.space || code === codes.horizontalTab) {
101352
+ effects.enter('magicBlockData');
101353
+ effects.consume(code);
101354
+ return beforeDataWhitespaceContinue;
101355
+ }
101356
+ if (code === codes.leftCurlyBrace) {
101357
+ seenOpenBrace = true;
101358
+ effects.enter('magicBlockData');
101359
+ return captureData(code);
101360
+ }
101361
+ return nok(code);
101362
+ }
101363
+ /**
101364
+ * Continue consuming whitespace or validate the opening brace.
101365
+ */
101366
+ function beforeDataWhitespaceContinue(code) {
101367
+ if (code === null) {
101368
+ effects.exit('magicBlockData');
101369
+ return nok(code);
101370
+ }
101371
+ if (markdownLineEnding(code)) {
101372
+ effects.exit('magicBlockData');
101373
+ effects.enter('magicBlockLineEnding');
101374
+ effects.consume(code);
101375
+ effects.exit('magicBlockLineEnding');
101376
+ return beforeData;
101377
+ }
101378
+ if (code === codes.space || code === codes.horizontalTab) {
101379
+ effects.consume(code);
101380
+ return beforeDataWhitespaceContinue;
101381
+ }
101382
+ if (code === codes.leftCurlyBrace) {
101383
+ seenOpenBrace = true;
101384
+ return captureData(code);
101385
+ }
101386
+ effects.exit('magicBlockData');
101387
+ return nok(code);
101388
+ }
101389
+ function captureData(code) {
101390
+ // Fail on EOF - magic block must be closed
101391
+ if (code === null) {
101392
+ effects.exit('magicBlockData');
101393
+ return nok(code);
101394
+ }
101395
+ // Handle multiline magic blocks within text/paragraphs
101396
+ // Exit data, consume line ending with proper token, then re-enter data
101397
+ if (markdownLineEnding(code)) {
101398
+ effects.exit('magicBlockData');
101399
+ effects.enter('magicBlockLineEnding');
101400
+ effects.consume(code);
101401
+ effects.exit('magicBlockLineEnding');
101402
+ return beforeData; // Go back to beforeData to handle potential empty lines
101403
+ }
101404
+ if (jsonState.escapeNext) {
101405
+ jsonState.escapeNext = false;
101406
+ effects.consume(code);
101407
+ return captureData;
101408
+ }
101409
+ if (jsonState.inString) {
101410
+ if (code === codes.backslash) {
101411
+ jsonState.escapeNext = true;
101412
+ effects.consume(code);
101413
+ return captureData;
101414
+ }
101415
+ if (code === codes.quotationMark) {
101416
+ jsonState.inString = false;
101417
+ }
101418
+ effects.consume(code);
101419
+ return captureData;
101420
+ }
101421
+ if (code === codes.quotationMark) {
101422
+ jsonState.inString = true;
101423
+ effects.consume(code);
101424
+ return captureData;
101425
+ }
101426
+ if (code === codes.leftSquareBracket) {
101427
+ effects.exit('magicBlockData');
101428
+ effects.enter('magicBlockMarkerEnd');
101429
+ effects.consume(code);
101430
+ return closingFromData.expectSlash;
101431
+ }
101432
+ effects.consume(code);
101433
+ return captureData;
101434
+ }
101435
+ }
101436
+ /* harmony default export */ const syntax = ((/* unused pure expression or super */ null && (magicBlock)));
101437
+
101438
+ ;// ./lib/micromark/magic-block/index.ts
101439
+ /**
101440
+ * Micromark extension for magic block syntax.
101441
+ *
101442
+ * Usage:
101443
+ * ```ts
101444
+ * import { magicBlock } from './lib/micromark/magic-block';
101445
+ *
101446
+ * const processor = unified()
101447
+ * .data('micromarkExtensions', [magicBlock()])
101448
+ * ```
101449
+ */
101450
+
101451
+
101452
+ ;// ./lib/micromark/mdx-component/syntax.ts
101453
+
101454
+
101455
+
101456
+
101457
+
101458
+ // Raw tags (type-1: pre/script/style/textarea) and block tags (type-6: div,
101459
+ // section, …) always start a block, so they stay flow even with trailing
101460
+ // content. Other lowercase tags (i, span, …) follow the type-7 rule and only
101461
+ // stay flow when nothing trails the close tag.
101462
+ const htmlFlowTagNames = new Set([...htmlRawNames, ...htmlBlockNames]);
101463
+ // Lowercase type-6 block tags claimable in flow even without a `{…}` attribute, so
101464
+ // blank lines between nested JSX siblings don't fragment the block. Excludes table
101465
+ // tags (mdxishTables owns their blank lines) and voids (never close).
101466
+ const plainBlockClaimTagNames = new Set([...htmlBlockNames].filter(tag => !HTML_TABLE_STRUCTURE_TAGS.has(tag) && !HTML_VOID_ELEMENTS.has(tag)));
101467
+ const mdx_component_syntax_nonLazyContinuationStart = {
101468
+ tokenize: mdx_component_syntax_tokenizeNonLazyContinuationStart,
101469
+ partial: true,
101470
+ };
101471
+ // Lookahead for `plainClaimLineStart`: is this line markup-only, or a paragraph
101472
+ // that merely starts with a tag? Run via `effects.check` so it never consumes.
101473
+ const markupOnlyContinuation = {
101474
+ tokenize: tokenizeMarkupOnlyContinuation,
101475
+ partial: true,
101476
+ };
101477
+ function resolveToMdxComponent(events) {
101478
+ let index = events.length;
101479
+ while (index > 0) {
101480
+ index -= 1;
101481
+ if (events[index][0] === 'enter' && events[index][1].type === 'mdxComponent') {
101482
+ break;
101483
+ }
101484
+ }
101485
+ if (index > 1 && events[index - 2][1].type === types_types.linePrefix) {
101486
+ events[index][1].start = events[index - 2][1].start;
101487
+ events[index + 1][1].start = events[index - 2][1].start;
101488
+ events.splice(index - 2, 2);
101489
+ }
101490
+ return events;
101491
+ }
101492
+ const mdxComponentFlowConstruct = {
101493
+ name: 'mdxComponent',
101494
+ tokenize: createTokenize('flow'),
101495
+ resolveTo: resolveToMdxComponent,
101496
+ concrete: true,
101497
+ };
101498
+ const mdxComponentTextConstruct = {
101499
+ name: 'mdxComponentText',
101500
+ tokenize: createTokenize('text'),
101501
+ };
101502
+ /**
101503
+ * Factory for both flow (block) and text (inline) variants.
101504
+ *
101505
+ * **Flow** — the original behavior: claims PascalCase components (always) and
101506
+ * lowercase HTML tags that carry at least one `{…}` attribute expression.
101507
+ * Multi-line, concrete, `afterClose` consumes the rest of the line.
101508
+ *
101509
+ * **Text** — runs inside paragraphs / inline context. Claims lowercase tags and
101510
+ * inline PascalCase components (`INLINE_COMPONENT_TAGS` — Anchor, Glossary), both
101511
+ * gated on at least one `{…}` brace attribute. All other PascalCase stays
101512
+ * flow-only, matching how ReadMe's custom components are authored. Aborts on line
101513
+ * endings (inline constructs don't span lines) and exits immediately after
101514
+ * `</tag>` so the paragraph's inline parser picks up the trailing text.
101515
+ */
101516
+ function createTokenize(mode) {
101517
+ const isFlow = mode === 'flow';
101518
+ return function tokenize(effects, ok, nok) {
101519
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
101520
+ const self = this;
101521
+ let tagName = '';
101522
+ let depth = 0;
101523
+ let closingTagName = '';
101524
+ // For lowercase tags we only want to claim the block if it uses JSX
101525
+ // attribute expression syntax (`attr={...}`). Plain HTML should fall
101526
+ // through to CommonMark html-flow. Flow mode claims any PascalCase block
101527
+ // component; text mode claims only inline PascalCase components
101528
+ // (INLINE_COMPONENT_TAGS — Anchor, Glossary), also brace-gated.
101529
+ let isLowercaseTag = false;
101530
+ let sawBraceAttr = false;
101531
+ // A plain lowercase block tag claimed without a `{…}` attribute, gated by
101532
+ // `plainClaimLineStart`: after a blank line it may only continue on a tag line.
101533
+ let isPlainBlockClaim = false;
101534
+ let pendingBlankLine = false;
101535
+ // Code span tracking
101536
+ let codeSpanOpenSize = 0;
101537
+ let codeSpanCloseSize = 0;
101538
+ // Fenced code block tracking
101539
+ let fenceChar = null;
101540
+ let fenceLength = 0;
101541
+ let fenceCloseLength = 0;
101542
+ let atLineStart = false;
101543
+ // True once this construct consumes any line ending; lets `afterClose`
101544
+ // treat only single-line lowercase tags as inline candidates.
101240
101545
  let sawLineEnding = false;
101241
101546
  // Bail when the opener line has unmatched tag-like tokens in its body.
101242
101547
  // `<Foo>_<Bar>.csv` leaves opens > closes; matched shapes like
@@ -101526,7 +101831,7 @@ function createTokenize(mode) {
101526
101831
  }
101527
101832
  // Continuation for multi-line opening tags
101528
101833
  function openTagContinuationStart(code) {
101529
- return effects.check(syntax_nonLazyContinuationStart, openTagContinuationNonLazy, continuationAfter)(code);
101834
+ return effects.check(mdx_component_syntax_nonLazyContinuationStart, openTagContinuationNonLazy, continuationAfter)(code);
101530
101835
  }
101531
101836
  function openTagContinuationNonLazy(code) {
101532
101837
  sawLineEnding = true;
@@ -101651,7 +101956,7 @@ function createTokenize(mode) {
101651
101956
  return inFencedCode;
101652
101957
  }
101653
101958
  function fencedCodeContinuationStart(code) {
101654
- return effects.check(syntax_nonLazyContinuationStart, fencedCodeContinuationNonLazy, continuationAfter)(code);
101959
+ return effects.check(mdx_component_syntax_nonLazyContinuationStart, fencedCodeContinuationNonLazy, continuationAfter)(code);
101655
101960
  }
101656
101961
  function fencedCodeContinuationNonLazy(code) {
101657
101962
  sawLineEnding = true;
@@ -101666,6 +101971,16 @@ function createTokenize(mode) {
101666
101971
  }
101667
101972
  effects.enter('mdxComponentData');
101668
101973
  fenceCloseLength = 0;
101974
+ return fencedCodeMaybeClose(code);
101975
+ }
101976
+ // Skip leading indentation before the closing-fence check: an indented fence
101977
+ // (the norm in a component body) closes on an equally-indented line, else the
101978
+ // closer is never matched and scanning runs to EOF (CX-3704).
101979
+ function fencedCodeMaybeClose(code) {
101980
+ if (markdownSpace(code)) {
101981
+ effects.consume(code);
101982
+ return fencedCodeMaybeClose;
101983
+ }
101669
101984
  // Check for closing fence
101670
101985
  if (code === fenceChar) {
101671
101986
  fenceCloseLength = 1;
@@ -101849,7 +102164,7 @@ function createTokenize(mode) {
101849
102164
  }
101850
102165
  // ── Body continuation (line endings) ───────────────────────────────────
101851
102166
  function bodyContinuationStart(code) {
101852
- return effects.check(syntax_nonLazyContinuationStart, bodyContinuationNonLazy, continuationAfter)(code);
102167
+ return effects.check(mdx_component_syntax_nonLazyContinuationStart, bodyContinuationNonLazy, continuationAfter)(code);
101853
102168
  }
101854
102169
  function bodyContinuationNonLazy(code) {
101855
102170
  sawLineEnding = true;
@@ -101881,6 +102196,13 @@ function createTokenize(mode) {
101881
102196
  }
101882
102197
  // Dispatch a non-blank continuation line: fenced code at line start, else body.
101883
102198
  function bodyLineStart(code) {
102199
+ // Skip leading indentation while staying "at line start" so an indented
102200
+ // fence is still recognized. Otherwise the first space clears `atLineStart`
102201
+ // and its content — including any unbalanced `{` — stays live text (CX-3704).
102202
+ if (atLineStart && markdownSpace(code)) {
102203
+ effects.consume(code);
102204
+ return bodyLineStart;
102205
+ }
101884
102206
  if (atLineStart && code === codes.tilde)
101885
102207
  return bodyAfterLineStart(code);
101886
102208
  if (atLineStart && code === codes.graveAccent) {
@@ -101931,7 +102253,7 @@ function createTokenize(mode) {
101931
102253
  }
101932
102254
  };
101933
102255
  }
101934
- function syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
102256
+ function mdx_component_syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
101935
102257
  // eslint-disable-next-line @typescript-eslint/no-this-alias
101936
102258
  const self = this;
101937
102259
  return start;
@@ -102039,9 +102361,20 @@ function mdxComponent() {
102039
102361
 
102040
102362
 
102041
102363
 
102364
+
102365
+
102366
+
102367
+
102368
+
102369
+
102042
102370
  const buildInlineMdProcessor = (safeMode) => {
102043
- const micromarkExts = [mdxComponent(), syntax_gemoji(), legacyVariable(), magicBlock()];
102371
+ // `jsxTable` must be present so a `<Table>`/`<table>` nested in a component
102372
+ // body (e.g. a `<Callout>`) is captured as one html node. Without it, blank
102373
+ // lines between rows let CommonMark HTML block type 6 fragment the table and
102374
+ // its rows spill out as text / indented code blocks (CX-3705).
102375
+ const micromarkExts = [jsxTable(), mdxComponent(), syntax_gemoji(), legacyVariable(), magicBlock()];
102044
102376
  const fromMarkdownExts = [
102377
+ jsxTableFromMarkdown(),
102045
102378
  mdxComponentFromMarkdown(),
102046
102379
  gemojiFromMarkdown(),
102047
102380
  legacyVariableFromMarkdown(),
@@ -102101,6 +102434,65 @@ const toMdxJsxTextElement = (name, attributes, children, position) => ({
102101
102434
  children,
102102
102435
  ...(position ? { position } : {}),
102103
102436
  });
102437
+ // Raw-body tags (pre/script/style/textarea) must stay byte-exact; table
102438
+ // structure (`table` + `tableTags`) is owned by `mdxishTables` and figures by
102439
+ // `mdxishJsxToMdast`, both of which run later on raw html nodes.
102440
+ const NON_PROMOTABLE_PLAIN_TAGS = new Set([...htmlRawNames, ...tableTags, 'table', 'figure', 'figcaption']);
102441
+ const NESTED_TABLE_RE = /<table[\s>]/i;
102442
+ const isMarkdownPromotableHtmlTag = (tag) => !NON_PROMOTABLE_PLAIN_TAGS.has(tag);
102443
+ // Expression nodes count as plain so `<div>{1+1}</div>` keeps its current
102444
+ // literal-brace behavior; variables/glossary already resolve inside raw html.
102445
+ const PLAIN_CONTENT_TYPES = new Set([
102446
+ 'paragraph',
102447
+ 'text',
102448
+ 'html',
102449
+ 'mdxTextExpression',
102450
+ 'mdxFlowExpression',
102451
+ NodeTypes.variable,
102452
+ NodeTypes.glossary,
102453
+ ]);
102454
+ // Promoting plain HTML is only worth bypassing rehype-raw's parse5 pass when
102455
+ // the body parses into an actual markdown construct.
102456
+ const containsMarkdownConstruct = (nodes) => nodes.some(node => !PLAIN_CONTENT_TYPES.has(node.type) ||
102457
+ ('children' in node && Array.isArray(node.children) && containsMarkdownConstruct(node.children)));
102458
+ /**
102459
+ * Index of the `</tag>` that balances the already-consumed opening tag (the
102460
+ * caller starts us one level deep). `lastIndexOf` mis-slices sibling same-tag
102461
+ * pairs like `<div>**a**</div><div>**b**</div>`, so we depth-match instead —
102462
+ * delegating to `walkTags` (htmlparser2) so quoted attributes (`title="</div>"`),
102463
+ * code spans, and legacy `<<VARIABLE>>` are handled for free. Returns -1 when
102464
+ * the wrapper is left open.
102465
+ */
102466
+ function findBalancedClosingTagIndex(content, tag) {
102467
+ const target = tag.toLowerCase();
102468
+ const canonicalCloserLength = tag.length + 3; // `</tag>`
102469
+ // The caller already stripped the opening tag, so re-attach one: htmlparser2
102470
+ // drops an unmatched closer, and we want it balanced. Offsets shift by the
102471
+ // prefix length.
102472
+ const prefix = `<${tag}>`;
102473
+ let depth = 0;
102474
+ let closeIndex = -1;
102475
+ walkTags(prefix + content, {
102476
+ onOpen: ({ name, isSelfClosing, isStrayCloser }) => {
102477
+ if (closeIndex >= 0 || isSelfClosing || isStrayCloser)
102478
+ return;
102479
+ if (name.toLowerCase() === target)
102480
+ depth += 1;
102481
+ },
102482
+ onClose: ({ name, start, end, implicit }) => {
102483
+ if (closeIndex >= 0 || implicit || name.toLowerCase() !== target)
102484
+ return;
102485
+ // Only canonical `</tag>` closers — the caller slices by that length, so a
102486
+ // whitespaced `</tag >` would misalign; leaving it unmatched keeps it raw.
102487
+ if (end - start !== canonicalCloserLength)
102488
+ return;
102489
+ depth -= 1;
102490
+ if (depth === 0)
102491
+ closeIndex = start - prefix.length;
102492
+ },
102493
+ });
102494
+ return closeIndex;
102495
+ }
102104
102496
 
102105
102497
  ;// ./processor/transform/mdxish/components/inline-html.ts
102106
102498
 
@@ -102425,6 +102817,10 @@ const substituteNodeWithMdxNode = (parent, index, mdxNode) => {
102425
102817
  * This transformer identifies these patterns and converts them to proper MDX JSX elements so they
102426
102818
  * can be accurately recognized and rendered later with their component definition code.
102427
102819
  *
102820
+ * Note: The main goal is to promote PascalCase tags to MDX elements, but we want to promote
102821
+ * normal HTML to MDX elements in some cases so they get the full custom parsing behavior.
102822
+ * E.g. tags with JSX expressions, nested components, etc.
102823
+ *
102428
102824
  * The mdx-component micromark tokenizer ensures that multi-line components are captured
102429
102825
  * as single HTML nodes, so this transformer only needs to handle two cases:
102430
102826
  *
@@ -102471,6 +102867,7 @@ const mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
102471
102867
  if (GENERIC_MDX_COMPONENT_EXCLUDED_TAGS.has(tag))
102472
102868
  return; // owned by dedicated transformers
102473
102869
  const isPascal = isPascalCase(tag);
102870
+ // ==== SPECIAL CASES TO PROMOTE NORMAL HTML TO MDX ELEMENTS ====
102474
102871
  // Lowercase inline tags with `{…}` attributes belong to
102475
102872
  // mdxishInlineComponentBlocks; leave them as html for that pass. PascalCase
102476
102873
  // components stay flow-level even when inline (ReadMe's component model).
@@ -102479,11 +102876,19 @@ const mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
102479
102876
  // A lowercase wrapper is only promoted when it (or a descendant) carries a
102480
102877
  // JSX expression or nests a component; otherwise it would swallow that inner
102481
102878
  // JSX/component as literal text that rehype-raw's parse5 pass can't handle.
102482
- // Table-structural wrappers are excluded — `mdxishTables` re-parses those.
102483
- const hasNestedExpressionAttr = !selfClosing && NESTED_ATTR_EXPRESSION_RE.test(contentAfterTag);
102879
+ // Table-structural wrappers are excluded from both — `mdxishTables` re-parses
102880
+ // those, so a `{…}` in a cell (e.g. `<code>--depth={n}</code>`) must not
102881
+ // accidentally promote the table to an MDX element prematurely.
102484
102882
  const isTableStructuralTag = tag === 'table' || tableTags.has(tag);
102883
+ const hasNestedExpressionAttr = !selfClosing && !isTableStructuralTag && NESTED_ATTR_EXPRESSION_RE.test(contentAfterTag);
102485
102884
  const hasNestedComponentTag = !selfClosing && !isTableStructuralTag && hasNestedGenericComponentTag(contentAfterTag);
102486
- if (!isPascal && !hasExpressionAttr(attributes) && !hasNestedExpressionAttr && !hasNestedComponentTag)
102885
+ // Promotion: By default commonmark doesn't parse markdown in single line HTML tags (e.g. <div>**bold**</div>)
102886
+ // To support that, we try to promote them to MDX elements so the markdown gets parsed
102887
+ const isPlainLowercaseHtml = !isPascal && !hasExpressionAttr(attributes) && !hasNestedExpressionAttr && !hasNestedComponentTag;
102888
+ const plainClosingTagIndex = isPlainLowercaseHtml && !selfClosing && isMarkdownPromotableHtmlTag(tag) && !NESTED_TABLE_RE.test(contentAfterTag)
102889
+ ? findBalancedClosingTagIndex(contentAfterTag, tag)
102890
+ : -1;
102891
+ if (isPlainLowercaseHtml && plainClosingTagIndex < 0)
102487
102892
  return;
102488
102893
  const closingTagStr = `</${tag}>`;
102489
102894
  // Case 1: Self-closing tag
@@ -102504,14 +102909,26 @@ const mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
102504
102909
  return;
102505
102910
  }
102506
102911
  // Case 2: Self-contained block (closing tag in content)
102507
- if (contentAfterTag.includes(closingTagStr)) {
102508
- const closingTagIndex = contentAfterTag.lastIndexOf(closingTagStr);
102912
+ const closingTagIndex = isPlainLowercaseHtml ? plainClosingTagIndex : contentAfterTag.lastIndexOf(closingTagStr);
102913
+ if (closingTagIndex >= 0) {
102509
102914
  // Untrimmed so parseMdChildren can dedent before trimming.
102510
102915
  const componentInnerContent = contentAfterTag.substring(0, closingTagIndex);
102511
102916
  const contentAfterClose = contentAfterTag.substring(closingTagIndex + closingTagStr.length).trim();
102512
- let parsedChildren = componentInnerContent.trim()
102513
- ? parseMdChildren(componentInnerContent, safeMode)
102514
- : [];
102917
+ let parsedChildren = [];
102918
+ if (componentInnerContent.trim()) {
102919
+ try {
102920
+ parsedChildren = parseMdChildren(componentInnerContent, safeMode);
102921
+ }
102922
+ catch (error) {
102923
+ // Plain HTML bodies can hold anything (e.g. stray braces the strict
102924
+ // expression parser rejects) — keep the node raw instead of throwing.
102925
+ if (isPlainLowercaseHtml)
102926
+ return;
102927
+ throw error;
102928
+ }
102929
+ }
102930
+ if (isPlainLowercaseHtml && !containsMarkdownConstruct(parsedChildren))
102931
+ return;
102515
102932
  // Lowercase tags are usually inline; unwrap a sole paragraph so their
102516
102933
  // phrasing content isn't spuriously block-wrapped.
102517
102934
  if (!isPascal && parsedChildren.length === 1 && parsedChildren[0].type === 'paragraph') {
@@ -104076,9 +104493,6 @@ const magicBlockTransformer = (options = {}) => tree => {
104076
104493
  // single-line `<div>…</div>`). CommonMark slurps the whole div as one `html`
104077
104494
  // node, so the tokenizer never sees the HTMLBlock — we recover it here.
104078
104495
  const RAW_HTML_BLOCK_RE = /<HTMLBlock\b([^>]*)>\s*\{\s*`((?:[^`\\]|\\.)*)`\s*\}\s*<\/HTMLBlock>/g;
104079
- // Opening `<HTMLBlock …>` as its own `html` node — produced inside a paragraph
104080
- // when an HTMLBlock appears inline alongside text.
104081
- const HTML_BLOCK_OPEN_RE = /^<HTMLBlock\b([^>]*)>$/;
104082
104496
  /**
104083
104497
  * Builds the canonical `html-block` MDAST node the renderer expects.
104084
104498
  */
@@ -104159,13 +104573,14 @@ const splitRawHtmlBlocks = (node) => {
104159
104573
  /**
104160
104574
  * Converts every `<HTMLBlock>` shape that survives parsing into the canonical
104161
104575
  * `html-block` MDAST node, reading the body from the tokenizer's template-literal
104162
- * expression. Three shapes occur:
104576
+ * expression. Two shapes occur:
104163
104577
  *
104164
- * 1. JSX element (`mdxJsxFlowElement`/`mdxJsxTextElement`) — multiline/block
104165
- * context and table cells (after their remarkMdx re-parse).
104166
- * 2. Raw `html` blob (`splitRawHtmlBlocks`) single-line top-level, or nested
104167
- * in raw HTML like an inline `<div>`.
104168
- * 3. Inline-in-paragraph split into `html` + expression + `html` siblings.
104578
+ * 1. JSX element (`mdxJsxFlowElement`/`mdxJsxTextElement`) — table cells, after
104579
+ * their remarkMdx re-parse (that re-parse runs without the htmlBlockComponent
104580
+ * tokenizer, so `<HTMLBlock>` arrives as JSX rather than an opaque `html` node).
104581
+ * 2. Raw `html` blob (`splitRawHtmlBlocks`) the htmlBlockComponent tokenizer's
104582
+ * opaque output (top-level and inline), or an `<HTMLBlock>` embedded in a
104583
+ * larger raw-HTML node like an inline `<div>` that the tokenizer never saw.
104169
104584
  *
104170
104585
  * Runs *after* `mdxishTables` so table cells are re-parsed first;
104171
104586
  * `mdxishTables` recognizes the still-JSX `<HTMLBlock>` element when deciding to
@@ -104190,36 +104605,6 @@ const mdxishHtmlBlocks = () => tree => {
104190
104605
  if (replacement)
104191
104606
  parent.children.splice(index, 1, ...replacement);
104192
104607
  });
104193
- // Shape 3: inline within a paragraph — `<HTMLBlock>` open/close arrive as
104194
- // separate `html` siblings with the template-literal expression between them.
104195
- visit(tree, 'paragraph', (paragraph) => {
104196
- // An html-block is block content, so it isn't a valid PhrasingContent child;
104197
- // widen to RootContent (which HTMLBlock belongs to) for the in-place splice.
104198
- const children = paragraph.children;
104199
- for (let i = 0; i < children.length; i += 1) {
104200
- const open = children[i];
104201
- const openMatch = open.type === 'html' ? open.value.match(HTML_BLOCK_OPEN_RE) : null;
104202
- if (!openMatch)
104203
- continue; // eslint-disable-line no-continue
104204
- const closeIdx = children.findIndex((child, j) => j > i && child.type === 'html' && child.value === '</HTMLBlock>');
104205
- if (closeIdx === -1)
104206
- continue; // eslint-disable-line no-continue
104207
- const body = children
104208
- .slice(i + 1, closeIdx)
104209
- .map(child => {
104210
- if (child.type === 'mdxTextExpression' || child.type === 'mdxFlowExpression') {
104211
- return extractTemplateLiteral(child.value);
104212
- }
104213
- // Preserve raw text from any other phrasing sibling (e.g. stray
104214
- // whitespace or content the tokenizer didn't claim) so it isn't
104215
- // silently dropped from the html payload.
104216
- return 'value' in child && typeof child.value === 'string' ? child.value : '';
104217
- })
104218
- .join('');
104219
- const openingTagIndent = (open.position?.start.column ?? 1) - 1;
104220
- children.splice(i, closeIdx - i + 1, htmlBlockFromRaw(openMatch[1], body, open.position, openingTagIndent));
104221
- }
104222
- });
104223
104608
  };
104224
104609
  /* harmony default export */ const mdxish_html_blocks = (mdxishHtmlBlocks);
104225
104610
 
@@ -104919,6 +105304,29 @@ const mdxishMermaidTransformer = () => (tree) => {
104919
105304
  };
104920
105305
  /* harmony default export */ const mdxish_mermaid = (mdxishMermaidTransformer);
104921
105306
 
105307
+ ;// ./processor/transform/mdxish/normalize-closing-tag-whitespace.ts
105308
+
105309
+
105310
+ // Spaces/tabs only — newlines would let prose `<` / `>` across lines look like one tag.
105311
+ const SPACED_CLOSING_TAG_RE = /<\/[ \t]*([a-zA-Z][a-zA-Z0-9-]*)[ \t]*>/g;
105312
+ /**
105313
+ * Canonicalize spaced closing tags (`</ td >` → `</td>`) for known HTML names.
105314
+ *
105315
+ * In HTML, `</` + whitespace is a bogus comment, so `</ table >` never closes the
105316
+ * table (jsxTable misses it → empty table + pre; CX-3706). Only standard HTML tags;
105317
+ * custom components, prose (`a </ b`), and code blocks are left alone.
105318
+ *
105319
+ * @example
105320
+ * normalizeClosingTagWhitespace('</ td >') // '</td>'
105321
+ * normalizeClosingTagWhitespace('</table >') // '</table>'
105322
+ * normalizeClosingTagWhitespace('a </ b >') // unchanged
105323
+ */
105324
+ function normalizeClosingTagWhitespace(content) {
105325
+ const { protectedContent, protectedCode } = protectCodeBlocks(content);
105326
+ const result = protectedContent.replace(SPACED_CLOSING_TAG_RE, (match, tagName) => STANDARD_HTML_TAGS.has(tagName.toLowerCase()) ? `</${tagName}>` : match);
105327
+ return restoreCodeBlocks(result, protectedCode);
105328
+ }
105329
+
104922
105330
  ;// ./processor/transform/mdxish/normalize-compact-headings.ts
104923
105331
 
104924
105332
  /**
@@ -105399,186 +105807,463 @@ function resolveCodeVariables(value, resolvedVariables) {
105399
105807
  return name.toUpperCase();
105400
105808
  return name in resolvedVariables ? resolvedVariables[name] : name.toUpperCase();
105401
105809
  }
105402
- // MDX variable: {user.*}
105403
- if (mdxEscapePrefix || mdxEscapeSuffix)
105404
- return match;
105405
- if (mdxVarName in resolvedVariables)
105406
- return resolvedVariables[mdxVarName];
105407
- const fullPath = match.slice(1, -1);
105408
- return fullPath.toUpperCase();
105409
- });
105410
- }
105411
- /**
105412
- * A remark mdast plugin that resolves legacy variables <<...>> and MDX variables {user.*} inside code and inline code nodes
105413
- * to their values. Uses regexes from the readme variable to search for variables in the code string.
105414
- *
105415
- * This is needed because variables in code blocks and inline cannot be tokenized, and also we need to maintain the code string
105416
- * in the code nodes. This enables engine side variable resolution in codes which improves UX
105417
- */
105418
- const variablesCodeResolver = ({ variables } = {}) => tree => {
105419
- const resolvedVariables = variables_code_flattenVariables(variables);
105420
- visit(tree, 'inlineCode', (node) => {
105421
- if (!node.value)
105422
- return;
105423
- node.value = resolveCodeVariables(node.value, resolvedVariables);
105424
- });
105425
- visit(tree, 'code', (node) => {
105426
- if (!node.value)
105427
- return;
105428
- if (node.lang === 'mermaid')
105429
- return;
105430
- const nextValue = resolveCodeVariables(node.value, resolvedVariables);
105431
- node.value = nextValue;
105432
- // Keep code-tabs/readme-components hProperties in sync with node.value
105433
- // because renderers read `value` from hProperties.
105434
- if (node.data?.hProperties && typeof node.data.hProperties === 'object') {
105435
- node.data.hProperties.value = nextValue;
105810
+ // MDX variable: {user.*}
105811
+ if (mdxEscapePrefix || mdxEscapeSuffix)
105812
+ return match;
105813
+ if (mdxVarName in resolvedVariables)
105814
+ return resolvedVariables[mdxVarName];
105815
+ const fullPath = match.slice(1, -1);
105816
+ return fullPath.toUpperCase();
105817
+ });
105818
+ }
105819
+ /**
105820
+ * A remark mdast plugin that resolves legacy variables <<...>> and MDX variables {user.*} inside code and inline code nodes
105821
+ * to their values. Uses regexes from the readme variable to search for variables in the code string.
105822
+ *
105823
+ * This is needed because variables in code blocks and inline cannot be tokenized, and also we need to maintain the code string
105824
+ * in the code nodes. This enables engine side variable resolution in codes which improves UX
105825
+ */
105826
+ const variablesCodeResolver = ({ variables } = {}) => tree => {
105827
+ const resolvedVariables = variables_code_flattenVariables(variables);
105828
+ visit(tree, 'inlineCode', (node) => {
105829
+ if (!node.value)
105830
+ return;
105831
+ node.value = resolveCodeVariables(node.value, resolvedVariables);
105832
+ });
105833
+ visit(tree, 'code', (node) => {
105834
+ if (!node.value)
105835
+ return;
105836
+ if (node.lang === 'mermaid')
105837
+ return;
105838
+ const nextValue = resolveCodeVariables(node.value, resolvedVariables);
105839
+ node.value = nextValue;
105840
+ // Keep code-tabs/readme-components hProperties in sync with node.value
105841
+ // because renderers read `value` from hProperties.
105842
+ if (node.data?.hProperties && typeof node.data.hProperties === 'object') {
105843
+ node.data.hProperties.value = nextValue;
105844
+ }
105845
+ });
105846
+ return tree;
105847
+ };
105848
+ /* harmony default export */ const variables_code = (variablesCodeResolver);
105849
+
105850
+ ;// ./processor/transform/mdxish/variables-text.ts
105851
+
105852
+
105853
+ /**
105854
+ * Matches {user.<field>} patterns:
105855
+ * - {user.name}
105856
+ * - {user.email}
105857
+ * - {user['field']}
105858
+ * - {user["field"]}
105859
+ *
105860
+ * Captures the field name in group 1 (dot notation) or group 2 (bracket notation)
105861
+ */
105862
+ const USER_VAR_REGEX = /\{user\.(\w+)\}|\{user\[['"](\w+)['"]\]\}/g;
105863
+ function makeVariableNode(varName, rawValue) {
105864
+ return {
105865
+ type: NodeTypes.variable,
105866
+ data: {
105867
+ hName: 'Variable',
105868
+ hProperties: { name: varName },
105869
+ },
105870
+ value: rawValue,
105871
+ };
105872
+ }
105873
+ /**
105874
+ * A remark plugin that parses {user.<field>} patterns from text nodes and
105875
+ * mdx expression nodes, creating Variable nodes for runtime resolution.
105876
+ *
105877
+ * Handles:
105878
+ * - `text` nodes: when safeMode is true or after expression evaluation
105879
+ * - `mdxTextExpression` nodes: when mdxExpression has parsed {user.*} before evaluation
105880
+ * - `mdxFlowExpression` nodes: when {user.*} appears on its own line (e.g. inside JSX table cells)
105881
+ *
105882
+ * Supports any user field: name, email, email_verified, exp, iat, etc.
105883
+ */
105884
+ function visitExpressionNode(node, index, parent) {
105885
+ if (index === undefined || !parent)
105886
+ return;
105887
+ const wrapped = `{${(node.value ?? '').trim()}}`;
105888
+ const matches = [...wrapped.matchAll(USER_VAR_REGEX)];
105889
+ if (matches.length !== 1)
105890
+ return;
105891
+ const varName = matches[0][1] || matches[0][2];
105892
+ parent.children.splice(index, 1, makeVariableNode(varName, wrapped));
105893
+ }
105894
+ const variablesTextTransformer = () => tree => {
105895
+ visit(tree, 'mdxTextExpression', (node, index, parent) => {
105896
+ visitExpressionNode(node, index, parent);
105897
+ });
105898
+ visit(tree, 'mdxFlowExpression', (node, index, parent) => {
105899
+ visitExpressionNode(node, index, parent);
105900
+ });
105901
+ visit(tree, 'text', (node, index, parent) => {
105902
+ if (index === undefined || !parent)
105903
+ return;
105904
+ // Skip if inside inline code
105905
+ if (parent.type === 'inlineCode')
105906
+ return;
105907
+ const text = node.value;
105908
+ if (typeof text !== 'string' || !text.trim())
105909
+ return;
105910
+ if (!text.includes('{user.') && !text.includes('{user['))
105911
+ return;
105912
+ const matches = [...text.matchAll(USER_VAR_REGEX)];
105913
+ if (matches.length === 0)
105914
+ return;
105915
+ const parts = [];
105916
+ let lastIndex = 0;
105917
+ matches.forEach(match => {
105918
+ const matchIndex = match.index ?? 0;
105919
+ // Add text before the match
105920
+ if (matchIndex > lastIndex) {
105921
+ parts.push({ type: 'text', value: text.slice(lastIndex, matchIndex) });
105922
+ }
105923
+ // Extract variable name from either capture group (dot or bracket notation)
105924
+ const varName = match[1] || match[2];
105925
+ parts.push(makeVariableNode(varName, match[0]));
105926
+ lastIndex = matchIndex + match[0].length;
105927
+ });
105928
+ // Add remaining text after last match
105929
+ if (lastIndex < text.length) {
105930
+ parts.push({ type: 'text', value: text.slice(lastIndex) });
105931
+ }
105932
+ // Replace node with parts
105933
+ if (parts.length > 1 || (parts.length === 1 && parts[0].type !== 'text')) {
105934
+ parent.children.splice(index, 1, ...parts);
105935
+ }
105936
+ });
105937
+ return tree;
105938
+ };
105939
+ /* harmony default export */ const variables_text = (variablesTextTransformer);
105940
+
105941
+ ;// ./lib/mdast-util/html-block-component/index.ts
105942
+ const html_block_component_contextMap = new WeakMap();
105943
+ function findHtmlBlockComponentToken() {
105944
+ const events = this.tokenStack;
105945
+ for (let i = events.length - 1; i >= 0; i -= 1) {
105946
+ if (events[i][0].type === 'htmlBlockComponent')
105947
+ return events[i][0];
105948
+ }
105949
+ return undefined;
105950
+ }
105951
+ function enterHtmlBlockComponent(token) {
105952
+ html_block_component_contextMap.set(token, { chunks: [], lastEndLine: token.start.line });
105953
+ this.enter({ type: 'html', value: '' }, token);
105954
+ }
105955
+ function exitHtmlBlockComponentData(token) {
105956
+ const componentToken = findHtmlBlockComponentToken.call(this);
105957
+ if (!componentToken)
105958
+ return;
105959
+ const ctx = html_block_component_contextMap.get(componentToken);
105960
+ if (ctx) {
105961
+ const gap = token.start.line - ctx.lastEndLine;
105962
+ if (ctx.chunks.length > 0 && gap > 0) {
105963
+ ctx.chunks.push('\n'.repeat(gap));
105964
+ }
105965
+ ctx.chunks.push(this.sliceSerialize(token));
105966
+ ctx.lastEndLine = token.end.line;
105967
+ }
105968
+ }
105969
+ function exitHtmlBlockComponent(token) {
105970
+ const ctx = html_block_component_contextMap.get(token);
105971
+ const node = this.stack[this.stack.length - 1];
105972
+ if (ctx) {
105973
+ node.value = ctx.chunks.join('');
105974
+ html_block_component_contextMap.delete(token);
105975
+ }
105976
+ this.exit(token);
105977
+ }
105978
+ function htmlBlockComponentFromMarkdown() {
105979
+ return {
105980
+ enter: {
105981
+ htmlBlockComponent: enterHtmlBlockComponent,
105982
+ },
105983
+ exit: {
105984
+ htmlBlockComponentData: exitHtmlBlockComponentData,
105985
+ htmlBlockComponent: exitHtmlBlockComponent,
105986
+ },
105987
+ };
105988
+ }
105989
+
105990
+ ;// ./lib/micromark/html-block-component/syntax.ts
105991
+
105992
+
105993
+ const TAG_SUFFIX = [
105994
+ codes.uppercaseT,
105995
+ codes.uppercaseM,
105996
+ codes.uppercaseL,
105997
+ codes.uppercaseB,
105998
+ codes.lowercaseL,
105999
+ codes.lowercaseO,
106000
+ codes.lowercaseC,
106001
+ codes.lowercaseK,
106002
+ ];
106003
+ // ---------------------------------------------------------------------------
106004
+ // Shared tokenizer factory
106005
+ // ---------------------------------------------------------------------------
106006
+ /**
106007
+ * Creates a tokenize function for `<HTMLBlock>...</HTMLBlock>`.
106008
+ *
106009
+ * - **flow** (block-level): supports multiline content via line continuations,
106010
+ * consumes trailing whitespace after the closing tag.
106011
+ * - **text** (inline): single-line only, exits immediately after the closing tag.
106012
+ */
106013
+ function syntax_createTokenize(mode) {
106014
+ return function tokenize(effects, ok, nok) {
106015
+ let depth = 1;
106016
+ function matchChars(chars, onMatch, onFail) {
106017
+ if (chars.length === 0)
106018
+ return onMatch;
106019
+ const next = (code) => {
106020
+ if (code === chars[0]) {
106021
+ effects.consume(code);
106022
+ return matchChars(chars.slice(1), onMatch, onFail);
106023
+ }
106024
+ return onFail(code);
106025
+ };
106026
+ return next;
106027
+ }
106028
+ function matchTagName(onMatch, onFail) {
106029
+ const next = (code) => {
106030
+ if (code === codes.uppercaseH) {
106031
+ effects.consume(code);
106032
+ return matchChars(TAG_SUFFIX, onMatch, onFail);
106033
+ }
106034
+ return onFail(code);
106035
+ };
106036
+ return next;
106037
+ }
106038
+ return start;
106039
+ function start(code) {
106040
+ if (code !== codes.lessThan)
106041
+ return nok(code);
106042
+ effects.enter('htmlBlockComponent');
106043
+ effects.enter('htmlBlockComponentData');
106044
+ effects.consume(code);
106045
+ return matchTagName(afterTagName, nok);
106046
+ }
106047
+ function afterTagName(code) {
106048
+ if (code === codes.greaterThan) {
106049
+ effects.consume(code);
106050
+ return body;
106051
+ }
106052
+ if (code === codes.space || code === codes.horizontalTab) {
106053
+ effects.consume(code);
106054
+ return inAttributes;
106055
+ }
106056
+ if (mode === 'flow' && markdownLineEnding(code)) {
106057
+ effects.exit('htmlBlockComponentData');
106058
+ return attributeContinuationStart(code);
106059
+ }
106060
+ if (code === codes.slash) {
106061
+ effects.consume(code);
106062
+ return selfClose;
106063
+ }
106064
+ return nok(code);
106065
+ }
106066
+ function inAttributes(code) {
106067
+ if (code === codes.greaterThan) {
106068
+ effects.consume(code);
106069
+ return body;
106070
+ }
106071
+ if (code === null) {
106072
+ return nok(code);
106073
+ }
106074
+ if (markdownLineEnding(code)) {
106075
+ if (mode === 'text')
106076
+ return nok(code);
106077
+ effects.exit('htmlBlockComponentData');
106078
+ return attributeContinuationStart(code);
106079
+ }
106080
+ effects.consume(code);
106081
+ return inAttributes;
106082
+ }
106083
+ function attributeContinuationStart(code) {
106084
+ return effects.check(html_block_component_syntax_nonLazyContinuationStart, attributeContinuationNonLazy, continuationAfter)(code);
106085
+ }
106086
+ function attributeContinuationNonLazy(code) {
106087
+ effects.enter(types_types.lineEnding);
106088
+ effects.consume(code);
106089
+ effects.exit(types_types.lineEnding);
106090
+ return attributeContinuationBefore;
106091
+ }
106092
+ function attributeContinuationBefore(code) {
106093
+ if (code === null || markdownLineEnding(code)) {
106094
+ return attributeContinuationStart(code);
106095
+ }
106096
+ effects.enter('htmlBlockComponentData');
106097
+ return inAttributes(code);
106098
+ }
106099
+ function selfClose(code) {
106100
+ if (code === codes.greaterThan) {
106101
+ effects.consume(code);
106102
+ return mode === 'flow' ? afterClose : done(code);
106103
+ }
106104
+ return nok(code);
106105
+ }
106106
+ function body(code) {
106107
+ if (code === null)
106108
+ return nok(code);
106109
+ if (markdownLineEnding(code)) {
106110
+ if (mode === 'text') {
106111
+ // Text constructs operate on paragraph content which spans lines
106112
+ effects.consume(code);
106113
+ return body;
106114
+ }
106115
+ effects.exit('htmlBlockComponentData');
106116
+ return continuationStart(code);
106117
+ }
106118
+ if (code === codes.lessThan) {
106119
+ effects.consume(code);
106120
+ return closeSlash;
106121
+ }
106122
+ effects.consume(code);
106123
+ return body;
106124
+ }
106125
+ function closeSlash(code) {
106126
+ if (code === codes.slash) {
106127
+ effects.consume(code);
106128
+ return matchTagName(closeGt, body);
106129
+ }
106130
+ return matchTagName(openAfterTagName, body)(code);
106131
+ }
106132
+ function openAfterTagName(code) {
106133
+ if (code === codes.greaterThan || code === codes.space || code === codes.horizontalTab) {
106134
+ depth += 1;
106135
+ effects.consume(code);
106136
+ return body;
106137
+ }
106138
+ return body(code);
106139
+ }
106140
+ function closeGt(code) {
106141
+ if (code === codes.greaterThan) {
106142
+ depth -= 1;
106143
+ effects.consume(code);
106144
+ if (depth === 0) {
106145
+ return mode === 'flow' ? afterClose : done(code);
106146
+ }
106147
+ return body;
106148
+ }
106149
+ return body(code);
105436
106150
  }
105437
- });
105438
- return tree;
105439
- };
105440
- /* harmony default export */ const variables_code = (variablesCodeResolver);
105441
-
105442
- ;// ./processor/transform/mdxish/variables-text.ts
105443
-
105444
-
105445
- /**
105446
- * Matches {user.<field>} patterns:
105447
- * - {user.name}
105448
- * - {user.email}
105449
- * - {user['field']}
105450
- * - {user["field"]}
105451
- *
105452
- * Captures the field name in group 1 (dot notation) or group 2 (bracket notation)
105453
- */
105454
- const USER_VAR_REGEX = /\{user\.(\w+)\}|\{user\[['"](\w+)['"]\]\}/g;
105455
- function makeVariableNode(varName, rawValue) {
105456
- return {
105457
- type: NodeTypes.variable,
105458
- data: {
105459
- hName: 'Variable',
105460
- hProperties: { name: varName },
105461
- },
105462
- value: rawValue,
105463
- };
105464
- }
105465
- /**
105466
- * A remark plugin that parses {user.<field>} patterns from text nodes and
105467
- * mdx expression nodes, creating Variable nodes for runtime resolution.
105468
- *
105469
- * Handles:
105470
- * - `text` nodes: when safeMode is true or after expression evaluation
105471
- * - `mdxTextExpression` nodes: when mdxExpression has parsed {user.*} before evaluation
105472
- * - `mdxFlowExpression` nodes: when {user.*} appears on its own line (e.g. inside JSX table cells)
105473
- *
105474
- * Supports any user field: name, email, email_verified, exp, iat, etc.
105475
- */
105476
- function visitExpressionNode(node, index, parent) {
105477
- if (index === undefined || !parent)
105478
- return;
105479
- const wrapped = `{${(node.value ?? '').trim()}}`;
105480
- const matches = [...wrapped.matchAll(USER_VAR_REGEX)];
105481
- if (matches.length !== 1)
105482
- return;
105483
- const varName = matches[0][1] || matches[0][2];
105484
- parent.children.splice(index, 1, makeVariableNode(varName, wrapped));
105485
- }
105486
- const variablesTextTransformer = () => tree => {
105487
- visit(tree, 'mdxTextExpression', (node, index, parent) => {
105488
- visitExpressionNode(node, index, parent);
105489
- });
105490
- visit(tree, 'mdxFlowExpression', (node, index, parent) => {
105491
- visitExpressionNode(node, index, parent);
105492
- });
105493
- visit(tree, 'text', (node, index, parent) => {
105494
- if (index === undefined || !parent)
105495
- return;
105496
- // Skip if inside inline code
105497
- if (parent.type === 'inlineCode')
105498
- return;
105499
- const text = node.value;
105500
- if (typeof text !== 'string' || !text.trim())
105501
- return;
105502
- if (!text.includes('{user.') && !text.includes('{user['))
105503
- return;
105504
- const matches = [...text.matchAll(USER_VAR_REGEX)];
105505
- if (matches.length === 0)
105506
- return;
105507
- const parts = [];
105508
- let lastIndex = 0;
105509
- matches.forEach(match => {
105510
- const matchIndex = match.index ?? 0;
105511
- // Add text before the match
105512
- if (matchIndex > lastIndex) {
105513
- parts.push({ type: 'text', value: text.slice(lastIndex, matchIndex) });
106151
+ // -- flow-only states ---------------------------------------------------
106152
+ function afterClose(code) {
106153
+ if (code === null || markdownLineEnding(code)) {
106154
+ return done(code);
105514
106155
  }
105515
- // Extract variable name from either capture group (dot or bracket notation)
105516
- const varName = match[1] || match[2];
105517
- parts.push(makeVariableNode(varName, match[0]));
105518
- lastIndex = matchIndex + match[0].length;
105519
- });
105520
- // Add remaining text after last match
105521
- if (lastIndex < text.length) {
105522
- parts.push({ type: 'text', value: text.slice(lastIndex) });
106156
+ if (code === codes.space || code === codes.horizontalTab) {
106157
+ effects.consume(code);
106158
+ return afterClose;
106159
+ }
106160
+ // Reject so the block re-parses as a paragraph, deferring to the
106161
+ // text tokenizer which preserves trailing content in the same line.
106162
+ return nok(code);
105523
106163
  }
105524
- // Replace node with parts
105525
- if (parts.length > 1 || (parts.length === 1 && parts[0].type !== 'text')) {
105526
- parent.children.splice(index, 1, ...parts);
106164
+ // -- flow-only: line continuation ---------------------------------------
106165
+ function continuationStart(code) {
106166
+ return effects.check(html_block_component_syntax_nonLazyContinuationStart, continuationStartNonLazy, continuationAfter)(code);
105527
106167
  }
105528
- });
105529
- return tree;
106168
+ function continuationStartNonLazy(code) {
106169
+ effects.enter(types_types.lineEnding);
106170
+ effects.consume(code);
106171
+ effects.exit(types_types.lineEnding);
106172
+ return continuationBefore;
106173
+ }
106174
+ function continuationBefore(code) {
106175
+ if (code === null || markdownLineEnding(code)) {
106176
+ return continuationStart(code);
106177
+ }
106178
+ effects.enter('htmlBlockComponentData');
106179
+ return body(code);
106180
+ }
106181
+ function continuationAfter(code) {
106182
+ if (code === null)
106183
+ return nok(code);
106184
+ effects.exit('htmlBlockComponent');
106185
+ return ok(code);
106186
+ }
106187
+ // -- shared exit --------------------------------------------------------
106188
+ function done(_code) {
106189
+ effects.exit('htmlBlockComponentData');
106190
+ effects.exit('htmlBlockComponent');
106191
+ return ok(_code);
106192
+ }
106193
+ };
106194
+ }
106195
+ // ---------------------------------------------------------------------------
106196
+ // Flow construct (block-level)
106197
+ // ---------------------------------------------------------------------------
106198
+ const html_block_component_syntax_nonLazyContinuationStart = {
106199
+ tokenize: html_block_component_syntax_tokenizeNonLazyContinuationStart,
106200
+ partial: true,
105530
106201
  };
105531
- /* harmony default export */ const variables_text = (variablesTextTransformer);
105532
-
105533
- ;// ./lib/mdast-util/jsx-table/index.ts
105534
- const jsx_table_contextMap = new WeakMap();
105535
- function findJsxTableToken() {
105536
- const events = this.tokenStack;
105537
- for (let i = events.length - 1; i >= 0; i -= 1) {
105538
- if (events[i][0].type === 'jsxTable')
105539
- return events[i][0];
106202
+ function resolveToHtmlBlockComponent(events) {
106203
+ let index = events.length;
106204
+ while (index > 0) {
106205
+ index -= 1;
106206
+ if (events[index][0] === 'enter' && events[index][1].type === 'htmlBlockComponent') {
106207
+ break;
106208
+ }
105540
106209
  }
105541
- return undefined;
105542
- }
105543
- function enterJsxTable(token) {
105544
- jsx_table_contextMap.set(token, { chunks: [], lastEndLine: token.start.line });
105545
- this.enter({ type: 'html', value: '' }, token);
106210
+ if (index > 1 && events[index - 2][1].type === types_types.linePrefix) {
106211
+ events[index][1].start = events[index - 2][1].start;
106212
+ events[index + 1][1].start = events[index - 2][1].start;
106213
+ events.splice(index - 2, 2);
106214
+ }
106215
+ return events;
105546
106216
  }
105547
- function exitJsxTableData(token) {
105548
- const tableToken = findJsxTableToken.call(this);
105549
- if (!tableToken)
105550
- return;
105551
- const ctx = jsx_table_contextMap.get(tableToken);
105552
- if (ctx) {
105553
- const gap = token.start.line - ctx.lastEndLine;
105554
- if (ctx.chunks.length > 0 && gap > 0) {
105555
- ctx.chunks.push('\n'.repeat(gap));
106217
+ const htmlBlockComponentFlowConstruct = {
106218
+ name: 'htmlBlockComponent',
106219
+ tokenize: syntax_createTokenize('flow'),
106220
+ resolveTo: resolveToHtmlBlockComponent,
106221
+ concrete: true,
106222
+ };
106223
+ function html_block_component_syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
106224
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
106225
+ const self = this;
106226
+ return start;
106227
+ function start(code) {
106228
+ if (markdownLineEnding(code)) {
106229
+ effects.enter(types_types.lineEnding);
106230
+ effects.consume(code);
106231
+ effects.exit(types_types.lineEnding);
106232
+ return after;
105556
106233
  }
105557
- ctx.chunks.push(this.sliceSerialize(token));
105558
- ctx.lastEndLine = token.end.line;
106234
+ return nok(code);
105559
106235
  }
105560
- }
105561
- function exitJsxTable(token) {
105562
- const ctx = jsx_table_contextMap.get(token);
105563
- const node = this.stack[this.stack.length - 1];
105564
- if (ctx) {
105565
- node.value = ctx.chunks.join('');
105566
- jsx_table_contextMap.delete(token);
106236
+ function after(code) {
106237
+ if (self.parser.lazy[self.now().line]) {
106238
+ return nok(code);
106239
+ }
106240
+ return ok(code);
105567
106241
  }
105568
- this.exit(token);
105569
106242
  }
105570
- function jsxTableFromMarkdown() {
106243
+ // ---------------------------------------------------------------------------
106244
+ // Text construct (inline)
106245
+ // ---------------------------------------------------------------------------
106246
+ const htmlBlockComponentTextConstruct = {
106247
+ name: 'htmlBlockComponent',
106248
+ tokenize: syntax_createTokenize('text'),
106249
+ };
106250
+ // ---------------------------------------------------------------------------
106251
+ // Extension
106252
+ // ---------------------------------------------------------------------------
106253
+ function htmlBlockComponent() {
105571
106254
  return {
105572
- enter: {
105573
- jsxTable: enterJsxTable,
106255
+ flow: {
106256
+ [codes.lessThan]: [htmlBlockComponentFlowConstruct],
105574
106257
  },
105575
- exit: {
105576
- jsxTableData: exitJsxTableData,
105577
- jsxTable: exitJsxTable,
106258
+ text: {
106259
+ [codes.lessThan]: [htmlBlockComponentTextConstruct],
105578
106260
  },
105579
106261
  };
105580
106262
  }
105581
106263
 
106264
+ ;// ./lib/micromark/html-block-component/index.ts
106265
+
106266
+
105582
106267
  ;// ./lib/micromark/jsx-comment/syntax.ts
105583
106268
 
105584
106269
 
@@ -105701,243 +106386,6 @@ function jsxComment() {
105701
106386
  };
105702
106387
  }
105703
106388
 
105704
- ;// ./lib/micromark/jsx-table/syntax.ts
105705
-
105706
-
105707
- const jsx_table_syntax_nonLazyContinuationStart = {
105708
- tokenize: jsx_table_syntax_tokenizeNonLazyContinuationStart,
105709
- partial: true,
105710
- };
105711
- function resolveToJsxTable(events) {
105712
- let index = events.length;
105713
- while (index > 0) {
105714
- index -= 1;
105715
- if (events[index][0] === 'enter' && events[index][1].type === 'jsxTable') {
105716
- break;
105717
- }
105718
- }
105719
- if (index > 1 && events[index - 2][1].type === types_types.linePrefix) {
105720
- events[index][1].start = events[index - 2][1].start;
105721
- events[index + 1][1].start = events[index - 2][1].start;
105722
- events.splice(index - 2, 2);
105723
- }
105724
- return events;
105725
- }
105726
- const jsxTableConstruct = {
105727
- name: 'jsxTable',
105728
- tokenize: tokenizeJsxTable,
105729
- resolveTo: resolveToJsxTable,
105730
- concrete: true,
105731
- };
105732
- function tokenizeJsxTable(effects, ok, nok) {
105733
- let codeSpanOpenSize = 0;
105734
- let codeSpanCloseSize = 0;
105735
- let depth = 1;
105736
- const ABLE_SUFFIX = [codes.lowercaseA, codes.lowercaseB, codes.lowercaseL, codes.lowercaseE];
105737
- /** Build a state chain that matches a sequence of character codes. */
105738
- function matchChars(chars, onMatch, onFail) {
105739
- if (chars.length === 0)
105740
- return onMatch;
105741
- return ((code) => {
105742
- if (code === chars[0]) {
105743
- effects.consume(code);
105744
- return matchChars(chars.slice(1), onMatch, onFail);
105745
- }
105746
- return onFail(code);
105747
- });
105748
- }
105749
- return start;
105750
- function start(code) {
105751
- if (code !== codes.lessThan)
105752
- return nok(code);
105753
- effects.enter('jsxTable');
105754
- effects.enter('jsxTableData');
105755
- effects.consume(code);
105756
- return afterLessThan;
105757
- }
105758
- function afterLessThan(code) {
105759
- if (code === codes.uppercaseT || code === codes.lowercaseT) {
105760
- effects.consume(code);
105761
- return matchChars(ABLE_SUFFIX, afterTagName, nok);
105762
- }
105763
- return nok(code);
105764
- }
105765
- function afterTagName(code) {
105766
- if (code === codes.greaterThan || code === codes.slash || code === codes.space || code === codes.horizontalTab) {
105767
- effects.consume(code);
105768
- return body;
105769
- }
105770
- return nok(code);
105771
- }
105772
- function body(code) {
105773
- // Reject unclosed <Table> so it falls back to normal HTML block parsing
105774
- // instead of swallowing all subsequent content to EOF
105775
- if (code === null) {
105776
- return nok(code);
105777
- }
105778
- if (markdownLineEnding(code)) {
105779
- effects.exit('jsxTableData');
105780
- return continuationStart(code);
105781
- }
105782
- if (code === codes.backslash) {
105783
- effects.consume(code);
105784
- return escapedChar;
105785
- }
105786
- if (code === codes.lessThan) {
105787
- effects.consume(code);
105788
- return closeSlash;
105789
- }
105790
- // Skip over backtick code spans so `</Table>` in inline code isn't
105791
- // treated as the closing tag
105792
- if (code === codes.graveAccent) {
105793
- codeSpanOpenSize = 0;
105794
- return countOpenTicks(code);
105795
- }
105796
- effects.consume(code);
105797
- return body;
105798
- }
105799
- function countOpenTicks(code) {
105800
- if (code === codes.graveAccent) {
105801
- codeSpanOpenSize += 1;
105802
- effects.consume(code);
105803
- return countOpenTicks;
105804
- }
105805
- return inCodeSpan(code);
105806
- }
105807
- function inCodeSpan(code) {
105808
- if (code === null || markdownLineEnding(code))
105809
- return body(code);
105810
- if (code === codes.graveAccent) {
105811
- codeSpanCloseSize = 0;
105812
- return countCloseTicks(code);
105813
- }
105814
- effects.consume(code);
105815
- return inCodeSpan;
105816
- }
105817
- function countCloseTicks(code) {
105818
- if (code === codes.graveAccent) {
105819
- codeSpanCloseSize += 1;
105820
- effects.consume(code);
105821
- return countCloseTicks;
105822
- }
105823
- return codeSpanCloseSize === codeSpanOpenSize ? body(code) : inCodeSpan(code);
105824
- }
105825
- function escapedChar(code) {
105826
- if (code === null || markdownLineEnding(code)) {
105827
- return body(code);
105828
- }
105829
- effects.consume(code);
105830
- return body;
105831
- }
105832
- function closeSlash(code) {
105833
- if (code === codes.slash) {
105834
- effects.consume(code);
105835
- return closeTagFirstChar;
105836
- }
105837
- if (code === codes.uppercaseT || code === codes.lowercaseT) {
105838
- effects.consume(code);
105839
- return matchChars(ABLE_SUFFIX, openAfterTagName, body);
105840
- }
105841
- return body(code);
105842
- }
105843
- function closeTagFirstChar(code) {
105844
- if (code === codes.uppercaseT || code === codes.lowercaseT) {
105845
- effects.consume(code);
105846
- return matchChars(ABLE_SUFFIX, closeGt, body);
105847
- }
105848
- return body(code);
105849
- }
105850
- function openAfterTagName(code) {
105851
- if (code === codes.greaterThan || code === codes.slash || code === codes.space || code === codes.horizontalTab) {
105852
- depth += 1;
105853
- effects.consume(code);
105854
- return body;
105855
- }
105856
- return body(code);
105857
- }
105858
- function closeGt(code) {
105859
- if (code === codes.greaterThan) {
105860
- depth -= 1;
105861
- effects.consume(code);
105862
- if (depth === 0) {
105863
- return afterClose;
105864
- }
105865
- return body;
105866
- }
105867
- return body(code);
105868
- }
105869
- function afterClose(code) {
105870
- if (code === null || markdownLineEnding(code)) {
105871
- effects.exit('jsxTableData');
105872
- effects.exit('jsxTable');
105873
- return ok(code);
105874
- }
105875
- effects.consume(code);
105876
- return afterClose;
105877
- }
105878
- // Line ending handling — follows the htmlFlow pattern
105879
- function continuationStart(code) {
105880
- return effects.check(jsx_table_syntax_nonLazyContinuationStart, continuationStartNonLazy, continuationAfter)(code);
105881
- }
105882
- function continuationStartNonLazy(code) {
105883
- effects.enter(types_types.lineEnding);
105884
- effects.consume(code);
105885
- effects.exit(types_types.lineEnding);
105886
- return continuationBefore;
105887
- }
105888
- function continuationBefore(code) {
105889
- if (code === null || markdownLineEnding(code)) {
105890
- return continuationStart(code);
105891
- }
105892
- effects.enter('jsxTableData');
105893
- return body(code);
105894
- }
105895
- function continuationAfter(code) {
105896
- // At EOF without </Table>, reject so content isn't swallowed
105897
- if (code === null) {
105898
- return nok(code);
105899
- }
105900
- effects.exit('jsxTable');
105901
- return ok(code);
105902
- }
105903
- }
105904
- function jsx_table_syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
105905
- // eslint-disable-next-line @typescript-eslint/no-this-alias
105906
- const self = this;
105907
- return start;
105908
- function start(code) {
105909
- if (markdownLineEnding(code)) {
105910
- effects.enter(types_types.lineEnding);
105911
- effects.consume(code);
105912
- effects.exit(types_types.lineEnding);
105913
- return after;
105914
- }
105915
- return nok(code);
105916
- }
105917
- function after(code) {
105918
- if (self.parser.lazy[self.now().line]) {
105919
- return nok(code);
105920
- }
105921
- return ok(code);
105922
- }
105923
- }
105924
- /**
105925
- * Micromark extension that tokenizes `<Table>...</Table>` and `<table>...</table>`
105926
- * as a single flow block.
105927
- *
105928
- * Prevents CommonMark HTML block type 6 from fragmenting table blocks at blank lines.
105929
- */
105930
- function jsxTable() {
105931
- return {
105932
- flow: {
105933
- [codes.lessThan]: [jsxTableConstruct],
105934
- },
105935
- };
105936
- }
105937
-
105938
- ;// ./lib/micromark/jsx-table/index.ts
105939
-
105940
-
105941
106389
  ;// ./lib/micromark/mdx-expression-lenient/syntax.ts
105942
106390
 
105943
106391
 
@@ -106113,6 +106561,9 @@ function loadComponents() {
106113
106561
 
106114
106562
 
106115
106563
 
106564
+
106565
+
106566
+
106116
106567
 
106117
106568
 
106118
106569
 
@@ -106127,15 +106578,19 @@ const defaultTransformers = [
106127
106578
  * CommonMark/remark limitations and reach parity with legacy (rdmd) rendering.
106128
106579
  *
106129
106580
  * Runs a series of string-level transformations before micromark/remark parsing:
106130
- * 1. Normalize malformed table separator syntax (e.g., `|: ---``| :---`)
106131
- * 2. Terminate HTML flow blocks so subsequent content isn't swallowed
106132
- * 3. Close invalid "self-closing" HTML tags (e.g., `<i />` → `<i></i>`)
106133
- * 4. Normalize compact ATX headings (e.g., `#Heading``# Heading`)
106134
- * 5. Replace snake_case component names with parser-safe placeholders
106581
+ * 1. Canonicalize closing tags with stray whitespace (e.g., `</ td >` `</td>`)
106582
+ * 2. Normalize malformed table separator syntax (e.g., `|: ---` → `| :---`)
106583
+ * 3. Terminate HTML flow blocks so subsequent content isn't swallowed
106584
+ * 4. Close invalid "self-closing" HTML tags (e.g., `<i />` `<i></i>`)
106585
+ * 5. Normalize compact ATX headings (e.g., `#Heading` → `# Heading`)
106586
+ * 6. Replace snake_case component names with parser-safe placeholders
106135
106587
  */
106136
106588
  function preprocessContent(content, opts) {
106137
106589
  const { knownComponents } = opts;
106138
- let result = normalizeTableSeparator(content);
106590
+ // Runs first so `jsxTable` sees a literal `</table>` (and the HTML-line
106591
+ // classification in `terminateHtmlFlowBlocks` is accurate)
106592
+ let result = normalizeClosingTagWhitespace(content);
106593
+ result = normalizeTableSeparator(result);
106139
106594
  result = terminateHtmlFlowBlocks(result);
106140
106595
  result = closeSelfClosingHtmlTags(result);
106141
106596
  result = normalizeCompactHeadings(result);
@@ -106164,6 +106619,7 @@ function mdxishAstProcessor(mdContent, opts = {}) {
106164
106619
  syntax_gemoji(),
106165
106620
  legacyVariable(),
106166
106621
  looseHtmlEntity(),
106622
+ htmlBlockComponent(),
106167
106623
  ];
106168
106624
  const fromMarkdownExts = [
106169
106625
  jsxTableFromMarkdown(),
@@ -106173,6 +106629,7 @@ function mdxishAstProcessor(mdContent, opts = {}) {
106173
106629
  legacyVariableFromMarkdown(),
106174
106630
  emptyTaskListItemFromMarkdown(),
106175
106631
  looseHtmlEntityFromMarkdown(),
106632
+ htmlBlockComponentFromMarkdown(),
106176
106633
  ];
106177
106634
  if (!safeMode) {
106178
106635
  // Insert mdx expression (text-only, no flow) after gemoji at index 3
@@ -106186,6 +106643,10 @@ function mdxishAstProcessor(mdContent, opts = {}) {
106186
106643
  // JSX comment tokenizer must come before magicBlock so it claims `{/* ... */}` first
106187
106644
  micromarkExts.unshift(jsxComment());
106188
106645
  }
106646
+ // Claim `<HTMLBlock>` as one opaque token so broad tokenizers can't fragment its body
106647
+ // We put this last as micromark tries the last-registered extension first, so push (not unshift) to win the `<` race.
106648
+ // micromarkExts.push(htmlBlockComponent());
106649
+ // fromMarkdownExts.push(htmlBlockComponentFromMarkdown());
106189
106650
  const processor = unified()
106190
106651
  .data('micromarkExtensions', micromarkExts)
106191
106652
  .data('fromMarkdownExtensions', fromMarkdownExts)
@@ -106785,332 +107246,6 @@ const mdxishTags_tags = (doc) => {
106785
107246
  };
106786
107247
  /* harmony default export */ const mdxishTags = (mdxishTags_tags);
106787
107248
 
106788
- ;// ./lib/mdast-util/html-block-component/index.ts
106789
- const html_block_component_contextMap = new WeakMap();
106790
- function findHtmlBlockComponentToken() {
106791
- const events = this.tokenStack;
106792
- for (let i = events.length - 1; i >= 0; i -= 1) {
106793
- if (events[i][0].type === 'htmlBlockComponent')
106794
- return events[i][0];
106795
- }
106796
- return undefined;
106797
- }
106798
- function enterHtmlBlockComponent(token) {
106799
- html_block_component_contextMap.set(token, { chunks: [], lastEndLine: token.start.line });
106800
- this.enter({ type: 'html', value: '' }, token);
106801
- }
106802
- function exitHtmlBlockComponentData(token) {
106803
- const componentToken = findHtmlBlockComponentToken.call(this);
106804
- if (!componentToken)
106805
- return;
106806
- const ctx = html_block_component_contextMap.get(componentToken);
106807
- if (ctx) {
106808
- const gap = token.start.line - ctx.lastEndLine;
106809
- if (ctx.chunks.length > 0 && gap > 0) {
106810
- ctx.chunks.push('\n'.repeat(gap));
106811
- }
106812
- ctx.chunks.push(this.sliceSerialize(token));
106813
- ctx.lastEndLine = token.end.line;
106814
- }
106815
- }
106816
- function exitHtmlBlockComponent(token) {
106817
- const ctx = html_block_component_contextMap.get(token);
106818
- const node = this.stack[this.stack.length - 1];
106819
- if (ctx) {
106820
- node.value = ctx.chunks.join('');
106821
- html_block_component_contextMap.delete(token);
106822
- }
106823
- this.exit(token);
106824
- }
106825
- function htmlBlockComponentFromMarkdown() {
106826
- return {
106827
- enter: {
106828
- htmlBlockComponent: enterHtmlBlockComponent,
106829
- },
106830
- exit: {
106831
- htmlBlockComponentData: exitHtmlBlockComponentData,
106832
- htmlBlockComponent: exitHtmlBlockComponent,
106833
- },
106834
- };
106835
- }
106836
-
106837
- ;// ./lib/micromark/html-block-component/syntax.ts
106838
-
106839
-
106840
- const TAG_SUFFIX = [
106841
- codes.uppercaseT,
106842
- codes.uppercaseM,
106843
- codes.uppercaseL,
106844
- codes.uppercaseB,
106845
- codes.lowercaseL,
106846
- codes.lowercaseO,
106847
- codes.lowercaseC,
106848
- codes.lowercaseK,
106849
- ];
106850
- // ---------------------------------------------------------------------------
106851
- // Shared tokenizer factory
106852
- // ---------------------------------------------------------------------------
106853
- /**
106854
- * Creates a tokenize function for `<HTMLBlock>...</HTMLBlock>`.
106855
- *
106856
- * - **flow** (block-level): supports multiline content via line continuations,
106857
- * consumes trailing whitespace after the closing tag.
106858
- * - **text** (inline): single-line only, exits immediately after the closing tag.
106859
- */
106860
- function syntax_createTokenize(mode) {
106861
- return function tokenize(effects, ok, nok) {
106862
- let depth = 1;
106863
- function matchChars(chars, onMatch, onFail) {
106864
- if (chars.length === 0)
106865
- return onMatch;
106866
- const next = (code) => {
106867
- if (code === chars[0]) {
106868
- effects.consume(code);
106869
- return matchChars(chars.slice(1), onMatch, onFail);
106870
- }
106871
- return onFail(code);
106872
- };
106873
- return next;
106874
- }
106875
- function matchTagName(onMatch, onFail) {
106876
- const next = (code) => {
106877
- if (code === codes.uppercaseH) {
106878
- effects.consume(code);
106879
- return matchChars(TAG_SUFFIX, onMatch, onFail);
106880
- }
106881
- return onFail(code);
106882
- };
106883
- return next;
106884
- }
106885
- return start;
106886
- function start(code) {
106887
- if (code !== codes.lessThan)
106888
- return nok(code);
106889
- effects.enter('htmlBlockComponent');
106890
- effects.enter('htmlBlockComponentData');
106891
- effects.consume(code);
106892
- return matchTagName(afterTagName, nok);
106893
- }
106894
- function afterTagName(code) {
106895
- if (code === codes.greaterThan) {
106896
- effects.consume(code);
106897
- return body;
106898
- }
106899
- if (code === codes.space || code === codes.horizontalTab) {
106900
- effects.consume(code);
106901
- return inAttributes;
106902
- }
106903
- if (mode === 'flow' && markdownLineEnding(code)) {
106904
- effects.exit('htmlBlockComponentData');
106905
- return attributeContinuationStart(code);
106906
- }
106907
- if (code === codes.slash) {
106908
- effects.consume(code);
106909
- return selfClose;
106910
- }
106911
- return nok(code);
106912
- }
106913
- function inAttributes(code) {
106914
- if (code === codes.greaterThan) {
106915
- effects.consume(code);
106916
- return body;
106917
- }
106918
- if (code === null) {
106919
- return nok(code);
106920
- }
106921
- if (markdownLineEnding(code)) {
106922
- if (mode === 'text')
106923
- return nok(code);
106924
- effects.exit('htmlBlockComponentData');
106925
- return attributeContinuationStart(code);
106926
- }
106927
- effects.consume(code);
106928
- return inAttributes;
106929
- }
106930
- function attributeContinuationStart(code) {
106931
- return effects.check(html_block_component_syntax_nonLazyContinuationStart, attributeContinuationNonLazy, continuationAfter)(code);
106932
- }
106933
- function attributeContinuationNonLazy(code) {
106934
- effects.enter(types_types.lineEnding);
106935
- effects.consume(code);
106936
- effects.exit(types_types.lineEnding);
106937
- return attributeContinuationBefore;
106938
- }
106939
- function attributeContinuationBefore(code) {
106940
- if (code === null || markdownLineEnding(code)) {
106941
- return attributeContinuationStart(code);
106942
- }
106943
- effects.enter('htmlBlockComponentData');
106944
- return inAttributes(code);
106945
- }
106946
- function selfClose(code) {
106947
- if (code === codes.greaterThan) {
106948
- effects.consume(code);
106949
- return mode === 'flow' ? afterClose : done(code);
106950
- }
106951
- return nok(code);
106952
- }
106953
- function body(code) {
106954
- if (code === null)
106955
- return nok(code);
106956
- if (markdownLineEnding(code)) {
106957
- if (mode === 'text') {
106958
- // Text constructs operate on paragraph content which spans lines
106959
- effects.consume(code);
106960
- return body;
106961
- }
106962
- effects.exit('htmlBlockComponentData');
106963
- return continuationStart(code);
106964
- }
106965
- if (code === codes.lessThan) {
106966
- effects.consume(code);
106967
- return closeSlash;
106968
- }
106969
- effects.consume(code);
106970
- return body;
106971
- }
106972
- function closeSlash(code) {
106973
- if (code === codes.slash) {
106974
- effects.consume(code);
106975
- return matchTagName(closeGt, body);
106976
- }
106977
- return matchTagName(openAfterTagName, body)(code);
106978
- }
106979
- function openAfterTagName(code) {
106980
- if (code === codes.greaterThan || code === codes.space || code === codes.horizontalTab) {
106981
- depth += 1;
106982
- effects.consume(code);
106983
- return body;
106984
- }
106985
- return body(code);
106986
- }
106987
- function closeGt(code) {
106988
- if (code === codes.greaterThan) {
106989
- depth -= 1;
106990
- effects.consume(code);
106991
- if (depth === 0) {
106992
- return mode === 'flow' ? afterClose : done(code);
106993
- }
106994
- return body;
106995
- }
106996
- return body(code);
106997
- }
106998
- // -- flow-only states ---------------------------------------------------
106999
- function afterClose(code) {
107000
- if (code === null || markdownLineEnding(code)) {
107001
- return done(code);
107002
- }
107003
- if (code === codes.space || code === codes.horizontalTab) {
107004
- effects.consume(code);
107005
- return afterClose;
107006
- }
107007
- // Reject so the block re-parses as a paragraph, deferring to the
107008
- // text tokenizer which preserves trailing content in the same line.
107009
- return nok(code);
107010
- }
107011
- // -- flow-only: line continuation ---------------------------------------
107012
- function continuationStart(code) {
107013
- return effects.check(html_block_component_syntax_nonLazyContinuationStart, continuationStartNonLazy, continuationAfter)(code);
107014
- }
107015
- function continuationStartNonLazy(code) {
107016
- effects.enter(types_types.lineEnding);
107017
- effects.consume(code);
107018
- effects.exit(types_types.lineEnding);
107019
- return continuationBefore;
107020
- }
107021
- function continuationBefore(code) {
107022
- if (code === null || markdownLineEnding(code)) {
107023
- return continuationStart(code);
107024
- }
107025
- effects.enter('htmlBlockComponentData');
107026
- return body(code);
107027
- }
107028
- function continuationAfter(code) {
107029
- if (code === null)
107030
- return nok(code);
107031
- effects.exit('htmlBlockComponent');
107032
- return ok(code);
107033
- }
107034
- // -- shared exit --------------------------------------------------------
107035
- function done(_code) {
107036
- effects.exit('htmlBlockComponentData');
107037
- effects.exit('htmlBlockComponent');
107038
- return ok(_code);
107039
- }
107040
- };
107041
- }
107042
- // ---------------------------------------------------------------------------
107043
- // Flow construct (block-level)
107044
- // ---------------------------------------------------------------------------
107045
- const html_block_component_syntax_nonLazyContinuationStart = {
107046
- tokenize: html_block_component_syntax_tokenizeNonLazyContinuationStart,
107047
- partial: true,
107048
- };
107049
- function resolveToHtmlBlockComponent(events) {
107050
- let index = events.length;
107051
- while (index > 0) {
107052
- index -= 1;
107053
- if (events[index][0] === 'enter' && events[index][1].type === 'htmlBlockComponent') {
107054
- break;
107055
- }
107056
- }
107057
- if (index > 1 && events[index - 2][1].type === types_types.linePrefix) {
107058
- events[index][1].start = events[index - 2][1].start;
107059
- events[index + 1][1].start = events[index - 2][1].start;
107060
- events.splice(index - 2, 2);
107061
- }
107062
- return events;
107063
- }
107064
- const htmlBlockComponentFlowConstruct = {
107065
- name: 'htmlBlockComponent',
107066
- tokenize: syntax_createTokenize('flow'),
107067
- resolveTo: resolveToHtmlBlockComponent,
107068
- concrete: true,
107069
- };
107070
- function html_block_component_syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
107071
- // eslint-disable-next-line @typescript-eslint/no-this-alias
107072
- const self = this;
107073
- return start;
107074
- function start(code) {
107075
- if (markdownLineEnding(code)) {
107076
- effects.enter(types_types.lineEnding);
107077
- effects.consume(code);
107078
- effects.exit(types_types.lineEnding);
107079
- return after;
107080
- }
107081
- return nok(code);
107082
- }
107083
- function after(code) {
107084
- if (self.parser.lazy[self.now().line]) {
107085
- return nok(code);
107086
- }
107087
- return ok(code);
107088
- }
107089
- }
107090
- // ---------------------------------------------------------------------------
107091
- // Text construct (inline)
107092
- // ---------------------------------------------------------------------------
107093
- const htmlBlockComponentTextConstruct = {
107094
- name: 'htmlBlockComponent',
107095
- tokenize: syntax_createTokenize('text'),
107096
- };
107097
- // ---------------------------------------------------------------------------
107098
- // Extension
107099
- // ---------------------------------------------------------------------------
107100
- function htmlBlockComponent() {
107101
- return {
107102
- flow: {
107103
- [codes.lessThan]: [htmlBlockComponentFlowConstruct],
107104
- },
107105
- text: {
107106
- [codes.lessThan]: [htmlBlockComponentTextConstruct],
107107
- },
107108
- };
107109
- }
107110
-
107111
- ;// ./lib/micromark/html-block-component/index.ts
107112
-
107113
-
107114
107249
  ;// ./lib/utils/extractMagicBlocks.ts
107115
107250
  /**
107116
107251
  * The content matching in this regex captures everything between `[block:TYPE]`