@readme/markdown 14.11.0 → 14.11.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
@@ -75719,6 +75719,18 @@ const tableTags = new Set([
75719
75719
  'th',
75720
75720
  'td',
75721
75721
  ]);
75722
+ /**
75723
+ * Replaces every paragraph node with its inline children. Used where paragraphs
75724
+ * are parser artifacts (remarkMdx wrapping inline JSX), not real content.
75725
+ */
75726
+ const unwrapParagraphNodes = (children) => {
75727
+ return children.flatMap(child => {
75728
+ if (child.type === 'paragraph' && 'children' in child && Array.isArray(child.children)) {
75729
+ return child.children;
75730
+ }
75731
+ return [child];
75732
+ });
75733
+ };
75722
75734
  /**
75723
75735
  * If the cell has exactly one paragraph child, unwrap it so its inline children sit
75724
75736
  * directly under the cell (matches GFM table cell shape and avoids stray `<p>` wrappers).
@@ -75730,12 +75742,7 @@ const unwrapSoleParagraph = (children) => {
75730
75742
  const paragraphCount = children.filter(c => c.type === 'paragraph').length;
75731
75743
  if (paragraphCount !== 1)
75732
75744
  return children;
75733
- return children.flatMap(child => {
75734
- if (child.type === 'paragraph' && 'children' in child && Array.isArray(child.children)) {
75735
- return child.children;
75736
- }
75737
- return [child];
75738
- });
75745
+ return unwrapParagraphNodes(children);
75739
75746
  };
75740
75747
  /**
75741
75748
  * Splice each text into `html` at its offset. Inserts at the same offset
@@ -76085,6 +76092,23 @@ const RUNTIME_COMPONENT_TAGS = new Set(['Variable', 'variable', 'html-block', 'r
76085
76092
  * Uses the html-tags package, converted to a Set<string> for efficient lookups.
76086
76093
  */
76087
76094
  const STANDARD_HTML_TAGS = new Set(html_tags_namespaceObject);
