@readme/markdown 14.11.3 → 14.11.4

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
@@ -12631,10 +12631,10 @@ const Tabs = ({ children }) => {
12631
12631
  const tabs = external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().Children.toArray(children);
12632
12632
  return (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("div", { className: "TabGroup" },
12633
12633
  external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("header", null,
12634
- external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("nav", { className: "TabGroup-nav" }, tabs.map((tab, index) => (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("button", { key: tab.props.title, className: `TabGroup-tab${activeTab === index ? '_active' : ''}`, onClick: () => setActiveTab(index) },
12634
+ external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("nav", { className: "TabGroup-nav" }, tabs.map((tab, index) => (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("button", { key: tab.key, className: `TabGroup-tab${activeTab === index ? '_active' : ''}`, onClick: () => setActiveTab(index) },
12635
12635
  tab.props.icon && (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement(components_Icon, { className: "TabGroup-icon", icon: tab.props.icon, iconColor: tab.props.iconColor })),
12636
12636
  tab.props.title))))),
12637
- external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("section", null, tabs[activeTab])));
12637
+ external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("section", null, tabs.map((tab, index) => (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("div", { key: tab.key, hidden: index !== activeTab }, tab))))));
12638
12638
  };
12639
12639
  /* harmony default export */ const components_Tabs = (Tabs);
12640
12640
 
@@ -54527,6 +54527,21 @@ function evaluate(source, scope = {}) {
54527
54527
  // eslint-disable-next-line no-new-func
54528
54528
  return new Function(...names, `return (${source})`)(...values);
54529
54529
  }
54530
+ /**
54531
+ * Advance a `Point` by the `consumed` substring that follows it, returning the
54532
+ * point at the consumed string's end. Lets split-out sub-nodes carry accurate
54533
+ * document positions so downstream offset shifting stays correct.
54534
+ */
54535
+ const pointAfter = (start, consumed) => {
54536
+ const newlineIndex = consumed.lastIndexOf('\n');
54537
+ const newlineCount = newlineIndex === -1 ? 0 : consumed.split('\n').length - 1;
54538
+ return {
54539
+ line: start.line + newlineCount,
54540
+ // Same line → advance the base column; a later line → column is the run since its newline.
54541
+ column: newlineCount === 0 ? start.column + consumed.length : consumed.length - newlineIndex,
54542
+ offset: (start.offset ?? 0) + consumed.length,
54543
+ };
54544
+ };
54530
54545
  /**
54531
54546
  * Formats the hProperties of a node as a string, so they can be compiled back into JSX/MDX.
54532
54547
  * This currently sets all the values to a string since we process/compile the MDX on the fly
@@ -75795,6 +75810,108 @@ const applyInserts = (html, inserts) => {
75795
75810
  return { value: out + html.slice(cursor), inserts: sorted };
75796
75811
  };
75797
75812
 
75813
+ ;// ./processor/transform/mdxish/tables/escape-crossing-emphasis.ts
75814
+
75815
+
75816
+
75817
+ // Maximal run of a single emphasis delimiter (`_`, `*`, `**`, `***`, …).
75818
+ const EMPHASIS_RUN_RE = /([*_])\1*/g;
75819
+ // String bounds (undefined) count as whitespace, not punctuation, per the
75820
+ // CommonMark flanking definition.
75821
+ const escape_crossing_emphasis_isWhitespace = (ch) => ch === undefined || unicodeWhitespace(ch.charCodeAt(0));
75822
+ const isPunctuation = (ch) => ch !== undefined && unicodePunctuation(ch.charCodeAt(0));
75823
+ /**
75824
+ * Whether a delimiter run can open and/or close emphasis, per CommonMark's
75825
+ * left/right-flanking rules. The extra `_` conditions forbid intraword
75826
+ * emphasis, which keeps `snake_case` from being treated as a delimiter.
75827
+ */
75828
+ const analyzeFlanking = (source, char, start, end) => {
75829
+ const before = source[start - 1];
75830
+ const after = source[end];
75831
+ const leftFlanking = !escape_crossing_emphasis_isWhitespace(after) && (!isPunctuation(after) || escape_crossing_emphasis_isWhitespace(before) || isPunctuation(before));
75832
+ const rightFlanking = !escape_crossing_emphasis_isWhitespace(before) && (!isPunctuation(before) || escape_crossing_emphasis_isWhitespace(after) || isPunctuation(after));
75833
+ if (char === '_') {
75834
+ return {
75835
+ canOpen: leftFlanking && (!rightFlanking || isPunctuation(before)),
75836
+ canClose: rightFlanking && (!leftFlanking || isPunctuation(after)),
75837
+ };
75838
+ }
75839
+ return { canOpen: leftFlanking, canClose: rightFlanking };
75840
+ };
75841
+ /**
75842
+ * Collect HTML tag boundaries (via htmlparser2) and emphasis delimiter runs
75843
+ * (via regex over the masked source, so code spans and escaped `<` are skipped)
75844
+ * into one list ordered by position. At a shared offset a tag opener sorts
75845
+ * before a closer, so a self-closing tag brackets rather than swallows a run.
75846
+ */
75847
+ const collectEvents = (html) => {
75848
+ const masked = maskNonTagRegions(html);
75849
+ const events = [];
75850
+ walkTags(html, {
75851
+ onOpen: ({ start }) => events.push({ kind: 'tagOpen', offset: start }),
75852
+ onClose: ({ start }) => events.push({ kind: 'tagClose', offset: start }),
75853
+ });
75854
+ EMPHASIS_RUN_RE.lastIndex = 0;
75855
+ let match;
75856
+ while ((match = EMPHASIS_RUN_RE.exec(masked)) !== null) {
75857
+ const [run, char] = match;
75858
+ const start = match.index;
75859
+ // eslint-disable-next-line no-continue
75860
+ if (html[start - 1] === '\\')
75861
+ continue; // already escaped
75862
+ events.push({ kind: 'emphasis', offset: start, char, length: run.length, flanking: analyzeFlanking(html, char, start, start + run.length) });
75863
+ }
75864
+ return events.sort((a, b) => a.offset - b.offset || (a.kind === 'tagClose' ? 1 : 0) - (b.kind === 'tagClose' ? 1 : 0));
75865
+ };
75866
+ /**
75867
+ * mdxjs rejects a table when a markdown emphasis run opens at one HTML
75868
+ * tag-nesting depth and closes at another — e.g. `_<ul><li>text_</li></ul>`,
75869
+ * where the `_` opens outside the list but closes inside a `<li>`. It throws
75870
+ * "Expected a closing tag for `<li>` before the end of `emphasis`" and the
75871
+ * whole `<Table>` fails to parse.
75872
+ *
75873
+ * We walk tags and emphasis together, tracking tag depth and a stack of open
75874
+ * emphasis. A delimiter only closes an opener at the same depth; any emphasis
75875
+ * still open when its enclosing tag closes (or at end of input), and any closer
75876
+ * with no same-depth opener, is escaped so mdxjs treats it as literal text.
75877
+ * Scoped to the malformed-retry path.
75878
+ */
75879
+ const escapeCrossingEmphasis = (html) => {
75880
+ const open = [];
75881
+ const orphans = [];
75882
+ let depth = 0;
75883
+ collectEvents(html).forEach(event => {
75884
+ if (event.kind === 'tagOpen') {
75885
+ depth += 1;
75886
+ return;
75887
+ }
75888
+ if (event.kind === 'tagClose') {
75889
+ depth -= 1;
75890
+ // Emphasis opened deeper than the surviving depth was inside the tag that
75891
+ // just closed, so it crosses the boundary.
75892
+ while (open.length > 0 && open[open.length - 1].depth > depth) {
75893
+ const crossed = open.pop();
75894
+ if (crossed)
75895
+ orphans.push(crossed);
75896
+ }
75897
+ return;
75898
+ }
75899
+ const top = open[open.length - 1];
75900
+ if (event.flanking.canClose && top?.char === event.char && top.depth === depth) {
75901
+ open.pop();
75902
+ }
75903
+ else if (event.flanking.canOpen) {
75904
+ open.push({ char: event.char, depth, offset: event.offset, length: event.length });
75905
+ }
75906
+ else if (event.flanking.canClose) {
75907
+ orphans.push({ offset: event.offset, length: event.length });
75908
+ }
75909
+ });
75910
+ orphans.push(...open); // anything still open never closed
75911
+ const inserts = orphans.flatMap(({ offset, length }) => Array.from({ length }, (_unused, i) => ({ offset: offset + i, text: '\\' })));
75912
+ return applyInserts(html, inserts);
75913
+ };
75914
+
75798
75915
  ;// ./processor/transform/mdxish/tables/escape-stray-less-than.ts
75799
75916
 
75800
75917
 
@@ -75947,6 +76064,21 @@ const buildOffsetMapper = (inserts) => {
75947
76064
  return repaired - shift;
75948
76065
  };
75949
76066
  };
76067
+ /**
76068
+ * Compose the per-repair offset mappers into one that maps an offset in the
76069
+ * fully-repaired string back to the original. `layers` are in application
76070
+ * order; each maps its own output space to its input space, so we apply them
76071
+ * last-repair-first to peel every edit back to the original coordinates.
76072
+ */
76073
+ const composeOffsetMapper = (layers) => {
76074
+ const mappers = layers.map(buildOffsetMapper);
76075
+ return (repaired) => {
76076
+ let offset = repaired;
76077
+ for (let i = mappers.length - 1; i >= 0; i -= 1)
76078
+ offset = mappers[i](offset);
76079
+ return offset;
76080
+ };
76081
+ };
75950
76082
  /**
75951
76083
  * Map an offset in `source` to its 1-based `{ line, column }`. `lineStarts`
75952
76084
  * is the precomputed array of offsets where each line begins.
@@ -75974,14 +76106,11 @@ const computeLineStarts = (source) => {
75974
76106
  };
75975
76107
  /**
75976
76108
  * Walk `tree`, translating every node's position from the repaired source's
75977
- * coordinate space back to the original source. Offsets are remapped via the
75978
- * insert list; line/column are recomputed from the original source so they
75979
- * remain accurate even if repairs introduced newlines.
76109
+ * coordinate space back to the original source via `mapOffset`. Line/column
76110
+ * are recomputed from the original source so they remain accurate even if
76111
+ * repairs introduced newlines.
75980
76112
  */
75981
- const remapPositionsToOriginal = (tree, originalSource, inserts) => {
75982
- if (inserts.length === 0)
75983
- return;
75984
- const mapOffset = buildOffsetMapper(inserts);
76113
+ const remapWithMapper = (tree, originalSource, mapOffset) => {
75985
76114
  const lineStarts = computeLineStarts(originalSource);
75986
76115
  visit(tree, child => {
75987
76116
  if (child.position?.start) {
@@ -76000,6 +76129,15 @@ const remapPositionsToOriginal = (tree, originalSource, inserts) => {
76000
76129
  }
76001
76130
  });
76002
76131
  };
76132
+ /**
76133
+ * Remap positions produced after a chain of repairs (each applied to the prior
76134
+ * one's output) back to the original source coordinates.
76135
+ */
76136
+ const remapPositionsThroughLayers = (tree, originalSource, layers) => {
76137
+ if (layers.length === 0)
76138
+ return;
76139
+ remapWithMapper(tree, originalSource, composeOffsetMapper(layers));
76140
+ };
76003
76141
 
76004
76142
  ;// ./processor/transform/mdxish/tables/repair-expression-escapes.ts
76005
76143
 
@@ -76299,6 +76437,83 @@ const repairUnclosedTags = (html) => {
76299
76437
  return applyInserts(html, inserts);
76300
76438
  };
76301
76439
 
76440
+ ;// ./processor/transform/mdxish/tables/split-nested-tables.ts
76441
+
76442
+
76443
+ const TOP_LEVEL_TABLE_TAG_RE = /^<(?:table|Table)(?=[\s/>])/;
76444
+ /**
76445
+ * Find every balanced, depth-matched `<table>…</table>` range in an html string.
76446
+ * Uses `walkTags` so `<table>`s inside code spans / fenced blocks (masked away)
76447
+ * are never matched.
76448
+ *
76449
+ * Note: An implicitly-closed table (no `</table>`, so htmlparser2 synthesizes the
76450
+ * close at a later tag) is skipped: splitting there would swallow whatever
76451
+ * followed the table into the fragment and drop it, so we leave such a node
76452
+ * whole for downstream raw-HTML handling instead.
76453
+ */
76454
+ const findTableRanges = (html) => {
76455
+ const ranges = [];
76456
+ let depth = 0;
76457
+ let start = 0;
76458
+ walkTags(html, {
76459
+ onOpen: ({ name, start: openStart, isStrayCloser }) => {
76460
+ if (name.toLowerCase() !== 'table' || isStrayCloser)
76461
+ return;
76462
+ if (depth === 0)
76463
+ start = openStart;
76464
+ depth += 1;
76465
+ },
76466
+ onClose: ({ name, end, implicit }) => {
76467
+ if (implicit || name.toLowerCase() !== 'table' || depth === 0)
76468
+ return;
76469
+ depth -= 1;
76470
+ if (depth === 0)
76471
+ ranges.push({ start, end });
76472
+ },
76473
+ });
76474
+ return ranges;
76475
+ };
76476
+ /**
76477
+ * Given an HTML node that might contain table sequences inside it, split
76478
+ * the node based on the table boundaries so they become a top level node.
76479
+ *
76480
+ * The surrounding raw HTML (the wrapper's open/close tags) would be re-nested
76481
+ * around the parsed tables by rehype-raw.
76482
+ *
76483
+ * Returns null when there is no wrapped table to extract.
76484
+ */
76485
+ const splitHtmlWithNestedTables = (node) => {
76486
+ const { value } = node;
76487
+ // This is a top-level table, so we don't need to split it
76488
+ if (TOP_LEVEL_TABLE_TAG_RE.test(value))
76489
+ return null;
76490
+ // No table text anywhere in the value → skip the htmlparser2 walk entirely.
76491
+ if (!/<\/?table/i.test(value))
76492
+ return null;
76493
+ const ranges = findTableRanges(value);
76494
+ if (ranges.length === 0)
76495
+ return null;
76496
+ const base = node.position?.start;
76497
+ const sliceToHtml = (from, to) => ({
76498
+ type: 'html',
76499
+ value: value.slice(from, to),
76500
+ ...(base && {
76501
+ position: { start: pointAfter(base, value.slice(0, from)), end: pointAfter(base, value.slice(0, to)) },
76502
+ }),
76503
+ });
76504
+ const parts = [];
76505
+ let cursor = 0;
76506
+ ranges.forEach(({ start, end }) => {
76507
+ if (start > cursor)
76508
+ parts.push(sliceToHtml(cursor, start));
76509
+ parts.push(sliceToHtml(start, end)); // starts with `<table` → picked up by the main pass
76510
+ cursor = end;
76511
+ });
76512
+ if (cursor < value.length)
76513
+ parts.push(sliceToHtml(cursor, value.length));
76514
+ return parts;
76515
+ };
76516
+
76302
76517
  ;// ./processor/transform/mdxish/tables/mdxish-tables.ts
76303
76518
 
76304
76519
 
@@ -76320,6 +76535,8 @@ const repairUnclosedTags = (html) => {
76320
76535
 
76321
76536
 
76322
76537
 
76538
+
76539
+
76323
76540
 
76324
76541
 
76325
76542
 
@@ -76349,6 +76566,21 @@ const buildTableNodeProcessor = (withMdx) => unified()
76349
76566
  .use(remarkGfm);
76350
76567
  const tableNodeProcessor = buildTableNodeProcessor(true);
76351
76568
  const fallbackTableNodeProcessor = buildTableNodeProcessor(false);
76569
+ // Targeted repairs for tables mdxjs rejects, tried cumulatively (each runs on
76570
+ // the prior's output) since one table can carry independent per-cell defects.
76571
+ // Each was added after seeing real customer content fail to parse:
76572
+ // - repairUnclosedTags: unclosed/orphan HTML tags
76573
+ // - normalizeTagSpacing: a line mixing text and an opening tag
76574
+ // - repairExpressionEscapes: backslash escapes inside a `{…}` expression
76575
+ // - escapeStrayLessThan: a `<` that doesn't begin a valid tag (`word <`)
76576
+ // - escapeCrossingEmphasis: emphasis opening/closing at different tag depths
76577
+ const tableRepairs = [
76578
+ repairUnclosedTags,
76579
+ normalizeTagSpacing,
76580
+ repairExpressionEscapes,
76581
+ escapeStrayLessThan,
76582
+ escapeCrossingEmphasis,
76583
+ ];
76352
76584
  /**
76353
76585
  * Parse the HTML node that contains the full table substring
76354
76586
  * into the table parts (headers, rows, cells).
@@ -76364,10 +76596,10 @@ const parseTableNode = (processor, node, repair) => {
76364
76596
  return undefined;
76365
76597
  }
76366
76598
  // If `node.value` was repaired before parsing, first remap positions back to
76367
- // the original (unrepaired) coordinates via the insert list — otherwise the
76599
+ // the original (unrepaired) coordinates via the insert layers — otherwise the
76368
76600
  // shift would land on synthetic characters and be inaccurate
76369
76601
  if (repair) {
76370
- remapPositionsToOriginal(parsed, repair.originalSource, repair.inserts);
76602
+ remapPositionsThroughLayers(parsed, repair.originalSource, repair.layers);
76371
76603
  }
76372
76604
  // The subparser produces positions relative to `node.value`; shift them by
76373
76605
  // the outer node's offset/line so consumers can slice the full source.
@@ -76464,9 +76696,7 @@ const processTableNode = (node, index, parent, documentPosition) => {
76464
76696
  visit(node, isMDXElement, (child) => {
76465
76697
  if (child.name === 'thead')
76466
76698
  hasThead = true;
76467
- if (tableTags.has(child.name) &&
76468
- Array.isArray(child.attributes) &&
76469
- child.attributes.length > 0) {
76699
+ if (tableTags.has(child.name) && Array.isArray(child.attributes) && child.attributes.length > 0) {
76470
76700
  hasStructuralAttributes = true;
76471
76701
  }
76472
76702
  });
@@ -76577,6 +76807,26 @@ const processTableNode = (node, index, parent, documentPosition) => {
76577
76807
  };
76578
76808
  parent.children[index] = mdNode;
76579
76809
  };
76810
+ /**
76811
+ * Apply `tableRepairs` cumulatively, re-parsing after every change and stopping
76812
+ * once the accumulated result parses. Each layer's inserts are relative to the
76813
+ * string that repair received, so they stay ordered for position remapping.
76814
+ */
76815
+ const repairAndReparse = (node) => {
76816
+ let repairedValue = node.value;
76817
+ const layers = [];
76818
+ let parsed;
76819
+ tableRepairs.some(repair => {
76820
+ const { value, inserts } = repair(repairedValue);
76821
+ if (value === repairedValue)
76822
+ return false;
76823
+ repairedValue = value;
76824
+ layers.push(inserts);
76825
+ parsed = parseTableNode(tableNodeProcessor, { ...node, value: repairedValue }, { layers, originalSource: node.value });
76826
+ return Boolean(parsed);
76827
+ });
76828
+ return parsed;
76829
+ };
76580
76830
  /**
76581
76831
  * Converts JSX Table elements to markdown table nodes and re-parses markdown in cells.
76582
76832
  *
@@ -76589,42 +76839,30 @@ const processTableNode = (node, index, parent, documentPosition) => {
76589
76839
  * is kept as a JSX <Table> element so that remarkRehype can properly handle the flow content.
76590
76840
  */
76591
76841
  const mdxishTables = () => tree => {
76842
+ // Pre-pass: lift `<table>`s wrapped in a raw HTML block out into their own
76843
+ // html nodes so the main pass below treats them like top-level tables.
76844
+ visit(tree, 'html', (_node, index, parent) => {
76845
+ const node = _node;
76846
+ if (typeof index !== 'number' || !parent || !('children' in parent))
76847
+ return;
76848
+ const parts = splitHtmlWithNestedTables(node);
76849
+ if (!parts)
76850
+ return;
76851
+ // The inserted parts can't re-trigger a split (table parts start with
76852
+ // `<table`; the wrapper slices hold no table), so plain in-place splicing
76853
+ // visits each once without looping.
76854
+ parent.children.splice(index, 1, ...parts);
76855
+ });
76592
76856
  visit(tree, 'html', (_node, index, parent) => {
76593
76857
  const node = _node;
76594
76858
  if (typeof index !== 'number' || !parent || !('children' in parent))
76595
76859
  return;
76596
76860
  if (!node.value.startsWith('<Table') && !node.value.startsWith('<table'))
76597
76861
  return;
76598
- // Main logic to transform table node to its parts
76599
76862
  // Because the processor uses remarkMdx, it is stricter in what it accepts
76600
- // and only accepts valid MDX syntax. in the table node.
76601
- // To get around that, we have some fallback logics after trying to repair the table content.
76602
- let parsed = parseTableNode(tableNodeProcessor, node);
76603
- if (!parsed) {
76604
- // Try a sequence of targeted repairs and re-parse
76605
- // after each, stopping at the first that yields a parseable tree:
76606
- // - repairUnclosedTags: unclosed/orphan HTML tags
76607
- // - normalizeTagSpacing: a line mixing text and an opening tag
76608
- // (e.g. `text <div> \n <div> text`)
76609
- // - repairExpressionEscapes: backslash escapes inside a `{…}` expression
76610
- // - escapeStrayLessThan: a `<` that doesn't begin a valid tag
76611
- // (e.g. `word <`, `a <1>`)
76612
- // These repairs are created after seeing real customer content that has failed to parse
76613
- const repairs = [
76614
- repairUnclosedTags,
76615
- normalizeTagSpacing,
76616
- repairExpressionEscapes,
76617
- escapeStrayLessThan,
76618
- ];
76619
- // Stops at the first repair that yields a parseable tree
76620
- repairs.some(repair => {
76621
- const { value, inserts } = repair(node.value);
76622
- if (value !== node.value) {
76623
- parsed = parseTableNode(tableNodeProcessor, { ...node, value }, { inserts, originalSource: node.value });
76624
- }
76625
- return Boolean(parsed);
76626
- });
76627
- }
76863
+ // and only accepts valid MDX syntax in the table node. To get around that,
76864
+ // fall back to the cumulative repairs when the first parse fails.
76865
+ const parsed = parseTableNode(tableNodeProcessor, node) ?? repairAndReparse(node);
76628
76866
  if (parsed) {
76629
76867
  // If the table is parsed successfully, we can now process it further
76630
76868
  // to build on the markdown / JSX table
@@ -98913,11 +99151,10 @@ const rehypeMdxishComponents = ({ components, processMarkdown }) => {
98913
99151
  ;// ./processor/plugin/mdxish-handlers.ts
98914
99152
 
98915
99153
 
98916
- // Convert MDX expressions to text nodes (evaluation happens earlier in pipeline)
98917
- const mdxExpressionHandler = (_state, node) => ({
98918
- type: 'text',
98919
- value: node.value || '',
98920
- });
99154
+ // If hChildren is populated, it means the node holds a renderable value (e.g. React)
99155
+ // See evaluate-expressions.ts for more details
99156
+ // Otherwise, it's a simple value and we fall back to text
99157
+ const mdxExpressionHandler = (_state, node) => node.data?.hChildren ?? { type: 'text', value: node.value || '' };
98921
99158
  // Convert MDX JSX elements to a custom mdx-jsx hast node that bypasses rehypeRaw's
98922
99159
  // HTML serialization round-trip; downstream normalization rewrites it to `element`.
98923
99160
  const mdxJsxElementHandler = (state, node) => {
@@ -101984,6 +102221,7 @@ const mdxishInlineMdxComponents = () => tree => {
101984
102221
 
101985
102222
 
101986
102223
 
102224
+
101987
102225
  /** Matches a JSX attribute expression (e.g. `key={i}`) anywhere in a string. */
101988
102226
  const NESTED_ATTR_EXPRESSION_RE = /[\w-]+\s*=\s*\{/;
101989
102227
  /**
@@ -102027,18 +102265,6 @@ const parseSibling = (stack, parent, index, sibling, safeMode) => {
102027
102265
  stack.push(parent);
102028
102266
  }
102029
102267
  };
102030
- /**
102031
- * Advance a point by the substring of source consumed from it.
102032
- */
102033
- const pointAfter = (start, consumed) => {
102034
- const newlineIndex = consumed.lastIndexOf('\n');
102035
- const newlineCount = newlineIndex === -1 ? 0 : consumed.split('\n').length - 1;
102036
- return {
102037
- line: start.line + newlineCount,
102038
- column: newlineCount === 0 ? start.column + consumed.length : consumed.length - newlineIndex,
102039
- offset: start.offset + consumed.length,
102040
- };
102041
- };
102042
102268
  /**
102043
102269
  * Build a position ending at `consumedLength` into the html node's value, so the
102044
102270
  * component doesn't claim trailing content the tokenizer swallowed into one node.
@@ -102541,8 +102767,6 @@ const evaluateExports = () => (tree, file) => {
102541
102767
  };
102542
102768
  /* harmony default export */ const evaluate_exports = (evaluateExports);
102543
102769
 
102544
- // EXTERNAL MODULE: ./node_modules/react-dom/server.browser.js
102545
- var server_browser = __webpack_require__(5848);
102546
102770
  ;// ./lib/utils/mdxish/mdxish-expression.ts
102547
102771
 
102548
102772
 
@@ -102588,26 +102812,185 @@ const evalExpression = (expression, scope) => {
102588
102812
  return evalJsxProgram(program, scope);
102589
102813
  };
102590
102814
 
102591
- ;// ./processor/transform/mdxish/evaluate-expressions.ts
102815
+ // EXTERNAL MODULE: ./node_modules/react-dom/server.browser.js
102816
+ var server_browser = __webpack_require__(5848);
102817
+ ;// ./processor/transform/mdxish/style-object-to-css.ts
102592
102818
 
102819
+ /**
102820
+ * CSS properties React treats as unitless — a bare number stays as-is instead of
102821
+ * getting `px` appended. Mirrors React DOM's `isUnitlessNumber` whitelist.
102822
+ * @see https://github.com/facebook/react/blob/main/packages/react-dom-bindings/src/shared/CSSProperty.js
102823
+ */
102824
+ const UNITLESS_CSS_PROPERTIES = new Set([
102825
+ 'animationIterationCount',
102826
+ 'aspectRatio',
102827
+ 'borderImageOutset',
102828
+ 'borderImageSlice',
102829
+ 'borderImageWidth',
102830
+ 'boxFlex',
102831
+ 'boxFlexGroup',
102832
+ 'boxOrdinalGroup',
102833
+ 'columnCount',
102834
+ 'columns',
102835
+ 'flex',
102836
+ 'flexGrow',
102837
+ 'flexPositive',
102838
+ 'flexShrink',
102839
+ 'flexNegative',
102840
+ 'flexOrder',
102841
+ 'gridArea',
102842
+ 'gridRow',
102843
+ 'gridRowEnd',
102844
+ 'gridRowSpan',
102845
+ 'gridRowStart',
102846
+ 'gridColumn',
102847
+ 'gridColumnEnd',
102848
+ 'gridColumnSpan',
102849
+ 'gridColumnStart',
102850
+ 'fontWeight',
102851
+ 'lineClamp',
102852
+ 'lineHeight',
102853
+ 'opacity',
102854
+ 'order',
102855
+ 'orphans',
102856
+ 'tabSize',
102857
+ 'widows',
102858
+ 'zIndex',
102859
+ 'zoom',
102860
+ 'fillOpacity',
102861
+ 'floodOpacity',
102862
+ 'stopOpacity',
102863
+ 'strokeDasharray',
102864
+ 'strokeDashoffset',
102865
+ 'strokeMiterlimit',
102866
+ 'strokeOpacity',
102867
+ 'strokeWidth',
102868
+ ]);
102869
+ /** Convert a camelCase (or CSS custom property) key into its kebab-case CSS name. */
102870
+ const cssPropertyName = (key) => (key.startsWith('--') ? key : key.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`));
102871
+ /** React appends `px` to non-zero numeric values, except unitless and custom properties. */
102872
+ const cssPropertyValue = (key, value) => typeof value === 'number' && value !== 0 && !key.startsWith('--') && !UNITLESS_CSS_PROPERTIES.has(key)
102873
+ ? `${value}px`
102874
+ : `${value}`;
102875
+ /**
102876
+ * True for a value that should be serialized as a style object rather than passed through
102877
+ * as an already-CSS string. React elements are excluded since they're valid objects too.
102878
+ */
102879
+ const style_object_to_css_isPlainObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value) && !external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().isValidElement(value);
102880
+ /**
102881
+ * Serialize a React-style inline style object (`{ color: "red", fontSize: 12 }`) into a
102882
+ * CSS declaration string (`color:red;font-size:12px`), the shape hast/HTML expects for a
102883
+ * `style` attribute. Empty (`undefined`/`null`/`''`) entries are dropped.
102884
+ */
102885
+ const styleObjectToCssText = (style) => Object.entries(style)
102886
+ .filter(([, value]) => value !== undefined && value !== null && value !== '')
102887
+ .map(([key, value]) => `${cssPropertyName(key)}:${cssPropertyValue(key, value)}`)
102888
+ .join(';');
102593
102889
 
102890
+ ;// ./processor/transform/mdxish/react-element-to-hast.ts
102594
102891
 
102595
102892
 
102596
- /** True for an array containing at least one React element, e.g. the result of `.map()` returning JSX. */
102597
- const isRenderableElementArray = (value) => Array.isArray(value) && value.some((external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default()).isValidElement);
102598
- /** Given the type of the expression result, create the corresponding mdast node. */
102599
- const createEvaluatedNode = (result, position) => {
102600
- if (result === null || result === undefined) {
102601
- return { type: 'text', value: '', position };
102893
+
102894
+ // React props that never map to an HTML/hast attribute.
102895
+ const RESERVED_PROPS = new Set(['children', 'key', 'ref']);
102896
+ /**
102897
+ * Translate React props into hast `properties`: reserved and function props (event handlers)
102898
+ * are dropped (known gap), `style` objects flatten to CSS text. Names stay as authored (`className`); the
102899
+ * hast → HTML boundary maps them to `class`/`for` downstream.
102900
+ */
102901
+ function propsToHastProperties(props) {
102902
+ const properties = {};
102903
+ Object.entries(props).forEach(([key, value]) => {
102904
+ if (RESERVED_PROPS.has(key) || typeof value === 'function' || value === undefined)
102905
+ return;
102906
+ properties[key] = key === 'style' && style_object_to_css_isPlainObject(value) ? styleObjectToCssText(value) : value;
102907
+ });
102908
+ // Values are resolved React props, wider than hast's HTML-attribute `PropertyValue` union.
102909
+ return properties;
102910
+ }
102911
+ /**
102912
+ * Render an element with React's own renderer as a last resort, wrapped as a hast `raw` node —
102913
+ * the same node type markdown's literal HTML blocks produce, so it re-enters rehypeRaw's
102914
+ * parse5 pass normally. Used for element types this converter can't resolve on its own (wrapped
102915
+ * component types, or a function component that throws when called outside React, e.g. one
102916
+ * using hooks). It's not immune to the invalid-HTML-nesting this module otherwise avoids, but
102917
+ * that's a fair trade against silently dropping the content.
102918
+ */
102919
+ function renderFallbackHtml(element) {
102920
+ try {
102921
+ const rawNode = { type: 'raw', value: (0,server_browser/* renderToStaticMarkup */.qV)(element) };
102922
+ return [rawNode];
102602
102923
  }
102603
- else if (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().isValidElement(result) || isRenderableElementArray(result)) {
102604
- // Convert react elements (or arrays of them, e.g. `.map()` returning JSX) to their HTML
102605
- // representation. This must come before the object check as both are a subset of it.
102606
- return { type: 'html', value: (0,server_browser/* renderToStaticMarkup */.qV)(external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement((external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default()).Fragment, null, result)), position };
102924
+ catch {
102925
+ return [];
102607
102926
  }
102608
- else if (typeof result === 'object') {
102609
- return { type: 'text', value: JSON.stringify(result), position };
102927
+ }
102928
+ /**
102929
+ * Convert a React element tree into hast. Emitting `mdx-jsx` nodes (rehypeRaw passthrough, later normalized to `element`)
102930
+ * preserves nesting that is valid JSX but not valid HTML, which parse5 would otherwise
102931
+ * restructure — e.g. an `<a>` wrapping another `<a>`.
102932
+ * Recursively converts the tree into an array of hast nodes, dealing with arrays and null/undefined/boolean values.
102933
+ */
102934
+ function reactElementToHast(node) {
102935
+ if (Array.isArray(node))
102936
+ return node.flatMap(reactElementToHast);
102937
+ if (node === null || node === undefined || typeof node === 'boolean')
102938
+ return [];
102939
+ if (typeof node === 'string' || typeof node === 'number') {
102940
+ const textNode = { type: 'text', value: String(node) };
102941
+ return [textNode];
102610
102942
  }
102943
+ if (!external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().isValidElement(node))
102944
+ return [];
102945
+ const { type, props } = node;
102946
+ // Fragments contribute their children with no wrapper element.
102947
+ if (type === (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default()).Fragment)
102948
+ return reactElementToHast(props.children);
102949
+ // Resolve function components to their rendered output so the tree is plain intrinsic
102950
+ // elements. If invoking it directly throws (e.g. it uses hooks, which need React's own
102951
+ // render context), fall back to React's renderer for just this subtree.
102952
+ if (typeof type === 'function') {
102953
+ try {
102954
+ return reactElementToHast(type(props));
102955
+ }
102956
+ catch {
102957
+ return renderFallbackHtml(node);
102958
+ }
102959
+ }
102960
+ // Non-intrinsic, non-callable element types — `React.memo`, `React.forwardRef`,
102961
+ // `Context.Provider`/`Consumer`, `React.lazy` — have no `type` we can resolve ourselves.
102962
+ if (typeof type !== 'string')
102963
+ return renderFallbackHtml(node);
102964
+ const mdxJsxNode = {
102965
+ type: 'mdx-jsx',
102966
+ tagName: type,
102967
+ properties: propsToHastProperties(props),
102968
+ children: reactElementToHast(props.children),
102969
+ };
102970
+ return [mdxJsxNode];
102971
+ }
102972
+
102973
+ ;// ./processor/transform/mdxish/evaluate-expressions.ts
102974
+
102975
+
102976
+
102977
+
102978
+ /**
102979
+ * We divide the result of an expression into two categories:
102980
+ * 1. Renderable values: HTML, JSX, e.g. .map() returning JSX
102981
+ * 2. Non-renderable values: a string, number, or object, regular JS values
102982
+ */
102983
+ const isRenderable = (value) => {
102984
+ if (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().isValidElement(value))
102985
+ return true;
102986
+ return Array.isArray(value) && value.some(isRenderable);
102987
+ };
102988
+ /** Turn a non-renderable evaluation result into a text node. */
102989
+ const createTextNode = (result, position) => {
102990
+ if (result === null || result === undefined)
102991
+ return { type: 'text', value: '', position };
102992
+ if (typeof result === 'object')
102993
+ return { type: 'text', value: JSON.stringify(result), position };
102611
102994
  return { type: 'text', value: String(result), position };
102612
102995
  };
102613
102996
  /**
@@ -102623,13 +103006,23 @@ const evaluateExpressions = () => (tree, file) => {
102623
103006
  visit(tree, ['mdxFlowExpression', 'mdxTextExpression'], (node, index, parent) => {
102624
103007
  if (!parent || index === null || index === undefined)
102625
103008
  return;
102626
- const { value, position } = node;
103009
+ const expressionNode = node;
103010
+ const { value, position } = expressionNode;
102627
103011
  const expression = value?.trim();
102628
103012
  if (!expression)
102629
103013
  return;
102630
103014
  try {
102631
103015
  const result = evalExpression(expression, scope);
102632
- parent.children.splice(index, 1, createEvaluatedNode(result, position));
103016
+ if (isRenderable(result)) {
103017
+ // Stash hast built straight from the React tree; `mdxExpressionHandler` emits it and it
103018
+ // passes through rehypeRaw/parse5 step later in the pipeline. This ensures that the
103019
+ // expression result is not parsed by parse5 and fragmenting the nesting that is valid JSX
103020
+ // but invalid HTML — e.g. an `<a>` wrapping `<a>`.
103021
+ expressionNode.data = { ...expressionNode.data, hChildren: reactElementToHast(result) };
103022
+ }
103023
+ else {
103024
+ parent.children.splice(index, 1, createTextNode(result, position));
103025
+ }
102633
103026
  }
102634
103027
  catch (_error) {
102635
103028
  // Evaluation failed — fall back to literal `{...}` text. The expression
@@ -104540,79 +104933,6 @@ function removeJSXComments(content) {
104540
104933
  return content.replace(JSX_COMMENT_REGEX, '');
104541
104934
  }
104542
104935
 
104543
- ;// ./processor/transform/mdxish/style-object-to-css.ts
104544
-
104545
- /**
104546
- * CSS properties React treats as unitless — a bare number stays as-is instead of
104547
- * getting `px` appended. Mirrors React DOM's `isUnitlessNumber` whitelist.
104548
- * @see https://github.com/facebook/react/blob/main/packages/react-dom-bindings/src/shared/CSSProperty.js
104549
- */
104550
- const UNITLESS_CSS_PROPERTIES = new Set([
104551
- 'animationIterationCount',
104552
- 'aspectRatio',
104553
- 'borderImageOutset',
104554
- 'borderImageSlice',
104555
- 'borderImageWidth',
104556
- 'boxFlex',
104557
- 'boxFlexGroup',
104558
- 'boxOrdinalGroup',
104559
- 'columnCount',
104560
- 'columns',
104561
- 'flex',
104562
- 'flexGrow',
104563
- 'flexPositive',
104564
- 'flexShrink',
104565
- 'flexNegative',
104566
- 'flexOrder',
104567
- 'gridArea',
104568
- 'gridRow',
104569
- 'gridRowEnd',
104570
- 'gridRowSpan',
104571
- 'gridRowStart',
104572
- 'gridColumn',
104573
- 'gridColumnEnd',
104574
- 'gridColumnSpan',
104575
- 'gridColumnStart',
104576
- 'fontWeight',
104577
- 'lineClamp',
104578
- 'lineHeight',
104579
- 'opacity',
104580
- 'order',
104581
- 'orphans',
104582
- 'tabSize',
104583
- 'widows',
104584
- 'zIndex',
104585
- 'zoom',
104586
- 'fillOpacity',
104587
- 'floodOpacity',
104588
- 'stopOpacity',
104589
- 'strokeDasharray',
104590
- 'strokeDashoffset',
104591
- 'strokeMiterlimit',
104592
- 'strokeOpacity',
104593
- 'strokeWidth',
104594
- ]);
104595
- /** Convert a camelCase (or CSS custom property) key into its kebab-case CSS name. */
104596
- const cssPropertyName = (key) => (key.startsWith('--') ? key : key.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`));
104597
- /** React appends `px` to non-zero numeric values, except unitless and custom properties. */
104598
- const cssPropertyValue = (key, value) => typeof value === 'number' && value !== 0 && !key.startsWith('--') && !UNITLESS_CSS_PROPERTIES.has(key)
104599
- ? `${value}px`
104600
- : `${value}`;
104601
- /**
104602
- * True for a value that should be serialized as a style object rather than passed through
104603
- * as an already-CSS string. React elements are excluded since they're valid objects too.
104604
- */
104605
- const style_object_to_css_isPlainObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value) && !external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().isValidElement(value);
104606
- /**
104607
- * Serialize a React-style inline style object (`{ color: "red", fontSize: 12 }`) into a
104608
- * CSS declaration string (`color:red;font-size:12px`), the shape hast/HTML expects for a
104609
- * `style` attribute. Empty (`undefined`/`null`/`''`) entries are dropped.
104610
- */
104611
- const styleObjectToCssText = (style) => Object.entries(style)
104612
- .filter(([, value]) => value !== undefined && value !== null && value !== '')
104613
- .map(([key, value]) => `${cssPropertyName(key)}:${cssPropertyValue(key, value)}`)
104614
- .join(';');
104615
-
104616
104936
  ;// ./processor/transform/mdxish/resolve-deferred-attribute-expression-props.ts
104617
104937
 
104618
104938