@readme/markdown 13.5.0 → 13.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -11357,6 +11357,7 @@ __webpack_require__.r(__webpack_exports__);
11357
11357
  // EXPORTS
11358
11358
  __webpack_require__.d(__webpack_exports__, {
11359
11359
  Components: () => (/* reexport */ components_namespaceObject),
11360
+ FLOW_TYPES: () => (/* reexport */ FLOW_TYPES),
11360
11361
  Owlmoji: () => (/* reexport */ Owlmoji),
11361
11362
  compile: () => (/* reexport */ lib_compile),
11362
11363
  exports: () => (/* reexport */ lib_exports),
@@ -12538,6 +12539,28 @@ var parseOptions = function parseOptions() {
12538
12539
  return opts;
12539
12540
  };
12540
12541
 
12542
+ ;// ./lib/constants.ts
12543
+ /**
12544
+ * Pattern to match component tags (PascalCase or snake_case)
12545
+ */
12546
+ const componentTagPattern = /<(\/?[A-Z][A-Za-z0-9_]*)([^>]*?)(\/?)>/g;
12547
+ /**
12548
+ * MDAST flow (block-level) content types that cannot be represented
12549
+ * inside GFM table cells. Used to decide whether a table should be
12550
+ * serialized as GFM or as JSX `<Table>` syntax.
12551
+ *
12552
+ * @see https://github.com/syntax-tree/mdast#flowcontent
12553
+ */
12554
+ const FLOW_TYPES = new Set([
12555
+ 'blockquote',
12556
+ 'code',
12557
+ 'heading',
12558
+ 'html',
12559
+ 'list',
12560
+ 'table',
12561
+ 'thematicBreak',
12562
+ ]);
12563
+
12541
12564
  ;// ./node_modules/github-slugger/regex.js
12542
12565
  // This module is generated by `script/`.
12543
12566
  /* eslint-disable no-control-regex, no-misleading-character-class, no-useless-escape */
@@ -41028,6 +41051,7 @@ function remarkMdx(options) {
41028
41051
  ;// ./enums.ts
41029
41052
  var NodeTypes;
41030
41053
  (function (NodeTypes) {
41054
+ NodeTypes["anchor"] = "readme-anchor";
41031
41055
  NodeTypes["callout"] = "rdme-callout";
41032
41056
  NodeTypes["codeTabs"] = "code-tabs";
41033
41057
  NodeTypes["embedBlock"] = "embed-block";
@@ -53002,6 +53026,10 @@ const plain = (node, opts = {}) => {
53002
53026
  };
53003
53027
  /* harmony default export */ const lib_plain = (plain);
53004
53028
 
53029
+ ;// ./processor/compile/variable.ts
53030
+ const variable = (node) => `{user.${node.data?.hProperties?.name || ''}}`;
53031
+ /* harmony default export */ const compile_variable = (variable);
53032
+
53005
53033
  ;// ./processor/transform/extract-text.ts
53006
53034
  /**
53007
53035
  * Extracts text content from a single AST node recursively.
@@ -53013,7 +53041,7 @@ const plain = (node, opts = {}) => {
53013
53041
  * @returns The concatenated text content
53014
53042
  */
53015
53043
  const extractText = (node) => {
53016
- if (node.type === 'text' && typeof node.value === 'string') {
53044
+ if ((node.type === 'text' || node.type === 'html') && typeof node.value === 'string') {
53017
53045
  return node.value;
53018
53046
  }
53019
53047
  // When a blockquote contains only an image (no text), treat it as having content
@@ -53041,6 +53069,23 @@ const extractText = (node) => {
53041
53069
 
53042
53070
 
53043
53071
 
53072
+
53073
+
53074
+
53075
+
53076
+
53077
+
53078
+
53079
+ const titleParser = unified().use(remarkParse).use(remarkGfm);
53080
+ // The title paragraph may contain custom AST nodes that `toMarkdown` doesn't
53081
+ // natively understand
53082
+ const toMarkdownExtensions = [
53083
+ gfmStrikethroughToMarkdown(),
53084
+ // For mdx variable syntaxes (e.g., {user.name})
53085
+ mdxExpressionToMarkdown(),
53086
+ // Important: This is required and would crash the parser if there's no variable node handler
53087
+ { handlers: { [NodeTypes.variable]: compile_variable } },
53088
+ ];
53044
53089
  const callouts_regex = `^(${emoji_regex().source}|⚠)(\\s+|$)`;
53045
53090
  const findFirst = (node) => {
53046
53091
  if ('children' in node)
@@ -53157,31 +53202,65 @@ const processBlockquote = (node, index, parent) => {
53157
53202
  // Example: "> ⚠️ **Bold heading**\nBody text here"
53158
53203
  const bodyChildren = splitParagraphAtNewline(firstParagraph);
53159
53204
  const didSplit = bodyChildren !== null;
53160
- // Extract heading text after removing the icon prefix.
53161
- // Use `plain()` to handle complex markdown structures (bold, inline code, etc.)
53162
- const headingText = lib_plain(firstParagraph)
53163
- .toString()
53164
- .slice(match.length);
53165
- // Clean up the raw AST by removing the icon prefix from the first text node
53166
53205
  removeIconPrefix(firstParagraph, match.length);
53167
- const empty = !headingText.length && firstParagraph.children.length === 1;
53206
+ const firstText = findFirst(firstParagraph);
53207
+ const rawValue = firstText?.value ?? '';
53208
+ const hasContent = rawValue.trim().length > 0 || firstParagraph.children.length > 1;
53209
+ const empty = !hasContent;
53168
53210
  const theme = themes[icon] || 'default';
53169
- // Convert the first paragraph (first children of node) to a heading if it has content or was split
53170
- if (headingText || didSplit) {
53171
- node.children[0] = wrapHeading(node);
53172
- // Adjust position to account for the stripped icon prefix
53173
- node.children[0].position.start.offset += match.length;
53174
- node.children[0].position.start.column += match.length;
53211
+ if (hasContent || didSplit) {
53212
+ const headingMatch = rawValue.match(/^(#{1,6})\s*/);
53213
+ // # heading syntax is handled via direct AST manipulation so we can
53214
+ // set the depth while preserving the original inline children (bold, etc.)
53215
+ if (headingMatch) {
53216
+ firstText.value = rawValue.slice(headingMatch[0].length);
53217
+ const heading = wrapHeading(node);
53218
+ heading.depth = headingMatch[1].length;
53219
+ node.children[0] = heading;
53220
+ node.children[0].position.start.offset += match.length;
53221
+ node.children[0].position.start.column += match.length;
53222
+ }
53223
+ else {
53224
+ const headingText = toMarkdown({ type: 'root', children: [firstParagraph] }, {
53225
+ extensions: toMarkdownExtensions,
53226
+ })
53227
+ .trim()
53228
+ .replace(/^\\(?=[>#+\-*])/, '');
53229
+ const parsedTitle = titleParser.parse(headingText);
53230
+ const parsedFirstChild = parsedTitle.children[0];
53231
+ // Block-level syntax ("> quote", "- list") produces non-paragraph nodes;
53232
+ // inline text parses as a paragraph and falls through to wrapHeading().
53233
+ if (parsedFirstChild && parsedFirstChild.type !== 'paragraph') {
53234
+ // Strip positions from re-parsed nodes since they're relative to the heading text, not the original source
53235
+ visit(parsedTitle, (n) => {
53236
+ delete n.position;
53237
+ });
53238
+ const heading = wrapHeading(node);
53239
+ heading.children = parsedTitle.children;
53240
+ delete heading.position;
53241
+ node.children[0] = heading;
53242
+ }
53243
+ else {
53244
+ node.children[0] = wrapHeading(node);
53245
+ node.children[0].position.start.offset += match.length;
53246
+ node.children[0].position.start.column += match.length;
53247
+ }
53248
+ }
53175
53249
  }
53176
53250
  // Insert body content as a separate paragraph after the heading
53177
53251
  if (bodyChildren) {
53252
+ const headingPosition = node.children[0].position;
53178
53253
  node.children.splice(1, 0, {
53179
53254
  type: 'paragraph',
53180
53255
  children: bodyChildren,
53181
- position: {
53182
- start: node.children[0].position.end,
53183
- end: firstParagraphOriginalEnd,
53184
- },
53256
+ ...(headingPosition && firstParagraphOriginalEnd
53257
+ ? {
53258
+ position: {
53259
+ start: headingPosition.end,
53260
+ end: firstParagraphOriginalEnd,
53261
+ },
53262
+ }
53263
+ : {}),
53185
53264
  });
53186
53265
  }
53187
53266
  Object.assign(node, {
@@ -53198,11 +53277,24 @@ const processBlockquote = (node, index, parent) => {
53198
53277
  }
53199
53278
  };
53200
53279
  const calloutTransformer = () => {
53201
- return (tree) => {
53202
- visit(tree, 'blockquote', (node, index, parent) => {
53280
+ const processNode = (root) => {
53281
+ visit(root, 'blockquote', (node, index, parent) => {
53203
53282
  processBlockquote(node, index, parent);
53283
+ if (node.type === NodeTypes.callout) {
53284
+ // SKIP prevents re-processing synthetic blockquotes in parsed title content
53285
+ // (e.g., blockquotes from "> Quote" titles). Recursively process body children
53286
+ // (index 1+, skipping the heading at 0) to handle nested callouts.
53287
+ for (let i = 1; i < node.children.length; i += 1) {
53288
+ processNode(node.children[i]);
53289
+ }
53290
+ return SKIP;
53291
+ }
53292
+ return undefined;
53204
53293
  });
53205
53294
  };
53295
+ return (tree) => {
53296
+ processNode(tree);
53297
+ };
53206
53298
  };
53207
53299
  /* harmony default export */ const callouts = (calloutTransformer);
53208
53300
 
@@ -53227,8 +53319,18 @@ const codeTabsTransformer = ({ copyButtons } = {}) => (tree) => {
53227
53319
  const sibling = parent.children[walker];
53228
53320
  if (!isCode(sibling))
53229
53321
  break;
53322
+ // Check that the two code blocks are truly adjacent (no blank lines or
53323
+ // other content between them). The `gap` is the number of raw characters
53324
+ // between the end of the previous block and the start of this one.
53325
+ // For a LF-separated pair the gap equals `start.column` (the newline
53326
+ // char(s) plus any indentation). CRLF line endings add one extra byte
53327
+ // (\r) without advancing the line count, so we also accept
53328
+ // `start.column + 1` provided the blocks are still on consecutive lines.
53230
53329
  const olderSibling = parent.children[walker - 1];
53231
- if (olderSibling.position.end.offset + sibling.position.start.column !== sibling.position.start.offset)
53330
+ const gap = sibling.position.start.offset - olderSibling.position.end.offset;
53331
+ const lineDiff = sibling.position.start.line - olderSibling.position.end.line;
53332
+ const isCRLF = gap === sibling.position.start.column + 1 && lineDiff === 1;
53333
+ if (gap !== sibling.position.start.column && !isCRLF)
53232
53334
  break;
53233
53335
  children.push(sibling);
53234
53336
  // eslint-disable-next-line no-plusplus
@@ -70804,687 +70906,348 @@ const mdxToHast = () => tree => {
70804
70906
  };
70805
70907
  /* harmony default export */ const mdx_to_hast = (mdxToHast);
70806
70908
 
70807
- ;// ./lib/mdast-util/empty-task-list-item/index.ts
70909
+ ;// ./processor/transform/mdxish/normalize-malformed-md-syntax.ts
70910
+
70911
+ // Marker patterns for multi-node emphasis detection
70912
+ const MARKER_PATTERNS = [
70913
+ { isBold: true, marker: '**' },
70914
+ { isBold: true, marker: '__' },
70915
+ { isBold: false, marker: '*' },
70916
+ { isBold: false, marker: '_' },
70917
+ ];
70918
+ // Patterns to detect for bold (** and __) and italic (* and _) syntax:
70919
+ // Bold: ** text**, **text **, word** text**, ** text **
70920
+ // Italic: * text*, *text *, word* text*, * text *
70921
+ // Same patterns for underscore variants
70922
+ // We use separate patterns for each marker type to allow this flexibility.
70923
+ // Pattern for ** bold **
70924
+ // Groups: 1=wordBefore, 2=marker, 3=contentWithSpaceAfter, 4=trailingSpace1, 5=contentWithSpaceBefore, 6=trailingSpace2, 7=afterChar
70925
+ // trailingSpace1 is for "** text **" pattern, trailingSpace2 is for "**text **" pattern
70926
+ const asteriskBoldRegex = /([^*\s]+)?\s*(\*\*)(?:\s+((?:[^*\n]|\*(?!\*))+?)(\s*)\2|((?:[^*\n]|\*(?!\*))+?)(\s+)\2)(\S|$)?/g;
70927
+ // Pattern for __ bold __
70928
+ const underscoreBoldRegex = /([^_\s]+)?\s*(__)(?:\s+((?:__(?! )|_(?!_)|[^_\n])+?)(\s*)\2|((?:__(?! )|_(?!_)|[^_\n])+?)(\s+)\2)(\S|$)?/g;
70929
+ // Pattern for * italic *
70930
+ const asteriskItalicRegex = /([^*\s]+)?\s*(\*)(?!\*)(?:\s+([^*\n]+?)(\s*)\2|([^*\n]+?)(\s+)\2)(\S|$)?/g;
70931
+ // Pattern for _ italic _
70932
+ const underscoreItalicRegex = /([^_\s]+)?\s*(_)(?!_)(?:\s+((?:[^_\n]|_(?! ))+?)(\s*)\2|((?:[^_\n]|_(?! ))+?)(\s+)\2)(\S|$)?/g;
70933
+ // CommonMark ignores intraword underscores or asteriks, but we want to italicize/bold the inner part
70934
+ // Pattern for intraword _word_ in words like hello_world_
70935
+ const intrawordUnderscoreItalicRegex = /(\w)_(?!_)([a-zA-Z0-9]+)_(?![\w_])/g;
70936
+ // Pattern for intraword __word__ in words like hello__world__
70937
+ const intrawordUnderscoreBoldRegex = /(\w)__([a-zA-Z0-9]+)__(?![\w_])/g;
70938
+ // Pattern for intraword *word* in words like hello*world*
70939
+ const intrawordAsteriskItalicRegex = /(\w)\*(?!\*)([a-zA-Z0-9]+)\*(?![\w*])/g;
70940
+ // Pattern for intraword **word** in words like hello**world**
70941
+ const intrawordAsteriskBoldRegex = /(\w)\*\*([a-zA-Z0-9]+)\*\*(?![\w*])/g;
70808
70942
  /**
70809
- * Normalizes list items that are written as only `[ ]` or `[x]` into GFM task
70810
- * list items during parse, but only when at least one whitespace character
70811
- * follows the closing bracket (`]`). This matches legacy behaviour for checkboxes
70812
- *
70813
- * The issue is `remark-gfm` does not actually classify these as task items when they have no content
70814
- * after the checkbox, which leaves them as plain text (`"[ ]"`). So a custom extension is needed to
70815
- * treat these as task items
70943
+ * Finds opening emphasis marker in a text value.
70944
+ * Returns marker info if found, null otherwise.
70816
70945
  */
70817
- function exitListItemWithEmptyTaskListItem(token) {
70818
- const node = this.stack[this.stack.length - 1];
70819
- if (node &&
70820
- node.type === 'listItem' &&
70821
- typeof node.checked !== 'boolean') {
70822
- const listItem = node;
70823
- const head = listItem.children[0];
70824
- if (head && head.type === 'paragraph' && head.children.length === 1) {
70825
- const text = head.children[0];
70826
- if (text.type === 'text') {
70827
- const hasTrailingWhitespace = typeof head.position?.end.offset === 'number' &&
70828
- typeof text.position?.end.offset === 'number' &&
70829
- head.position.end.offset > text.position.end.offset;
70830
- if (!hasTrailingWhitespace) {
70831
- this.exit(token);
70832
- return;
70833
- }
70834
- const value = text.value;
70835
- if (value === '[ ]') {
70836
- listItem.checked = false;
70837
- head.children = [];
70838
- }
70839
- else if (value === '[x]' || value === '[X]') {
70840
- listItem.checked = true;
70841
- head.children = [];
70842
- }
70946
+ function findOpeningMarker(text) {
70947
+ const results = MARKER_PATTERNS.map(({ isBold, marker }) => {
70948
+ if (marker === '*' && text.startsWith('**'))
70949
+ return null;
70950
+ if (marker === '_' && text.startsWith('__'))
70951
+ return null;
70952
+ if (text.startsWith(marker) && text.length > marker.length) {
70953
+ return { isBold, marker, textAfter: text.slice(marker.length), textBefore: '' };
70954
+ }
70955
+ const idx = text.indexOf(marker);
70956
+ if (idx > 0 && !/\s/.test(text[idx - 1])) {
70957
+ if (marker === '*' && text.slice(idx).startsWith('**'))
70958
+ return null;
70959
+ if (marker === '_' && text.slice(idx).startsWith('__'))
70960
+ return null;
70961
+ const after = text.slice(idx + marker.length);
70962
+ if (after.length > 0) {
70963
+ return { isBold, marker, textAfter: after, textBefore: text.slice(0, idx) };
70843
70964
  }
70844
70965
  }
70845
- }
70846
- this.exit(token);
70847
- }
70848
- function emptyTaskListItemFromMarkdown() {
70849
- return {
70850
- exit: {
70851
- listItem: exitListItemWithEmptyTaskListItem,
70852
- },
70853
- };
70966
+ return null;
70967
+ });
70968
+ return results.find(r => r !== null) ?? null;
70854
70969
  }
70855
-
70856
- ;// ./lib/mdast-util/legacy-variable/index.ts
70857
-
70858
- const contextMap = new WeakMap();
70859
- function findlegacyVariableToken() {
70860
- // tokenStack is micromark's current open token ancestry; find the nearest legacyVariable token.
70861
- const events = this.tokenStack;
70862
- for (let i = events.length - 1; i >= 0; i -= 1) {
70863
- const token = events[i][0];
70864
- if (token.type === 'legacyVariable')
70865
- return token;
70970
+ /**
70971
+ * Finds the end/closing marker in a text node for multi-node emphasis.
70972
+ */
70973
+ function findEndMarker(text, marker) {
70974
+ const spacePattern = ` ${marker}`;
70975
+ const spaceIdx = text.indexOf(spacePattern);
70976
+ if (spaceIdx >= 0) {
70977
+ if (marker === '*' && text.slice(spaceIdx + 1).startsWith('**'))
70978
+ return null;
70979
+ if (marker === '_' && text.slice(spaceIdx + 1).startsWith('__'))
70980
+ return null;
70981
+ return {
70982
+ textAfter: text.slice(spaceIdx + spacePattern.length),
70983
+ textBefore: text.slice(0, spaceIdx),
70984
+ };
70866
70985
  }
70867
- return undefined;
70868
- }
70869
- function enterlegacyVariable(token) {
70870
- contextMap.set(token, { value: '' });
70871
- }
70872
- function exitlegacyVariableValue(token) {
70873
- const variableToken = findlegacyVariableToken.call(this);
70874
- if (!variableToken)
70875
- return;
70876
- const ctx = contextMap.get(variableToken);
70877
- // Build up the variable characters
70878
- if (ctx)
70879
- ctx.value += this.sliceSerialize(token);
70880
- }
70881
- function exitlegacyVariable(token) {
70882
- const ctx = contextMap.get(token);
70883
- const serialized = this.sliceSerialize(token);
70884
- const variableName = serialized.startsWith('<<') && serialized.endsWith('>>')
70885
- ? serialized.slice(2, -2)
70886
- : ctx?.value ?? '';
70887
- const nodePosition = {
70888
- start: {
70889
- offset: token.start.offset,
70890
- line: token.start.line,
70891
- column: token.start.column,
70892
- },
70893
- end: {
70894
- offset: token.end.offset,
70895
- line: token.end.line,
70896
- column: token.end.column,
70897
- },
70898
- };
70899
- if (variableName.startsWith('glossary:')) {
70900
- const term = variableName.slice('glossary:'.length).trim();
70901
- this.enter({
70902
- type: NodeTypes.glossary,
70903
- data: {
70904
- hName: 'Glossary',
70905
- hProperties: { term },
70906
- },
70907
- children: [{ type: 'text', value: term }],
70908
- position: nodePosition,
70909
- }, token);
70910
- this.exit(token);
70911
- contextMap.delete(token);
70912
- return;
70986
+ if (text.startsWith(marker)) {
70987
+ if (marker === '*' && text.startsWith('**'))
70988
+ return null;
70989
+ if (marker === '_' && text.startsWith('__'))
70990
+ return null;
70991
+ return {
70992
+ textAfter: text.slice(marker.length),
70993
+ textBefore: '',
70994
+ };
70913
70995
  }
70914
- this.enter({
70915
- type: NodeTypes.variable,
70916
- data: {
70917
- hName: 'Variable',
70918
- hProperties: { name: variableName.trim(), isLegacy: true },
70919
- },
70920
- value: `<<${variableName}>>`,
70921
- }, token);
70922
- this.exit(token);
70923
- contextMap.delete(token);
70924
- }
70925
- function legacyVariableFromMarkdown() {
70926
- return {
70927
- enter: {
70928
- legacyVariable: enterlegacyVariable,
70929
- },
70930
- exit: {
70931
- legacyVariableValue: exitlegacyVariableValue,
70932
- legacyVariable: exitlegacyVariable,
70933
- },
70934
- };
70996
+ return null;
70935
70997
  }
70936
-
70937
- ;// ./node_modules/micromark-util-symbol/lib/codes.js
70938
70998
  /**
70939
- * Character codes.
70940
- *
70941
- * This module is compiled away!
70942
- *
70943
- * micromark works based on character codes.
70944
- * This module contains constants for the ASCII block and the replacement
70945
- * character.
70946
- * A couple of them are handled in a special way, such as the line endings
70947
- * (CR, LF, and CR+LF, commonly known as end-of-line: EOLs), the tab (horizontal
70948
- * tab) and its expansion based on what column it’s at (virtual space),
70949
- * and the end-of-file (eof) character.
70950
- * As values are preprocessed before handling them, the actual characters LF,
70951
- * CR, HT, and NUL (which is present as the replacement character), are
70952
- * guaranteed to not exist.
70953
- *
70954
- * Unicode basic latin block.
70999
+ * Scan children for an opening emphasis marker in a text node.
70955
71000
  */
70956
- const codes = /** @type {const} */ ({
70957
- carriageReturn: -5,
70958
- lineFeed: -4,
70959
- carriageReturnLineFeed: -3,
70960
- horizontalTab: -2,
70961
- virtualSpace: -1,
70962
- eof: null,
70963
- nul: 0,
70964
- soh: 1,
70965
- stx: 2,
70966
- etx: 3,
70967
- eot: 4,
70968
- enq: 5,
70969
- ack: 6,
70970
- bel: 7,
70971
- bs: 8,
70972
- ht: 9, // `\t`
70973
- lf: 10, // `\n`
70974
- vt: 11, // `\v`
70975
- ff: 12, // `\f`
70976
- cr: 13, // `\r`
70977
- so: 14,
70978
- si: 15,
70979
- dle: 16,
70980
- dc1: 17,
70981
- dc2: 18,
70982
- dc3: 19,
70983
- dc4: 20,
70984
- nak: 21,
70985
- syn: 22,
70986
- etb: 23,
70987
- can: 24,
70988
- em: 25,
70989
- sub: 26,
70990
- esc: 27,
70991
- fs: 28,
70992
- gs: 29,
70993
- rs: 30,
70994
- us: 31,
70995
- space: 32,
70996
- exclamationMark: 33, // `!`
70997
- quotationMark: 34, // `"`
70998
- numberSign: 35, // `#`
70999
- dollarSign: 36, // `$`
71000
- percentSign: 37, // `%`
71001
- ampersand: 38, // `&`
71002
- apostrophe: 39, // `'`
71003
- leftParenthesis: 40, // `(`
71004
- rightParenthesis: 41, // `)`
71005
- asterisk: 42, // `*`
71006
- plusSign: 43, // `+`
71007
- comma: 44, // `,`
71008
- dash: 45, // `-`
71009
- dot: 46, // `.`
71010
- slash: 47, // `/`
71011
- digit0: 48, // `0`
71012
- digit1: 49, // `1`
71013
- digit2: 50, // `2`
71014
- digit3: 51, // `3`
71015
- digit4: 52, // `4`
71016
- digit5: 53, // `5`
71017
- digit6: 54, // `6`
71018
- digit7: 55, // `7`
71019
- digit8: 56, // `8`
71020
- digit9: 57, // `9`
71021
- colon: 58, // `:`
71022
- semicolon: 59, // `;`
71023
- lessThan: 60, // `<`
71024
- equalsTo: 61, // `=`
71025
- greaterThan: 62, // `>`
71026
- questionMark: 63, // `?`
71027
- atSign: 64, // `@`
71028
- uppercaseA: 65, // `A`
71029
- uppercaseB: 66, // `B`
71030
- uppercaseC: 67, // `C`
71031
- uppercaseD: 68, // `D`
71032
- uppercaseE: 69, // `E`
71033
- uppercaseF: 70, // `F`
71034
- uppercaseG: 71, // `G`
71035
- uppercaseH: 72, // `H`
71036
- uppercaseI: 73, // `I`
71037
- uppercaseJ: 74, // `J`
71038
- uppercaseK: 75, // `K`
71039
- uppercaseL: 76, // `L`
71040
- uppercaseM: 77, // `M`
71041
- uppercaseN: 78, // `N`
71042
- uppercaseO: 79, // `O`
71043
- uppercaseP: 80, // `P`
71044
- uppercaseQ: 81, // `Q`
71045
- uppercaseR: 82, // `R`
71046
- uppercaseS: 83, // `S`
71047
- uppercaseT: 84, // `T`
71048
- uppercaseU: 85, // `U`
71049
- uppercaseV: 86, // `V`
71050
- uppercaseW: 87, // `W`
71051
- uppercaseX: 88, // `X`
71052
- uppercaseY: 89, // `Y`
71053
- uppercaseZ: 90, // `Z`
71054
- leftSquareBracket: 91, // `[`
71055
- backslash: 92, // `\`
71056
- rightSquareBracket: 93, // `]`
71057
- caret: 94, // `^`
71058
- underscore: 95, // `_`
71059
- graveAccent: 96, // `` ` ``
71060
- lowercaseA: 97, // `a`
71061
- lowercaseB: 98, // `b`
71062
- lowercaseC: 99, // `c`
71063
- lowercaseD: 100, // `d`
71064
- lowercaseE: 101, // `e`
71065
- lowercaseF: 102, // `f`
71066
- lowercaseG: 103, // `g`
71067
- lowercaseH: 104, // `h`
71068
- lowercaseI: 105, // `i`
71069
- lowercaseJ: 106, // `j`
71070
- lowercaseK: 107, // `k`
71071
- lowercaseL: 108, // `l`
71072
- lowercaseM: 109, // `m`
71073
- lowercaseN: 110, // `n`
71074
- lowercaseO: 111, // `o`
71075
- lowercaseP: 112, // `p`
71076
- lowercaseQ: 113, // `q`
71077
- lowercaseR: 114, // `r`
71078
- lowercaseS: 115, // `s`
71079
- lowercaseT: 116, // `t`
71080
- lowercaseU: 117, // `u`
71081
- lowercaseV: 118, // `v`
71082
- lowercaseW: 119, // `w`
71083
- lowercaseX: 120, // `x`
71084
- lowercaseY: 121, // `y`
71085
- lowercaseZ: 122, // `z`
71086
- leftCurlyBrace: 123, // `{`
71087
- verticalBar: 124, // `|`
71088
- rightCurlyBrace: 125, // `}`
71089
- tilde: 126, // `~`
71090
- del: 127,
71091
- // Unicode Specials block.
71092
- byteOrderMarker: 65_279,
71093
- // Unicode Specials block.
71094
- replacementCharacter: 65_533 // `�`
71095
- })
71096
-
71097
- ;// ./lib/micromark/legacy-variable/syntax.ts
71098
-
71099
-
71100
- function isAllowedValueChar(code) {
71101
- return (code !== null &&
71102
- code !== codes.lessThan &&
71103
- code !== codes.greaterThan &&
71104
- !markdownLineEnding(code));
71105
- }
71106
- const legacyVariableConstruct = {
71107
- name: 'legacyVariable',
71108
- tokenize,
71109
- };
71110
- function tokenize(effects, ok, nok) {
71111
- let hasValue = false;
71112
- const start = (code) => {
71113
- if (code !== codes.lessThan)
71114
- return nok(code);
71115
- effects.enter('legacyVariable');
71116
- effects.enter('legacyVariableMarkerStart');
71117
- effects.consume(code); // <
71118
- return open2;
71119
- };
71120
- const open2 = (code) => {
71121
- if (code !== codes.lessThan)
71122
- return nok(code);
71123
- effects.consume(code); // <<
71124
- effects.exit('legacyVariableMarkerStart');
71125
- effects.enter('legacyVariableValue');
71126
- return value;
71127
- };
71128
- const value = (code) => {
71129
- if (code === codes.greaterThan) {
71130
- if (!hasValue)
71131
- return nok(code);
71132
- effects.exit('legacyVariableValue');
71133
- effects.enter('legacyVariableMarkerEnd');
71134
- effects.consume(code); // >
71135
- return close2;
71001
+ function findOpeningInChildren(children) {
71002
+ let result = null;
71003
+ children.some((child, idx) => {
71004
+ if (child.type !== 'text')
71005
+ return false;
71006
+ const found = findOpeningMarker(child.value);
71007
+ if (found) {
71008
+ result = { idx, opening: found };
71009
+ return true;
71136
71010
  }
71137
- if (!isAllowedValueChar(code))
71138
- return nok(code);
71139
- hasValue = true;
71140
- effects.consume(code);
71141
- return value;
71142
- };
71143
- const close2 = (code) => {
71144
- if (code !== codes.greaterThan)
71145
- return nok(code);
71146
- effects.consume(code); // >>
71147
- effects.exit('legacyVariableMarkerEnd');
71148
- effects.exit('legacyVariable');
71149
- return ok;
71150
- };
71151
- return start;
71152
- }
71153
- function legacyVariable() {
71154
- return {
71155
- text: { [codes.lessThan]: legacyVariableConstruct },
71156
- };
71011
+ return false;
71012
+ });
71013
+ return result;
71157
71014
  }
71158
-
71159
- ;// ./lib/micromark/legacy-variable/index.ts
71160
71015
  /**
71161
- * Micromark extension for <<variable>> / <<glossary:term>> inline syntax.
71016
+ * Scan children (after openingIdx) for a closing emphasis marker.
71162
71017
  */
71163
-
71164
-
71165
- ;// ./processor/transform/mdxish/mdxish-component-blocks.ts
71166
-
71167
-
71168
-
71169
-
71170
-
71171
-
71172
- const pascalCaseTagPattern = /^<([A-Z][A-Za-z0-9_]*)([^>]*?)(\/?)>([\s\S]*)?$/;
71173
- const tagAttributePattern = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*("[^"]*"|'[^']*'|[^\s"'>]+))?/g;
71018
+ function findClosingInChildren(children, openingIdx, marker) {
71019
+ let result = null;
71020
+ children.slice(openingIdx + 1).some((child, relativeIdx) => {
71021
+ if (child.type !== 'text')
71022
+ return false;
71023
+ const found = findEndMarker(child.value, marker);
71024
+ if (found) {
71025
+ result = { closingIdx: openingIdx + 1 + relativeIdx, closing: found };
71026
+ return true;
71027
+ }
71028
+ return false;
71029
+ });
71030
+ return result;
71031
+ }
71174
71032
  /**
71175
- * Maximum number of siblings to scan forward when looking for a closing tag
71176
- * to avoid scanning too far and degrading performance
71033
+ * Build the replacement nodes for a matched emphasis pair.
71177
71034
  */
71178
- const MAX_LOOKAHEAD = 30;
71179
- /**
71180
- * Tags that have dedicated transformers and should NOT be handled by this plugin.
71181
- * These components either have special parsing requirements that the generic component
71182
- * block transformer cannot handle correctly, or are inline components that we don't
71183
- * want to convert to mdxJsxFlowElement which is a block level element.
71184
- *
71185
- * Glossary and Anchor are inline components.
71186
- */
71187
- const EXCLUDED_TAGS = new Set(['HTMLBlock', 'Table', 'Glossary', 'Anchor']);
71188
- const inlineMdProcessor = unified()
71189
- .data('micromarkExtensions', [legacyVariable()])
71190
- .data('fromMarkdownExtensions', [legacyVariableFromMarkdown(), emptyTaskListItemFromMarkdown()])
71191
- .use(remarkParse)
71192
- .use(remarkGfm);
71193
- const isClosingTag = (value, tag) => value.trim() === `</${tag}>`;
71194
- /**
71195
- * Parse markdown content into mdast children nodes.
71196
- */
71197
- const parseMdChildren = (value) => {
71198
- const parsed = inlineMdProcessor.parse(value);
71199
- return parsed.children || [];
71200
- };
71201
- /**
71202
- * Convert raw attribute string into mdxJsxAttribute entries.
71203
- * Handles both key-value attributes (theme="info") and boolean attributes (empty).
71204
- */
71205
- const parseAttributes = (raw) => {
71206
- const attributes = [];
71207
- const attrString = raw.trim();
71208
- if (!attrString)
71209
- return attributes;
71210
- tagAttributePattern.lastIndex = 0;
71211
- let match = tagAttributePattern.exec(attrString);
71212
- while (match !== null) {
71213
- const [, attrName, attrValue] = match;
71214
- const value = attrValue ? attrValue.replace(/^['"]|['"]$/g, '') : null;
71215
- attributes.push({ type: 'mdxJsxAttribute', name: attrName, value });
71216
- match = tagAttributePattern.exec(attrString);
71035
+ function buildReplacementNodes(container, { opening, openingIdx, closing, closingIdx }) {
71036
+ const newNodes = [];
71037
+ if (opening.textBefore) {
71038
+ newNodes.push({ type: 'text', value: `${opening.textBefore} ` });
71217
71039
  }
71218
- return attributes;
71219
- };
71220
- /**
71221
- * Parse an HTML tag string into structured data.
71222
- */
71223
- const parseTag = (value) => {
71224
- const match = value.match(pascalCaseTagPattern);
71225
- if (!match)
71226
- return null;
71227
- const [, tag, attrString = '', selfClosing = '', contentAfterTag = ''] = match;
71228
- return {
71229
- tag,
71230
- attributes: parseAttributes(attrString),
71231
- selfClosing: !!selfClosing,
71232
- contentAfterTag,
71233
- };
71234
- };
71235
- /**
71236
- * Parse substring content of a node and update the parent's children to include the new nodes.
71237
- */
71238
- const parseSibling = (stack, parent, index, sibling) => {
71239
- const siblingNodes = parseMdChildren(sibling);
71240
- // The new sibling nodes might contain new components to be processed
71241
- if (siblingNodes.length > 0) {
71242
- parent.children.splice(index + 1, 0, ...siblingNodes);
71243
- stack.push(parent);
71040
+ const emphasisChildren = [];
71041
+ const openingText = opening.textAfter.replace(/^\s+/, '');
71042
+ if (openingText) {
71043
+ emphasisChildren.push({ type: 'text', value: openingText });
71244
71044
  }
71245
- };
71246
- /**
71247
- * Create an MdxJsxFlowElement node from component data.
71248
- */
71249
- const createComponentNode = ({ tag, attributes, children, startPosition, endPosition }) => ({
71250
- type: 'mdxJsxFlowElement',
71251
- name: tag,
71252
- attributes,
71253
- children,
71254
- position: {
71255
- start: startPosition?.start,
71256
- end: endPosition?.end ?? startPosition?.end,
71257
- },
71258
- });
71045
+ container.children.slice(openingIdx + 1, closingIdx).forEach(child => {
71046
+ emphasisChildren.push(child);
71047
+ });
71048
+ const closingText = closing.textBefore.replace(/\s+$/, '');
71049
+ if (closingText) {
71050
+ emphasisChildren.push({ type: 'text', value: closingText });
71051
+ }
71052
+ if (emphasisChildren.length > 0) {
71053
+ const emphasisNode = opening.isBold
71054
+ ? { type: 'strong', children: emphasisChildren }
71055
+ : { type: 'emphasis', children: emphasisChildren };
71056
+ newNodes.push(emphasisNode);
71057
+ }
71058
+ if (closing.textAfter) {
71059
+ newNodes.push({ type: 'text', value: closing.textAfter });
71060
+ }
71061
+ return newNodes;
71062
+ }
71259
71063
  /**
71260
- * Remove a closing tag from a paragraph's children and return the updated paragraph.
71064
+ * Find and transform one multi-node emphasis pair in the container.
71065
+ * Returns true if a pair was found and transformed, false otherwise.
71261
71066
  */
71262
- const stripClosingTagFromParagraph = (node, tag) => {
71263
- if (!Array.isArray(node.children))
71264
- return { paragraph: node, found: false };
71265
- const children = [...node.children];
71266
- const closingIndex = children.findIndex(child => child.type === 'html' && isClosingTag(child.value || '', tag));
71267
- if (closingIndex === -1)
71268
- return { paragraph: node, found: false };
71269
- children.splice(closingIndex, 1);
71270
- return { paragraph: { ...node, children }, found: true };
71271
- };
71067
+ function processOneEmphasisPair(container) {
71068
+ const openingResult = findOpeningInChildren(container.children);
71069
+ if (!openingResult)
71070
+ return false;
71071
+ const { idx: openingIdx, opening } = openingResult;
71072
+ const closingResult = findClosingInChildren(container.children, openingIdx, opening.marker);
71073
+ if (!closingResult)
71074
+ return false;
71075
+ const { closingIdx, closing } = closingResult;
71076
+ const newNodes = buildReplacementNodes(container, { opening, openingIdx, closing, closingIdx });
71077
+ const deleteCount = closingIdx - openingIdx + 1;
71078
+ container.children.splice(openingIdx, deleteCount, ...newNodes);
71079
+ return true;
71080
+ }
71272
71081
  /**
71273
- * Scan forward through siblings to find a closing tag.
71274
- * Handles:
71275
- * - Exact match HTML siblings (e.g., `</Tag>`)
71276
- * - HTML siblings with embedded closing tag (e.g., `...\n</Tag>`)
71277
- * - Paragraph siblings containing the closing tag as a child
71278
- *
71279
- * Returns null if not found within MAX_LOOKAHEAD siblings
71082
+ * Handle malformed emphasis that spans multiple AST nodes.
71083
+ * E.g., "**bold [link](url)**" where markers are in different text nodes.
71280
71084
  */
71281
- const scanForClosingTag = (parent, startIndex, tag) => {
71282
- const closingTagStr = `</${tag}>`;
71283
- const maxIndex = Math.min(startIndex + MAX_LOOKAHEAD, parent.children.length);
71284
- let i = startIndex + 1;
71285
- for (; i < maxIndex; i += 1) {
71286
- const sibling = parent.children[i];
71287
- // Check HTML siblings
71288
- if (sibling.type === 'html') {
71289
- const siblingValue = sibling.value || '';
71290
- // Exact match (standalone closing tag)
71291
- if (isClosingTag(siblingValue, tag)) {
71292
- return { closingIndex: i, extraClosingChildren: [] };
71293
- }
71294
- // Embedded closing tag (closing tag within HTML block content)
71295
- if (siblingValue.includes(closingTagStr)) {
71296
- const closeTagPos = siblingValue.indexOf(closingTagStr);
71297
- const contentBeforeClose = siblingValue.substring(0, closeTagPos).trim();
71298
- const contentAfterClose = siblingValue.substring(closeTagPos + closingTagStr.length).trim();
71299
- const extraChildren = contentBeforeClose
71300
- ? parseMdChildren(contentBeforeClose)
71301
- : [];
71302
- return { closingIndex: i, extraClosingChildren: extraChildren, contentAfterClose: contentAfterClose || undefined };
71303
- }
71304
- }
71305
- // Check paragraph siblings
71306
- if (sibling.type === 'paragraph') {
71307
- const { paragraph, found } = stripClosingTagFromParagraph(sibling, tag);
71308
- if (found) {
71309
- return { closingIndex: i, extraClosingChildren: [], strippedParagraph: paragraph };
71310
- }
71085
+ function visitMultiNodeEmphasis(tree) {
71086
+ const containerTypes = ['paragraph', 'heading', 'tableCell', 'listItem', 'blockquote'];
71087
+ visit(tree, node => {
71088
+ if (!containerTypes.includes(node.type))
71089
+ return;
71090
+ if (!('children' in node) || !Array.isArray(node.children))
71091
+ return;
71092
+ const container = node;
71093
+ let foundPair = true;
71094
+ while (foundPair) {
71095
+ foundPair = processOneEmphasisPair(container);
71311
71096
  }
71312
- }
71313
- if (i < parent.children.length) {
71314
- // eslint-disable-next-line no-console
71315
- console.warn(`Closing tag </${tag}> not found within ${MAX_LOOKAHEAD} siblings, stopping scan`);
71316
- }
71317
- return null;
71318
- };
71319
- const substituteNodeWithMdxNode = (parent, index, mdxNode) => {
71320
- parent.children.splice(index, 1, mdxNode);
71321
- };
71097
+ });
71098
+ }
71322
71099
  /**
71323
- * Transform PascalCase HTML nodes into mdxJsxFlowElement nodes.
71324
- *
71325
- * Remark parses unknown/custom component tags as raw HTML nodes.
71326
- * These are the custom readme MDX syntax for components.
71327
- * This transformer identifies these patterns and converts them to proper MDX JSX elements so they
71328
- * can be accurately recognized and rendered later with their component definition code.
71329
- * Though for some tags, we need to handle them specially
71330
- *
71331
- * ## Supported HTML Structures
71332
- *
71333
- * ### 1. Self-closing tags
71334
- * ```
71335
- * <Component />
71336
- * ```
71337
- * Parsed as: `html: "<Component />"`
71338
- *
71339
- * ### 2. Self-contained blocks (entire component in single HTML node)
71340
- * ```
71341
- * <Button>Click me</Button>
71342
- * ```
71343
- * ```
71344
- * <Component>
71345
- * <h2>Title</h2>
71346
- * <p>Content</p>
71347
- * </Component>
71348
- * ```
71349
- * Parsed as: `html: "<Component>\n <h2>Title</h2>\n <p>Content</p>\n</Component>"`
71350
- * The opening tag, content, and closing tag are all captured in one HTML node.
71351
- *
71352
- * ### 3. Multi-sibling components (closing tag in a following sibling)
71353
- * Handles various structures where the closing tag is in a later sibling, such as:
71354
- *
71355
- * #### 3a. Block components (closing tag in sibling paragraph)
71356
- * ```
71357
- * <Callout>
71358
- * Some **markdown** content
71359
- * </Callout>
71360
- * ```
71361
- *
71362
- * #### 3b. Multi-paragraph components (closing tag several siblings away)
71363
- * ```
71364
- * <Callout>
71365
- *
71366
- * First paragraph
71367
- *
71368
- * Second paragraph
71369
- * </Callout>
71370
- * ```
71100
+ * A remark plugin that normalizes malformed bold and italic markers in text nodes.
71101
+ * Detects patterns like `** bold**`, `Hello** Wrong Bold**`, `__ bold__`, `Hello__ Wrong Bold__`,
71102
+ * `* italic*`, `Hello* Wrong Italic*`, `_ italic_`, or `Hello_ Wrong Italic_`
71103
+ * and converts them to proper strong/emphasis nodes, matching the behavior of the legacy rdmd engine.
71371
71104
  *
71372
- * #### 3c. Nested components split by blank lines (closing tag embedded in HTML sibling)
71373
- * ```
71374
- * <Outer>
71375
- * <Inner>content</Inner>
71105
+ * Supports both asterisk (`**bold**`, `*italic*`) and underscore (`__bold__`, `_italic_`) syntax.
71106
+ * Also supports snake_case content like `** some_snake_case**`.
71376
71107
  *
71377
- * <Inner>content</Inner>
71378
- * </Outer>
71379
- * ```
71108
+ * This runs after remark-parse, which (in v11+) is strict and doesn't parse
71109
+ * malformed emphasis syntax. This plugin post-processes the AST to handle these cases.
71380
71110
  */
71381
- const mdxishComponentBlocks = () => tree => {
71382
- const stack = [tree];
71383
- const processChildNode = (parent, index) => {
71384
- const node = parent.children[index];
71385
- if (!node)
71386
- return;
71387
- if ('children' in node && Array.isArray(node.children)) {
71388
- stack.push(node);
71111
+ const normalizeEmphasisAST = () => (tree) => {
71112
+ visit(tree, 'text', function visitor(node, index, parent) {
71113
+ if (index === undefined || !parent)
71114
+ return undefined;
71115
+ // Skip if inside code blocks or inline code
71116
+ if (parent.type === 'inlineCode' || parent.type === 'code') {
71117
+ return undefined;
71389
71118
  }
71390
- // Only visit HTML nodes with an actual html tag,
71391
- // which means a potential unparsed MDX component
71392
- const value = node.value;
71393
- if (node.type !== 'html' || typeof value !== 'string')
71394
- return;
71395
- const parsed = parseTag(value.trim());
71396
- if (!parsed)
71397
- return;
71398
- const { tag, attributes, selfClosing, contentAfterTag = '' } = parsed;
71399
- // Skip tags that have dedicated transformers
71400
- if (EXCLUDED_TAGS.has(tag))
71401
- return;
71402
- const closingTagStr = `</${tag}>`;
71403
- // Case 1: Self-closing tag
71404
- if (selfClosing) {
71405
- const componentNode = createComponentNode({
71406
- tag,
71407
- attributes,
71408
- children: [],
71409
- startPosition: node.position,
71410
- });
71411
- substituteNodeWithMdxNode(parent, index, componentNode);
71412
- // Check and parse if there's relevant content after the current closing tag
71413
- const remainingContent = contentAfterTag.trim();
71414
- if (remainingContent) {
71415
- parseSibling(stack, parent, index, remainingContent);
71119
+ const text = node.value;
71120
+ const allMatches = [];
71121
+ [...text.matchAll(asteriskBoldRegex)].forEach(match => {
71122
+ allMatches.push({ isBold: true, marker: '**', match });
71123
+ });
71124
+ [...text.matchAll(underscoreBoldRegex)].forEach(match => {
71125
+ allMatches.push({ isBold: true, marker: '__', match });
71126
+ });
71127
+ [...text.matchAll(asteriskItalicRegex)].forEach(match => {
71128
+ allMatches.push({ isBold: false, marker: '*', match });
71129
+ });
71130
+ [...text.matchAll(underscoreItalicRegex)].forEach(match => {
71131
+ allMatches.push({ isBold: false, marker: '_', match });
71132
+ });
71133
+ [...text.matchAll(intrawordUnderscoreItalicRegex)].forEach(match => {
71134
+ allMatches.push({ isBold: false, isIntraword: true, marker: '_', match });
71135
+ });
71136
+ [...text.matchAll(intrawordUnderscoreBoldRegex)].forEach(match => {
71137
+ allMatches.push({ isBold: true, isIntraword: true, marker: '__', match });
71138
+ });
71139
+ [...text.matchAll(intrawordAsteriskItalicRegex)].forEach(match => {
71140
+ allMatches.push({ isBold: false, isIntraword: true, marker: '*', match });
71141
+ });
71142
+ [...text.matchAll(intrawordAsteriskBoldRegex)].forEach(match => {
71143
+ allMatches.push({ isBold: true, isIntraword: true, marker: '**', match });
71144
+ });
71145
+ if (allMatches.length === 0)
71146
+ return undefined;
71147
+ allMatches.sort((a, b) => (a.match.index ?? 0) - (b.match.index ?? 0));
71148
+ const filteredMatches = [];
71149
+ let lastEnd = 0;
71150
+ allMatches.forEach(info => {
71151
+ const start = info.match.index ?? 0;
71152
+ const end = start + info.match[0].length;
71153
+ if (start >= lastEnd) {
71154
+ filteredMatches.push(info);
71155
+ lastEnd = end;
71416
71156
  }
71417
- return;
71418
- }
71419
- // Case 2: Self-contained block (closing tag in content)
71420
- if (contentAfterTag.includes(closingTagStr)) {
71421
- // Find the first closing tag
71422
- const closingTagIndex = contentAfterTag.indexOf(closingTagStr);
71423
- const componentInnerContent = contentAfterTag.substring(0, closingTagIndex).trim();
71424
- const contentAfterClose = contentAfterTag.substring(closingTagIndex + closingTagStr.length).trim();
71425
- const componentNode = createComponentNode({
71426
- tag,
71427
- attributes,
71428
- children: componentInnerContent ? parseMdChildren(componentInnerContent) : [],
71429
- startPosition: node.position,
71430
- });
71431
- substituteNodeWithMdxNode(parent, index, componentNode);
71432
- // After the closing tag, there might be more content to be processed
71433
- if (contentAfterClose) {
71434
- parseSibling(stack, parent, index, contentAfterClose);
71157
+ });
71158
+ if (filteredMatches.length === 0)
71159
+ return undefined;
71160
+ const parts = [];
71161
+ let lastIndex = 0;
71162
+ filteredMatches.forEach(({ isBold, isIntraword, marker, match }) => {
71163
+ const matchIndex = match.index ?? 0;
71164
+ const fullMatch = match[0];
71165
+ if (isIntraword) {
71166
+ // handles cases like hello_world_ where we only want to italicize 'world'
71167
+ const charBefore = match[1] || ''; // e.g., "l" in "hello_world_"
71168
+ const content = match[2]; // e.g., "world"
71169
+ const combinedBefore = text.slice(lastIndex, matchIndex) + charBefore;
71170
+ if (combinedBefore) {
71171
+ parts.push({ type: 'text', value: combinedBefore });
71172
+ }
71173
+ if (isBold) {
71174
+ parts.push({
71175
+ type: 'strong',
71176
+ children: [{ type: 'text', value: content }],
71177
+ });
71178
+ }
71179
+ else {
71180
+ parts.push({
71181
+ type: 'emphasis',
71182
+ children: [{ type: 'text', value: content }],
71183
+ });
71184
+ }
71185
+ lastIndex = matchIndex + fullMatch.length;
71186
+ return;
71435
71187
  }
71436
- else if (componentNode.children.length > 0) {
71437
- // The content inside the component block might contain new components to be processed
71438
- stack.push(componentNode);
71188
+ if (matchIndex > lastIndex) {
71189
+ const beforeText = text.slice(lastIndex, matchIndex);
71190
+ if (beforeText) {
71191
+ parts.push({ type: 'text', value: beforeText });
71192
+ }
71439
71193
  }
71440
- return;
71441
- }
71442
- // Case 3: Multi-sibling component (closing tag in a following sibling)
71443
- // Scans forward through siblings to find closing tag in HTML or paragraph nodes
71444
- const scanResult = scanForClosingTag(parent, index, tag);
71445
- if (!scanResult)
71446
- return;
71447
- const { closingIndex, extraClosingChildren, strippedParagraph, contentAfterClose: remainingAfterClose } = scanResult;
71448
- const extraChildren = contentAfterTag ? parseMdChildren(contentAfterTag.trimStart()) : [];
71449
- // Collect all intermediate siblings between opening tag and closing tag
71450
- const intermediateChildren = parent.children.slice(index + 1, closingIndex);
71451
- // For paragraph siblings, include the paragraph's children (with closing tag stripped)
71452
- // For HTML siblings, include any content parsed from before the closing tag
71453
- const closingChildren = strippedParagraph
71454
- ? strippedParagraph.children
71455
- : extraClosingChildren;
71456
- const componentNode = createComponentNode({
71457
- tag,
71458
- attributes,
71459
- children: [...extraChildren, ...intermediateChildren, ...closingChildren],
71460
- startPosition: node.position,
71461
- endPosition: parent.children[closingIndex]?.position,
71194
+ const wordBefore = match[1]; // e.g., "Hello" in "Hello** Wrong Bold**"
71195
+ const contentWithSpaceAfter = match[3]; // Content when there's a space after opening markers
71196
+ const trailingSpace1 = match[4] || ''; // Space before closing markers (for "** text **" pattern)
71197
+ const contentWithSpaceBefore = match[5]; // Content when there's only a space before closing markers
71198
+ const trailingSpace2 = match[6] || ''; // Space before closing markers (for "**text **" pattern)
71199
+ const trailingSpace = trailingSpace1 || trailingSpace2; // Combined trailing space
71200
+ const content = (contentWithSpaceAfter || contentWithSpaceBefore || '').trim();
71201
+ const afterChar = match[7]; // Character after closing markers (if any)
71202
+ const markerPos = fullMatch.indexOf(marker);
71203
+ const spacesBeforeMarkers = wordBefore
71204
+ ? fullMatch.slice(wordBefore.length, markerPos)
71205
+ : fullMatch.slice(0, markerPos);
71206
+ const shouldAddSpace = !!contentWithSpaceAfter && !!wordBefore && !spacesBeforeMarkers;
71207
+ if (wordBefore) {
71208
+ const spacing = spacesBeforeMarkers + (shouldAddSpace ? ' ' : '');
71209
+ parts.push({ type: 'text', value: wordBefore + spacing });
71210
+ }
71211
+ else if (spacesBeforeMarkers) {
71212
+ parts.push({ type: 'text', value: spacesBeforeMarkers });
71213
+ }
71214
+ if (content) {
71215
+ if (isBold) {
71216
+ parts.push({
71217
+ type: 'strong',
71218
+ children: [{ type: 'text', value: content }],
71219
+ });
71220
+ }
71221
+ else {
71222
+ parts.push({
71223
+ type: 'emphasis',
71224
+ children: [{ type: 'text', value: content }],
71225
+ });
71226
+ }
71227
+ }
71228
+ if (afterChar) {
71229
+ const prefix = trailingSpace ? ' ' : '';
71230
+ parts.push({ type: 'text', value: prefix + afterChar });
71231
+ }
71232
+ lastIndex = matchIndex + fullMatch.length;
71462
71233
  });
71463
- // Remove all nodes from opening tag to closing tag (inclusive) and replace with component node
71464
- parent.children.splice(index, closingIndex - index + 1, componentNode);
71465
- // Since we might be merging sibling nodes together and combining content,
71466
- // there might be new components to process
71467
- if (componentNode.children.length > 0) {
71468
- stack.push(componentNode);
71469
- }
71470
- // If the closing tag sibling had content after it (e.g., another component opening tag),
71471
- // re-insert it as a sibling so it can be processed in subsequent iterations
71472
- if (remainingAfterClose) {
71473
- parseSibling(stack, parent, index, remainingAfterClose);
71234
+ if (lastIndex < text.length) {
71235
+ const remainingText = text.slice(lastIndex);
71236
+ if (remainingText) {
71237
+ parts.push({ type: 'text', value: remainingText });
71238
+ }
71474
71239
  }
71475
- };
71476
- // Process the nodes with the components depth-first to maintain the correct order of the nodes
71477
- while (stack.length) {
71478
- const parent = stack.pop();
71479
- if (parent?.children) {
71480
- parent.children.forEach((_child, index) => {
71481
- processChildNode(parent, index);
71482
- });
71240
+ if (parts.length > 0) {
71241
+ parent.children.splice(index, 1, ...parts);
71242
+ return [SKIP, index + parts.length];
71483
71243
  }
71484
- }
71244
+ return undefined;
71245
+ });
71246
+ // Handle malformed emphasis spanning multiple nodes (e.g., **text [link](url) **)
71247
+ visitMultiNodeEmphasis(tree);
71485
71248
  return tree;
71486
71249
  };
71487
- /* harmony default export */ const mdxish_component_blocks = (mdxishComponentBlocks);
71250
+ /* harmony default export */ const normalize_malformed_md_syntax = (normalizeEmphasisAST);
71488
71251
 
71489
71252
  ;// ./processor/transform/mdxish/mdxish-tables.ts
71490
71253
 
@@ -71495,14 +71258,21 @@ const mdxishComponentBlocks = () => tree => {
71495
71258
 
71496
71259
 
71497
71260
 
71261
+
71262
+
71263
+
71498
71264
  const isTableCell = (node) => isMDXElement(node) && ['th', 'td'].includes(node.name);
71499
71265
  const tableTypes = {
71500
71266
  tr: 'tableRow',
71501
71267
  th: 'tableCell',
71502
71268
  td: 'tableCell',
71503
71269
  };
71504
- const mdCellProcessor = unified().use(remarkParse).use(remarkGfm);
71505
- const tableNodeProcessor = unified().use(remarkParse).use(remarkMdx).use(mdxish_component_blocks);
71270
+ const tableNodeProcessor = unified()
71271
+ .use(remarkParse)
71272
+ .use(remarkMdx)
71273
+ .use(normalize_malformed_md_syntax)
71274
+ .use([callouts, gemoji_])
71275
+ .use(remarkGfm);
71506
71276
  /**
71507
71277
  * Check if children are only text nodes that might contain markdown
71508
71278
  */
@@ -71532,14 +71302,14 @@ const extractTextFromChildren = (children) => {
71532
71302
  .join('');
71533
71303
  };
71534
71304
  /**
71535
- * Parse markdown text into MDAST nodes
71305
+ * Returns true if any node in the array is block-level (non-phrasing) content.
71536
71306
  */
71537
- const parseMarkdown = (text) => {
71538
- const tree = mdCellProcessor.runSync(mdCellProcessor.parse(text));
71539
- return (tree.children || []);
71307
+ const hasFlowContent = (nodes) => {
71308
+ return nodes.some(node => !phrasing(node) && node.type !== 'paragraph');
71540
71309
  };
71541
71310
  /**
71542
- * Process a Table node (either MDX JSX element or parsed from HTML) and convert to markdown table
71311
+ * Process a Table node: re-parse text-only cell content, then output as
71312
+ * a markdown table (phrasing-only) or keep as JSX <Table> (has flow content).
71543
71313
  */
71544
71314
  const processTableNode = (node, index, parent) => {
71545
71315
  if (node.name !== 'Table')
@@ -71547,54 +71317,88 @@ const processTableNode = (node, index, parent) => {
71547
71317
  const { position } = node;
71548
71318
  const { align: alignAttr } = getAttrs(node);
71549
71319
  const align = Array.isArray(alignAttr) ? alignAttr : null;
71550
- const children = [];
71551
- // Process rows from thead and tbody
71552
- // The structure is: Table -> thead/tbody -> tr -> td/th
71553
- const processRow = (row) => {
71554
- const rowChildren = [];
71555
- visit(row, isTableCell, ({ name, children: cellChildren, position: cellPosition }) => {
71556
- let parsedChildren = cellChildren;
71557
- // If cell contains only text nodes, try to re-parse as markdown
71558
- if (isTextOnly(cellChildren)) {
71559
- const textContent = extractTextFromChildren(cellChildren);
71560
- if (textContent.trim()) {
71561
- try {
71562
- const parsed = parseMarkdown(textContent);
71563
- // If parsing produced nodes, use them; otherwise keep original
71564
- if (parsed.length > 0) {
71565
- // Flatten paragraphs if they contain only phrasing content
71566
- parsedChildren = parsed.flatMap(parsedNode => {
71567
- if (parsedNode.type === 'paragraph' && 'children' in parsedNode && parsedNode.children) {
71568
- return parsedNode.children;
71569
- }
71570
- return [parsedNode];
71571
- });
71572
- }
71573
- }
71574
- catch {
71575
- // If parsing fails, keep original children
71576
- }
71320
+ let tableHasFlowContent = false;
71321
+ // Re-parse text-only cells through markdown and detect flow content
71322
+ visit(node, isTableCell, (cell) => {
71323
+ if (!isTextOnly(cell.children))
71324
+ return;
71325
+ const textContent = extractTextFromChildren(cell.children);
71326
+ if (!textContent.trim())
71327
+ return;
71328
+ // Since now we are using remarkMdx, which can fail and error, we need to
71329
+ // gate this behind a try/catch to ensure that malformed syntaxes do not
71330
+ // crash the page
71331
+ try {
71332
+ const parsed = tableNodeProcessor.runSync(tableNodeProcessor.parse(textContent));
71333
+ if (parsed.children.length > 0) {
71334
+ cell.children = parsed.children;
71335
+ if (hasFlowContent(parsed.children)) {
71336
+ tableHasFlowContent = true;
71577
71337
  }
71578
71338
  }
71579
- rowChildren.push({
71580
- type: tableTypes[name],
71581
- children: parsedChildren,
71582
- position: cellPosition,
71583
- });
71584
- });
71585
- children.push({
71586
- type: tableTypes[row.name],
71587
- children: rowChildren,
71588
- position: row.position,
71339
+ }
71340
+ catch {
71341
+ // If parsing fails, keep original children
71342
+ }
71343
+ });
71344
+ // mdast's table node always treats the first tableRow as <thead>, so we can't
71345
+ // represent a header-less table in mdast without the first body row getting
71346
+ // promoted. Keep as JSX instead so remarkRehype renders it correctly
71347
+ let hasThead = false;
71348
+ visit(node, isMDXElement, (child) => {
71349
+ if (child.name === 'thead')
71350
+ hasThead = true;
71351
+ });
71352
+ if (tableHasFlowContent || !hasThead) {
71353
+ // remarkMdx wraps inline elements in paragraph nodes (e.g. <td> on the
71354
+ // same line as content becomes mdxJsxTextElement inside a paragraph).
71355
+ // Unwrap these so <td>/<th> sit directly under <tr>, and strip
71356
+ // whitespace-only text nodes to avoid rendering empty <p>/<br>.
71357
+ const cleanChildren = (children) => children
71358
+ .flatMap(child => {
71359
+ if (child.type === 'paragraph' && 'children' in child && Array.isArray(child.children)) {
71360
+ return child.children;
71361
+ }
71362
+ return [child];
71363
+ })
71364
+ .filter(child => !(child.type === 'text' && 'value' in child && typeof child.value === 'string' && !child.value.trim()));
71365
+ visit(node, isMDXElement, (el) => {
71366
+ if ('children' in el && Array.isArray(el.children)) {
71367
+ el.children = cleanChildren(el.children);
71368
+ }
71589
71369
  });
71590
- };
71591
- // Visit thead and tbody, then find tr elements within them
71370
+ parent.children[index] = {
71371
+ ...node,
71372
+ position,
71373
+ };
71374
+ return;
71375
+ }
71376
+ // All cells are phrasing-only — convert to markdown table
71377
+ const children = [];
71592
71378
  visit(node, isMDXElement, (child) => {
71593
71379
  if (child.name === 'thead' || child.name === 'tbody') {
71594
71380
  visit(child, isMDXElement, (row) => {
71595
- if (row.name === 'tr' && row.type === 'mdxJsxFlowElement') {
71596
- processRow(row);
71597
- }
71381
+ if (row.name !== 'tr')
71382
+ return;
71383
+ const rowChildren = [];
71384
+ visit(row, isTableCell, ({ name, children: cellChildren, position: cellPosition }) => {
71385
+ const parsedChildren = cellChildren.flatMap(parsedNode => {
71386
+ if (parsedNode.type === 'paragraph' && 'children' in parsedNode && parsedNode.children) {
71387
+ return parsedNode.children;
71388
+ }
71389
+ return [parsedNode];
71390
+ });
71391
+ rowChildren.push({
71392
+ type: tableTypes[name],
71393
+ children: parsedChildren,
71394
+ position: cellPosition,
71395
+ });
71396
+ });
71397
+ children.push({
71398
+ type: 'tableRow',
71399
+ children: rowChildren,
71400
+ position: row.position,
71401
+ });
71598
71402
  });
71599
71403
  }
71600
71404
  });
@@ -71614,54 +71418,35 @@ const processTableNode = (node, index, parent) => {
71614
71418
  /**
71615
71419
  * Converts JSX Table elements to markdown table nodes and re-parses markdown in cells.
71616
71420
  *
71617
- * Since mdxish doesn't use remarkMdx, we manually parse cell contents through
71618
- * remarkParse and remarkGfm to convert markdown to MDAST nodes.
71421
+ * The jsxTable micromark tokenizer captures `<Table>...</Table>` as a single html node,
71422
+ * preventing CommonMark HTML block type 6 from fragmenting it at blank lines. This
71423
+ * transformer then re-parses the html node with remarkMdx to produce proper JSX AST nodes
71424
+ * and converts them to MDAST table/tableRow/tableCell nodes.
71425
+ *
71426
+ * When cell content contains block-level nodes (callouts, code blocks, etc.), the table
71427
+ * is kept as a JSX <Table> element so that remarkRehype can properly handle the flow content.
71619
71428
  */
71620
71429
  const mdxishTables = () => tree => {
71621
- // First, handle MDX JSX elements (already converted by mdxishComponentBlocks)
71622
- visit(tree, isMDXElement, (node, index, parent) => {
71623
- if (node.name === 'Table') {
71624
- processTableNode(node, index, parent);
71625
- return SKIP;
71626
- }
71627
- });
71628
- // Also handle HTML and raw nodes that contain Table tags (in case mdxishComponentBlocks didn't convert them)
71629
- // This happens when the entire <Table>...</Table> block is in a single HTML node, which mdxishComponentBlocks
71630
- // doesn't handle (it only handles split nodes: opening tag, content paragraph, closing tag)
71631
- const handleTableInNode = (node, index, parent) => {
71430
+ visit(tree, 'html', (_node, index, parent) => {
71431
+ const node = _node;
71632
71432
  if (typeof index !== 'number' || !parent || !('children' in parent))
71633
71433
  return;
71634
- if (typeof node.value !== 'string')
71635
- return;
71636
- if (!node.value.includes('<Table') || !node.value.includes('</Table>'))
71434
+ if (!node.value.startsWith('<Table'))
71637
71435
  return;
71638
71436
  try {
71639
- // Parse the HTML content with remarkMdx and mdxishComponentBlocks to convert it to MDX JSX elements
71640
- // This creates a proper AST that we can then process
71641
71437
  const parsed = tableNodeProcessor.runSync(tableNodeProcessor.parse(node.value));
71642
- // Find the Table element in the parsed result and process it
71643
71438
  visit(parsed, isMDXElement, (tableNode) => {
71644
71439
  if (tableNode.name === 'Table') {
71645
- // Process the table and replace the HTML node with a markdown table node
71646
71440
  processTableNode(tableNode, index, parent);
71441
+ // Stop after the outermost Table so nested Tables don't overwrite parent.children[index]
71442
+ // we let it get handled naturally
71443
+ return EXIT;
71647
71444
  }
71648
71445
  });
71649
71446
  }
71650
71447
  catch {
71651
71448
  // If parsing fails, leave the node as-is
71652
71449
  }
71653
- };
71654
- // Handle HTML nodes (created by remark-parse for HTML blocks)
71655
- visit(tree, 'html', (node, index, parent) => {
71656
- if (typeof index === 'number' && parent && 'children' in parent) {
71657
- handleTableInNode(node, index, parent);
71658
- }
71659
- });
71660
- // Handle raw nodes (created by remark-parse for certain HTML structures)
71661
- visit(tree, 'raw', (node, index, parent) => {
71662
- if (typeof index === 'number' && parent && 'children' in parent) {
71663
- handleTableInNode(node, index, parent);
71664
- }
71665
71450
  });
71666
71451
  return tree;
71667
71452
  };
@@ -92157,10 +91942,6 @@ const compile_list_item_listItem = (node, parent, state, info) => {
92157
91942
  const plain_plain = (node) => node.value;
92158
91943
  /* harmony default export */ const compile_plain = (plain_plain);
92159
91944
 
92160
- ;// ./processor/compile/variable.ts
92161
- const variable = (node) => `{user.${node.data?.hProperties?.name || ''}}`;
92162
- /* harmony default export */ const compile_variable = (variable);
92163
-
92164
91945
  ;// ./processor/compile/index.ts
92165
91946
 
92166
91947
 
@@ -94284,10 +94065,14 @@ function extractBalancedBraces(content, start) {
94284
94065
  return { content: content.slice(start, pos - 1), end: pos };
94285
94066
  }
94286
94067
  /**
94287
- * Escapes unbalanced braces in content to prevent MDX expression parsing errors.
94288
- * Handles: already-escaped braces, string literals inside expressions, nested balanced braces.
94068
+ * Escapes problematic braces in content to prevent MDX expression parsing errors.
94069
+ * Handles three cases:
94070
+ * 1. Unbalanced braces (e.g., `{foo` without closing `}`)
94071
+ * 2. Paragraph-spanning expressions (e.g., `{\n\n}` where blank line splits paragraphs)
94072
+ * 3. Skips HTML elements to prevent backslashes appearing in output
94073
+ *
94289
94074
  */
94290
- function escapeUnbalancedBraces(content) {
94075
+ function escapeProblematicBraces(content) {
94291
94076
  // Skip HTML elements — their content should never be escaped because
94292
94077
  // rehypeRaw parses them into hast elements, making `\` literal text in output
94293
94078
  const htmlElements = [];
@@ -94296,16 +94081,19 @@ function escapeUnbalancedBraces(content) {
94296
94081
  htmlElements.push(match);
94297
94082
  return `___HTML_ELEM_${idx}___`;
94298
94083
  });
94299
- const opens = [];
94300
- const unbalanced = new Set();
94301
- let strDelim = null;
94302
- let strEscaped = false;
94084
+ const toEscape = new Set();
94303
94085
  // Convert to array of Unicode code points to handle emojis and multi-byte characters correctly
94304
94086
  const chars = Array.from(safe);
94087
+ let strDelim = null;
94088
+ let strEscaped = false;
94089
+ // Stack of open braces with their state
94090
+ const openStack = [];
94091
+ // Track position of last newline (outside strings) to detect blank lines
94092
+ let lastNewlinePos = -2; // -2 means no recent newline
94305
94093
  for (let i = 0; i < chars.length; i += 1) {
94306
94094
  const ch = chars[i];
94307
- // Track strings inside expressions to ignore braces within them
94308
- if (opens.length > 0) {
94095
+ // Track string delimiters inside expressions to ignore braces within them
94096
+ if (openStack.length > 0) {
94309
94097
  if (strDelim) {
94310
94098
  if (strEscaped)
94311
94099
  strEscaped = false;
@@ -94321,6 +94109,20 @@ function escapeUnbalancedBraces(content) {
94321
94109
  // eslint-disable-next-line no-continue
94322
94110
  continue;
94323
94111
  }
94112
+ // Track newlines to detect blank lines (paragraph boundaries)
94113
+ if (ch === '\n') {
94114
+ // Check if this newline creates a blank line (only whitespace since last newline)
94115
+ if (lastNewlinePos >= 0) {
94116
+ const between = chars.slice(lastNewlinePos + 1, i).join('');
94117
+ if (/^[ \t]*$/.test(between)) {
94118
+ // This is a blank line - mark all open expressions as paragraph-spanning
94119
+ openStack.forEach(entry => {
94120
+ entry.hasBlankLine = true;
94121
+ });
94122
+ }
94123
+ }
94124
+ lastNewlinePos = i;
94125
+ }
94324
94126
  }
94325
94127
  // Skip already-escaped braces (count preceding backslashes)
94326
94128
  if (ch === '{' || ch === '}') {
@@ -94332,21 +94134,33 @@ function escapeUnbalancedBraces(content) {
94332
94134
  continue;
94333
94135
  }
94334
94136
  }
94335
- if (ch === '{')
94336
- opens.push(i);
94137
+ if (ch === '{') {
94138
+ openStack.push({ pos: i, hasBlankLine: false });
94139
+ lastNewlinePos = -2; // Reset newline tracking for new expression
94140
+ }
94337
94141
  else if (ch === '}') {
94338
- if (opens.length > 0)
94339
- opens.pop();
94340
- else
94341
- unbalanced.add(i);
94142
+ if (openStack.length > 0) {
94143
+ const entry = openStack.pop();
94144
+ // If expression spans paragraph boundary, escape both braces
94145
+ if (entry.hasBlankLine) {
94146
+ toEscape.add(entry.pos);
94147
+ toEscape.add(i);
94148
+ }
94149
+ }
94150
+ else {
94151
+ // Unbalanced closing brace (no matching open)
94152
+ toEscape.add(i);
94153
+ }
94342
94154
  }
94343
94155
  }
94344
- opens.forEach(pos => unbalanced.add(pos));
94345
- // If there are no unbalanced braces, return content as-is;
94346
- // otherwise, escape each unbalanced `{` or `}` so MDX doesn't treat them as expressions.
94347
- let result = unbalanced.size === 0
94156
+ // Any remaining open braces are unbalanced
94157
+ openStack.forEach(entry => toEscape.add(entry.pos));
94158
+ // If there are no problematic braces, return safe content as-is;
94159
+ // otherwise, escape each problematic `{` or `}` so MDX doesn't treat them as expressions.
94160
+ let result = toEscape.size === 0
94348
94161
  ? safe
94349
- : chars.map((ch, i) => (unbalanced.has(i) ? `\\${ch}` : ch)).join('');
94162
+ : chars.map((ch, i) => (toEscape.has(i) ? `\\${ch}` : ch)).join('');
94163
+ // Restore HTML elements
94350
94164
  if (htmlElements.length > 0) {
94351
94165
  result = result.replace(/___HTML_ELEM_(\d+)___/g, (_m, idx) => htmlElements[parseInt(idx, 10)]);
94352
94166
  }
@@ -94444,8 +94258,9 @@ function preprocessJSXExpressions(content, context = {}) {
94444
94258
  // For inline expressions, we use a library to parse the expression & evaluate it later
94445
94259
  // For attribute expressions, it was difficult to use a library to parse them, so do it manually
94446
94260
  processed = evaluateAttributeExpressions(protectedContent, context, protectedCode);
94447
- // Step 3: Escape unbalanced braces to prevent MDX expression parsing errors
94448
- processed = escapeUnbalancedBraces(processed);
94261
+ // Step 3: Escape problematic braces to prevent MDX expression parsing errors
94262
+ // This handles both unbalanced braces and paragraph-spanning expressions in one pass
94263
+ processed = escapeProblematicBraces(processed);
94449
94264
  // Step 4: Restore protected code blocks
94450
94265
  processed = restoreCodeBlocks(processed, protectedCode);
94451
94266
  return processed;
@@ -94505,110 +94320,468 @@ const evaluateExpressions = ({ context = {} } = {}) => tree => {
94505
94320
  };
94506
94321
  /* harmony default export */ const evaluate_expressions = (evaluateExpressions);
94507
94322
 
94508
- ;// ./processor/transform/mdxish/heading-slugs.ts
94323
+ ;// ./processor/transform/mdxish/heading-slugs.ts
94324
+
94325
+
94326
+ function isHeading(node) {
94327
+ return /^h[1-6]$/.test(node.tagName);
94328
+ }
94329
+ function textContent(node) {
94330
+ if (node.type === 'text')
94331
+ return node.value;
94332
+ // Process variable nodes by using their variable name for the id generation
94333
+ if (node.type === 'element' && node.tagName === 'variable' && node.properties?.name) {
94334
+ if (node.properties.isLegacy) {
94335
+ return node.properties.name;
94336
+ }
94337
+ return `user.${node.properties.name}`;
94338
+ }
94339
+ if ('children' in node)
94340
+ return node.children.map(textContent).join('');
94341
+ return '';
94342
+ }
94343
+ /**
94344
+ * Rehype plugin that constructs ids for headings
94345
+ * Id's are used to construct slug anchor links & Table of Contents during rendering
94346
+ * Use the text / nodes that make up the heading to generate the id
94347
+ */
94348
+ const generateSlugForHeadings = () => (tree) => {
94349
+ const slugger = new BananaSlug();
94350
+ visit(tree, 'element', (node) => {
94351
+ if (isHeading(node) && !node.properties.id) {
94352
+ const text = node.children.map(textContent).join('');
94353
+ node.properties.id = slugger.slug(text);
94354
+ }
94355
+ });
94356
+ return tree;
94357
+ };
94358
+ /* harmony default export */ const heading_slugs = (generateSlugForHeadings);
94359
+
94360
+ // EXTERNAL MODULE: external "@readme/variable"
94361
+ var variable_ = __webpack_require__(8167);
94362
+ var variable_default = /*#__PURE__*/__webpack_require__.n(variable_);
94363
+ ;// ./node_modules/rehype-parse/lib/index.js
94364
+ /**
94365
+ * @import {Root} from 'hast'
94366
+ * @import {Options as FromHtmlOptions} from 'hast-util-from-html'
94367
+ * @import {Parser, Processor} from 'unified'
94368
+ */
94369
+
94370
+ /**
94371
+ * @typedef {Omit<FromHtmlOptions, 'onerror'> & RehypeParseFields} Options
94372
+ * Configuration.
94373
+ *
94374
+ * @typedef RehypeParseFields
94375
+ * Extra fields.
94376
+ * @property {boolean | null | undefined} [emitParseErrors=false]
94377
+ * Whether to emit parse errors while parsing (default: `false`).
94378
+ *
94379
+ * > 👉 **Note**: parse errors are currently being added to HTML.
94380
+ * > Not all errors emitted by parse5 (or us) are specced yet.
94381
+ * > Some documentation may still be missing.
94382
+ */
94383
+
94384
+
94385
+
94386
+ /**
94387
+ * Plugin to add support for parsing from HTML.
94388
+ *
94389
+ * > 👉 **Note**: this is not an XML parser.
94390
+ * > It supports SVG as embedded in HTML.
94391
+ * > It does not support the features available in XML.
94392
+ * > Passing SVG files might break but fragments of modern SVG should be fine.
94393
+ * > Use [`xast-util-from-xml`][xast-util-from-xml] to parse XML.
94394
+ *
94395
+ * @param {Options | null | undefined} [options]
94396
+ * Configuration (optional).
94397
+ * @returns {undefined}
94398
+ * Nothing.
94399
+ */
94400
+ function rehypeParse(options) {
94401
+ /** @type {Processor<Root>} */
94402
+ // @ts-expect-error: TS in JSDoc generates wrong types if `this` is typed regularly.
94403
+ const self = this
94404
+ const {emitParseErrors, ...settings} = {...self.data('settings'), ...options}
94405
+
94406
+ self.parser = parser
94407
+
94408
+ /**
94409
+ * @type {Parser<Root>}
94410
+ */
94411
+ function parser(document, file) {
94412
+ return fromHtml(document, {
94413
+ ...settings,
94414
+ onerror: emitParseErrors
94415
+ ? function (message) {
94416
+ if (file.path) {
94417
+ message.name = file.path + ':' + message.name
94418
+ message.file = file.path
94419
+ }
94420
+
94421
+ file.messages.push(message)
94422
+ }
94423
+ : undefined
94424
+ })
94425
+ }
94426
+ }
94427
+
94428
+ ;// ./lib/mdast-util/empty-task-list-item/index.ts
94429
+ /**
94430
+ * Normalizes list items that are written as only `[ ]` or `[x]` into GFM task
94431
+ * list items during parse, but only when at least one whitespace character
94432
+ * follows the closing bracket (`]`). This matches legacy behaviour for checkboxes
94433
+ *
94434
+ * The issue is `remark-gfm` does not actually classify these as task items when they have no content
94435
+ * after the checkbox, which leaves them as plain text (`"[ ]"`). So a custom extension is needed to
94436
+ * treat these as task items
94437
+ */
94438
+ function exitListItemWithEmptyTaskListItem(token) {
94439
+ const node = this.stack[this.stack.length - 1];
94440
+ if (node &&
94441
+ node.type === 'listItem' &&
94442
+ typeof node.checked !== 'boolean') {
94443
+ const listItem = node;
94444
+ const head = listItem.children[0];
94445
+ if (head && head.type === 'paragraph' && head.children.length === 1) {
94446
+ const text = head.children[0];
94447
+ if (text.type === 'text') {
94448
+ const hasTrailingWhitespace = typeof head.position?.end.offset === 'number' &&
94449
+ typeof text.position?.end.offset === 'number' &&
94450
+ head.position.end.offset > text.position.end.offset;
94451
+ if (!hasTrailingWhitespace) {
94452
+ this.exit(token);
94453
+ return;
94454
+ }
94455
+ const value = text.value;
94456
+ if (value === '[ ]') {
94457
+ listItem.checked = false;
94458
+ head.children = [];
94459
+ }
94460
+ else if (value === '[x]' || value === '[X]') {
94461
+ listItem.checked = true;
94462
+ head.children = [];
94463
+ }
94464
+ }
94465
+ }
94466
+ }
94467
+ this.exit(token);
94468
+ }
94469
+ function emptyTaskListItemFromMarkdown() {
94470
+ return {
94471
+ exit: {
94472
+ listItem: exitListItemWithEmptyTaskListItem,
94473
+ },
94474
+ };
94475
+ }
94476
+
94477
+ ;// ./lib/mdast-util/legacy-variable/index.ts
94478
+
94479
+ const contextMap = new WeakMap();
94480
+ function findlegacyVariableToken() {
94481
+ // tokenStack is micromark's current open token ancestry; find the nearest legacyVariable token.
94482
+ const events = this.tokenStack;
94483
+ for (let i = events.length - 1; i >= 0; i -= 1) {
94484
+ const token = events[i][0];
94485
+ if (token.type === 'legacyVariable')
94486
+ return token;
94487
+ }
94488
+ return undefined;
94489
+ }
94490
+ function enterlegacyVariable(token) {
94491
+ contextMap.set(token, { value: '' });
94492
+ }
94493
+ function exitlegacyVariableValue(token) {
94494
+ const variableToken = findlegacyVariableToken.call(this);
94495
+ if (!variableToken)
94496
+ return;
94497
+ const ctx = contextMap.get(variableToken);
94498
+ // Build up the variable characters
94499
+ if (ctx)
94500
+ ctx.value += this.sliceSerialize(token);
94501
+ }
94502
+ function exitlegacyVariable(token) {
94503
+ const ctx = contextMap.get(token);
94504
+ const serialized = this.sliceSerialize(token);
94505
+ const variableName = serialized.startsWith('<<') && serialized.endsWith('>>')
94506
+ ? serialized.slice(2, -2)
94507
+ : ctx?.value ?? '';
94508
+ const nodePosition = {
94509
+ start: {
94510
+ offset: token.start.offset,
94511
+ line: token.start.line,
94512
+ column: token.start.column,
94513
+ },
94514
+ end: {
94515
+ offset: token.end.offset,
94516
+ line: token.end.line,
94517
+ column: token.end.column,
94518
+ },
94519
+ };
94520
+ if (variableName.startsWith('glossary:')) {
94521
+ const term = variableName.slice('glossary:'.length).trim();
94522
+ this.enter({
94523
+ type: NodeTypes.glossary,
94524
+ data: {
94525
+ hName: 'Glossary',
94526
+ hProperties: { term },
94527
+ },
94528
+ children: [{ type: 'text', value: term }],
94529
+ position: nodePosition,
94530
+ }, token);
94531
+ this.exit(token);
94532
+ contextMap.delete(token);
94533
+ return;
94534
+ }
94535
+ this.enter({
94536
+ type: NodeTypes.variable,
94537
+ data: {
94538
+ hName: 'Variable',
94539
+ hProperties: { name: variableName.trim(), isLegacy: true },
94540
+ },
94541
+ value: `<<${variableName}>>`,
94542
+ }, token);
94543
+ this.exit(token);
94544
+ contextMap.delete(token);
94545
+ }
94546
+ function legacyVariableFromMarkdown() {
94547
+ return {
94548
+ enter: {
94549
+ legacyVariable: enterlegacyVariable,
94550
+ },
94551
+ exit: {
94552
+ legacyVariableValue: exitlegacyVariableValue,
94553
+ legacyVariable: exitlegacyVariable,
94554
+ },
94555
+ };
94556
+ }
94557
+
94558
+ ;// ./node_modules/micromark-util-symbol/lib/codes.js
94559
+ /**
94560
+ * Character codes.
94561
+ *
94562
+ * This module is compiled away!
94563
+ *
94564
+ * micromark works based on character codes.
94565
+ * This module contains constants for the ASCII block and the replacement
94566
+ * character.
94567
+ * A couple of them are handled in a special way, such as the line endings
94568
+ * (CR, LF, and CR+LF, commonly known as end-of-line: EOLs), the tab (horizontal
94569
+ * tab) and its expansion based on what column it’s at (virtual space),
94570
+ * and the end-of-file (eof) character.
94571
+ * As values are preprocessed before handling them, the actual characters LF,
94572
+ * CR, HT, and NUL (which is present as the replacement character), are
94573
+ * guaranteed to not exist.
94574
+ *
94575
+ * Unicode basic latin block.
94576
+ */
94577
+ const codes = /** @type {const} */ ({
94578
+ carriageReturn: -5,
94579
+ lineFeed: -4,
94580
+ carriageReturnLineFeed: -3,
94581
+ horizontalTab: -2,
94582
+ virtualSpace: -1,
94583
+ eof: null,
94584
+ nul: 0,
94585
+ soh: 1,
94586
+ stx: 2,
94587
+ etx: 3,
94588
+ eot: 4,
94589
+ enq: 5,
94590
+ ack: 6,
94591
+ bel: 7,
94592
+ bs: 8,
94593
+ ht: 9, // `\t`
94594
+ lf: 10, // `\n`
94595
+ vt: 11, // `\v`
94596
+ ff: 12, // `\f`
94597
+ cr: 13, // `\r`
94598
+ so: 14,
94599
+ si: 15,
94600
+ dle: 16,
94601
+ dc1: 17,
94602
+ dc2: 18,
94603
+ dc3: 19,
94604
+ dc4: 20,
94605
+ nak: 21,
94606
+ syn: 22,
94607
+ etb: 23,
94608
+ can: 24,
94609
+ em: 25,
94610
+ sub: 26,
94611
+ esc: 27,
94612
+ fs: 28,
94613
+ gs: 29,
94614
+ rs: 30,
94615
+ us: 31,
94616
+ space: 32,
94617
+ exclamationMark: 33, // `!`
94618
+ quotationMark: 34, // `"`
94619
+ numberSign: 35, // `#`
94620
+ dollarSign: 36, // `$`
94621
+ percentSign: 37, // `%`
94622
+ ampersand: 38, // `&`
94623
+ apostrophe: 39, // `'`
94624
+ leftParenthesis: 40, // `(`
94625
+ rightParenthesis: 41, // `)`
94626
+ asterisk: 42, // `*`
94627
+ plusSign: 43, // `+`
94628
+ comma: 44, // `,`
94629
+ dash: 45, // `-`
94630
+ dot: 46, // `.`
94631
+ slash: 47, // `/`
94632
+ digit0: 48, // `0`
94633
+ digit1: 49, // `1`
94634
+ digit2: 50, // `2`
94635
+ digit3: 51, // `3`
94636
+ digit4: 52, // `4`
94637
+ digit5: 53, // `5`
94638
+ digit6: 54, // `6`
94639
+ digit7: 55, // `7`
94640
+ digit8: 56, // `8`
94641
+ digit9: 57, // `9`
94642
+ colon: 58, // `:`
94643
+ semicolon: 59, // `;`
94644
+ lessThan: 60, // `<`
94645
+ equalsTo: 61, // `=`
94646
+ greaterThan: 62, // `>`
94647
+ questionMark: 63, // `?`
94648
+ atSign: 64, // `@`
94649
+ uppercaseA: 65, // `A`
94650
+ uppercaseB: 66, // `B`
94651
+ uppercaseC: 67, // `C`
94652
+ uppercaseD: 68, // `D`
94653
+ uppercaseE: 69, // `E`
94654
+ uppercaseF: 70, // `F`
94655
+ uppercaseG: 71, // `G`
94656
+ uppercaseH: 72, // `H`
94657
+ uppercaseI: 73, // `I`
94658
+ uppercaseJ: 74, // `J`
94659
+ uppercaseK: 75, // `K`
94660
+ uppercaseL: 76, // `L`
94661
+ uppercaseM: 77, // `M`
94662
+ uppercaseN: 78, // `N`
94663
+ uppercaseO: 79, // `O`
94664
+ uppercaseP: 80, // `P`
94665
+ uppercaseQ: 81, // `Q`
94666
+ uppercaseR: 82, // `R`
94667
+ uppercaseS: 83, // `S`
94668
+ uppercaseT: 84, // `T`
94669
+ uppercaseU: 85, // `U`
94670
+ uppercaseV: 86, // `V`
94671
+ uppercaseW: 87, // `W`
94672
+ uppercaseX: 88, // `X`
94673
+ uppercaseY: 89, // `Y`
94674
+ uppercaseZ: 90, // `Z`
94675
+ leftSquareBracket: 91, // `[`
94676
+ backslash: 92, // `\`
94677
+ rightSquareBracket: 93, // `]`
94678
+ caret: 94, // `^`
94679
+ underscore: 95, // `_`
94680
+ graveAccent: 96, // `` ` ``
94681
+ lowercaseA: 97, // `a`
94682
+ lowercaseB: 98, // `b`
94683
+ lowercaseC: 99, // `c`
94684
+ lowercaseD: 100, // `d`
94685
+ lowercaseE: 101, // `e`
94686
+ lowercaseF: 102, // `f`
94687
+ lowercaseG: 103, // `g`
94688
+ lowercaseH: 104, // `h`
94689
+ lowercaseI: 105, // `i`
94690
+ lowercaseJ: 106, // `j`
94691
+ lowercaseK: 107, // `k`
94692
+ lowercaseL: 108, // `l`
94693
+ lowercaseM: 109, // `m`
94694
+ lowercaseN: 110, // `n`
94695
+ lowercaseO: 111, // `o`
94696
+ lowercaseP: 112, // `p`
94697
+ lowercaseQ: 113, // `q`
94698
+ lowercaseR: 114, // `r`
94699
+ lowercaseS: 115, // `s`
94700
+ lowercaseT: 116, // `t`
94701
+ lowercaseU: 117, // `u`
94702
+ lowercaseV: 118, // `v`
94703
+ lowercaseW: 119, // `w`
94704
+ lowercaseX: 120, // `x`
94705
+ lowercaseY: 121, // `y`
94706
+ lowercaseZ: 122, // `z`
94707
+ leftCurlyBrace: 123, // `{`
94708
+ verticalBar: 124, // `|`
94709
+ rightCurlyBrace: 125, // `}`
94710
+ tilde: 126, // `~`
94711
+ del: 127,
94712
+ // Unicode Specials block.
94713
+ byteOrderMarker: 65_279,
94714
+ // Unicode Specials block.
94715
+ replacementCharacter: 65_533 // `�`
94716
+ })
94717
+
94718
+ ;// ./lib/micromark/legacy-variable/syntax.ts
94509
94719
 
94510
94720
 
94511
- function isHeading(node) {
94512
- return /^h[1-6]$/.test(node.tagName);
94721
+ function isAllowedValueChar(code) {
94722
+ return (code !== null &&
94723
+ code !== codes.lessThan &&
94724
+ code !== codes.greaterThan &&
94725
+ !markdownLineEnding(code));
94513
94726
  }
94514
- function textContent(node) {
94515
- if (node.type === 'text')
94516
- return node.value;
94517
- // Process variable nodes by using their variable name for the id generation
94518
- if (node.type === 'element' && node.tagName === 'variable' && node.properties?.name) {
94519
- if (node.properties.isLegacy) {
94520
- return node.properties.name;
94727
+ const legacyVariableConstruct = {
94728
+ name: 'legacyVariable',
94729
+ tokenize,
94730
+ };
94731
+ function tokenize(effects, ok, nok) {
94732
+ let hasValue = false;
94733
+ const start = (code) => {
94734
+ if (code !== codes.lessThan)
94735
+ return nok(code);
94736
+ effects.enter('legacyVariable');
94737
+ effects.enter('legacyVariableMarkerStart');
94738
+ effects.consume(code); // <
94739
+ return open2;
94740
+ };
94741
+ const open2 = (code) => {
94742
+ if (code !== codes.lessThan)
94743
+ return nok(code);
94744
+ effects.consume(code); // <<
94745
+ effects.exit('legacyVariableMarkerStart');
94746
+ effects.enter('legacyVariableValue');
94747
+ return value;
94748
+ };
94749
+ const value = (code) => {
94750
+ if (code === codes.greaterThan) {
94751
+ if (!hasValue)
94752
+ return nok(code);
94753
+ effects.exit('legacyVariableValue');
94754
+ effects.enter('legacyVariableMarkerEnd');
94755
+ effects.consume(code); // >
94756
+ return close2;
94521
94757
  }
94522
- return `user.${node.properties.name}`;
94523
- }
94524
- if ('children' in node)
94525
- return node.children.map(textContent).join('');
94526
- return '';
94758
+ if (!isAllowedValueChar(code))
94759
+ return nok(code);
94760
+ hasValue = true;
94761
+ effects.consume(code);
94762
+ return value;
94763
+ };
94764
+ const close2 = (code) => {
94765
+ if (code !== codes.greaterThan)
94766
+ return nok(code);
94767
+ effects.consume(code); // >>
94768
+ effects.exit('legacyVariableMarkerEnd');
94769
+ effects.exit('legacyVariable');
94770
+ return ok;
94771
+ };
94772
+ return start;
94773
+ }
94774
+ function legacyVariable() {
94775
+ return {
94776
+ text: { [codes.lessThan]: legacyVariableConstruct },
94777
+ };
94527
94778
  }
94528
- /**
94529
- * Rehype plugin that constructs ids for headings
94530
- * Id's are used to construct slug anchor links & Table of Contents during rendering
94531
- * Use the text / nodes that make up the heading to generate the id
94532
- */
94533
- const generateSlugForHeadings = () => (tree) => {
94534
- const slugger = new BananaSlug();
94535
- visit(tree, 'element', (node) => {
94536
- if (isHeading(node) && !node.properties.id) {
94537
- const text = node.children.map(textContent).join('');
94538
- node.properties.id = slugger.slug(text);
94539
- }
94540
- });
94541
- return tree;
94542
- };
94543
- /* harmony default export */ const heading_slugs = (generateSlugForHeadings);
94544
-
94545
- // EXTERNAL MODULE: external "@readme/variable"
94546
- var variable_ = __webpack_require__(8167);
94547
- var variable_default = /*#__PURE__*/__webpack_require__.n(variable_);
94548
- ;// ./node_modules/rehype-parse/lib/index.js
94549
- /**
94550
- * @import {Root} from 'hast'
94551
- * @import {Options as FromHtmlOptions} from 'hast-util-from-html'
94552
- * @import {Parser, Processor} from 'unified'
94553
- */
94554
-
94555
- /**
94556
- * @typedef {Omit<FromHtmlOptions, 'onerror'> & RehypeParseFields} Options
94557
- * Configuration.
94558
- *
94559
- * @typedef RehypeParseFields
94560
- * Extra fields.
94561
- * @property {boolean | null | undefined} [emitParseErrors=false]
94562
- * Whether to emit parse errors while parsing (default: `false`).
94563
- *
94564
- * > 👉 **Note**: parse errors are currently being added to HTML.
94565
- * > Not all errors emitted by parse5 (or us) are specced yet.
94566
- * > Some documentation may still be missing.
94567
- */
94568
-
94569
-
94570
94779
 
94780
+ ;// ./lib/micromark/legacy-variable/index.ts
94571
94781
  /**
94572
- * Plugin to add support for parsing from HTML.
94573
- *
94574
- * > 👉 **Note**: this is not an XML parser.
94575
- * > It supports SVG as embedded in HTML.
94576
- * > It does not support the features available in XML.
94577
- * > Passing SVG files might break but fragments of modern SVG should be fine.
94578
- * > Use [`xast-util-from-xml`][xast-util-from-xml] to parse XML.
94579
- *
94580
- * @param {Options | null | undefined} [options]
94581
- * Configuration (optional).
94582
- * @returns {undefined}
94583
- * Nothing.
94782
+ * Micromark extension for <<variable>> / <<glossary:term>> inline syntax.
94584
94783
  */
94585
- function rehypeParse(options) {
94586
- /** @type {Processor<Root>} */
94587
- // @ts-expect-error: TS in JSDoc generates wrong types if `this` is typed regularly.
94588
- const self = this
94589
- const {emitParseErrors, ...settings} = {...self.data('settings'), ...options}
94590
-
94591
- self.parser = parser
94592
-
94593
- /**
94594
- * @type {Parser<Root>}
94595
- */
94596
- function parser(document, file) {
94597
- return fromHtml(document, {
94598
- ...settings,
94599
- onerror: emitParseErrors
94600
- ? function (message) {
94601
- if (file.path) {
94602
- message.name = file.path + ':' + message.name
94603
- message.file = file.path
94604
- }
94605
94784
 
94606
- file.messages.push(message)
94607
- }
94608
- : undefined
94609
- })
94610
- }
94611
- }
94612
94785
 
94613
94786
  ;// ./node_modules/entities/lib/esm/generated/encode-html.js
94614
94787
  // Generated using scripts/write-encode-map.ts
@@ -94915,349 +95088,6 @@ function looseHtmlEntityFromMarkdown() {
94915
95088
  */
94916
95089
 
94917
95090
 
94918
- ;// ./processor/transform/mdxish/normalize-malformed-md-syntax.ts
94919
-
94920
- // Marker patterns for multi-node emphasis detection
94921
- const MARKER_PATTERNS = [
94922
- { isBold: true, marker: '**' },
94923
- { isBold: true, marker: '__' },
94924
- { isBold: false, marker: '*' },
94925
- { isBold: false, marker: '_' },
94926
- ];
94927
- // Patterns to detect for bold (** and __) and italic (* and _) syntax:
94928
- // Bold: ** text**, **text **, word** text**, ** text **
94929
- // Italic: * text*, *text *, word* text*, * text *
94930
- // Same patterns for underscore variants
94931
- // We use separate patterns for each marker type to allow this flexibility.
94932
- // Pattern for ** bold **
94933
- // Groups: 1=wordBefore, 2=marker, 3=contentWithSpaceAfter, 4=trailingSpace1, 5=contentWithSpaceBefore, 6=trailingSpace2, 7=afterChar
94934
- // trailingSpace1 is for "** text **" pattern, trailingSpace2 is for "**text **" pattern
94935
- const asteriskBoldRegex = /([^*\s]+)?\s*(\*\*)(?:\s+((?:[^*\n]|\*(?!\*))+?)(\s*)\2|((?:[^*\n]|\*(?!\*))+?)(\s+)\2)(\S|$)?/g;
94936
- // Pattern for __ bold __
94937
- const underscoreBoldRegex = /([^_\s]+)?\s*(__)(?:\s+((?:__(?! )|_(?!_)|[^_\n])+?)(\s*)\2|((?:__(?! )|_(?!_)|[^_\n])+?)(\s+)\2)(\S|$)?/g;
94938
- // Pattern for * italic *
94939
- const asteriskItalicRegex = /([^*\s]+)?\s*(\*)(?!\*)(?:\s+([^*\n]+?)(\s*)\2|([^*\n]+?)(\s+)\2)(\S|$)?/g;
94940
- // Pattern for _ italic _
94941
- const underscoreItalicRegex = /([^_\s]+)?\s*(_)(?!_)(?:\s+((?:[^_\n]|_(?! ))+?)(\s*)\2|((?:[^_\n]|_(?! ))+?)(\s+)\2)(\S|$)?/g;
94942
- // CommonMark ignores intraword underscores or asteriks, but we want to italicize/bold the inner part
94943
- // Pattern for intraword _word_ in words like hello_world_
94944
- const intrawordUnderscoreItalicRegex = /(\w)_(?!_)([a-zA-Z0-9]+)_(?![\w_])/g;
94945
- // Pattern for intraword __word__ in words like hello__world__
94946
- const intrawordUnderscoreBoldRegex = /(\w)__([a-zA-Z0-9]+)__(?![\w_])/g;
94947
- // Pattern for intraword *word* in words like hello*world*
94948
- const intrawordAsteriskItalicRegex = /(\w)\*(?!\*)([a-zA-Z0-9]+)\*(?![\w*])/g;
94949
- // Pattern for intraword **word** in words like hello**world**
94950
- const intrawordAsteriskBoldRegex = /(\w)\*\*([a-zA-Z0-9]+)\*\*(?![\w*])/g;
94951
- /**
94952
- * Finds opening emphasis marker in a text value.
94953
- * Returns marker info if found, null otherwise.
94954
- */
94955
- function findOpeningMarker(text) {
94956
- const results = MARKER_PATTERNS.map(({ isBold, marker }) => {
94957
- if (marker === '*' && text.startsWith('**'))
94958
- return null;
94959
- if (marker === '_' && text.startsWith('__'))
94960
- return null;
94961
- if (text.startsWith(marker) && text.length > marker.length) {
94962
- return { isBold, marker, textAfter: text.slice(marker.length), textBefore: '' };
94963
- }
94964
- const idx = text.indexOf(marker);
94965
- if (idx > 0 && !/\s/.test(text[idx - 1])) {
94966
- if (marker === '*' && text.slice(idx).startsWith('**'))
94967
- return null;
94968
- if (marker === '_' && text.slice(idx).startsWith('__'))
94969
- return null;
94970
- const after = text.slice(idx + marker.length);
94971
- if (after.length > 0) {
94972
- return { isBold, marker, textAfter: after, textBefore: text.slice(0, idx) };
94973
- }
94974
- }
94975
- return null;
94976
- });
94977
- return results.find(r => r !== null) ?? null;
94978
- }
94979
- /**
94980
- * Finds the end/closing marker in a text node for multi-node emphasis.
94981
- */
94982
- function findEndMarker(text, marker) {
94983
- const spacePattern = ` ${marker}`;
94984
- const spaceIdx = text.indexOf(spacePattern);
94985
- if (spaceIdx >= 0) {
94986
- if (marker === '*' && text.slice(spaceIdx + 1).startsWith('**'))
94987
- return null;
94988
- if (marker === '_' && text.slice(spaceIdx + 1).startsWith('__'))
94989
- return null;
94990
- return {
94991
- textAfter: text.slice(spaceIdx + spacePattern.length),
94992
- textBefore: text.slice(0, spaceIdx),
94993
- };
94994
- }
94995
- if (text.startsWith(marker)) {
94996
- if (marker === '*' && text.startsWith('**'))
94997
- return null;
94998
- if (marker === '_' && text.startsWith('__'))
94999
- return null;
95000
- return {
95001
- textAfter: text.slice(marker.length),
95002
- textBefore: '',
95003
- };
95004
- }
95005
- return null;
95006
- }
95007
- /**
95008
- * Scan children for an opening emphasis marker in a text node.
95009
- */
95010
- function findOpeningInChildren(children) {
95011
- let result = null;
95012
- children.some((child, idx) => {
95013
- if (child.type !== 'text')
95014
- return false;
95015
- const found = findOpeningMarker(child.value);
95016
- if (found) {
95017
- result = { idx, opening: found };
95018
- return true;
95019
- }
95020
- return false;
95021
- });
95022
- return result;
95023
- }
95024
- /**
95025
- * Scan children (after openingIdx) for a closing emphasis marker.
95026
- */
95027
- function findClosingInChildren(children, openingIdx, marker) {
95028
- let result = null;
95029
- children.slice(openingIdx + 1).some((child, relativeIdx) => {
95030
- if (child.type !== 'text')
95031
- return false;
95032
- const found = findEndMarker(child.value, marker);
95033
- if (found) {
95034
- result = { closingIdx: openingIdx + 1 + relativeIdx, closing: found };
95035
- return true;
95036
- }
95037
- return false;
95038
- });
95039
- return result;
95040
- }
95041
- /**
95042
- * Build the replacement nodes for a matched emphasis pair.
95043
- */
95044
- function buildReplacementNodes(container, { opening, openingIdx, closing, closingIdx }) {
95045
- const newNodes = [];
95046
- if (opening.textBefore) {
95047
- newNodes.push({ type: 'text', value: `${opening.textBefore} ` });
95048
- }
95049
- const emphasisChildren = [];
95050
- const openingText = opening.textAfter.replace(/^\s+/, '');
95051
- if (openingText) {
95052
- emphasisChildren.push({ type: 'text', value: openingText });
95053
- }
95054
- container.children.slice(openingIdx + 1, closingIdx).forEach(child => {
95055
- emphasisChildren.push(child);
95056
- });
95057
- const closingText = closing.textBefore.replace(/\s+$/, '');
95058
- if (closingText) {
95059
- emphasisChildren.push({ type: 'text', value: closingText });
95060
- }
95061
- if (emphasisChildren.length > 0) {
95062
- const emphasisNode = opening.isBold
95063
- ? { type: 'strong', children: emphasisChildren }
95064
- : { type: 'emphasis', children: emphasisChildren };
95065
- newNodes.push(emphasisNode);
95066
- }
95067
- if (closing.textAfter) {
95068
- newNodes.push({ type: 'text', value: closing.textAfter });
95069
- }
95070
- return newNodes;
95071
- }
95072
- /**
95073
- * Find and transform one multi-node emphasis pair in the container.
95074
- * Returns true if a pair was found and transformed, false otherwise.
95075
- */
95076
- function processOneEmphasisPair(container) {
95077
- const openingResult = findOpeningInChildren(container.children);
95078
- if (!openingResult)
95079
- return false;
95080
- const { idx: openingIdx, opening } = openingResult;
95081
- const closingResult = findClosingInChildren(container.children, openingIdx, opening.marker);
95082
- if (!closingResult)
95083
- return false;
95084
- const { closingIdx, closing } = closingResult;
95085
- const newNodes = buildReplacementNodes(container, { opening, openingIdx, closing, closingIdx });
95086
- const deleteCount = closingIdx - openingIdx + 1;
95087
- container.children.splice(openingIdx, deleteCount, ...newNodes);
95088
- return true;
95089
- }
95090
- /**
95091
- * Handle malformed emphasis that spans multiple AST nodes.
95092
- * E.g., "**bold [link](url)**" where markers are in different text nodes.
95093
- */
95094
- function visitMultiNodeEmphasis(tree) {
95095
- const containerTypes = ['paragraph', 'heading', 'tableCell', 'listItem', 'blockquote'];
95096
- visit(tree, node => {
95097
- if (!containerTypes.includes(node.type))
95098
- return;
95099
- if (!('children' in node) || !Array.isArray(node.children))
95100
- return;
95101
- const container = node;
95102
- let foundPair = true;
95103
- while (foundPair) {
95104
- foundPair = processOneEmphasisPair(container);
95105
- }
95106
- });
95107
- }
95108
- /**
95109
- * A remark plugin that normalizes malformed bold and italic markers in text nodes.
95110
- * Detects patterns like `** bold**`, `Hello** Wrong Bold**`, `__ bold__`, `Hello__ Wrong Bold__`,
95111
- * `* italic*`, `Hello* Wrong Italic*`, `_ italic_`, or `Hello_ Wrong Italic_`
95112
- * and converts them to proper strong/emphasis nodes, matching the behavior of the legacy rdmd engine.
95113
- *
95114
- * Supports both asterisk (`**bold**`, `*italic*`) and underscore (`__bold__`, `_italic_`) syntax.
95115
- * Also supports snake_case content like `** some_snake_case**`.
95116
- *
95117
- * This runs after remark-parse, which (in v11+) is strict and doesn't parse
95118
- * malformed emphasis syntax. This plugin post-processes the AST to handle these cases.
95119
- */
95120
- const normalizeEmphasisAST = () => (tree) => {
95121
- visit(tree, 'text', function visitor(node, index, parent) {
95122
- if (index === undefined || !parent)
95123
- return undefined;
95124
- // Skip if inside code blocks or inline code
95125
- if (parent.type === 'inlineCode' || parent.type === 'code') {
95126
- return undefined;
95127
- }
95128
- const text = node.value;
95129
- const allMatches = [];
95130
- [...text.matchAll(asteriskBoldRegex)].forEach(match => {
95131
- allMatches.push({ isBold: true, marker: '**', match });
95132
- });
95133
- [...text.matchAll(underscoreBoldRegex)].forEach(match => {
95134
- allMatches.push({ isBold: true, marker: '__', match });
95135
- });
95136
- [...text.matchAll(asteriskItalicRegex)].forEach(match => {
95137
- allMatches.push({ isBold: false, marker: '*', match });
95138
- });
95139
- [...text.matchAll(underscoreItalicRegex)].forEach(match => {
95140
- allMatches.push({ isBold: false, marker: '_', match });
95141
- });
95142
- [...text.matchAll(intrawordUnderscoreItalicRegex)].forEach(match => {
95143
- allMatches.push({ isBold: false, isIntraword: true, marker: '_', match });
95144
- });
95145
- [...text.matchAll(intrawordUnderscoreBoldRegex)].forEach(match => {
95146
- allMatches.push({ isBold: true, isIntraword: true, marker: '__', match });
95147
- });
95148
- [...text.matchAll(intrawordAsteriskItalicRegex)].forEach(match => {
95149
- allMatches.push({ isBold: false, isIntraword: true, marker: '*', match });
95150
- });
95151
- [...text.matchAll(intrawordAsteriskBoldRegex)].forEach(match => {
95152
- allMatches.push({ isBold: true, isIntraword: true, marker: '**', match });
95153
- });
95154
- if (allMatches.length === 0)
95155
- return undefined;
95156
- allMatches.sort((a, b) => (a.match.index ?? 0) - (b.match.index ?? 0));
95157
- const filteredMatches = [];
95158
- let lastEnd = 0;
95159
- allMatches.forEach(info => {
95160
- const start = info.match.index ?? 0;
95161
- const end = start + info.match[0].length;
95162
- if (start >= lastEnd) {
95163
- filteredMatches.push(info);
95164
- lastEnd = end;
95165
- }
95166
- });
95167
- if (filteredMatches.length === 0)
95168
- return undefined;
95169
- const parts = [];
95170
- let lastIndex = 0;
95171
- filteredMatches.forEach(({ isBold, isIntraword, marker, match }) => {
95172
- const matchIndex = match.index ?? 0;
95173
- const fullMatch = match[0];
95174
- if (isIntraword) {
95175
- // handles cases like hello_world_ where we only want to italicize 'world'
95176
- const charBefore = match[1] || ''; // e.g., "l" in "hello_world_"
95177
- const content = match[2]; // e.g., "world"
95178
- const combinedBefore = text.slice(lastIndex, matchIndex) + charBefore;
95179
- if (combinedBefore) {
95180
- parts.push({ type: 'text', value: combinedBefore });
95181
- }
95182
- if (isBold) {
95183
- parts.push({
95184
- type: 'strong',
95185
- children: [{ type: 'text', value: content }],
95186
- });
95187
- }
95188
- else {
95189
- parts.push({
95190
- type: 'emphasis',
95191
- children: [{ type: 'text', value: content }],
95192
- });
95193
- }
95194
- lastIndex = matchIndex + fullMatch.length;
95195
- return;
95196
- }
95197
- if (matchIndex > lastIndex) {
95198
- const beforeText = text.slice(lastIndex, matchIndex);
95199
- if (beforeText) {
95200
- parts.push({ type: 'text', value: beforeText });
95201
- }
95202
- }
95203
- const wordBefore = match[1]; // e.g., "Hello" in "Hello** Wrong Bold**"
95204
- const contentWithSpaceAfter = match[3]; // Content when there's a space after opening markers
95205
- const trailingSpace1 = match[4] || ''; // Space before closing markers (for "** text **" pattern)
95206
- const contentWithSpaceBefore = match[5]; // Content when there's only a space before closing markers
95207
- const trailingSpace2 = match[6] || ''; // Space before closing markers (for "**text **" pattern)
95208
- const trailingSpace = trailingSpace1 || trailingSpace2; // Combined trailing space
95209
- const content = (contentWithSpaceAfter || contentWithSpaceBefore || '').trim();
95210
- const afterChar = match[7]; // Character after closing markers (if any)
95211
- const markerPos = fullMatch.indexOf(marker);
95212
- const spacesBeforeMarkers = wordBefore
95213
- ? fullMatch.slice(wordBefore.length, markerPos)
95214
- : fullMatch.slice(0, markerPos);
95215
- const shouldAddSpace = !!contentWithSpaceAfter && !!wordBefore && !spacesBeforeMarkers;
95216
- if (wordBefore) {
95217
- const spacing = spacesBeforeMarkers + (shouldAddSpace ? ' ' : '');
95218
- parts.push({ type: 'text', value: wordBefore + spacing });
95219
- }
95220
- else if (spacesBeforeMarkers) {
95221
- parts.push({ type: 'text', value: spacesBeforeMarkers });
95222
- }
95223
- if (content) {
95224
- if (isBold) {
95225
- parts.push({
95226
- type: 'strong',
95227
- children: [{ type: 'text', value: content }],
95228
- });
95229
- }
95230
- else {
95231
- parts.push({
95232
- type: 'emphasis',
95233
- children: [{ type: 'text', value: content }],
95234
- });
95235
- }
95236
- }
95237
- if (afterChar) {
95238
- const prefix = trailingSpace ? ' ' : '';
95239
- parts.push({ type: 'text', value: prefix + afterChar });
95240
- }
95241
- lastIndex = matchIndex + fullMatch.length;
95242
- });
95243
- if (lastIndex < text.length) {
95244
- const remainingText = text.slice(lastIndex);
95245
- if (remainingText) {
95246
- parts.push({ type: 'text', value: remainingText });
95247
- }
95248
- }
95249
- if (parts.length > 0) {
95250
- parent.children.splice(index, 1, ...parts);
95251
- return [SKIP, index + parts.length];
95252
- }
95253
- return undefined;
95254
- });
95255
- // Handle malformed emphasis spanning multiple nodes (e.g., **text [link](url) **)
95256
- visitMultiNodeEmphasis(tree);
95257
- return tree;
95258
- };
95259
- /* harmony default export */ const normalize_malformed_md_syntax = (normalizeEmphasisAST);
95260
-
95261
95091
  ;// ./processor/transform/mdxish/magic-blocks/patterns.ts
95262
95092
  /** Matches HTML tags (open, close, self-closing) with optional attributes. */
95263
95093
  const HTML_TAG_RE = /<\/?([a-zA-Z][a-zA-Z0-9-]*)((?:[^>"']*(?:"[^"]*"|'[^']*'))*[^>"']*)>/g;
@@ -95875,6 +95705,336 @@ const magicBlockTransformer = (options = {}) => tree => {
95875
95705
  };
95876
95706
  /* harmony default export */ const magic_block_transformer = (magicBlockTransformer);
95877
95707
 
95708
+ ;// ./processor/transform/mdxish/constants.ts
95709
+ /**
95710
+ * Inline component tags handled by mdxish-inline-components.ts.
95711
+ * Also excluded from block-level handling in mdxish-component-blocks.ts.
95712
+ */
95713
+ const constants_INLINE_COMPONENT_TAGS = new Set(['Anchor']);
95714
+
95715
+ ;// ./processor/transform/mdxish/mdxish-component-blocks.ts
95716
+
95717
+
95718
+
95719
+
95720
+
95721
+
95722
+
95723
+ const pascalCaseTagPattern = /^<([A-Z][A-Za-z0-9_]*)([^>]*?)(\/?)>([\s\S]*)?$/;
95724
+ const tagAttributePattern = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*("[^"]*"|'[^']*'|[^\s"'>]+))?/g;
95725
+ /**
95726
+ * Maximum number of siblings to scan forward when looking for a closing tag
95727
+ * to avoid scanning too far and degrading performance
95728
+ */
95729
+ const MAX_LOOKAHEAD = 30;
95730
+ /**
95731
+ * Tags that have dedicated transformers and should NOT be handled by this plugin.
95732
+ * These components either have special parsing requirements that the generic component
95733
+ * block transformer cannot handle correctly, or are inline components that we don't
95734
+ * want to convert to mdxJsxFlowElement which is a block level element.
95735
+ */
95736
+ const EXCLUDED_TAGS = new Set(['HTMLBlock', 'Table', 'Glossary', ...constants_INLINE_COMPONENT_TAGS]);
95737
+ const inlineMdProcessor = unified()
95738
+ .data('micromarkExtensions', [legacyVariable()])
95739
+ .data('fromMarkdownExtensions', [legacyVariableFromMarkdown(), emptyTaskListItemFromMarkdown()])
95740
+ .use(remarkParse)
95741
+ .use(remarkGfm);
95742
+ const isClosingTag = (value, tag) => value.trim() === `</${tag}>`;
95743
+ /**
95744
+ * Parse markdown content into mdast children nodes.
95745
+ */
95746
+ const parseMdChildren = (value) => {
95747
+ const parsed = inlineMdProcessor.parse(value);
95748
+ return parsed.children || [];
95749
+ };
95750
+ /**
95751
+ * Convert raw attribute string into mdxJsxAttribute entries.
95752
+ * Handles both key-value attributes (theme="info") and boolean attributes (empty).
95753
+ */
95754
+ const parseAttributes = (raw) => {
95755
+ const attributes = [];
95756
+ const attrString = raw.trim();
95757
+ if (!attrString)
95758
+ return attributes;
95759
+ tagAttributePattern.lastIndex = 0;
95760
+ let match = tagAttributePattern.exec(attrString);
95761
+ while (match !== null) {
95762
+ const [, attrName, attrValue] = match;
95763
+ const value = attrValue ? attrValue.replace(/^['"]|['"]$/g, '') : null;
95764
+ attributes.push({ type: 'mdxJsxAttribute', name: attrName, value });
95765
+ match = tagAttributePattern.exec(attrString);
95766
+ }
95767
+ return attributes;
95768
+ };
95769
+ /**
95770
+ * Parse an HTML tag string into structured data.
95771
+ */
95772
+ const parseTag = (value) => {
95773
+ const match = value.match(pascalCaseTagPattern);
95774
+ if (!match)
95775
+ return null;
95776
+ const [, tag, attrString = '', selfClosing = '', contentAfterTag = ''] = match;
95777
+ return {
95778
+ tag,
95779
+ attributes: parseAttributes(attrString),
95780
+ selfClosing: !!selfClosing,
95781
+ contentAfterTag,
95782
+ };
95783
+ };
95784
+ /**
95785
+ * Parse substring content of a node and update the parent's children to include the new nodes.
95786
+ */
95787
+ const parseSibling = (stack, parent, index, sibling) => {
95788
+ const siblingNodes = parseMdChildren(sibling);
95789
+ // The new sibling nodes might contain new components to be processed
95790
+ if (siblingNodes.length > 0) {
95791
+ parent.children.splice(index + 1, 0, ...siblingNodes);
95792
+ stack.push(parent);
95793
+ }
95794
+ };
95795
+ /**
95796
+ * Create an MdxJsxFlowElement node from component data.
95797
+ */
95798
+ const createComponentNode = ({ tag, attributes, children, startPosition, endPosition }) => ({
95799
+ type: 'mdxJsxFlowElement',
95800
+ name: tag,
95801
+ attributes,
95802
+ children,
95803
+ position: {
95804
+ start: startPosition?.start,
95805
+ end: endPosition?.end ?? startPosition?.end,
95806
+ },
95807
+ });
95808
+ /**
95809
+ * Remove a closing tag from a paragraph's children and return the updated paragraph.
95810
+ */
95811
+ const stripClosingTagFromParagraph = (node, tag) => {
95812
+ if (!Array.isArray(node.children))
95813
+ return { paragraph: node, found: false };
95814
+ const children = [...node.children];
95815
+ const closingIndex = children.findIndex(child => child.type === 'html' && isClosingTag(child.value || '', tag));
95816
+ if (closingIndex === -1)
95817
+ return { paragraph: node, found: false };
95818
+ children.splice(closingIndex, 1);
95819
+ return { paragraph: { ...node, children }, found: true };
95820
+ };
95821
+ /**
95822
+ * Scan forward through siblings to find a closing tag.
95823
+ * Handles:
95824
+ * - Exact match HTML siblings (e.g., `</Tag>`)
95825
+ * - HTML siblings with embedded closing tag (e.g., `...\n</Tag>`)
95826
+ * - Paragraph siblings containing the closing tag as a child
95827
+ *
95828
+ * Returns null if not found within MAX_LOOKAHEAD siblings
95829
+ */
95830
+ const scanForClosingTag = (parent, startIndex, tag) => {
95831
+ const closingTagStr = `</${tag}>`;
95832
+ const maxIndex = Math.min(startIndex + MAX_LOOKAHEAD, parent.children.length);
95833
+ let i = startIndex + 1;
95834
+ for (; i < maxIndex; i += 1) {
95835
+ const sibling = parent.children[i];
95836
+ // Check HTML siblings
95837
+ if (sibling.type === 'html') {
95838
+ const siblingValue = sibling.value || '';
95839
+ // Exact match (standalone closing tag)
95840
+ if (isClosingTag(siblingValue, tag)) {
95841
+ return { closingIndex: i, extraClosingChildren: [] };
95842
+ }
95843
+ // Embedded closing tag (closing tag within HTML block content)
95844
+ if (siblingValue.includes(closingTagStr)) {
95845
+ const closeTagPos = siblingValue.indexOf(closingTagStr);
95846
+ const contentBeforeClose = siblingValue.substring(0, closeTagPos).trim();
95847
+ const contentAfterClose = siblingValue.substring(closeTagPos + closingTagStr.length).trim();
95848
+ const extraChildren = contentBeforeClose
95849
+ ? parseMdChildren(contentBeforeClose)
95850
+ : [];
95851
+ return { closingIndex: i, extraClosingChildren: extraChildren, contentAfterClose: contentAfterClose || undefined };
95852
+ }
95853
+ }
95854
+ // Check paragraph siblings
95855
+ if (sibling.type === 'paragraph') {
95856
+ const { paragraph, found } = stripClosingTagFromParagraph(sibling, tag);
95857
+ if (found) {
95858
+ return { closingIndex: i, extraClosingChildren: [], strippedParagraph: paragraph };
95859
+ }
95860
+ }
95861
+ }
95862
+ if (i < parent.children.length) {
95863
+ // eslint-disable-next-line no-console
95864
+ console.warn(`Closing tag </${tag}> not found within ${MAX_LOOKAHEAD} siblings, stopping scan`);
95865
+ }
95866
+ return null;
95867
+ };
95868
+ const substituteNodeWithMdxNode = (parent, index, mdxNode) => {
95869
+ parent.children.splice(index, 1, mdxNode);
95870
+ };
95871
+ /**
95872
+ * Transform PascalCase HTML nodes into mdxJsxFlowElement nodes.
95873
+ *
95874
+ * Remark parses unknown/custom component tags as raw HTML nodes.
95875
+ * These are the custom readme MDX syntax for components.
95876
+ * This transformer identifies these patterns and converts them to proper MDX JSX elements so they
95877
+ * can be accurately recognized and rendered later with their component definition code.
95878
+ * Though for some tags, we need to handle them specially
95879
+ *
95880
+ * ## Supported HTML Structures
95881
+ *
95882
+ * ### 1. Self-closing tags
95883
+ * ```
95884
+ * <Component />
95885
+ * ```
95886
+ * Parsed as: `html: "<Component />"`
95887
+ *
95888
+ * ### 2. Self-contained blocks (entire component in single HTML node)
95889
+ * ```
95890
+ * <Button>Click me</Button>
95891
+ * ```
95892
+ * ```
95893
+ * <Component>
95894
+ * <h2>Title</h2>
95895
+ * <p>Content</p>
95896
+ * </Component>
95897
+ * ```
95898
+ * Parsed as: `html: "<Component>\n <h2>Title</h2>\n <p>Content</p>\n</Component>"`
95899
+ * The opening tag, content, and closing tag are all captured in one HTML node.
95900
+ *
95901
+ * ### 3. Multi-sibling components (closing tag in a following sibling)
95902
+ * Handles various structures where the closing tag is in a later sibling, such as:
95903
+ *
95904
+ * #### 3a. Block components (closing tag in sibling paragraph)
95905
+ * ```
95906
+ * <Callout>
95907
+ * Some **markdown** content
95908
+ * </Callout>
95909
+ * ```
95910
+ *
95911
+ * #### 3b. Multi-paragraph components (closing tag several siblings away)
95912
+ * ```
95913
+ * <Callout>
95914
+ *
95915
+ * First paragraph
95916
+ *
95917
+ * Second paragraph
95918
+ * </Callout>
95919
+ * ```
95920
+ *
95921
+ * #### 3c. Nested components split by blank lines (closing tag embedded in HTML sibling)
95922
+ * ```
95923
+ * <Outer>
95924
+ * <Inner>content</Inner>
95925
+ *
95926
+ * <Inner>content</Inner>
95927
+ * </Outer>
95928
+ * ```
95929
+ */
95930
+ const mdxishComponentBlocks = () => tree => {
95931
+ const stack = [tree];
95932
+ const processChildNode = (parent, index) => {
95933
+ const node = parent.children[index];
95934
+ if (!node)
95935
+ return;
95936
+ if ('children' in node && Array.isArray(node.children)) {
95937
+ stack.push(node);
95938
+ }
95939
+ // Only visit HTML nodes with an actual html tag,
95940
+ // which means a potential unparsed MDX component
95941
+ const value = node.value;
95942
+ if (node.type !== 'html' || typeof value !== 'string')
95943
+ return;
95944
+ const parsed = parseTag(value.trim());
95945
+ if (!parsed)
95946
+ return;
95947
+ const { tag, attributes, selfClosing, contentAfterTag = '' } = parsed;
95948
+ // Skip tags that have dedicated transformers
95949
+ if (EXCLUDED_TAGS.has(tag))
95950
+ return;
95951
+ const closingTagStr = `</${tag}>`;
95952
+ // Case 1: Self-closing tag
95953
+ if (selfClosing) {
95954
+ const componentNode = createComponentNode({
95955
+ tag,
95956
+ attributes,
95957
+ children: [],
95958
+ startPosition: node.position,
95959
+ });
95960
+ substituteNodeWithMdxNode(parent, index, componentNode);
95961
+ // Check and parse if there's relevant content after the current closing tag
95962
+ const remainingContent = contentAfterTag.trim();
95963
+ if (remainingContent) {
95964
+ parseSibling(stack, parent, index, remainingContent);
95965
+ }
95966
+ return;
95967
+ }
95968
+ // Case 2: Self-contained block (closing tag in content)
95969
+ if (contentAfterTag.includes(closingTagStr)) {
95970
+ // Find the first closing tag
95971
+ const closingTagIndex = contentAfterTag.indexOf(closingTagStr);
95972
+ const componentInnerContent = contentAfterTag.substring(0, closingTagIndex).trim();
95973
+ const contentAfterClose = contentAfterTag.substring(closingTagIndex + closingTagStr.length).trim();
95974
+ const componentNode = createComponentNode({
95975
+ tag,
95976
+ attributes,
95977
+ children: componentInnerContent ? parseMdChildren(componentInnerContent) : [],
95978
+ startPosition: node.position,
95979
+ });
95980
+ substituteNodeWithMdxNode(parent, index, componentNode);
95981
+ // After the closing tag, there might be more content to be processed
95982
+ if (contentAfterClose) {
95983
+ parseSibling(stack, parent, index, contentAfterClose);
95984
+ }
95985
+ else if (componentNode.children.length > 0) {
95986
+ // The content inside the component block might contain new components to be processed
95987
+ stack.push(componentNode);
95988
+ }
95989
+ return;
95990
+ }
95991
+ // Case 3: Multi-sibling component (closing tag in a following sibling)
95992
+ // Scans forward through siblings to find closing tag in HTML or paragraph nodes
95993
+ const scanResult = scanForClosingTag(parent, index, tag);
95994
+ if (!scanResult)
95995
+ return;
95996
+ const { closingIndex, extraClosingChildren, strippedParagraph, contentAfterClose: remainingAfterClose } = scanResult;
95997
+ const extraChildren = contentAfterTag ? parseMdChildren(contentAfterTag.trimStart()) : [];
95998
+ // Collect all intermediate siblings between opening tag and closing tag
95999
+ const intermediateChildren = parent.children.slice(index + 1, closingIndex);
96000
+ // For paragraph siblings, include the full paragraph (with closing tag stripped)
96001
+ // For HTML siblings, include any content parsed from before the closing tag
96002
+ const closingChildren = strippedParagraph
96003
+ ? (strippedParagraph.children.length > 0 ? [strippedParagraph] : [])
96004
+ : extraClosingChildren;
96005
+ const componentNode = createComponentNode({
96006
+ tag,
96007
+ attributes,
96008
+ children: [...extraChildren, ...intermediateChildren, ...closingChildren],
96009
+ startPosition: node.position,
96010
+ endPosition: parent.children[closingIndex]?.position,
96011
+ });
96012
+ // Remove all nodes from opening tag to closing tag (inclusive) and replace with component node
96013
+ parent.children.splice(index, closingIndex - index + 1, componentNode);
96014
+ // Since we might be merging sibling nodes together and combining content,
96015
+ // there might be new components to process
96016
+ if (componentNode.children.length > 0) {
96017
+ stack.push(componentNode);
96018
+ }
96019
+ // If the closing tag sibling had content after it (e.g., another component opening tag),
96020
+ // re-insert it as a sibling so it can be processed in subsequent iterations
96021
+ if (remainingAfterClose) {
96022
+ parseSibling(stack, parent, index, remainingAfterClose);
96023
+ }
96024
+ };
96025
+ // Process the nodes with the components depth-first to maintain the correct order of the nodes
96026
+ while (stack.length) {
96027
+ const parent = stack.pop();
96028
+ if (parent?.children) {
96029
+ parent.children.forEach((_child, index) => {
96030
+ processChildNode(parent, index);
96031
+ });
96032
+ }
96033
+ }
96034
+ return tree;
96035
+ };
96036
+ /* harmony default export */ const mdxish_component_blocks = (mdxishComponentBlocks);
96037
+
95878
96038
  ;// ./processor/transform/mdxish/mdxish-html-blocks.ts
95879
96039
 
95880
96040
 
@@ -96210,10 +96370,82 @@ const mdxishHtmlBlocks = () => tree => {
96210
96370
  };
96211
96371
  /* harmony default export */ const mdxish_html_blocks = (mdxishHtmlBlocks);
96212
96372
 
96373
+ ;// ./processor/transform/mdxish/mdxish-inline-components.ts
96374
+
96375
+
96376
+
96377
+ // Matches any PascalCase inline component opening tag. Groups: (name, attrs).
96378
+ // Uses [A-Za-z0-9_]* to match block version in mdxish-component-blocks.ts
96379
+ const INLINE_COMPONENT_OPEN_RE = /^<([A-Z][A-Za-z0-9_]*)(\s[^>]*)?>$/;
96380
+ function toMdxJsxTextElement(name, attributes, children) {
96381
+ return {
96382
+ type: 'mdxJsxTextElement',
96383
+ name,
96384
+ attributes,
96385
+ children,
96386
+ };
96387
+ }
96388
+ /**
96389
+ * Transforms inline html component nodes (e.g. <Anchor>) into proper MDAST phrasing content.
96390
+ *
96391
+ * Inline components are excluded from mdxishComponentBlocks (which only handles block-level
96392
+ * elements), so they remain as scattered html/text/html sibling nodes inside a paragraph.
96393
+ * This plugin merges them into a single typed MDAST node.
96394
+ */
96395
+ const mdxishInlineComponents = () => tree => {
96396
+ visit(tree, 'html', (node, index, parent) => {
96397
+ if (!parent || index === undefined)
96398
+ return;
96399
+ const match = node.value?.match(INLINE_COMPONENT_OPEN_RE);
96400
+ if (!match)
96401
+ return;
96402
+ const [, name, attrStr] = match;
96403
+ if (!constants_INLINE_COMPONENT_TAGS.has(name))
96404
+ return;
96405
+ // Parse attributes directly - preserves all attribute types (strings, booleans, objects, arrays)
96406
+ const attributes = parseAttributes(attrStr ?? '');
96407
+ // Find closing tag with whitespace-tolerant matching
96408
+ let closeIdx = index + 1;
96409
+ while (closeIdx < parent.children.length) {
96410
+ const sib = parent.children[closeIdx];
96411
+ if (sib.type === 'html' && sib.value?.trim() === `</${name}>`)
96412
+ break;
96413
+ closeIdx += 1;
96414
+ }
96415
+ if (closeIdx >= parent.children.length)
96416
+ return;
96417
+ // Extract all nodes between opening tag (index) and closing tag (closeIdx).
96418
+ // These are the inline component's children (e.g., text, emphasis, links).
96419
+ // Example: "<Anchor>click **here**</Anchor>" → children = [text, strong]
96420
+ const children = parent.children.slice(index + 1, closeIdx);
96421
+ const newNode = toMdxJsxTextElement(name, attributes, children);
96422
+ parent.children.splice(index, closeIdx - index + 1, newNode);
96423
+ });
96424
+ };
96425
+ /* harmony default export */ const mdxish_inline_components = (mdxishInlineComponents);
96426
+
96213
96427
  ;// ./processor/transform/mdxish/mdxish-jsx-to-mdast.ts
96214
96428
 
96215
96429
 
96216
96430
 
96431
+ const transformAnchor = (jsx) => {
96432
+ const attrs = getAttrs(jsx);
96433
+ const { href = '', label, target, title } = attrs;
96434
+ return {
96435
+ type: NodeTypes.anchor,
96436
+ children: jsx.children,
96437
+ data: {
96438
+ hName: 'Anchor',
96439
+ hProperties: {
96440
+ href,
96441
+ ...(label && { label }),
96442
+ ...(target && { target }),
96443
+ ...(title && { title }),
96444
+ },
96445
+ },
96446
+ position: jsx.position,
96447
+ };
96448
+ };
96217
96449
  const transformImage = (jsx) => {
96218
96450
  const attrs = getAttrs(jsx);
96219
96451
  const { align, alt = '', border, caption, className, height, lazy, src = '', title = '', width } = attrs;
@@ -96267,7 +96499,7 @@ const transformCallout = (jsx) => {
96267
96499
  };
96268
96500
  const transformEmbed = (jsx) => {
96269
96501
  const attrs = getAttrs(jsx);
96270
- const { favicon, html, iframe, image, providerName, providerUrl, title = '', url = '' } = attrs;
96502
+ const { favicon, height, html, iframe, image, providerName, providerUrl, title = '', typeOfEmbed, url = '', width } = attrs;
96271
96503
  return {
96272
96504
  type: NodeTypes.embedBlock,
96273
96505
  title,
@@ -96278,11 +96510,14 @@ const transformEmbed = (jsx) => {
96278
96510
  title,
96279
96511
  url,
96280
96512
  ...(favicon && { favicon }),
96513
+ ...(height && { height }),
96281
96514
  ...(html && { html }),
96282
96515
  ...(iframe !== undefined && { iframe }),
96283
96516
  ...(image && { image }),
96284
96517
  ...(providerName && { providerName }),
96285
96518
  ...(providerUrl && { providerUrl }),
96519
+ ...(typeOfEmbed && { typeOfEmbed }),
96520
+ ...(width && { width }),
96286
96521
  },
96287
96522
  },
96288
96523
  position: jsx.position,
@@ -96378,7 +96613,7 @@ const COMPONENT_MAP = {
96378
96613
  * This is controlled by the `newEditorTypes` flag to maintain backwards compatibility.
96379
96614
  */
96380
96615
  const mdxishJsxToMdast = () => tree => {
96381
- // Transform JSX components (Image, Callout, Embed, Recipe)
96616
+ // Block JSX components (Image, Callout, Embed, Recipe)
96382
96617
  visit(tree, 'mdxJsxFlowElement', (node, index, parent) => {
96383
96618
  if (!parent || index === undefined || !node.name)
96384
96619
  return;
@@ -96389,6 +96624,15 @@ const mdxishJsxToMdast = () => tree => {
96389
96624
  // Replace the JSX node with the MDAST node
96390
96625
  parent.children[index] = newNode;
96391
96626
  });
96627
+ // Inline JSX components (Anchor)
96628
+ visit(tree, 'mdxJsxTextElement', (node, index, parent) => {
96629
+ if (!parent || index === undefined || !node.name)
96630
+ return;
96631
+ if (node.name === 'Anchor') {
96632
+ const newNode = transformAnchor(node);
96633
+ parent.children[index] = newNode;
96634
+ }
96635
+ });
96392
96636
  // Transform magic block images (type: 'image') to image-block
96393
96637
  // Note: Standard markdown images are wrapped in paragraphs and handled by imageTransformer
96394
96638
  // Magic block images are direct children of root, so we handle them here
@@ -96457,12 +96701,6 @@ const mdxishMermaidTransformer = () => (tree) => {
96457
96701
  };
96458
96702
  /* harmony default export */ const mdxish_mermaid = (mdxishMermaidTransformer);
96459
96703
 
96460
- ;// ./lib/constants.ts
96461
- /**
96462
- * Pattern to match component tags (PascalCase or snake_case)
96463
- */
96464
- const componentTagPattern = /<(\/?[A-Z][A-Za-z0-9_]*)([^>]*?)(\/?)>/g;
96465
-
96466
96704
  ;// ./processor/transform/mdxish/mdxish-snake-case-components.ts
96467
96705
 
96468
96706
 
@@ -96898,6 +97136,49 @@ const variablesTextTransformer = () => tree => {
96898
97136
  };
96899
97137
  /* harmony default export */ const variables_text = (variablesTextTransformer);
96900
97138
 
97139
+ ;// ./lib/mdast-util/jsx-table/index.ts
97140
+ const jsx_table_contextMap = new WeakMap();
97141
+ function findJsxTableToken() {
97142
+ const events = this.tokenStack;
97143
+ for (let i = events.length - 1; i >= 0; i -= 1) {
97144
+ if (events[i][0].type === 'jsxTable')
97145
+ return events[i][0];
97146
+ }
97147
+ return undefined;
97148
+ }
97149
+ function enterJsxTable(token) {
97150
+ jsx_table_contextMap.set(token, { chunks: [] });
97151
+ this.enter({ type: 'html', value: '' }, token);
97152
+ }
97153
+ function exitJsxTableData(token) {
97154
+ const tableToken = findJsxTableToken.call(this);
97155
+ if (!tableToken)
97156
+ return;
97157
+ const ctx = jsx_table_contextMap.get(tableToken);
97158
+ if (ctx)
97159
+ ctx.chunks.push(this.sliceSerialize(token));
97160
+ }
97161
+ function exitJsxTable(token) {
97162
+ const ctx = jsx_table_contextMap.get(token);
97163
+ const node = this.stack[this.stack.length - 1];
97164
+ if (ctx) {
97165
+ node.value = ctx.chunks.join('\n');
97166
+ jsx_table_contextMap.delete(token);
97167
+ }
97168
+ this.exit(token);
97169
+ }
97170
+ function jsxTableFromMarkdown() {
97171
+ return {
97172
+ enter: {
97173
+ jsxTable: enterJsxTable,
97174
+ },
97175
+ exit: {
97176
+ jsxTableData: exitJsxTableData,
97177
+ jsxTable: exitJsxTable,
97178
+ },
97179
+ };
97180
+ }
97181
+
96901
97182
  ;// ./lib/mdast-util/magic-block/index.ts
96902
97183
  const magic_block_contextMap = new WeakMap();
96903
97184
  /**
@@ -97054,6 +97335,685 @@ function magicBlockToMarkdown() {
97054
97335
  };
97055
97336
  }
97056
97337
 
97338
+ ;// ./node_modules/micromark-util-symbol/lib/types.js
97339
+ /**
97340
+ * This module is compiled away!
97341
+ *
97342
+ * Here is the list of all types of tokens exposed by micromark, with a short
97343
+ * explanation of what they include and where they are found.
97344
+ * In picking names, generally, the rule is to be as explicit as possible
97345
+ * instead of reusing names.
97346
+ * For example, there is a `definitionDestination` and a `resourceDestination`,
97347
+ * instead of one shared name.
97348
+ */
97349
+
97350
+ // Note: when changing the next record, you must also change `TokenTypeMap`
97351
+ // in `micromark-util-types/index.d.ts`.
97352
+ const types_types = /** @type {const} */ ({
97353
+ // Generic type for data, such as in a title, a destination, etc.
97354
+ data: 'data',
97355
+
97356
+ // Generic type for syntactic whitespace (tabs, virtual spaces, spaces).
97357
+ // Such as, between a fenced code fence and an info string.
97358
+ whitespace: 'whitespace',
97359
+
97360
+ // Generic type for line endings (line feed, carriage return, carriage return +
97361
+ // line feed).
97362
+ lineEnding: 'lineEnding',
97363
+
97364
+ // A line ending, but ending a blank line.
97365
+ lineEndingBlank: 'lineEndingBlank',
97366
+
97367
+ // Generic type for whitespace (tabs, virtual spaces, spaces) at the start of a
97368
+ // line.
97369
+ linePrefix: 'linePrefix',
97370
+
97371
+ // Generic type for whitespace (tabs, virtual spaces, spaces) at the end of a
97372
+ // line.
97373
+ lineSuffix: 'lineSuffix',
97374
+
97375
+ // Whole ATX heading:
97376
+ //
97377
+ // ```markdown
97378
+ // #
97379
+ // ## Alpha
97380
+ // ### Bravo ###
97381
+ // ```
97382
+ //
97383
+ // Includes `atxHeadingSequence`, `whitespace`, `atxHeadingText`.
97384
+ atxHeading: 'atxHeading',
97385
+
97386
+ // Sequence of number signs in an ATX heading (`###`).
97387
+ atxHeadingSequence: 'atxHeadingSequence',
97388
+
97389
+ // Content in an ATX heading (`alpha`).
97390
+ // Includes text.
97391
+ atxHeadingText: 'atxHeadingText',
97392
+
97393
+ // Whole autolink (`<https://example.com>` or `<admin@example.com>`)
97394
+ // Includes `autolinkMarker` and `autolinkProtocol` or `autolinkEmail`.
97395
+ autolink: 'autolink',
97396
+
97397
+ // Email autolink w/o markers (`admin@example.com`)
97398
+ autolinkEmail: 'autolinkEmail',
97399
+
97400
+ // Marker around an `autolinkProtocol` or `autolinkEmail` (`<` or `>`).
97401
+ autolinkMarker: 'autolinkMarker',
97402
+
97403
+ // Protocol autolink w/o markers (`https://example.com`)
97404
+ autolinkProtocol: 'autolinkProtocol',
97405
+
97406
+ // A whole character escape (`\-`).
97407
+ // Includes `escapeMarker` and `characterEscapeValue`.
97408
+ characterEscape: 'characterEscape',
97409
+
97410
+ // The escaped character (`-`).
97411
+ characterEscapeValue: 'characterEscapeValue',
97412
+
97413
+ // A whole character reference (`&amp;`, `&#8800;`, or `&#x1D306;`).
97414
+ // Includes `characterReferenceMarker`, an optional
97415
+ // `characterReferenceMarkerNumeric`, in which case an optional
97416
+ // `characterReferenceMarkerHexadecimal`, and a `characterReferenceValue`.
97417
+ characterReference: 'characterReference',
97418
+
97419
+ // The start or end marker (`&` or `;`).
97420
+ characterReferenceMarker: 'characterReferenceMarker',
97421
+
97422
+ // Mark reference as numeric (`#`).
97423
+ characterReferenceMarkerNumeric: 'characterReferenceMarkerNumeric',
97424
+
97425
+ // Mark reference as numeric (`x` or `X`).
97426
+ characterReferenceMarkerHexadecimal: 'characterReferenceMarkerHexadecimal',
97427
+
97428
+ // Value of character reference w/o markers (`amp`, `8800`, or `1D306`).
97429
+ characterReferenceValue: 'characterReferenceValue',
97430
+
97431
+ // Whole fenced code:
97432
+ //
97433
+ // ````markdown
97434
+ // ```js
97435
+ // alert(1)
97436
+ // ```
97437
+ // ````
97438
+ codeFenced: 'codeFenced',
97439
+
97440
+ // A fenced code fence, including whitespace, sequence, info, and meta
97441
+ // (` ```js `).
97442
+ codeFencedFence: 'codeFencedFence',
97443
+
97444
+ // Sequence of grave accent or tilde characters (` ``` `) in a fence.
97445
+ codeFencedFenceSequence: 'codeFencedFenceSequence',
97446
+
97447
+ // Info word (`js`) in a fence.
97448
+ // Includes string.
97449
+ codeFencedFenceInfo: 'codeFencedFenceInfo',
97450
+
97451
+ // Meta words (`highlight="1"`) in a fence.
97452
+ // Includes string.
97453
+ codeFencedFenceMeta: 'codeFencedFenceMeta',
97454
+
97455
+ // A line of code.
97456
+ codeFlowValue: 'codeFlowValue',
97457
+
97458
+ // Whole indented code:
97459
+ //
97460
+ // ```markdown
97461
+ // alert(1)
97462
+ // ```
97463
+ //
97464
+ // Includes `lineEnding`, `linePrefix`, and `codeFlowValue`.
97465
+ codeIndented: 'codeIndented',
97466
+
97467
+ // A text code (``` `alpha` ```).
97468
+ // Includes `codeTextSequence`, `codeTextData`, `lineEnding`, and can include
97469
+ // `codeTextPadding`.
97470
+ codeText: 'codeText',
97471
+
97472
+ codeTextData: 'codeTextData',
97473
+
97474
+ // A space or line ending right after or before a tick.
97475
+ codeTextPadding: 'codeTextPadding',
97476
+
97477
+ // A text code fence (` `` `).
97478
+ codeTextSequence: 'codeTextSequence',
97479
+
97480
+ // Whole content:
97481
+ //
97482
+ // ```markdown
97483
+ // [a]: b
97484
+ // c
97485
+ // =
97486
+ // d
97487
+ // ```
97488
+ //
97489
+ // Includes `paragraph` and `definition`.
97490
+ content: 'content',
97491
+ // Whole definition:
97492
+ //
97493
+ // ```markdown
97494
+ // [micromark]: https://github.com/micromark/micromark
97495
+ // ```
97496
+ //
97497
+ // Includes `definitionLabel`, `definitionMarker`, `whitespace`,
97498
+ // `definitionDestination`, and optionally `lineEnding` and `definitionTitle`.
97499
+ definition: 'definition',
97500
+
97501
+ // Destination of a definition (`https://github.com/micromark/micromark` or
97502
+ // `<https://github.com/micromark/micromark>`).
97503
+ // Includes `definitionDestinationLiteral` or `definitionDestinationRaw`.
97504
+ definitionDestination: 'definitionDestination',
97505
+
97506
+ // Enclosed destination of a definition
97507
+ // (`<https://github.com/micromark/micromark>`).
97508
+ // Includes `definitionDestinationLiteralMarker` and optionally
97509
+ // `definitionDestinationString`.
97510
+ definitionDestinationLiteral: 'definitionDestinationLiteral',
97511
+
97512
+ // Markers of an enclosed definition destination (`<` or `>`).
97513
+ definitionDestinationLiteralMarker: 'definitionDestinationLiteralMarker',
97514
+
97515
+ // Unenclosed destination of a definition
97516
+ // (`https://github.com/micromark/micromark`).
97517
+ // Includes `definitionDestinationString`.
97518
+ definitionDestinationRaw: 'definitionDestinationRaw',
97519
+
97520
+ // Text in an destination (`https://github.com/micromark/micromark`).
97521
+ // Includes string.
97522
+ definitionDestinationString: 'definitionDestinationString',
97523
+
97524
+ // Label of a definition (`[micromark]`).
97525
+ // Includes `definitionLabelMarker` and `definitionLabelString`.
97526
+ definitionLabel: 'definitionLabel',
97527
+
97528
+ // Markers of a definition label (`[` or `]`).
97529
+ definitionLabelMarker: 'definitionLabelMarker',
97530
+
97531
+ // Value of a definition label (`micromark`).
97532
+ // Includes string.
97533
+ definitionLabelString: 'definitionLabelString',
97534
+
97535
+ // Marker between a label and a destination (`:`).
97536
+ definitionMarker: 'definitionMarker',
97537
+
97538
+ // Title of a definition (`"x"`, `'y'`, or `(z)`).
97539
+ // Includes `definitionTitleMarker` and optionally `definitionTitleString`.
97540
+ definitionTitle: 'definitionTitle',
97541
+
97542
+ // Marker around a title of a definition (`"`, `'`, `(`, or `)`).
97543
+ definitionTitleMarker: 'definitionTitleMarker',
97544
+
97545
+ // Data without markers in a title (`z`).
97546
+ // Includes string.
97547
+ definitionTitleString: 'definitionTitleString',
97548
+
97549
+ // Emphasis (`*alpha*`).
97550
+ // Includes `emphasisSequence` and `emphasisText`.
97551
+ emphasis: 'emphasis',
97552
+
97553
+ // Sequence of emphasis markers (`*` or `_`).
97554
+ emphasisSequence: 'emphasisSequence',
97555
+
97556
+ // Emphasis text (`alpha`).
97557
+ // Includes text.
97558
+ emphasisText: 'emphasisText',
97559
+
97560
+ // The character escape marker (`\`).
97561
+ escapeMarker: 'escapeMarker',
97562
+
97563
+ // A hard break created with a backslash (`\\n`).
97564
+ // Note: does not include the line ending.
97565
+ hardBreakEscape: 'hardBreakEscape',
97566
+
97567
+ // A hard break created with trailing spaces (` \n`).
97568
+ // Does not include the line ending.
97569
+ hardBreakTrailing: 'hardBreakTrailing',
97570
+
97571
+ // Flow HTML:
97572
+ //
97573
+ // ```markdown
97574
+ // <div
97575
+ // ```
97576
+ //
97577
+ // Inlcudes `lineEnding`, `htmlFlowData`.
97578
+ htmlFlow: 'htmlFlow',
97579
+
97580
+ htmlFlowData: 'htmlFlowData',
97581
+
97582
+ // HTML in text (the tag in `a <i> b`).
97583
+ // Includes `lineEnding`, `htmlTextData`.
97584
+ htmlText: 'htmlText',
97585
+
97586
+ htmlTextData: 'htmlTextData',
97587
+
97588
+ // Whole image (`![alpha](bravo)`, `![alpha][bravo]`, `![alpha][]`, or
97589
+ // `![alpha]`).
97590
+ // Includes `label` and an optional `resource` or `reference`.
97591
+ image: 'image',
97592
+
97593
+ // Whole link label (`[*alpha*]`).
97594
+ // Includes `labelLink` or `labelImage`, `labelText`, and `labelEnd`.
97595
+ label: 'label',
97596
+
97597
+ // Text in an label (`*alpha*`).
97598
+ // Includes text.
97599
+ labelText: 'labelText',
97600
+
97601
+ // Start a link label (`[`).
97602
+ // Includes a `labelMarker`.
97603
+ labelLink: 'labelLink',
97604
+
97605
+ // Start an image label (`![`).
97606
+ // Includes `labelImageMarker` and `labelMarker`.
97607
+ labelImage: 'labelImage',
97608
+
97609
+ // Marker of a label (`[` or `]`).
97610
+ labelMarker: 'labelMarker',
97611
+
97612
+ // Marker to start an image (`!`).
97613
+ labelImageMarker: 'labelImageMarker',
97614
+
97615
+ // End a label (`]`).
97616
+ // Includes `labelMarker`.
97617
+ labelEnd: 'labelEnd',
97618
+
97619
+ // Whole link (`[alpha](bravo)`, `[alpha][bravo]`, `[alpha][]`, or `[alpha]`).
97620
+ // Includes `label` and an optional `resource` or `reference`.
97621
+ link: 'link',
97622
+
97623
+ // Whole paragraph:
97624
+ //
97625
+ // ```markdown
97626
+ // alpha
97627
+ // bravo.
97628
+ // ```
97629
+ //
97630
+ // Includes text.
97631
+ paragraph: 'paragraph',
97632
+
97633
+ // A reference (`[alpha]` or `[]`).
97634
+ // Includes `referenceMarker` and an optional `referenceString`.
97635
+ reference: 'reference',
97636
+
97637
+ // A reference marker (`[` or `]`).
97638
+ referenceMarker: 'referenceMarker',
97639
+
97640
+ // Reference text (`alpha`).
97641
+ // Includes string.
97642
+ referenceString: 'referenceString',
97643
+
97644
+ // A resource (`(https://example.com "alpha")`).
97645
+ // Includes `resourceMarker`, an optional `resourceDestination` with an optional
97646
+ // `whitespace` and `resourceTitle`.
97647
+ resource: 'resource',
97648
+
97649
+ // A resource destination (`https://example.com`).
97650
+ // Includes `resourceDestinationLiteral` or `resourceDestinationRaw`.
97651
+ resourceDestination: 'resourceDestination',
97652
+
97653
+ // A literal resource destination (`<https://example.com>`).
97654
+ // Includes `resourceDestinationLiteralMarker` and optionally
97655
+ // `resourceDestinationString`.
97656
+ resourceDestinationLiteral: 'resourceDestinationLiteral',
97657
+
97658
+ // A resource destination marker (`<` or `>`).
97659
+ resourceDestinationLiteralMarker: 'resourceDestinationLiteralMarker',
97660
+
97661
+ // A raw resource destination (`https://example.com`).
97662
+ // Includes `resourceDestinationString`.
97663
+ resourceDestinationRaw: 'resourceDestinationRaw',
97664
+
97665
+ // Resource destination text (`https://example.com`).
97666
+ // Includes string.
97667
+ resourceDestinationString: 'resourceDestinationString',
97668
+
97669
+ // A resource marker (`(` or `)`).
97670
+ resourceMarker: 'resourceMarker',
97671
+
97672
+ // A resource title (`"alpha"`, `'alpha'`, or `(alpha)`).
97673
+ // Includes `resourceTitleMarker` and optionally `resourceTitleString`.
97674
+ resourceTitle: 'resourceTitle',
97675
+
97676
+ // A resource title marker (`"`, `'`, `(`, or `)`).
97677
+ resourceTitleMarker: 'resourceTitleMarker',
97678
+
97679
+ // Resource destination title (`alpha`).
97680
+ // Includes string.
97681
+ resourceTitleString: 'resourceTitleString',
97682
+
97683
+ // Whole setext heading:
97684
+ //
97685
+ // ```markdown
97686
+ // alpha
97687
+ // bravo
97688
+ // =====
97689
+ // ```
97690
+ //
97691
+ // Includes `setextHeadingText`, `lineEnding`, `linePrefix`, and
97692
+ // `setextHeadingLine`.
97693
+ setextHeading: 'setextHeading',
97694
+
97695
+ // Content in a setext heading (`alpha\nbravo`).
97696
+ // Includes text.
97697
+ setextHeadingText: 'setextHeadingText',
97698
+
97699
+ // Underline in a setext heading, including whitespace suffix (`==`).
97700
+ // Includes `setextHeadingLineSequence`.
97701
+ setextHeadingLine: 'setextHeadingLine',
97702
+
97703
+ // Sequence of equals or dash characters in underline in a setext heading (`-`).
97704
+ setextHeadingLineSequence: 'setextHeadingLineSequence',
97705
+
97706
+ // Strong (`**alpha**`).
97707
+ // Includes `strongSequence` and `strongText`.
97708
+ strong: 'strong',
97709
+
97710
+ // Sequence of strong markers (`**` or `__`).
97711
+ strongSequence: 'strongSequence',
97712
+
97713
+ // Strong text (`alpha`).
97714
+ // Includes text.
97715
+ strongText: 'strongText',
97716
+
97717
+ // Whole thematic break:
97718
+ //
97719
+ // ```markdown
97720
+ // * * *
97721
+ // ```
97722
+ //
97723
+ // Includes `thematicBreakSequence` and `whitespace`.
97724
+ thematicBreak: 'thematicBreak',
97725
+
97726
+ // A sequence of one or more thematic break markers (`***`).
97727
+ thematicBreakSequence: 'thematicBreakSequence',
97728
+
97729
+ // Whole block quote:
97730
+ //
97731
+ // ```markdown
97732
+ // > a
97733
+ // >
97734
+ // > b
97735
+ // ```
97736
+ //
97737
+ // Includes `blockQuotePrefix` and flow.
97738
+ blockQuote: 'blockQuote',
97739
+ // The `>` or `> ` of a block quote.
97740
+ blockQuotePrefix: 'blockQuotePrefix',
97741
+ // The `>` of a block quote prefix.
97742
+ blockQuoteMarker: 'blockQuoteMarker',
97743
+ // The optional ` ` of a block quote prefix.
97744
+ blockQuotePrefixWhitespace: 'blockQuotePrefixWhitespace',
97745
+
97746
+ // Whole ordered list:
97747
+ //
97748
+ // ```markdown
97749
+ // 1. a
97750
+ // b
97751
+ // ```
97752
+ //
97753
+ // Includes `listItemPrefix`, flow, and optionally `listItemIndent` on further
97754
+ // lines.
97755
+ listOrdered: 'listOrdered',
97756
+
97757
+ // Whole unordered list:
97758
+ //
97759
+ // ```markdown
97760
+ // - a
97761
+ // b
97762
+ // ```
97763
+ //
97764
+ // Includes `listItemPrefix`, flow, and optionally `listItemIndent` on further
97765
+ // lines.
97766
+ listUnordered: 'listUnordered',
97767
+
97768
+ // The indent of further list item lines.
97769
+ listItemIndent: 'listItemIndent',
97770
+
97771
+ // A marker, as in, `*`, `+`, `-`, `.`, or `)`.
97772
+ listItemMarker: 'listItemMarker',
97773
+
97774
+ // The thing that starts a list item, such as `1. `.
97775
+ // Includes `listItemValue` if ordered, `listItemMarker`, and
97776
+ // `listItemPrefixWhitespace` (unless followed by a line ending).
97777
+ listItemPrefix: 'listItemPrefix',
97778
+
97779
+ // The whitespace after a marker.
97780
+ listItemPrefixWhitespace: 'listItemPrefixWhitespace',
97781
+
97782
+ // The numerical value of an ordered item.
97783
+ listItemValue: 'listItemValue',
97784
+
97785
+ // Internal types used for subtokenizers, compiled away
97786
+ chunkDocument: 'chunkDocument',
97787
+ chunkContent: 'chunkContent',
97788
+ chunkFlow: 'chunkFlow',
97789
+ chunkText: 'chunkText',
97790
+ chunkString: 'chunkString'
97791
+ })
97792
+
97793
+ ;// ./lib/micromark/jsx-table/syntax.ts
97794
+
97795
+
97796
+ const syntax_nonLazyContinuationStart = {
97797
+ tokenize: syntax_tokenizeNonLazyContinuationStart,
97798
+ partial: true,
97799
+ };
97800
+ function resolveToJsxTable(events) {
97801
+ let index = events.length;
97802
+ while (index > 0) {
97803
+ index -= 1;
97804
+ if (events[index][0] === 'enter' && events[index][1].type === 'jsxTable') {
97805
+ break;
97806
+ }
97807
+ }
97808
+ if (index > 1 && events[index - 2][1].type === types_types.linePrefix) {
97809
+ events[index][1].start = events[index - 2][1].start;
97810
+ events[index + 1][1].start = events[index - 2][1].start;
97811
+ events.splice(index - 2, 2);
97812
+ }
97813
+ return events;
97814
+ }
97815
+ const jsxTableConstruct = {
97816
+ name: 'jsxTable',
97817
+ tokenize: tokenizeJsxTable,
97818
+ resolveTo: resolveToJsxTable,
97819
+ concrete: true,
97820
+ };
97821
+ function tokenizeJsxTable(effects, ok, nok) {
97822
+ let codeSpanOpenSize = 0;
97823
+ let codeSpanCloseSize = 0;
97824
+ let depth = 1;
97825
+ const TABLE_NAME = [codes.uppercaseT, codes.lowercaseA, codes.lowercaseB, codes.lowercaseL, codes.lowercaseE];
97826
+ const ABLE_SUFFIX = TABLE_NAME.slice(1);
97827
+ /** Build a state chain that matches a sequence of character codes. */
97828
+ function matchChars(chars, onMatch, onFail) {
97829
+ if (chars.length === 0)
97830
+ return onMatch;
97831
+ return ((code) => {
97832
+ if (code === chars[0]) {
97833
+ effects.consume(code);
97834
+ return matchChars(chars.slice(1), onMatch, onFail);
97835
+ }
97836
+ return onFail(code);
97837
+ });
97838
+ }
97839
+ return start;
97840
+ function start(code) {
97841
+ if (code !== codes.lessThan)
97842
+ return nok(code);
97843
+ effects.enter('jsxTable');
97844
+ effects.enter('jsxTableData');
97845
+ effects.consume(code);
97846
+ return matchChars(TABLE_NAME, afterTagName, nok);
97847
+ }
97848
+ function afterTagName(code) {
97849
+ if (code === codes.greaterThan || code === codes.slash || code === codes.space || code === codes.horizontalTab) {
97850
+ effects.consume(code);
97851
+ return body;
97852
+ }
97853
+ return nok(code);
97854
+ }
97855
+ function body(code) {
97856
+ // Reject unclosed <Table> so it falls back to normal HTML block parsing
97857
+ // instead of swallowing all subsequent content to EOF
97858
+ if (code === null) {
97859
+ return nok(code);
97860
+ }
97861
+ if (markdownLineEnding(code)) {
97862
+ effects.exit('jsxTableData');
97863
+ return continuationStart(code);
97864
+ }
97865
+ if (code === codes.backslash) {
97866
+ effects.consume(code);
97867
+ return escapedChar;
97868
+ }
97869
+ if (code === codes.lessThan) {
97870
+ effects.consume(code);
97871
+ return closeSlash;
97872
+ }
97873
+ // Skip over backtick code spans so `</Table>` in inline code isn't
97874
+ // treated as the closing tag
97875
+ if (code === codes.graveAccent) {
97876
+ codeSpanOpenSize = 0;
97877
+ return countOpenTicks(code);
97878
+ }
97879
+ effects.consume(code);
97880
+ return body;
97881
+ }
97882
+ function countOpenTicks(code) {
97883
+ if (code === codes.graveAccent) {
97884
+ codeSpanOpenSize += 1;
97885
+ effects.consume(code);
97886
+ return countOpenTicks;
97887
+ }
97888
+ return inCodeSpan(code);
97889
+ }
97890
+ function inCodeSpan(code) {
97891
+ if (code === null || markdownLineEnding(code))
97892
+ return body(code);
97893
+ if (code === codes.graveAccent) {
97894
+ codeSpanCloseSize = 0;
97895
+ return countCloseTicks(code);
97896
+ }
97897
+ effects.consume(code);
97898
+ return inCodeSpan;
97899
+ }
97900
+ function countCloseTicks(code) {
97901
+ if (code === codes.graveAccent) {
97902
+ codeSpanCloseSize += 1;
97903
+ effects.consume(code);
97904
+ return countCloseTicks;
97905
+ }
97906
+ return codeSpanCloseSize === codeSpanOpenSize ? body(code) : inCodeSpan(code);
97907
+ }
97908
+ function escapedChar(code) {
97909
+ if (code === null || markdownLineEnding(code)) {
97910
+ return body(code);
97911
+ }
97912
+ effects.consume(code);
97913
+ return body;
97914
+ }
97915
+ function closeSlash(code) {
97916
+ if (code === codes.slash) {
97917
+ effects.consume(code);
97918
+ return matchChars(TABLE_NAME, closeGt, body);
97919
+ }
97920
+ if (code === codes.uppercaseT) {
97921
+ effects.consume(code);
97922
+ return matchChars(ABLE_SUFFIX, openAfterTagName, body);
97923
+ }
97924
+ return body(code);
97925
+ }
97926
+ function openAfterTagName(code) {
97927
+ if (code === codes.greaterThan || code === codes.slash || code === codes.space || code === codes.horizontalTab) {
97928
+ depth += 1;
97929
+ effects.consume(code);
97930
+ return body;
97931
+ }
97932
+ return body(code);
97933
+ }
97934
+ function closeGt(code) {
97935
+ if (code === codes.greaterThan) {
97936
+ depth -= 1;
97937
+ effects.consume(code);
97938
+ if (depth === 0) {
97939
+ return afterClose;
97940
+ }
97941
+ return body;
97942
+ }
97943
+ return body(code);
97944
+ }
97945
+ function afterClose(code) {
97946
+ if (code === null || markdownLineEnding(code)) {
97947
+ effects.exit('jsxTableData');
97948
+ effects.exit('jsxTable');
97949
+ return ok(code);
97950
+ }
97951
+ effects.consume(code);
97952
+ return afterClose;
97953
+ }
97954
+ // Line ending handling — follows the htmlFlow pattern
97955
+ function continuationStart(code) {
97956
+ return effects.check(syntax_nonLazyContinuationStart, continuationStartNonLazy, continuationAfter)(code);
97957
+ }
97958
+ function continuationStartNonLazy(code) {
97959
+ effects.enter(types_types.lineEnding);
97960
+ effects.consume(code);
97961
+ effects.exit(types_types.lineEnding);
97962
+ return continuationBefore;
97963
+ }
97964
+ function continuationBefore(code) {
97965
+ if (code === null || markdownLineEnding(code)) {
97966
+ return continuationStart(code);
97967
+ }
97968
+ effects.enter('jsxTableData');
97969
+ return body(code);
97970
+ }
97971
+ function continuationAfter(code) {
97972
+ // At EOF without </Table>, reject so content isn't swallowed
97973
+ if (code === null) {
97974
+ return nok(code);
97975
+ }
97976
+ effects.exit('jsxTable');
97977
+ return ok(code);
97978
+ }
97979
+ }
97980
+ function syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
97981
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
97982
+ const self = this;
97983
+ return start;
97984
+ function start(code) {
97985
+ if (markdownLineEnding(code)) {
97986
+ effects.enter(types_types.lineEnding);
97987
+ effects.consume(code);
97988
+ effects.exit(types_types.lineEnding);
97989
+ return after;
97990
+ }
97991
+ return nok(code);
97992
+ }
97993
+ function after(code) {
97994
+ if (self.parser.lazy[self.now().line]) {
97995
+ return nok(code);
97996
+ }
97997
+ return ok(code);
97998
+ }
97999
+ }
98000
+ /**
98001
+ * Micromark extension that tokenizes `<Table>...</Table>` as a single flow block.
98002
+ *
98003
+ * Prevents CommonMark HTML block type 6 from matching `<Table>` (case-insensitive
98004
+ * match against `table`) and fragmenting it at blank lines.
98005
+ */
98006
+ function jsxTable() {
98007
+ return {
98008
+ flow: {
98009
+ [codes.lessThan]: [jsxTableConstruct],
98010
+ },
98011
+ };
98012
+ }
98013
+
98014
+ ;// ./lib/micromark/jsx-table/index.ts
98015
+
98016
+
97057
98017
  ;// ./lib/micromark/magic-block/syntax.ts
97058
98018
 
97059
98019
 
@@ -97980,6 +98940,9 @@ function loadComponents() {
97980
98940
 
97981
98941
 
97982
98942
 
98943
+
98944
+
98945
+
97983
98946
 
97984
98947
 
97985
98948
 
@@ -98028,11 +98991,11 @@ function mdxishAstProcessor(mdContent, opts = {}) {
98028
98991
  };
98029
98992
  const processor = unified()
98030
98993
  .data('micromarkExtensions', safeMode
98031
- ? [magicBlock(), legacyVariable(), looseHtmlEntity()]
98032
- : [magicBlock(), mdxExprTextOnly, legacyVariable(), looseHtmlEntity()])
98994
+ ? [jsxTable(), magicBlock(), legacyVariable(), looseHtmlEntity()]
98995
+ : [jsxTable(), magicBlock(), mdxExprTextOnly, legacyVariable(), looseHtmlEntity()])
98033
98996
  .data('fromMarkdownExtensions', safeMode
98034
- ? [magicBlockFromMarkdown(), legacyVariableFromMarkdown(), emptyTaskListItemFromMarkdown(), looseHtmlEntityFromMarkdown()]
98035
- : [magicBlockFromMarkdown(), mdxExpressionFromMarkdown(), legacyVariableFromMarkdown(), emptyTaskListItemFromMarkdown(), looseHtmlEntityFromMarkdown()])
98997
+ ? [jsxTableFromMarkdown(), magicBlockFromMarkdown(), legacyVariableFromMarkdown(), emptyTaskListItemFromMarkdown(), looseHtmlEntityFromMarkdown()]
98998
+ : [jsxTableFromMarkdown(), magicBlockFromMarkdown(), mdxExpressionFromMarkdown(), legacyVariableFromMarkdown(), emptyTaskListItemFromMarkdown(), looseHtmlEntityFromMarkdown()])
98036
98999
  .use(remarkParse)
98037
99000
  .use(remarkFrontmatter)
98038
99001
  .use(normalize_malformed_md_syntax)
@@ -98043,7 +99006,9 @@ function mdxishAstProcessor(mdContent, opts = {}) {
98043
99006
  .use(restore_snake_case_component_name, { mapping: snakeCaseMapping })
98044
99007
  .use(mdxish_tables)
98045
99008
  .use(mdxish_html_blocks)
98046
- .use(newEditorTypes ? mdxish_jsx_to_mdast : undefined) // Convert JSX elements to MDAST types
99009
+ .use(newEditorTypes ? mdxish_inline_components : undefined) // Merge inline html components (e.g. <Anchor>) into MDAST nodes
99010
+ .use(newEditorTypes ? mdxish_jsx_to_mdast : undefined) // Convert block JSX elements to MDAST types
99011
+ .use(safeMode ? undefined : evaluate_expressions, { context: jsxContext }) // Evaluate MDX expressions using jsxContext
98047
99012
  .use(variables_text) // Parse {user.*} patterns from text nodes
98048
99013
  .use(useTailwind ? transform_tailwind : undefined, { components: tempComponentsMap })
98049
99014
  .use(remarkGfm);
@@ -98650,6 +99615,8 @@ function restoreMagicBlocks(replaced, blocks) {
98650
99615
 
98651
99616
 
98652
99617
 
99618
+
99619
+
98653
99620
  /**
98654
99621
  * Removes Markdown and MDX comments.
98655
99622
  */
@@ -98661,8 +99628,8 @@ async function stripComments(doc, { mdx, mdxish } = {}) {
98661
99628
  // 2. we need to parse JSX comments into mdxTextExpression nodes so that the transformers can pick them up
98662
99629
  if (mdxish) {
98663
99630
  processor
98664
- .data('micromarkExtensions', [mdxExpression({ allowEmpty: true })])
98665
- .data('fromMarkdownExtensions', [mdxExpressionFromMarkdown()])
99631
+ .data('micromarkExtensions', [jsxTable(), mdxExpression({ allowEmpty: true })])
99632
+ .data('fromMarkdownExtensions', [jsxTableFromMarkdown(), mdxExpressionFromMarkdown()])
98666
99633
  .data('toMarkdownExtensions', [mdxExpressionToMarkdown()]);
98667
99634
  }
98668
99635
  processor