76095
+ /**
76096
+ * Table structural tags. Blank lines inside these carry deliberate meaning for
76097
+ * `mdxishTables` (e.g. splitting cell content into paragraphs, or deciding
76098
+ * whether a table stays plain HTML vs a JSX `<Table>`), so transforms that
76099
+ * neutralize or claim across blank lines must leave them alone.
76100
+ */
76101
+ const HTML_TABLE_STRUCTURE_TAGS = new Set([
76102
+ 'table',
76103
+ 'thead',
76104
+ 'tbody',
76105
+ 'tfoot',
76106
+ 'tr',
76107
+ 'td',
76108
+ 'th',
76109
+ 'caption',
76110
+ 'colgroup',
76111
+ ]);
76088
76112
  /**
76089
76113
  * HTML void elements — elements that have no closing tag and no children.
76090
76114
  *
@@ -76396,18 +76420,17 @@ const processTableNode = (node, index, parent, documentPosition) => {
76396
76420
  // same line as content becomes mdxJsxTextElement inside a paragraph).
76397
76421
  // Unwrap these so <td>/<th> sit directly under <tr>, and strip
76398
76422
  // whitespace-only text nodes to avoid rendering empty <p>/<br>.
76399
- const cleanChildren = (children) => children
76400
- .flatMap(child => {
76401
- if (child.type === 'paragraph' && 'children' in child && Array.isArray(child.children)) {
76402
- return child.children;
76403
- }
76404
- return [child];
76405
- })
76406
- .filter(child => !(child.type === 'text' && 'value' in child && typeof child.value === 'string' && !child.value.trim()));
76423
+ const removeWhitespaceOnlyTextNodes = (children) => children.filter(child => !(child.type === 'text' && 'value' in child && typeof child.value === 'string' && !child.value.trim()));
76407
76424
  visit(node, isMDXElement, (el) => {
76408
- if ('children' in el && Array.isArray(el.children)) {
76409
- el.children = cleanChildren(el.children);
76410
- }
76425
+ if (!('children' in el) || !Array.isArray(el.children))
76426
+ return;
76427
+ // Filtering transformers
76428
+ // A cell only unwraps a sole paragraph: multiple paragraphs are real
76429
+ // blank-line-separated content that must stay separated
76430
+ const unwrapped = isTableCell(el)
76431
+ ? unwrapSoleParagraph(el.children)
76432
+ : unwrapParagraphNodes(el.children);
76433
+ el.children = removeWhitespaceOnlyTextNodes(unwrapped);
76411
76434
  });
76412
76435
  parent.children[index] = {
76413
76436
  ...node,
@@ -100797,15 +100820,26 @@ const types_types = /** @type {const} */ ({
100797
100820
 
100798
100821
 
100799
100822
 
100823
+
100800
100824
  // Raw tags (type-1: pre/script/style/textarea) and block tags (type-6: div,
100801
100825
  // section, …) always start a block, so they stay flow even with trailing
100802
100826
  // content. Other lowercase tags (i, span, …) follow the type-7 rule and only
100803
100827
  // stay flow when nothing trails the close tag.
100804
100828
  const htmlFlowTagNames = new Set([...htmlRawNames, ...htmlBlockNames]);
100829
+ // Lowercase type-6 block tags claimable in flow even without a `{…}` attribute, so
100830
+ // blank lines between nested JSX siblings don't fragment the block. Excludes table
100831
+ // tags (mdxishTables owns their blank lines) and voids (never close).
100832
+ const plainBlockClaimTagNames = new Set([...htmlBlockNames].filter(tag => !HTML_TABLE_STRUCTURE_TAGS.has(tag) && !HTML_VOID_ELEMENTS.has(tag)));
100805
100833
  const syntax_nonLazyContinuationStart = {
100806
100834
  tokenize: syntax_tokenizeNonLazyContinuationStart,
100807
100835
  partial: true,
100808
100836
  };
100837
+ // Lookahead for `plainClaimLineStart`: is this line markup-only, or a paragraph
100838
+ // that merely starts with a tag? Run via `effects.check` so it never consumes.
100839
+ const markupOnlyContinuation = {
100840
+ tokenize: tokenizeMarkupOnlyContinuation,
100841
+ partial: true,
100842
+ };
100809
100843
  function resolveToMdxComponent(events) {
100810
100844
  let index = events.length;
100811
100845
  while (index > 0) {
@@ -100860,6 +100894,10 @@ function createTokenize(mode) {
100860
100894
  // (INLINE_COMPONENT_TAGS — Anchor, Glossary), also brace-gated.
100861
100895
  let isLowercaseTag = false;
100862
100896
  let sawBraceAttr = false;
100897
+ // A plain lowercase block tag claimed without a `{…}` attribute, gated by
100898
+ // `plainClaimLineStart`: after a blank line it may only continue on a tag line.
100899
+ let isPlainBlockClaim = false;
100900
+ let pendingBlankLine = false;
100863
100901
  // Code span tracking
100864
100902
  let codeSpanOpenSize = 0;
100865
100903
  let codeSpanCloseSize = 0;
@@ -101093,8 +101131,13 @@ function createTokenize(mode) {
101093
101131
  }
101094
101132
  // End of opening tag
101095
101133
  if (code === codes.greaterThan) {
101096
- if (requiresBraceAttr && !sawBraceAttr)
101097
- return nok(code);
101134
+ if (requiresBraceAttr && !sawBraceAttr) {
101135
+ // Plain lowercase block tags stay claimable in flow, gated per line by
101136
+ // `plainClaimLineStart`; everything else falls through to CommonMark.
101137
+ if (!isFlow || !plainBlockClaimTagNames.has(tagName))
101138
+ return nok(code);
101139
+ isPlainBlockClaim = true;
101140
+ }
101098
101141
  effects.consume(code);
101099
101142
  onOpenerLine = isFlow;
101100
101143
  return body;
@@ -101244,6 +101287,7 @@ function createTokenize(mode) {
101244
101287
  if (atLineStart && codeSpanOpenSize >= 3) {
101245
101288
  fenceChar = codes.graveAccent;
101246
101289
  fenceLength = codeSpanOpenSize;
101290
+ atLineStart = false;
101247
101291
  return inFencedCode(code);
101248
101292
  }
101249
101293
  return inCodeSpan(code);
@@ -101391,8 +101435,14 @@ function createTokenize(mode) {
101391
101435
  effects.consume(code);
101392
101436
  return nestedOpenTagName;
101393
101437
  }
101394
- // Only increment depth for same-name tags that are followed by valid tag-end chars
101395
- if (closingTagName === tagName && (code === codes.greaterThan || code === codes.slash || code === codes.space || code === codes.horizontalTab)) {
101438
+ // Same-name opener followed by a tag-end char bumps depth. A line ending
101439
+ // counts too: Prettier puts a newline right after the name (`<div\n …\n>`).
101440
+ if (closingTagName === tagName &&
101441
+ (code === codes.greaterThan ||
101442
+ code === codes.slash ||
101443
+ code === codes.space ||
101444
+ code === codes.horizontalTab ||
101445
+ markdownLineEnding(code))) {
101396
101446
  depth += 1;
101397
101447
  }
101398
101448
  atLineStart = false;
@@ -101481,6 +101531,10 @@ function createTokenize(mode) {
101481
101531
  }
101482
101532
  function bodyContinuationBefore(code) {
101483
101533
  if (code === null || markdownLineEnding(code)) {
101534
+ // Empty line: outside any `{…}` expression this is CommonMark's html-block
101535
+ // terminator, so a plain block claim must pass the guard below to continue.
101536
+ if (isPlainBlockClaim && braceDepth === 0)
101537
+ pendingBlankLine = true;
101484
101538
  return bodyContinuationStart(code);
101485
101539
  }
101486
101540
  effects.enter('mdxComponentData');
@@ -101492,19 +101546,52 @@ function createTokenize(mode) {
101492
101546
  return inBodyBraceString(code);
101493
101547
  return inBodyBraceExpr(code);
101494
101548
  }
101495
- // Detect tilde fences at line start
101496
- if (atLineStart && code === codes.tilde) {
101549
+ if (isPlainBlockClaim)
101550
+ return plainClaimLineStart(code);
101551
+ return bodyLineStart(code);
101552
+ }
101553
+ // Dispatch a non-blank continuation line: fenced code at line start, else body.
101554
+ function bodyLineStart(code) {
101555
+ if (atLineStart && code === codes.tilde)
101497
101556
  return bodyAfterLineStart(code);
101498
- }
101499
- // Detect backtick fences at line start
101500
101557
  if (atLineStart && code === codes.graveAccent) {
101501
101558
  codeSpanOpenSize = 0;
101502
- atLineStart = false;
101559
+ // Leave `atLineStart` set — `countOpenTicks` needs it to tell a fence from an
101560
+ // inline code span once the run of backticks is fully counted; it's cleared once
101561
+ // that fence-vs-span decision has actually been made.
101503
101562
  return countOpenTicks(code);
101504
101563
  }
101505
101564
  atLineStart = false;
101506
101565
  return body(code);
101507
101566
  }
101567
+ // Line-start gate for plain block claims. After a blank line the block may only
101568
+ // continue on a tag line (`<…`); any markdown island (`**bold**`, `[block:…]`, a
101569
+ // fence) refuses so CommonMark html-flow reparses it exactly as it does today.
101570
+ function plainClaimLineStart(code) {
101571
+ // Leading whitespace only → treat as a blank line, matching CommonMark.
101572
+ if (code === codes.space || code === codes.horizontalTab) {
101573
+ effects.consume(code);
101574
+ return plainClaimLineStart;
101575
+ }
101576
+ if (code === null || markdownLineEnding(code)) {
101577
+ pendingBlankLine = true;
101578
+ effects.exit('mdxComponentData');
101579
+ return bodyContinuationStart(code);
101580
+ }
101581
+ // Across a blank line the block only continues onto a markup-only line; a
101582
+ // paragraph that merely starts with a tag must fall back so its markdown
101583
+ // parses and rehype-raw re-nests it into the wrapper.
101584
+ if (pendingBlankLine) {
101585
+ if (code !== codes.lessThan)
101586
+ return nok(code);
101587
+ return effects.check(markupOnlyContinuation, plainClaimContinue, nok)(code);
101588
+ }
101589
+ return bodyLineStart(code);
101590
+ }
101591
+ function plainClaimContinue(code) {
101592
+ pendingBlankLine = false;
101593
+ return bodyLineStart(code);
101594
+ }
101508
101595
  // ── Shared lazy continuation failure ───────────────────────────────────
101509
101596
  function continuationAfter(code) {
101510
101597
  if (code === null) {
@@ -101535,6 +101622,46 @@ function syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
101535
101622
  return ok(code);
101536
101623
  }
101537
101624
  }
101625
+ // A markup-only line opens with a tag (`<x`/`</x`) and ends (ignoring trailing
101626
+ // spaces) at a `>`. That distinguishes a structural continuation like
101627
+ // `<span>b</span></div>` from a paragraph like `<b>Note:</b> read *this*`.
101628
+ function tokenizeMarkupOnlyContinuation(effects, ok, nok) {
101629
+ let lastNonSpace = null;
101630
+ return start;
101631
+ function start(code) {
101632
+ // Caller guarantees we are at `<` at the (already de-indented) line start.
101633
+ effects.enter(types_types.data);
101634
+ effects.consume(code);
101635
+ return afterLessThan;
101636
+ }
101637
+ function afterLessThan(code) {
101638
+ if (code === codes.slash) {
101639
+ effects.consume(code);
101640
+ return afterSlash;
101641
+ }
101642
+ return afterSlash(code);
101643
+ }
101644
+ // The `<` (or `</`) must introduce a real tag, not a stray `<` in prose.
101645
+ function afterSlash(code) {
101646
+ if (asciiAlpha(code)) {
101647
+ lastNonSpace = code;
101648
+ effects.consume(code);
101649
+ return scanToLineEnd;
101650
+ }
101651
+ effects.exit(types_types.data);
101652
+ return nok(code);
101653
+ }
101654
+ function scanToLineEnd(code) {
101655
+ if (code === null || markdownLineEnding(code)) {
101656
+ effects.exit(types_types.data);
101657
+ return lastNonSpace === codes.greaterThan ? ok(code) : nok(code);
101658
+ }
101659
+ if (!markdownSpace(code))
101660
+ lastNonSpace = code;
101661
+ effects.consume(code);
101662
+ return scanToLineEnd;
101663
+ }
101664
+ }
101538
101665
  /**
101539
101666
  * Micromark extension that tokenizes MDX-like components.
101540
101667
  *
@@ -101781,6 +101908,8 @@ const mdxishInlineMdxComponents = () => tree => {
101781
101908
 
101782
101909
 
101783
101910
 
101911
+ /** Matches a JSX attribute expression (e.g. `key={i}`) anywhere in a string. */
101912
+ const NESTED_ATTR_EXPRESSION_RE = /[\w-]+\s*=\s*\{/;
101784
101913
  /**
101785
101914
  * Reduce leading whitespace on all lines just enough to prevent
101786
101915
  * remark from treating indented content as code blocks (4+ spaces).
@@ -101940,10 +102069,16 @@ const mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
101940
102069
  // inline, which is how ReadMe's custom components are modeled).
101941
102070
  if (!isPascal && parent.type === 'paragraph')
101942
102071
  return;
101943
- // Lowercase HTML tags are only eligible when the tokenizer claimed them
101944
- // for JSX-expression attributes. Plain HTML should stay as html nodes so
102072
+ // Lowercase HTML tags are eligible when they (or a descendant tag in their
102073
+ // content, e.g. a `.map()` body returning JSX with `key={i}`) carry a
102074
+ // JSX-expression attribute. Without this, a wrapper `<div>` with only plain
102075
+ // attributes (or none) swallows its whole nested block — including any
102076
+ // `style={{...}}`/`.map()` JSX inside it — as literal HTML text, which
102077
+ // rehype-raw's parse5 pass then garbles (it has no notion of JS expressions).
102078
+ // Plain HTML with no expressions anywhere stays as an html node so
101945
102079
  // rehype-raw handles it as normal.
101946
- if (!isPascal && !hasExpressionAttr(attributes))
102080
+ const hasNestedExpressionAttr = !selfClosing && NESTED_ATTR_EXPRESSION_RE.test(contentAfterTag);
102081
+ if (!isPascal && !hasExpressionAttr(attributes) && !hasNestedExpressionAttr)
101947
102082
  return;
101948
102083
  const closingTagStr = `</${tag}>`;
101949
102084
  // Case 1: Self-closing tag
@@ -102382,15 +102517,17 @@ const evalExpression = (expression, scope) => {
102382
102517
 
102383
102518
 
102384
102519
 
102520
+ /** True for an array containing at least one React element, e.g. the result of `.map()` returning JSX. */
102521
+ const isRenderableElementArray = (value) => Array.isArray(value) && value.some((external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default()).isValidElement);
102385
102522
  /** Given the type of the expression result, create the corresponding mdast node. */
102386
102523
  const createEvaluatedNode = (result, position) => {
102387
102524
  if (result === null || result === undefined) {
102388
102525
  return { type: 'text', value: '', position };
102389
102526
  }
102390
- else if (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().isValidElement(result)) {
102391
- // Convert react elements to its HTML representation
102392
- // This must come before the object check as this is a subset of it
102393
- return { type: 'html', value: (0,server_browser/* renderToStaticMarkup */.qV)(result), position };
102527
+ else if (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().isValidElement(result) || isRenderableElementArray(result)) {
102528
+ // Convert react elements (or arrays of them, e.g. `.map()` returning JSX) to their HTML
102529
+ // representation. This must come before the object check as both are a subset of it.
102530
+ 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 };
102394
102531
  }
102395
102532
  else if (typeof result === 'object') {
102396
102533
  return { type: 'text', value: JSON.stringify(result), position };
@@ -102430,6 +102567,47 @@ const evaluateExpressions = () => (tree, file) => {
102430
102567
  };
102431
102568
  /* harmony default export */ const evaluate_expressions = (evaluateExpressions);
102432
102569
 
102570
+ ;// ./processor/transform/mdxish/evaluate-style-block-expressions.ts
102571
+
102572
+
102573
+
102574
+ // Matches a standalone `<style ...>{ <expr> }</style>` block — the JSX shape MDX evaluates
102575
+ // (typically a template-literal-wrapped CSS string) but which mdxish otherwise leaves as
102576
+ // literal, invalid-CSS text (see CX-3646).
102577
+ const STYLE_EXPRESSION_RE = /^(<style\b[^>]*>)\s*\{([\s\S]*)\}\s*(<\/style>)$/i;
102578
+ /**
102579
+ * Evaluate the JSX expression wrapping a `<style>` tag's contents (typically a template
102580
+ * literal, e.g. `<style>{\`.foo { color: red; }\`}</style>`) so the tag ends up holding plain
102581
+ * CSS text instead of the literal `{`...`}` wrapper — which the browser treats as invalid CSS
102582
+ * and drops the entire stylesheet for.
102583
+ *
102584
+ * `<style>` is one of CommonMark's "raw text" HTML elements (along with script/pre/textarea):
102585
+ * its contents are captured verbatim as a single `html` mdast node with no inner tokenization,
102586
+ * so this expression never reaches the mdxFlowExpression tokenizer or `evaluateExpressions` —
102587
+ * it has to be matched and evaluated directly against the raw node's string value.
102588
+ *
102589
+ * Must run after `evaluateExports` (needs `file.data.mdxishScope`) and before `remarkRehype`
102590
+ * turns `html` mdast nodes into raw hast strings. Skipped in safeMode.
102591
+ */
102592
+ const evaluateStyleBlockExpressions = () => (tree, file) => {
102593
+ const scope = { ...file.data.mdxishScope, React: (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default()) };
102594
+ visit(tree, 'html', (node) => {
102595
+ const match = node.value.trim().match(STYLE_EXPRESSION_RE);
102596
+ if (!match)
102597
+ return;
102598
+ const [, openTag, expression, closeTag] = match;
102599
+ try {
102600
+ const css = evalExpression(expression, scope);
102601
+ node.value = `${openTag}${String(css)}${closeTag}`;
102602
+ }
102603
+ catch {
102604
+ // Evaluation failed — leave the node untouched so it round-trips as literal text.
102605
+ }
102606
+ });
102607
+ return tree;
102608
+ };
102609
+ /* harmony default export */ const evaluate_style_block_expressions = (evaluateStyleBlockExpressions);
102610
+
102433
102611
  ;// ./processor/transform/mdxish/heading-slugs.ts
102434
102612
 
102435
102613
 
@@ -104286,10 +104464,84 @@ function removeJSXComments(content) {
104286
104464
  return content.replace(JSX_COMMENT_REGEX, '');
104287
104465
  }
104288
104466
 
104467
+ ;// ./processor/transform/mdxish/style-object-to-css.ts
104468
+
104469
+ /**
104470
+ * CSS properties React treats as unitless — a bare number stays as-is instead of
104471
+ * getting `px` appended. Mirrors React DOM's `isUnitlessNumber` whitelist.
104472
+ * @see https://github.com/facebook/react/blob/main/packages/react-dom-bindings/src/shared/CSSProperty.js
104473
+ */
104474
+ const UNITLESS_CSS_PROPERTIES = new Set([
104475
+ 'animationIterationCount',
104476
+ 'aspectRatio',
104477
+ 'borderImageOutset',
104478
+ 'borderImageSlice',
104479
+ 'borderImageWidth',
104480
+ 'boxFlex',
104481
+ 'boxFlexGroup',
104482
+ 'boxOrdinalGroup',
104483
+ 'columnCount',
104484
+ 'columns',
104485
+ 'flex',
104486
+ 'flexGrow',
104487
+ 'flexPositive',
104488
+ 'flexShrink',
104489
+ 'flexNegative',
104490
+ 'flexOrder',
104491
+ 'gridArea',
104492
+ 'gridRow',
104493
+ 'gridRowEnd',
104494
+ 'gridRowSpan',
104495
+ 'gridRowStart',
104496
+ 'gridColumn',
104497
+ 'gridColumnEnd',
104498
+ 'gridColumnSpan',
104499
+ 'gridColumnStart',
104500
+ 'fontWeight',
104501
+ 'lineClamp',
104502
+ 'lineHeight',
104503
+ 'opacity',
104504
+ 'order',
104505
+ 'orphans',
104506
+ 'tabSize',
104507
+ 'widows',
104508
+ 'zIndex',
104509
+ 'zoom',
104510
+ 'fillOpacity',
104511
+ 'floodOpacity',
104512
+ 'stopOpacity',
104513
+ 'strokeDasharray',
104514
+ 'strokeDashoffset',
104515
+ 'strokeMiterlimit',
104516
+ 'strokeOpacity',
104517
+ 'strokeWidth',
104518
+ ]);
104519
+ /** Convert a camelCase (or CSS custom property) key into its kebab-case CSS name. */
104520
+ const cssPropertyName = (key) => (key.startsWith('--') ? key : key.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`));
104521
+ /** React appends `px` to non-zero numeric values, except unitless and custom properties. */
104522
+ const cssPropertyValue = (key, value) => typeof value === 'number' && value !== 0 && !key.startsWith('--') && !UNITLESS_CSS_PROPERTIES.has(key)
104523
+ ? `${value}px`
104524
+ : `${value}`;
104525
+ /**
104526
+ * True for a value that should be serialized as a style object rather than passed through
104527
+ * as an already-CSS string. React elements are excluded since they're valid objects too.
104528
+ */
104529
+ 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);
104530
+ /**
104531
+ * Serialize a React-style inline style object (`{ color: "red", fontSize: 12 }`) into a
104532
+ * CSS declaration string (`color:red;font-size:12px`), the shape hast/HTML expects for a
104533
+ * `style` attribute. Empty (`undefined`/`null`/`''`) entries are dropped.
104534
+ */
104535
+ const styleObjectToCssText = (style) => Object.entries(style)
104536
+ .filter(([, value]) => value !== undefined && value !== null && value !== '')
104537
+ .map(([key, value]) => `${cssPropertyName(key)}:${cssPropertyValue(key, value)}`)
104538
+ .join(';');
104539
+
104289
104540
  ;// ./processor/transform/mdxish/resolve-deferred-attribute-expression-props.ts
104290
104541
 
104291
104542
 
104292
104543
 
104544
+
104293
104545
  /**
104294
104546
  * Resolve attribute expressions that `mdxJsxElementHandler` deferred.
104295
104547
  *
@@ -104311,7 +104563,10 @@ const resolveDeferredAttributeExpressionProps = () => (tree, file) => {
104311
104563
  const properties = node.properties;
104312
104564
  Object.entries(deferredExpressions).forEach(([name, source]) => {
104313
104565
  try {
104314
- properties[name] = evalExpression(source, scope);
104566
+ const result = evalExpression(source, scope);
104567
+ // hast/HTML `style` is a plain CSS string; a `style={{...}}` expression evaluates to
104568
+ // a JS object, which must be serialized or it renders as the literal "[object Object]".
104569
+ properties[name] = name === 'style' && style_object_to_css_isPlainObject(result) ? styleObjectToCssText(result) : result;
104315
104570
  }
104316
104571
  catch {
104317
104572
  // Evaluation failed — fall back to the raw expression source so the attribute
@@ -104631,13 +104886,13 @@ function normalizeTableSeparator(content) {
104631
104886
  ;// ./processor/transform/mdxish/terminate-html-flow-blocks.ts
104632
104887
 
104633
104888
 
104889
+
104634
104890
  const STANDALONE_HTML_LINE_REGEX = /^(<[a-z][^<>]*>|<\/[a-z][^<>]*>)+\s*$/;
104635
104891
  const HTML_LINE_WITH_CONTENT_REGEX = /^<[a-z][^<>]*>.*<\/[a-z][^<>]*>(?:[^<]*)$/;
104636
- const terminate_html_flow_blocks_TABLE_STRUCTURE_TAGS = ['table', 'thead', 'tbody', 'tfoot', 'tr', 'td', 'th', 'caption', 'colgroup'];
104637
104892
  // Tags whose contents must be preserved as is, inserting a blank line after the
104638
104893
  // opener corrupts the payload.
104639
104894
  // htmlRawNames here refer to <pre>, <textarea>, <script>, <style>
104640
- const RAW_CONTENT_TAGS = [...htmlRawNames, ...terminate_html_flow_blocks_TABLE_STRUCTURE_TAGS];
104895
+ const RAW_CONTENT_TAGS = [...htmlRawNames, ...HTML_TABLE_STRUCTURE_TAGS];
104641
104896
  // The `(?=[\s/>])` lookahead avoids false matches on lookalike names like `<script-foo>`.
104642
104897
  const RAW_CONTENT_TAG_MATCHERS = RAW_CONTENT_TAGS.map(tag => ({
104643
104898
  open: new RegExp(`<${tag}(?=[\\s/>])[^>]*?(?<!/)>`, 'gi'),
@@ -105435,6 +105690,7 @@ function loadComponents() {
105435
105690
 
105436
105691
 
105437
105692
 
105693
+
105438
105694
 
105439
105695
 
105440
105696
  const defaultTransformers = [
@@ -105585,6 +105841,7 @@ function mdxish(mdContent, opts = {}) {
105585
105841
  .use(safeMode ? undefined : evaluate_exports) // Evaluate `export const/function` and stash scope on file.data.mdxishScope
105586
105842
  .use(remarkBreaks) // Must precede evaluateExpressions to avoid splitting the \n in an evaluated template literal into a <br> node
105587
105843
  .use(safeMode ? undefined : evaluate_expressions) // Evaluate self-contained MDX expressions (e.g. `{1+1}`)
105844
+ .use(safeMode ? undefined : evaluate_style_block_expressions) // Evaluate `<style>{`...`}</style>` template literals into plain CSS
105588
105845
  .use(variables_code, { variables }) // Resolve <<...>> and {user.*} inside code and inline code nodes
105589
105846
  .use(remarkRehype, { allowDangerousHtml: true, handlers: mdxComponentHandlers })
105590
105847
  .use(preserveBooleanProperties) // RehypeRaw converts boolean properties to empty strings