@readme/markdown 14.10.3 → 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/index.d.ts +1 -0
- package/dist/lib/index.d.ts +1 -0
- package/dist/lib/micromark/mdx-expression-lenient/index.d.ts +1 -0
- package/dist/lib/micromark/mdx-expression-lenient/syntax.d.ts +2 -0
- package/dist/main.js +430 -237
- package/dist/main.node.js +430 -237
- package/dist/main.node.js.map +1 -1
- package/dist/processor/transform/mdxish/evaluate-style-block-expressions.d.ts +18 -0
- package/dist/processor/transform/mdxish/remove-jsx-comments.d.ts +11 -0
- package/dist/processor/transform/mdxish/resolve-esm-imports.d.ts +13 -0
- package/dist/processor/transform/mdxish/style-object-to-css.d.ts +11 -0
- package/dist/processor/transform/mdxish/tables/utils.d.ts +5 -0
- package/dist/render-fixture.node.js +430 -237
- package/dist/render-fixture.node.js.map +1 -1
- package/dist/utils/common-html-words.d.ts +7 -0
- package/package.json +2 -2
- package/dist/processor/transform/mdxish/preprocess-jsx-expressions.d.ts +0 -23
package/dist/main.node.js
CHANGED
|
@@ -95943,6 +95943,18 @@ const tableTags = new Set([
|
|
|
95943
95943
|
'th',
|
|
95944
95944
|
'td',
|
|
95945
95945
|
]);
|
|
95946
|
+
/**
|
|
95947
|
+
* Replaces every paragraph node with its inline children. Used where paragraphs
|
|
95948
|
+
* are parser artifacts (remarkMdx wrapping inline JSX), not real content.
|
|
95949
|
+
*/
|
|
95950
|
+
const unwrapParagraphNodes = (children) => {
|
|
95951
|
+
return children.flatMap(child => {
|
|
95952
|
+
if (child.type === 'paragraph' && 'children' in child && Array.isArray(child.children)) {
|
|
95953
|
+
return child.children;
|
|
95954
|
+
}
|
|
95955
|
+
return [child];
|
|
95956
|
+
});
|
|
95957
|
+
};
|
|
95946
95958
|
/**
|
|
95947
95959
|
* If the cell has exactly one paragraph child, unwrap it so its inline children sit
|
|
95948
95960
|
* directly under the cell (matches GFM table cell shape and avoids stray `<p>` wrappers).
|
|
@@ -95954,12 +95966,7 @@ const unwrapSoleParagraph = (children) => {
|
|
|
95954
95966
|
const paragraphCount = children.filter(c => c.type === 'paragraph').length;
|
|
95955
95967
|
if (paragraphCount !== 1)
|
|
95956
95968
|
return children;
|
|
95957
|
-
return children
|
|
95958
|
-
if (child.type === 'paragraph' && 'children' in child && Array.isArray(child.children)) {
|
|
95959
|
-
return child.children;
|
|
95960
|
-
}
|
|
95961
|
-
return [child];
|
|
95962
|
-
});
|
|
95969
|
+
return unwrapParagraphNodes(children);
|
|
95963
95970
|
};
|
|
95964
95971
|
/**
|
|
95965
95972
|
* Splice each text into `html` at its offset. Inserts at the same offset
|
|
@@ -96309,6 +96316,23 @@ const RUNTIME_COMPONENT_TAGS = new Set(['Variable', 'variable', 'html-block', 'r
|
|
|
96309
96316
|
* Uses the html-tags package, converted to a Set<string> for efficient lookups.
|
|
96310
96317
|
*/
|
|
96311
96318
|
const STANDARD_HTML_TAGS = new Set(html_tags_namespaceObject);
|
|
96319
|
+
/**
|
|
96320
|
+
* Table structural tags. Blank lines inside these carry deliberate meaning for
|
|
96321
|
+
* `mdxishTables` (e.g. splitting cell content into paragraphs, or deciding
|
|
96322
|
+
* whether a table stays plain HTML vs a JSX `<Table>`), so transforms that
|
|
96323
|
+
* neutralize or claim across blank lines must leave them alone.
|
|
96324
|
+
*/
|
|
96325
|
+
const HTML_TABLE_STRUCTURE_TAGS = new Set([
|
|
96326
|
+
'table',
|
|
96327
|
+
'thead',
|
|
96328
|
+
'tbody',
|
|
96329
|
+
'tfoot',
|
|
96330
|
+
'tr',
|
|
96331
|
+
'td',
|
|
96332
|
+
'th',
|
|
96333
|
+
'caption',
|
|
96334
|
+
'colgroup',
|
|
96335
|
+
]);
|
|
96312
96336
|
/**
|
|
96313
96337
|
* HTML void elements — elements that have no closing tag and no children.
|
|
96314
96338
|
*
|
|
@@ -96620,18 +96644,17 @@ const processTableNode = (node, index, parent, documentPosition) => {
|
|
|
96620
96644
|
// same line as content becomes mdxJsxTextElement inside a paragraph).
|
|
96621
96645
|
// Unwrap these so <td>/<th> sit directly under <tr>, and strip
|
|
96622
96646
|
// whitespace-only text nodes to avoid rendering empty <p>/<br>.
|
|
96623
|
-
const
|
|
96624
|
-
.flatMap(child => {
|
|
96625
|
-
if (child.type === 'paragraph' && 'children' in child && Array.isArray(child.children)) {
|
|
96626
|
-
return child.children;
|
|
96627
|
-
}
|
|
96628
|
-
return [child];
|
|
96629
|
-
})
|
|
96630
|
-
.filter(child => !(child.type === 'text' && 'value' in child && typeof child.value === 'string' && !child.value.trim()));
|
|
96647
|
+
const removeWhitespaceOnlyTextNodes = (children) => children.filter(child => !(child.type === 'text' && 'value' in child && typeof child.value === 'string' && !child.value.trim()));
|
|
96631
96648
|
visit(node, isMDXElement, (el) => {
|
|
96632
|
-
if ('children' in el
|
|
96633
|
-
|
|
96634
|
-
|
|
96649
|
+
if (!('children' in el) || !Array.isArray(el.children))
|
|
96650
|
+
return;
|
|
96651
|
+
// Filtering transformers
|
|
96652
|
+
// A cell only unwraps a sole paragraph: multiple paragraphs are real
|
|
96653
|
+
// blank-line-separated content that must stay separated
|
|
96654
|
+
const unwrapped = isTableCell(el)
|
|
96655
|
+
? unwrapSoleParagraph(el.children)
|
|
96656
|
+
: unwrapParagraphNodes(el.children);
|
|
96657
|
+
el.children = removeWhitespaceOnlyTextNodes(unwrapped);
|
|
96635
96658
|
});
|
|
96636
96659
|
parent.children[index] = {
|
|
96637
96660
|
...node,
|
|
@@ -121021,15 +121044,26 @@ const types_types = /** @type {const} */ ({
|
|
|
121021
121044
|
|
|
121022
121045
|
|
|
121023
121046
|
|
|
121047
|
+
|
|
121024
121048
|
// Raw tags (type-1: pre/script/style/textarea) and block tags (type-6: div,
|
|
121025
121049
|
// section, …) always start a block, so they stay flow even with trailing
|
|
121026
121050
|
// content. Other lowercase tags (i, span, …) follow the type-7 rule and only
|
|
121027
121051
|
// stay flow when nothing trails the close tag.
|
|
121028
121052
|
const htmlFlowTagNames = new Set([...htmlRawNames, ...htmlBlockNames]);
|
|
121053
|
+
// Lowercase type-6 block tags claimable in flow even without a `{…}` attribute, so
|
|
121054
|
+
// blank lines between nested JSX siblings don't fragment the block. Excludes table
|
|
121055
|
+
// tags (mdxishTables owns their blank lines) and voids (never close).
|
|
121056
|
+
const plainBlockClaimTagNames = new Set([...htmlBlockNames].filter(tag => !HTML_TABLE_STRUCTURE_TAGS.has(tag) && !HTML_VOID_ELEMENTS.has(tag)));
|
|
121029
121057
|
const syntax_nonLazyContinuationStart = {
|
|
121030
121058
|
tokenize: syntax_tokenizeNonLazyContinuationStart,
|
|
121031
121059
|
partial: true,
|
|
121032
121060
|
};
|
|
121061
|
+
// Lookahead for `plainClaimLineStart`: is this line markup-only, or a paragraph
|
|
121062
|
+
// that merely starts with a tag? Run via `effects.check` so it never consumes.
|
|
121063
|
+
const markupOnlyContinuation = {
|
|
121064
|
+
tokenize: tokenizeMarkupOnlyContinuation,
|
|
121065
|
+
partial: true,
|
|
121066
|
+
};
|
|
121033
121067
|
function resolveToMdxComponent(events) {
|
|
121034
121068
|
let index = events.length;
|
|
121035
121069
|
while (index > 0) {
|
|
@@ -121084,6 +121118,10 @@ function createTokenize(mode) {
|
|
|
121084
121118
|
// (INLINE_COMPONENT_TAGS — Anchor, Glossary), also brace-gated.
|
|
121085
121119
|
let isLowercaseTag = false;
|
|
121086
121120
|
let sawBraceAttr = false;
|
|
121121
|
+
// A plain lowercase block tag claimed without a `{…}` attribute, gated by
|
|
121122
|
+
// `plainClaimLineStart`: after a blank line it may only continue on a tag line.
|
|
121123
|
+
let isPlainBlockClaim = false;
|
|
121124
|
+
let pendingBlankLine = false;
|
|
121087
121125
|
// Code span tracking
|
|
121088
121126
|
let codeSpanOpenSize = 0;
|
|
121089
121127
|
let codeSpanCloseSize = 0;
|
|
@@ -121317,8 +121355,13 @@ function createTokenize(mode) {
|
|
|
121317
121355
|
}
|
|
121318
121356
|
// End of opening tag
|
|
121319
121357
|
if (code === codes.greaterThan) {
|
|
121320
|
-
if (requiresBraceAttr && !sawBraceAttr)
|
|
121321
|
-
|
|
121358
|
+
if (requiresBraceAttr && !sawBraceAttr) {
|
|
121359
|
+
// Plain lowercase block tags stay claimable in flow, gated per line by
|
|
121360
|
+
// `plainClaimLineStart`; everything else falls through to CommonMark.
|
|
121361
|
+
if (!isFlow || !plainBlockClaimTagNames.has(tagName))
|
|
121362
|
+
return nok(code);
|
|
121363
|
+
isPlainBlockClaim = true;
|
|
121364
|
+
}
|
|
121322
121365
|
effects.consume(code);
|
|
121323
121366
|
onOpenerLine = isFlow;
|
|
121324
121367
|
return body;
|
|
@@ -121468,6 +121511,7 @@ function createTokenize(mode) {
|
|
|
121468
121511
|
if (atLineStart && codeSpanOpenSize >= 3) {
|
|
121469
121512
|
fenceChar = codes.graveAccent;
|
|
121470
121513
|
fenceLength = codeSpanOpenSize;
|
|
121514
|
+
atLineStart = false;
|
|
121471
121515
|
return inFencedCode(code);
|
|
121472
121516
|
}
|
|
121473
121517
|
return inCodeSpan(code);
|
|
@@ -121615,8 +121659,14 @@ function createTokenize(mode) {
|
|
|
121615
121659
|
effects.consume(code);
|
|
121616
121660
|
return nestedOpenTagName;
|
|
121617
121661
|
}
|
|
121618
|
-
//
|
|
121619
|
-
|
|
121662
|
+
// Same-name opener followed by a tag-end char bumps depth. A line ending
|
|
121663
|
+
// counts too: Prettier puts a newline right after the name (`<div\n …\n>`).
|
|
121664
|
+
if (closingTagName === tagName &&
|
|
121665
|
+
(code === codes.greaterThan ||
|
|
121666
|
+
code === codes.slash ||
|
|
121667
|
+
code === codes.space ||
|
|
121668
|
+
code === codes.horizontalTab ||
|
|
121669
|
+
markdownLineEnding(code))) {
|
|
121620
121670
|
depth += 1;
|
|
121621
121671
|
}
|
|
121622
121672
|
atLineStart = false;
|
|
@@ -121705,6 +121755,10 @@ function createTokenize(mode) {
|
|
|
121705
121755
|
}
|
|
121706
121756
|
function bodyContinuationBefore(code) {
|
|
121707
121757
|
if (code === null || markdownLineEnding(code)) {
|
|
121758
|
+
// Empty line: outside any `{…}` expression this is CommonMark's html-block
|
|
121759
|
+
// terminator, so a plain block claim must pass the guard below to continue.
|
|
121760
|
+
if (isPlainBlockClaim && braceDepth === 0)
|
|
121761
|
+
pendingBlankLine = true;
|
|
121708
121762
|
return bodyContinuationStart(code);
|
|
121709
121763
|
}
|
|
121710
121764
|
effects.enter('mdxComponentData');
|
|
@@ -121716,19 +121770,52 @@ function createTokenize(mode) {
|
|
|
121716
121770
|
return inBodyBraceString(code);
|
|
121717
121771
|
return inBodyBraceExpr(code);
|
|
121718
121772
|
}
|
|
121719
|
-
|
|
121720
|
-
|
|
121773
|
+
if (isPlainBlockClaim)
|
|
121774
|
+
return plainClaimLineStart(code);
|
|
121775
|
+
return bodyLineStart(code);
|
|
121776
|
+
}
|
|
121777
|
+
// Dispatch a non-blank continuation line: fenced code at line start, else body.
|
|
121778
|
+
function bodyLineStart(code) {
|
|
121779
|
+
if (atLineStart && code === codes.tilde)
|
|
121721
121780
|
return bodyAfterLineStart(code);
|
|
121722
|
-
}
|
|
121723
|
-
// Detect backtick fences at line start
|
|
121724
121781
|
if (atLineStart && code === codes.graveAccent) {
|
|
121725
121782
|
codeSpanOpenSize = 0;
|
|
121726
|
-
atLineStart
|
|
121783
|
+
// Leave `atLineStart` set — `countOpenTicks` needs it to tell a fence from an
|
|
121784
|
+
// inline code span once the run of backticks is fully counted; it's cleared once
|
|
121785
|
+
// that fence-vs-span decision has actually been made.
|
|
121727
121786
|
return countOpenTicks(code);
|
|
121728
121787
|
}
|
|
121729
121788
|
atLineStart = false;
|
|
121730
121789
|
return body(code);
|
|
121731
121790
|
}
|
|
121791
|
+
// Line-start gate for plain block claims. After a blank line the block may only
|
|
121792
|
+
// continue on a tag line (`<…`); any markdown island (`**bold**`, `[block:…]`, a
|
|
121793
|
+
// fence) refuses so CommonMark html-flow reparses it exactly as it does today.
|
|
121794
|
+
function plainClaimLineStart(code) {
|
|
121795
|
+
// Leading whitespace only → treat as a blank line, matching CommonMark.
|
|
121796
|
+
if (code === codes.space || code === codes.horizontalTab) {
|
|
121797
|
+
effects.consume(code);
|
|
121798
|
+
return plainClaimLineStart;
|
|
121799
|
+
}
|
|
121800
|
+
if (code === null || markdownLineEnding(code)) {
|
|
121801
|
+
pendingBlankLine = true;
|
|
121802
|
+
effects.exit('mdxComponentData');
|
|
121803
|
+
return bodyContinuationStart(code);
|
|
121804
|
+
}
|
|
121805
|
+
// Across a blank line the block only continues onto a markup-only line; a
|
|
121806
|
+
// paragraph that merely starts with a tag must fall back so its markdown
|
|
121807
|
+
// parses and rehype-raw re-nests it into the wrapper.
|
|
121808
|
+
if (pendingBlankLine) {
|
|
121809
|
+
if (code !== codes.lessThan)
|
|
121810
|
+
return nok(code);
|
|
121811
|
+
return effects.check(markupOnlyContinuation, plainClaimContinue, nok)(code);
|
|
121812
|
+
}
|
|
121813
|
+
return bodyLineStart(code);
|
|
121814
|
+
}
|
|
121815
|
+
function plainClaimContinue(code) {
|
|
121816
|
+
pendingBlankLine = false;
|
|
121817
|
+
return bodyLineStart(code);
|
|
121818
|
+
}
|
|
121732
121819
|
// ── Shared lazy continuation failure ───────────────────────────────────
|
|
121733
121820
|
function continuationAfter(code) {
|
|
121734
121821
|
if (code === null) {
|
|
@@ -121759,6 +121846,46 @@ function syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
|
|
|
121759
121846
|
return ok(code);
|
|
121760
121847
|
}
|
|
121761
121848
|
}
|
|
121849
|
+
// A markup-only line opens with a tag (`<x`/`</x`) and ends (ignoring trailing
|
|
121850
|
+
// spaces) at a `>`. That distinguishes a structural continuation like
|
|
121851
|
+
// `<span>b</span></div>` from a paragraph like `<b>Note:</b> read *this*`.
|
|
121852
|
+
function tokenizeMarkupOnlyContinuation(effects, ok, nok) {
|
|
121853
|
+
let lastNonSpace = null;
|
|
121854
|
+
return start;
|
|
121855
|
+
function start(code) {
|
|
121856
|
+
// Caller guarantees we are at `<` at the (already de-indented) line start.
|
|
121857
|
+
effects.enter(types_types.data);
|
|
121858
|
+
effects.consume(code);
|
|
121859
|
+
return afterLessThan;
|
|
121860
|
+
}
|
|
121861
|
+
function afterLessThan(code) {
|
|
121862
|
+
if (code === codes.slash) {
|
|
121863
|
+
effects.consume(code);
|
|
121864
|
+
return afterSlash;
|
|
121865
|
+
}
|
|
121866
|
+
return afterSlash(code);
|
|
121867
|
+
}
|
|
121868
|
+
// The `<` (or `</`) must introduce a real tag, not a stray `<` in prose.
|
|
121869
|
+
function afterSlash(code) {
|
|
121870
|
+
if (asciiAlpha(code)) {
|
|
121871
|
+
lastNonSpace = code;
|
|
121872
|
+
effects.consume(code);
|
|
121873
|
+
return scanToLineEnd;
|
|
121874
|
+
}
|
|
121875
|
+
effects.exit(types_types.data);
|
|
121876
|
+
return nok(code);
|
|
121877
|
+
}
|
|
121878
|
+
function scanToLineEnd(code) {
|
|
121879
|
+
if (code === null || markdownLineEnding(code)) {
|
|
121880
|
+
effects.exit(types_types.data);
|
|
121881
|
+
return lastNonSpace === codes.greaterThan ? ok(code) : nok(code);
|
|
121882
|
+
}
|
|
121883
|
+
if (!markdownSpace(code))
|
|
121884
|
+
lastNonSpace = code;
|
|
121885
|
+
effects.consume(code);
|
|
121886
|
+
return scanToLineEnd;
|
|
121887
|
+
}
|
|
121888
|
+
}
|
|
121762
121889
|
/**
|
|
121763
121890
|
* Micromark extension that tokenizes MDX-like components.
|
|
121764
121891
|
*
|
|
@@ -122005,6 +122132,8 @@ const mdxishInlineMdxComponents = () => tree => {
|
|
|
122005
122132
|
|
|
122006
122133
|
|
|
122007
122134
|
|
|
122135
|
+
/** Matches a JSX attribute expression (e.g. `key={i}`) anywhere in a string. */
|
|
122136
|
+
const NESTED_ATTR_EXPRESSION_RE = /[\w-]+\s*=\s*\{/;
|
|
122008
122137
|
/**
|
|
122009
122138
|
* Reduce leading whitespace on all lines just enough to prevent
|
|
122010
122139
|
* remark from treating indented content as code blocks (4+ spaces).
|
|
@@ -122164,10 +122293,16 @@ const mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
|
|
|
122164
122293
|
// inline, which is how ReadMe's custom components are modeled).
|
|
122165
122294
|
if (!isPascal && parent.type === 'paragraph')
|
|
122166
122295
|
return;
|
|
122167
|
-
// Lowercase HTML tags are
|
|
122168
|
-
//
|
|
122296
|
+
// Lowercase HTML tags are eligible when they (or a descendant tag in their
|
|
122297
|
+
// content, e.g. a `.map()` body returning JSX with `key={i}`) carry a
|
|
122298
|
+
// JSX-expression attribute. Without this, a wrapper `<div>` with only plain
|
|
122299
|
+
// attributes (or none) swallows its whole nested block — including any
|
|
122300
|
+
// `style={{...}}`/`.map()` JSX inside it — as literal HTML text, which
|
|
122301
|
+
// rehype-raw's parse5 pass then garbles (it has no notion of JS expressions).
|
|
122302
|
+
// Plain HTML with no expressions anywhere stays as an html node so
|
|
122169
122303
|
// rehype-raw handles it as normal.
|
|
122170
|
-
|
|
122304
|
+
const hasNestedExpressionAttr = !selfClosing && NESTED_ATTR_EXPRESSION_RE.test(contentAfterTag);
|
|
122305
|
+
if (!isPascal && !hasExpressionAttr(attributes) && !hasNestedExpressionAttr)
|
|
122171
122306
|
return;
|
|
122172
122307
|
const closingTagStr = `</${tag}>`;
|
|
122173
122308
|
// Case 1: Self-closing tag
|
|
@@ -122390,12 +122525,60 @@ function restoreSnakeCase(placeholderName, mapping) {
|
|
|
122390
122525
|
return matchingKey ? mapping[matchingKey] : placeholderName;
|
|
122391
122526
|
}
|
|
122392
122527
|
|
|
122528
|
+
;// ./processor/transform/mdxish/resolve-esm-imports.ts
|
|
122529
|
+
|
|
122530
|
+
// We provide React as a default module so that components can use hooks
|
|
122531
|
+
// and it's a common use case. Add other common libraries here.
|
|
122532
|
+
const defaultModuleRegistry = { react: (external_react_default()) };
|
|
122533
|
+
const isRecord = (value) => typeof value === 'object' && value !== null;
|
|
122534
|
+
// Get the value of a named export from a module
|
|
122535
|
+
const getModuleExport = (module, importedName) => isRecord(module) && importedName in module ? module[importedName] : undefined;
|
|
122536
|
+
/**
|
|
122537
|
+
* Turn `import` declarations into a flat map of binding → value.
|
|
122538
|
+
*
|
|
122539
|
+
* A "binding" is a mapping of a local name to the value of it in the module exports
|
|
122540
|
+
* Example: `import { useState } from 'react'` yields `{ useState: React.useState }`.
|
|
122541
|
+
*
|
|
122542
|
+
* Unsupported specifiers are skipped with a warning rather than throwing, so a
|
|
122543
|
+
* single unknown import can't break the rest of the document.
|
|
122544
|
+
*/
|
|
122545
|
+
const collectImportValues = (importDeclarations, registry = defaultModuleRegistry) => {
|
|
122546
|
+
const importValues = {};
|
|
122547
|
+
importDeclarations.forEach(declaration => {
|
|
122548
|
+
const libraryName = declaration.source.value;
|
|
122549
|
+
if (typeof libraryName !== 'string')
|
|
122550
|
+
return;
|
|
122551
|
+
if (!(libraryName in registry)) {
|
|
122552
|
+
// eslint-disable-next-line no-console
|
|
122553
|
+
console.warn(`[WARNING] Cannot resolve import "${libraryName}"; it is not a supported library.`);
|
|
122554
|
+
return;
|
|
122555
|
+
}
|
|
122556
|
+
const module = registry[libraryName];
|
|
122557
|
+
declaration.specifiers.forEach(spec => {
|
|
122558
|
+
// Default (`import React`) and namespace (`import * as React`) both bind
|
|
122559
|
+
// the whole module under the local name.
|
|
122560
|
+
if (spec.type === 'ImportDefaultSpecifier' || spec.type === 'ImportNamespaceSpecifier') {
|
|
122561
|
+
importValues[spec.local.name] = module;
|
|
122562
|
+
}
|
|
122563
|
+
else if (spec.type === 'ImportSpecifier') {
|
|
122564
|
+
// Named imports (e.g. `import { useState } from 'react'`, useState is the import name)
|
|
122565
|
+
const importName = spec.imported.type === 'Identifier' ? spec.imported.name : spec.imported.value;
|
|
122566
|
+
if (typeof importName === 'string') {
|
|
122567
|
+
importValues[spec.local.name] = getModuleExport(module, importName);
|
|
122568
|
+
}
|
|
122569
|
+
}
|
|
122570
|
+
});
|
|
122571
|
+
});
|
|
122572
|
+
return importValues;
|
|
122573
|
+
};
|
|
122574
|
+
|
|
122393
122575
|
;// ./processor/transform/mdxish/evaluate-exports.ts
|
|
122394
122576
|
|
|
122395
122577
|
|
|
122396
122578
|
|
|
122397
122579
|
|
|
122398
122580
|
|
|
122581
|
+
|
|
122399
122582
|
/**
|
|
122400
122583
|
* Recursively extract all identifier names introduced by a binding pattern.
|
|
122401
122584
|
* Handles destructuring (`{ a, b }`, `[x, y]`), rest elements (`...rest`),
|
|
@@ -122443,6 +122626,7 @@ const collectExportNames = (declaration) => {
|
|
|
122443
122626
|
const evaluateExports = () => (tree, file) => {
|
|
122444
122627
|
const programBody = [];
|
|
122445
122628
|
const exportNames = [];
|
|
122629
|
+
const importDeclarations = [];
|
|
122446
122630
|
const nodesToRemove = [];
|
|
122447
122631
|
visit(tree, isMDXEsm, (node, index, parent) => {
|
|
122448
122632
|
if (parent && typeof index === 'number') {
|
|
@@ -122456,6 +122640,10 @@ const evaluateExports = () => (tree, file) => {
|
|
|
122456
122640
|
// handled the same as a named export — the inner declaration carries the
|
|
122457
122641
|
// binding name
|
|
122458
122642
|
estreeBody.forEach(statement => {
|
|
122643
|
+
if (statement.type === 'ImportDeclaration') {
|
|
122644
|
+
importDeclarations.push(statement);
|
|
122645
|
+
return;
|
|
122646
|
+
}
|
|
122459
122647
|
let declaration = null;
|
|
122460
122648
|
if (statement.type === 'ExportNamedDeclaration' && statement.declaration) {
|
|
122461
122649
|
declaration = statement.declaration;
|
|
@@ -122483,9 +122671,11 @@ const evaluateExports = () => (tree, file) => {
|
|
|
122483
122671
|
const program = { type: 'Program', sourceType: 'module', body: programBody };
|
|
122484
122672
|
buildJsx(program, { runtime: 'classic', pragma: 'React.createElement', pragmaFrag: 'React.Fragment' });
|
|
122485
122673
|
const { value: source } = toJs(program);
|
|
122674
|
+
// Make sure import values are available in the scope
|
|
122675
|
+
const importValues = collectImportValues(importDeclarations);
|
|
122486
122676
|
// Evaluate and build on the expression source
|
|
122487
122677
|
// Use react to compile JSX codes
|
|
122488
|
-
const evaluatedExports = evaluate(`(() => { ${source}\nreturn { ${exportNames.join(', ')} }; })()`, { React: (external_react_default()) });
|
|
122678
|
+
const evaluatedExports = evaluate(`(() => { ${source}\nreturn { ${exportNames.join(', ')} }; })()`, { React: (external_react_default()), ...importValues });
|
|
122489
122679
|
Object.assign(scope, evaluatedExports);
|
|
122490
122680
|
}
|
|
122491
122681
|
catch (error) {
|
|
@@ -122551,15 +122741,17 @@ const evalExpression = (expression, scope) => {
|
|
|
122551
122741
|
|
|
122552
122742
|
|
|
122553
122743
|
|
|
122744
|
+
/** True for an array containing at least one React element, e.g. the result of `.map()` returning JSX. */
|
|
122745
|
+
const isRenderableElementArray = (value) => Array.isArray(value) && value.some((external_react_default()).isValidElement);
|
|
122554
122746
|
/** Given the type of the expression result, create the corresponding mdast node. */
|
|
122555
122747
|
const createEvaluatedNode = (result, position) => {
|
|
122556
122748
|
if (result === null || result === undefined) {
|
|
122557
122749
|
return { type: 'text', value: '', position };
|
|
122558
122750
|
}
|
|
122559
|
-
else if (external_react_default().isValidElement(result)) {
|
|
122560
|
-
// Convert react elements to
|
|
122561
|
-
// This must come before the object check as
|
|
122562
|
-
return { type: 'html', value: (0,server_node/* renderToStaticMarkup */.qV)(result), position };
|
|
122751
|
+
else if (external_react_default().isValidElement(result) || isRenderableElementArray(result)) {
|
|
122752
|
+
// Convert react elements (or arrays of them, e.g. `.map()` returning JSX) to their HTML
|
|
122753
|
+
// representation. This must come before the object check as both are a subset of it.
|
|
122754
|
+
return { type: 'html', value: (0,server_node/* renderToStaticMarkup */.qV)(external_react_default().createElement((external_react_default()).Fragment, null, result)), position };
|
|
122563
122755
|
}
|
|
122564
122756
|
else if (typeof result === 'object') {
|
|
122565
122757
|
return { type: 'text', value: JSON.stringify(result), position };
|
|
@@ -122599,6 +122791,47 @@ const evaluateExpressions = () => (tree, file) => {
|
|
|
122599
122791
|
};
|
|
122600
122792
|
/* harmony default export */ const evaluate_expressions = (evaluateExpressions);
|
|
122601
122793
|
|
|
122794
|
+
;// ./processor/transform/mdxish/evaluate-style-block-expressions.ts
|
|
122795
|
+
|
|
122796
|
+
|
|
122797
|
+
|
|
122798
|
+
// Matches a standalone `<style ...>{ <expr> }</style>` block — the JSX shape MDX evaluates
|
|
122799
|
+
// (typically a template-literal-wrapped CSS string) but which mdxish otherwise leaves as
|
|
122800
|
+
// literal, invalid-CSS text (see CX-3646).
|
|
122801
|
+
const STYLE_EXPRESSION_RE = /^(<style\b[^>]*>)\s*\{([\s\S]*)\}\s*(<\/style>)$/i;
|
|
122802
|
+
/**
|
|
122803
|
+
* Evaluate the JSX expression wrapping a `<style>` tag's contents (typically a template
|
|
122804
|
+
* literal, e.g. `<style>{\`.foo { color: red; }\`}</style>`) so the tag ends up holding plain
|
|
122805
|
+
* CSS text instead of the literal `{`...`}` wrapper — which the browser treats as invalid CSS
|
|
122806
|
+
* and drops the entire stylesheet for.
|
|
122807
|
+
*
|
|
122808
|
+
* `<style>` is one of CommonMark's "raw text" HTML elements (along with script/pre/textarea):
|
|
122809
|
+
* its contents are captured verbatim as a single `html` mdast node with no inner tokenization,
|
|
122810
|
+
* so this expression never reaches the mdxFlowExpression tokenizer or `evaluateExpressions` —
|
|
122811
|
+
* it has to be matched and evaluated directly against the raw node's string value.
|
|
122812
|
+
*
|
|
122813
|
+
* Must run after `evaluateExports` (needs `file.data.mdxishScope`) and before `remarkRehype`
|
|
122814
|
+
* turns `html` mdast nodes into raw hast strings. Skipped in safeMode.
|
|
122815
|
+
*/
|
|
122816
|
+
const evaluateStyleBlockExpressions = () => (tree, file) => {
|
|
122817
|
+
const scope = { ...file.data.mdxishScope, React: (external_react_default()) };
|
|
122818
|
+
visit(tree, 'html', (node) => {
|
|
122819
|
+
const match = node.value.trim().match(STYLE_EXPRESSION_RE);
|
|
122820
|
+
if (!match)
|
|
122821
|
+
return;
|
|
122822
|
+
const [, openTag, expression, closeTag] = match;
|
|
122823
|
+
try {
|
|
122824
|
+
const css = evalExpression(expression, scope);
|
|
122825
|
+
node.value = `${openTag}${String(css)}${closeTag}`;
|
|
122826
|
+
}
|
|
122827
|
+
catch {
|
|
122828
|
+
// Evaluation failed — leave the node untouched so it round-trips as literal text.
|
|
122829
|
+
}
|
|
122830
|
+
});
|
|
122831
|
+
return tree;
|
|
122832
|
+
};
|
|
122833
|
+
/* harmony default export */ const evaluate_style_block_expressions = (evaluateStyleBlockExpressions);
|
|
122834
|
+
|
|
122602
122835
|
;// ./processor/transform/mdxish/heading-slugs.ts
|
|
122603
122836
|
|
|
122604
122837
|
|
|
@@ -124439,219 +124672,100 @@ const normalizeMdxJsxNodes = () => tree => {
|
|
|
124439
124672
|
*/
|
|
124440
124673
|
const JSX_COMMENT_REGEX = /\{\/\*[^*]*(?:\*(?!\/)[^*]*)*\*\/\}/g;
|
|
124441
124674
|
|
|
124442
|
-
;// ./processor/transform/mdxish/
|
|
124443
|
-
|
|
124675
|
+
;// ./processor/transform/mdxish/remove-jsx-comments.ts
|
|
124444
124676
|
|
|
124445
124677
|
/**
|
|
124446
124678
|
* Removes JSX-style comments (e.g., { /* comment *\/ }) from content.
|
|
124447
124679
|
*
|
|
124448
|
-
*
|
|
124449
|
-
*
|
|
124450
|
-
*
|
|
124680
|
+
* `@param` content
|
|
124681
|
+
* `@returns` Content with JSX comments removed
|
|
124682
|
+
* `@example`
|
|
124451
124683
|
* ```typescript
|
|
124452
|
-
* removeJSXComments('Text {
|
|
124453
|
-
* // Returns: 'Text more text'
|
|
124684
|
+
* removeJSXComments('Text {/* comment *\/} more text') // => 'Text more text'
|
|
124454
124685
|
* ```
|
|
124455
124686
|
*/
|
|
124456
124687
|
function removeJSXComments(content) {
|
|
124457
124688
|
return content.replace(JSX_COMMENT_REGEX, '');
|
|
124458
124689
|
}
|
|
124459
|
-
|
|
124460
|
-
|
|
124461
|
-
|
|
124462
|
-
// Allows optional leading indentation and lazily matches until the same closing tag.
|
|
124463
|
-
const BLOCK_HTML_RE = /(?<=^|\n)[ \t]*<([a-z][a-zA-Z0-9]*)(?:\s[^>]*)?>[\s\S]*?<\/\1>[ \t]*(?=\n|$)/g;
|
|
124464
|
-
/**
|
|
124465
|
-
* Hides line-anchored HTML elements from the brace-escaping pass so we don't leak `\{`
|
|
124466
|
-
* into rendered output (rehypeRaw renders the `\` literally, e.g. `<div>{foo</div>`).
|
|
124467
|
-
*
|
|
124468
|
-
* One carve-out: if an interior line at column 0 has bare text containing `{`, mdxish
|
|
124469
|
-
* parses that line as a paragraph and the mdxExpression step would throw without an
|
|
124470
|
-
* escape — so we leave that case to the brace balancer.
|
|
124471
|
-
*/
|
|
124472
|
-
function protectHTMLElements(content) {
|
|
124473
|
-
const htmlElements = [];
|
|
124474
|
-
const protectedContent = content.replace(BLOCK_HTML_RE, match => {
|
|
124475
|
-
// Look at the lines between the open and close tags. If any of them starts
|
|
124476
|
-
// at column 0 with bare text (not whitespace, not another tag) and contains
|
|
124477
|
-
// `{`, mdxish will parse that line as a paragraph and the brace as an MDX
|
|
124478
|
-
// expression, which would throw an error. So we let the brace balancer escape it.
|
|
124479
|
-
// Otherwise, we need to extract the sequence to protect it from the brace escaping.
|
|
124480
|
-
const interior = match.split('\n').slice(1, -1);
|
|
124481
|
-
const hazard = interior.some(line => line.length > 0 && line[0] !== ' ' && line[0] !== '\t' && line[0] !== '<' && line.includes('{'));
|
|
124482
|
-
if (hazard)
|
|
124483
|
-
return match;
|
|
124484
|
-
htmlElements.push(match);
|
|
124485
|
-
return `${HTML_ELEM_PLACEHOLDER_PREFIX}${htmlElements.length - 1}___`;
|
|
124486
|
-
});
|
|
124487
|
-
return { htmlElements, protectedContent };
|
|
124488
|
-
}
|
|
124489
|
-
function restoreHTMLElements(content, htmlElements) {
|
|
124490
|
-
if (htmlElements.length === 0)
|
|
124491
|
-
return content;
|
|
124492
|
-
return content.replace(HTML_ELEM_PLACEHOLDER, (_m, idx) => htmlElements[parseInt(idx, 10)]);
|
|
124493
|
-
}
|
|
124494
|
-
const ESM_DECLARATION_START = /^(?:export|import)\b/;
|
|
124690
|
+
|
|
124691
|
+
;// ./processor/transform/mdxish/style-object-to-css.ts
|
|
124692
|
+
|
|
124495
124693
|
/**
|
|
124496
|
-
*
|
|
124497
|
-
*
|
|
124498
|
-
*
|
|
124694
|
+
* CSS properties React treats as unitless — a bare number stays as-is instead of
|
|
124695
|
+
* getting `px` appended. Mirrors React DOM's `isUnitlessNumber` whitelist.
|
|
124696
|
+
* @see https://github.com/facebook/react/blob/main/packages/react-dom-bindings/src/shared/CSSProperty.js
|
|
124499
124697
|
*/
|
|
124500
|
-
|
|
124501
|
-
|
|
124502
|
-
|
|
124503
|
-
|
|
124504
|
-
|
|
124505
|
-
|
|
124506
|
-
|
|
124507
|
-
|
|
124508
|
-
|
|
124509
|
-
|
|
124510
|
-
|
|
124511
|
-
|
|
124698
|
+
const UNITLESS_CSS_PROPERTIES = new Set([
|
|
124699
|
+
'animationIterationCount',
|
|
124700
|
+
'aspectRatio',
|
|
124701
|
+
'borderImageOutset',
|
|
124702
|
+
'borderImageSlice',
|
|
124703
|
+
'borderImageWidth',
|
|
124704
|
+
'boxFlex',
|
|
124705
|
+
'boxFlexGroup',
|
|
124706
|
+
'boxOrdinalGroup',
|
|
124707
|
+
'columnCount',
|
|
124708
|
+
'columns',
|
|
124709
|
+
'flex',
|
|
124710
|
+
'flexGrow',
|
|
124711
|
+
'flexPositive',
|
|
124712
|
+
'flexShrink',
|
|
124713
|
+
'flexNegative',
|
|
124714
|
+
'flexOrder',
|
|
124715
|
+
'gridArea',
|
|
124716
|
+
'gridRow',
|
|
124717
|
+
'gridRowEnd',
|
|
124718
|
+
'gridRowSpan',
|
|
124719
|
+
'gridRowStart',
|
|
124720
|
+
'gridColumn',
|
|
124721
|
+
'gridColumnEnd',
|
|
124722
|
+
'gridColumnSpan',
|
|
124723
|
+
'gridColumnStart',
|
|
124724
|
+
'fontWeight',
|
|
124725
|
+
'lineClamp',
|
|
124726
|
+
'lineHeight',
|
|
124727
|
+
'opacity',
|
|
124728
|
+
'order',
|
|
124729
|
+
'orphans',
|
|
124730
|
+
'tabSize',
|
|
124731
|
+
'widows',
|
|
124732
|
+
'zIndex',
|
|
124733
|
+
'zoom',
|
|
124734
|
+
'fillOpacity',
|
|
124735
|
+
'floodOpacity',
|
|
124736
|
+
'stopOpacity',
|
|
124737
|
+
'strokeDasharray',
|
|
124738
|
+
'strokeDashoffset',
|
|
124739
|
+
'strokeMiterlimit',
|
|
124740
|
+
'strokeOpacity',
|
|
124741
|
+
'strokeWidth',
|
|
124742
|
+
]);
|
|
124743
|
+
/** Convert a camelCase (or CSS custom property) key into its kebab-case CSS name. */
|
|
124744
|
+
const cssPropertyName = (key) => (key.startsWith('--') ? key : key.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`));
|
|
124745
|
+
/** React appends `px` to non-zero numeric values, except unitless and custom properties. */
|
|
124746
|
+
const cssPropertyValue = (key, value) => typeof value === 'number' && value !== 0 && !key.startsWith('--') && !UNITLESS_CSS_PROPERTIES.has(key)
|
|
124747
|
+
? `${value}px`
|
|
124748
|
+
: `${value}`;
|
|
124512
124749
|
/**
|
|
124513
|
-
*
|
|
124750
|
+
* True for a value that should be serialized as a style object rather than passed through
|
|
124751
|
+
* as an already-CSS string. React elements are excluded since they're valid objects too.
|
|
124514
124752
|
*/
|
|
124515
|
-
|
|
124516
|
-
const { htmlElements, protectedContent } = protectHTMLElements(content);
|
|
124517
|
-
let strDelim = null;
|
|
124518
|
-
let strEscaped = false;
|
|
124519
|
-
// Track position of last newline (outside strings) to detect blank lines
|
|
124520
|
-
// -2 means no recent newline
|
|
124521
|
-
let lastNewlinePos = -2;
|
|
124522
|
-
// Character state machine trackers
|
|
124523
|
-
const toEscape = new Set();
|
|
124524
|
-
// Convert to array of Unicode code points so that emojis and multi-byte characters are correctly tracked
|
|
124525
|
-
const chars = Array.from(protectedContent);
|
|
124526
|
-
const openStack = [];
|
|
124527
|
-
// Whether the current top-level statement is an `export`/`import` declaration.
|
|
124528
|
-
let insideEsmDeclaration = false;
|
|
124529
|
-
for (let i = 0; i < chars.length; i += 1) {
|
|
124530
|
-
const ch = chars[i];
|
|
124531
|
-
// At a top-level (brace depth 0) line start, decide whether we're inside an
|
|
124532
|
-
// ESM declaration. The flag persists across the declaration's own lines.
|
|
124533
|
-
if (openStack.length === 0 && (i === 0 || chars[i - 1] === '\n')) {
|
|
124534
|
-
if (startsEsmDeclaration(chars, i))
|
|
124535
|
-
insideEsmDeclaration = true;
|
|
124536
|
-
else if (isBlankLine(chars, i))
|
|
124537
|
-
insideEsmDeclaration = false;
|
|
124538
|
-
}
|
|
124539
|
-
// Track string delimiters inside expressions to ignore braces within them
|
|
124540
|
-
if (openStack.length > 0) {
|
|
124541
|
-
if (strDelim) {
|
|
124542
|
-
if (strEscaped)
|
|
124543
|
-
strEscaped = false;
|
|
124544
|
-
else if (ch === '\\')
|
|
124545
|
-
strEscaped = true;
|
|
124546
|
-
else if (ch === strDelim)
|
|
124547
|
-
strDelim = null;
|
|
124548
|
-
// eslint-disable-next-line no-continue
|
|
124549
|
-
continue;
|
|
124550
|
-
}
|
|
124551
|
-
if (ch === '"' || ch === "'" || ch === '`') {
|
|
124552
|
-
strDelim = ch;
|
|
124553
|
-
// eslint-disable-next-line no-continue
|
|
124554
|
-
continue;
|
|
124555
|
-
}
|
|
124556
|
-
if (ch === '\n') {
|
|
124557
|
-
if (lastNewlinePos >= 0) {
|
|
124558
|
-
const between = chars.slice(lastNewlinePos + 1, i).join('');
|
|
124559
|
-
if (/^[ \t]*$/.test(between)) {
|
|
124560
|
-
openStack.forEach(entry => { entry.hasBlankLine = true; });
|
|
124561
|
-
}
|
|
124562
|
-
}
|
|
124563
|
-
lastNewlinePos = i;
|
|
124564
|
-
}
|
|
124565
|
-
}
|
|
124566
|
-
// Skip already-escaped braces (odd run of preceding backslashes).
|
|
124567
|
-
if (ch === '{' || ch === '}') {
|
|
124568
|
-
let bs = 0;
|
|
124569
|
-
for (let j = i - 1; j >= 0 && chars[j] === '\\'; j -= 1)
|
|
124570
|
-
bs += 1;
|
|
124571
|
-
if (bs % 2 === 1) {
|
|
124572
|
-
// eslint-disable-next-line no-continue
|
|
124573
|
-
continue;
|
|
124574
|
-
}
|
|
124575
|
-
}
|
|
124576
|
-
if (ch === '{') {
|
|
124577
|
-
// `=` (after whitespace) before `{` ⇒ JSX attribute expression. The
|
|
124578
|
-
// mdxComponent tokenizer captures the whole component, so blank lines
|
|
124579
|
-
// inside attribute values are harmless. Nested `{` inherits the flag.
|
|
124580
|
-
let isAttrExpr = false;
|
|
124581
|
-
for (let j = i - 1; j >= 0; j -= 1) {
|
|
124582
|
-
const pc = chars[j];
|
|
124583
|
-
if (pc === '=') {
|
|
124584
|
-
isAttrExpr = true;
|
|
124585
|
-
break;
|
|
124586
|
-
}
|
|
124587
|
-
if (pc !== ' ' && pc !== '\t')
|
|
124588
|
-
break;
|
|
124589
|
-
}
|
|
124590
|
-
// Nested `{ ... }` inside an attribute value (e.g. `data={[{ ... }]}` or
|
|
124591
|
-
// `data={{ a: { b: 1 } }}`) must inherit the same exemption; only the
|
|
124592
|
-
// outer `{` is directly after `=`.
|
|
124593
|
-
if (!isAttrExpr && openStack.length > 0 && openStack[openStack.length - 1].isAttrExpr) {
|
|
124594
|
-
isAttrExpr = true;
|
|
124595
|
-
}
|
|
124596
|
-
openStack.push({ pos: i, hasBlankLine: false, isAttrExpr, isEsmDeclaration: insideEsmDeclaration });
|
|
124597
|
-
lastNewlinePos = -2;
|
|
124598
|
-
}
|
|
124599
|
-
else if (ch === '}') {
|
|
124600
|
-
if (openStack.length > 0) {
|
|
124601
|
-
const entry = openStack.pop();
|
|
124602
|
-
// The declaration's braces are closed; later top-level braces are not ESM.
|
|
124603
|
-
if (openStack.length === 0)
|
|
124604
|
-
insideEsmDeclaration = false;
|
|
124605
|
-
// Pure `{/* ... */}` comments are handled downstream by the jsxComment
|
|
124606
|
-
// tokenizer — escaping their braces would prevent it from running.
|
|
124607
|
-
const isPureJsxComment = chars[entry.pos + 1] === '/' &&
|
|
124608
|
-
chars[entry.pos + 2] === '*' &&
|
|
124609
|
-
chars[i - 1] === '/' &&
|
|
124610
|
-
chars[i - 2] === '*';
|
|
124611
|
-
if (entry.hasBlankLine && !isPureJsxComment && !entry.isAttrExpr && !entry.isEsmDeclaration) {
|
|
124612
|
-
toEscape.add(entry.pos);
|
|
124613
|
-
toEscape.add(i);
|
|
124614
|
-
}
|
|
124615
|
-
}
|
|
124616
|
-
else {
|
|
124617
|
-
toEscape.add(i);
|
|
124618
|
-
}
|
|
124619
|
-
}
|
|
124620
|
-
else if (ch === ';' && openStack.length === 0) {
|
|
124621
|
-
// A top-level `;` ends the current statement, ESM or otherwise.
|
|
124622
|
-
insideEsmDeclaration = false;
|
|
124623
|
-
}
|
|
124624
|
-
}
|
|
124625
|
-
// Anything still open is unbalanced.
|
|
124626
|
-
openStack.forEach(entry => {
|
|
124627
|
-
if (!entry.isEsmDeclaration)
|
|
124628
|
-
toEscape.add(entry.pos);
|
|
124629
|
-
});
|
|
124630
|
-
// Reconstruct the content with the escaped braces.
|
|
124631
|
-
const escapedContent = toEscape.size === 0 ? protectedContent : chars.map((ch, i) => (toEscape.has(i) ? `\\${ch}` : ch)).join('');
|
|
124632
|
-
return restoreHTMLElements(escapedContent, htmlElements);
|
|
124633
|
-
}
|
|
124753
|
+
const style_object_to_css_isPlainObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value) && !external_react_default().isValidElement(value);
|
|
124634
124754
|
/**
|
|
124635
|
-
*
|
|
124636
|
-
*
|
|
124637
|
-
*
|
|
124638
|
-
* they flow through the tokenizer as `mdxJsxAttributeValueExpression` nodes
|
|
124639
|
-
* and are evaluated at the hast handler step.
|
|
124640
|
-
*
|
|
124641
|
-
* @param content
|
|
124642
|
-
* @returns Preprocessed content ready for markdown parsing
|
|
124755
|
+
* Serialize a React-style inline style object (`{ color: "red", fontSize: 12 }`) into a
|
|
124756
|
+
* CSS declaration string (`color:red;font-size:12px`), the shape hast/HTML expects for a
|
|
124757
|
+
* `style` attribute. Empty (`undefined`/`null`/`''`) entries are dropped.
|
|
124643
124758
|
*/
|
|
124644
|
-
|
|
124645
|
-
|
|
124646
|
-
|
|
124647
|
-
|
|
124648
|
-
return processed;
|
|
124649
|
-
}
|
|
124759
|
+
const styleObjectToCssText = (style) => Object.entries(style)
|
|
124760
|
+
.filter(([, value]) => value !== undefined && value !== null && value !== '')
|
|
124761
|
+
.map(([key, value]) => `${cssPropertyName(key)}:${cssPropertyValue(key, value)}`)
|
|
124762
|
+
.join(';');
|
|
124650
124763
|
|
|
124651
124764
|
;// ./processor/transform/mdxish/resolve-deferred-attribute-expression-props.ts
|
|
124652
124765
|
|
|
124653
124766
|
|
|
124654
124767
|
|
|
124768
|
+
|
|
124655
124769
|
/**
|
|
124656
124770
|
* Resolve attribute expressions that `mdxJsxElementHandler` deferred.
|
|
124657
124771
|
*
|
|
@@ -124673,7 +124787,10 @@ const resolveDeferredAttributeExpressionProps = () => (tree, file) => {
|
|
|
124673
124787
|
const properties = node.properties;
|
|
124674
124788
|
Object.entries(deferredExpressions).forEach(([name, source]) => {
|
|
124675
124789
|
try {
|
|
124676
|
-
|
|
124790
|
+
const result = evalExpression(source, scope);
|
|
124791
|
+
// hast/HTML `style` is a plain CSS string; a `style={{...}}` expression evaluates to
|
|
124792
|
+
// a JS object, which must be serialized or it renders as the literal "[object Object]".
|
|
124793
|
+
properties[name] = name === 'style' && style_object_to_css_isPlainObject(result) ? styleObjectToCssText(result) : result;
|
|
124677
124794
|
}
|
|
124678
124795
|
catch {
|
|
124679
124796
|
// Evaluation failed — fall back to the raw expression source so the attribute
|
|
@@ -124993,13 +125110,13 @@ function normalizeTableSeparator(content) {
|
|
|
124993
125110
|
;// ./processor/transform/mdxish/terminate-html-flow-blocks.ts
|
|
124994
125111
|
|
|
124995
125112
|
|
|
125113
|
+
|
|
124996
125114
|
const STANDALONE_HTML_LINE_REGEX = /^(<[a-z][^<>]*>|<\/[a-z][^<>]*>)+\s*$/;
|
|
124997
125115
|
const HTML_LINE_WITH_CONTENT_REGEX = /^<[a-z][^<>]*>.*<\/[a-z][^<>]*>(?:[^<]*)$/;
|
|
124998
|
-
const terminate_html_flow_blocks_TABLE_STRUCTURE_TAGS = ['table', 'thead', 'tbody', 'tfoot', 'tr', 'td', 'th', 'caption', 'colgroup'];
|
|
124999
125116
|
// Tags whose contents must be preserved as is, inserting a blank line after the
|
|
125000
125117
|
// opener corrupts the payload.
|
|
125001
125118
|
// htmlRawNames here refer to <pre>, <textarea>, <script>, <style>
|
|
125002
|
-
const RAW_CONTENT_TAGS = [...htmlRawNames, ...
|
|
125119
|
+
const RAW_CONTENT_TAGS = [...htmlRawNames, ...HTML_TABLE_STRUCTURE_TAGS];
|
|
125003
125120
|
// The `(?=[\s/>])` lookahead avoids false matches on lookalike names like `<script-foo>`.
|
|
125004
125121
|
const RAW_CONTENT_TAG_MATCHERS = RAW_CONTENT_TAGS.map(tag => ({
|
|
125005
125122
|
open: new RegExp(`<${tag}(?=[\\s/>])[^>]*?(?<!/)>`, 'gi'),
|
|
@@ -125621,6 +125738,85 @@ function jsxTable() {
|
|
|
125621
125738
|
;// ./lib/micromark/jsx-table/index.ts
|
|
125622
125739
|
|
|
125623
125740
|
|
|
125741
|
+
;// ./lib/micromark/mdx-expression-lenient/syntax.ts
|
|
125742
|
+
|
|
125743
|
+
|
|
125744
|
+
/**
|
|
125745
|
+
* Lenient MDX text-expression tokenizer (agnostic / no acorn).
|
|
125746
|
+
*
|
|
125747
|
+
* Matches a balanced `{ ... }` run — tracking nested braces and spanning soft
|
|
125748
|
+
* line breaks — and emits the standard `mdxTextExpression*` tokens so the
|
|
125749
|
+
* upstream `mdxExpressionFromMarkdown()` builds the node.
|
|
125750
|
+
*
|
|
125751
|
+
* Reimplements the official micromark mdxExpression, but an unbalanced brace that
|
|
125752
|
+
* reaches end of input returns `nok` instead of throwing: micromark rolls back
|
|
125753
|
+
* and the `{` renders as literal text, making the pipeline forgiving of stray
|
|
125754
|
+
* braces that upstream would hard-error on.
|
|
125755
|
+
*/
|
|
125756
|
+
function tokenizeTextExpression(effects, ok, nok) {
|
|
125757
|
+
let depth = 0;
|
|
125758
|
+
return start;
|
|
125759
|
+
function start(code) {
|
|
125760
|
+
if (code !== codes.leftCurlyBrace)
|
|
125761
|
+
return nok(code);
|
|
125762
|
+
effects.enter('mdxTextExpression');
|
|
125763
|
+
effects.enter('mdxTextExpressionMarker');
|
|
125764
|
+
effects.consume(code);
|
|
125765
|
+
effects.exit('mdxTextExpressionMarker');
|
|
125766
|
+
return before;
|
|
125767
|
+
}
|
|
125768
|
+
function before(code) {
|
|
125769
|
+
if (code === codes.eof) {
|
|
125770
|
+
effects.exit('mdxTextExpression');
|
|
125771
|
+
return nok(code);
|
|
125772
|
+
}
|
|
125773
|
+
if (markdownLineEnding(code)) {
|
|
125774
|
+
effects.enter('lineEnding');
|
|
125775
|
+
effects.consume(code);
|
|
125776
|
+
effects.exit('lineEnding');
|
|
125777
|
+
return before;
|
|
125778
|
+
}
|
|
125779
|
+
if (code === codes.rightCurlyBrace && depth === 0) {
|
|
125780
|
+
return close(code);
|
|
125781
|
+
}
|
|
125782
|
+
effects.enter('mdxTextExpressionChunk');
|
|
125783
|
+
return inside(code);
|
|
125784
|
+
}
|
|
125785
|
+
function inside(code) {
|
|
125786
|
+
if (code === codes.eof || markdownLineEnding(code)) {
|
|
125787
|
+
effects.exit('mdxTextExpressionChunk');
|
|
125788
|
+
return before(code);
|
|
125789
|
+
}
|
|
125790
|
+
if (code === codes.rightCurlyBrace && depth === 0) {
|
|
125791
|
+
effects.exit('mdxTextExpressionChunk');
|
|
125792
|
+
return close(code);
|
|
125793
|
+
}
|
|
125794
|
+
if (code === codes.leftCurlyBrace)
|
|
125795
|
+
depth += 1;
|
|
125796
|
+
else if (code === codes.rightCurlyBrace)
|
|
125797
|
+
depth -= 1;
|
|
125798
|
+
effects.consume(code);
|
|
125799
|
+
return inside;
|
|
125800
|
+
}
|
|
125801
|
+
function close(code) {
|
|
125802
|
+
effects.enter('mdxTextExpressionMarker');
|
|
125803
|
+
effects.consume(code);
|
|
125804
|
+
effects.exit('mdxTextExpressionMarker');
|
|
125805
|
+
effects.exit('mdxTextExpression');
|
|
125806
|
+
return ok;
|
|
125807
|
+
}
|
|
125808
|
+
}
|
|
125809
|
+
function mdxExpressionLenient() {
|
|
125810
|
+
return {
|
|
125811
|
+
text: {
|
|
125812
|
+
[codes.leftCurlyBrace]: {
|
|
125813
|
+
name: 'mdxTextExpression',
|
|
125814
|
+
tokenize: tokenizeTextExpression,
|
|
125815
|
+
},
|
|
125816
|
+
},
|
|
125817
|
+
};
|
|
125818
|
+
}
|
|
125819
|
+
|
|
125624
125820
|
;// ./lib/utils/mdxish/mdxish-load-components.ts
|
|
125625
125821
|
|
|
125626
125822
|
|
|
@@ -125718,6 +125914,7 @@ function loadComponents() {
|
|
|
125718
125914
|
|
|
125719
125915
|
|
|
125720
125916
|
|
|
125917
|
+
|
|
125721
125918
|
|
|
125722
125919
|
|
|
125723
125920
|
const defaultTransformers = [
|
|
@@ -125733,7 +125930,7 @@ const defaultTransformers = [
|
|
|
125733
125930
|
* 1. Normalize malformed table separator syntax (e.g., `|: ---` → `| :---`)
|
|
125734
125931
|
* 2. Terminate HTML flow blocks so subsequent content isn't swallowed
|
|
125735
125932
|
* 3. Close invalid "self-closing" HTML tags (e.g., `<i />` → `<i></i>`)
|
|
125736
|
-
* 4.
|
|
125933
|
+
* 4. Normalize compact ATX headings (e.g., `#Heading` → `# Heading`)
|
|
125737
125934
|
* 5. Replace snake_case component names with parser-safe placeholders
|
|
125738
125935
|
*/
|
|
125739
125936
|
function preprocessContent(content, opts) {
|
|
@@ -125742,7 +125939,6 @@ function preprocessContent(content, opts) {
|
|
|
125742
125939
|
result = terminateHtmlFlowBlocks(result);
|
|
125743
125940
|
result = closeSelfClosingHtmlTags(result);
|
|
125744
125941
|
result = normalizeCompactHeadings(result);
|
|
125745
|
-
result = preprocessJSXExpressions(result);
|
|
125746
125942
|
return processSnakeCaseComponent(result, { knownComponents });
|
|
125747
125943
|
}
|
|
125748
125944
|
function mdxishAstProcessor(mdContent, opts = {}) {
|
|
@@ -125759,12 +125955,8 @@ function mdxishAstProcessor(mdContent, opts = {}) {
|
|
|
125759
125955
|
acc[key] = String(value);
|
|
125760
125956
|
return acc;
|
|
125761
125957
|
}, {});
|
|
125762
|
-
//
|
|
125763
|
-
|
|
125764
|
-
const mdxExprExt = mdxExpression({ allowEmpty: true });
|
|
125765
|
-
const mdxExprTextOnly = {
|
|
125766
|
-
text: mdxExprExt.text,
|
|
125767
|
-
};
|
|
125958
|
+
// Parser extension for MDX expressions {}
|
|
125959
|
+
const mdxExprTextOnly = mdxExpressionLenient();
|
|
125768
125960
|
const micromarkExts = [
|
|
125769
125961
|
jsxTable(),
|
|
125770
125962
|
magicBlock(),
|
|
@@ -125873,6 +126065,7 @@ function mdxish(mdContent, opts = {}) {
|
|
|
125873
126065
|
.use(safeMode ? undefined : evaluate_exports) // Evaluate `export const/function` and stash scope on file.data.mdxishScope
|
|
125874
126066
|
.use(remarkBreaks) // Must precede evaluateExpressions to avoid splitting the \n in an evaluated template literal into a <br> node
|
|
125875
126067
|
.use(safeMode ? undefined : evaluate_expressions) // Evaluate self-contained MDX expressions (e.g. `{1+1}`)
|
|
126068
|
+
.use(safeMode ? undefined : evaluate_style_block_expressions) // Evaluate `<style>{`...`}</style>` template literals into plain CSS
|
|
125876
126069
|
.use(variables_code, { variables }) // Resolve <<...>> and {user.*} inside code and inline code nodes
|
|
125877
126070
|
.use(remarkRehype, { allowDangerousHtml: true, handlers: mdxComponentHandlers })
|
|
125878
126071
|
.use(preserveBooleanProperties) // RehypeRaw converts boolean properties to empty strings
|