@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.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
|
|
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
|
|
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
|
|
76409
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
101395
|
-
|
|
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
|
-
|
|
101496
|
-
|
|
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
|
|
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
|
|
101944
|
-
//
|
|
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
|
-
|
|
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
|
|
@@ -102166,12 +102301,60 @@ function restoreSnakeCase(placeholderName, mapping) {
|
|
|
102166
102301
|
return matchingKey ? mapping[matchingKey] : placeholderName;
|
|
102167
102302
|
}
|
|
102168
102303
|
|
|
102304
|
+
;// ./processor/transform/mdxish/resolve-esm-imports.ts
|
|
102305
|
+
|
|
102306
|
+
// We provide React as a default module so that components can use hooks
|
|
102307
|
+
// and it's a common use case. Add other common libraries here.
|
|
102308
|
+
const defaultModuleRegistry = { react: (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default()) };
|
|
102309
|
+
const isRecord = (value) => typeof value === 'object' && value !== null;
|
|
102310
|
+
// Get the value of a named export from a module
|
|
102311
|
+
const getModuleExport = (module, importedName) => isRecord(module) && importedName in module ? module[importedName] : undefined;
|
|
102312
|
+
/**
|
|
102313
|
+
* Turn `import` declarations into a flat map of binding → value.
|
|
102314
|
+
*
|
|
102315
|
+
* A "binding" is a mapping of a local name to the value of it in the module exports
|
|
102316
|
+
* Example: `import { useState } from 'react'` yields `{ useState: React.useState }`.
|
|
102317
|
+
*
|
|
102318
|
+
* Unsupported specifiers are skipped with a warning rather than throwing, so a
|
|
102319
|
+
* single unknown import can't break the rest of the document.
|
|
102320
|
+
*/
|
|
102321
|
+
const collectImportValues = (importDeclarations, registry = defaultModuleRegistry) => {
|
|
102322
|
+
const importValues = {};
|
|
102323
|
+
importDeclarations.forEach(declaration => {
|
|
102324
|
+
const libraryName = declaration.source.value;
|
|
102325
|
+
if (typeof libraryName !== 'string')
|
|
102326
|
+
return;
|
|
102327
|
+
if (!(libraryName in registry)) {
|
|
102328
|
+
// eslint-disable-next-line no-console
|
|
102329
|
+
console.warn(`[WARNING] Cannot resolve import "${libraryName}"; it is not a supported library.`);
|
|
102330
|
+
return;
|
|
102331
|
+
}
|
|
102332
|
+
const module = registry[libraryName];
|
|
102333
|
+
declaration.specifiers.forEach(spec => {
|
|
102334
|
+
// Default (`import React`) and namespace (`import * as React`) both bind
|
|
102335
|
+
// the whole module under the local name.
|
|
102336
|
+
if (spec.type === 'ImportDefaultSpecifier' || spec.type === 'ImportNamespaceSpecifier') {
|
|
102337
|
+
importValues[spec.local.name] = module;
|
|
102338
|
+
}
|
|
102339
|
+
else if (spec.type === 'ImportSpecifier') {
|
|
102340
|
+
// Named imports (e.g. `import { useState } from 'react'`, useState is the import name)
|
|
102341
|
+
const importName = spec.imported.type === 'Identifier' ? spec.imported.name : spec.imported.value;
|
|
102342
|
+
if (typeof importName === 'string') {
|
|
102343
|
+
importValues[spec.local.name] = getModuleExport(module, importName);
|
|
102344
|
+
}
|
|
102345
|
+
}
|
|
102346
|
+
});
|
|
102347
|
+
});
|
|
102348
|
+
return importValues;
|
|
102349
|
+
};
|
|
102350
|
+
|
|
102169
102351
|
;// ./processor/transform/mdxish/evaluate-exports.ts
|
|
102170
102352
|
|
|
102171
102353
|
|
|
102172
102354
|
|
|
102173
102355
|
|
|
102174
102356
|
|
|
102357
|
+
|
|
102175
102358
|
/**
|
|
102176
102359
|
* Recursively extract all identifier names introduced by a binding pattern.
|
|
102177
102360
|
* Handles destructuring (`{ a, b }`, `[x, y]`), rest elements (`...rest`),
|
|
@@ -102219,6 +102402,7 @@ const collectExportNames = (declaration) => {
|
|
|
102219
102402
|
const evaluateExports = () => (tree, file) => {
|
|
102220
102403
|
const programBody = [];
|
|
102221
102404
|
const exportNames = [];
|
|
102405
|
+
const importDeclarations = [];
|
|
102222
102406
|
const nodesToRemove = [];
|
|
102223
102407
|
visit(tree, isMDXEsm, (node, index, parent) => {
|
|
102224
102408
|
if (parent && typeof index === 'number') {
|
|
@@ -102232,6 +102416,10 @@ const evaluateExports = () => (tree, file) => {
|
|
|
102232
102416
|
// handled the same as a named export — the inner declaration carries the
|
|
102233
102417
|
// binding name
|
|
102234
102418
|
estreeBody.forEach(statement => {
|
|
102419
|
+
if (statement.type === 'ImportDeclaration') {
|
|
102420
|
+
importDeclarations.push(statement);
|
|
102421
|
+
return;
|
|
102422
|
+
}
|
|
102235
102423
|
let declaration = null;
|
|
102236
102424
|
if (statement.type === 'ExportNamedDeclaration' && statement.declaration) {
|
|
102237
102425
|
declaration = statement.declaration;
|
|
@@ -102259,9 +102447,11 @@ const evaluateExports = () => (tree, file) => {
|
|
|
102259
102447
|
const program = { type: 'Program', sourceType: 'module', body: programBody };
|
|
102260
102448
|
buildJsx(program, { runtime: 'classic', pragma: 'React.createElement', pragmaFrag: 'React.Fragment' });
|
|
102261
102449
|
const { value: source } = toJs(program);
|
|
102450
|
+
// Make sure import values are available in the scope
|
|
102451
|
+
const importValues = collectImportValues(importDeclarations);
|
|
102262
102452
|
// Evaluate and build on the expression source
|
|
102263
102453
|
// Use react to compile JSX codes
|
|
102264
|
-
const evaluatedExports = evaluate(`(() => { ${source}\nreturn { ${exportNames.join(', ')} }; })()`, { React: (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default()) });
|
|
102454
|
+
const evaluatedExports = evaluate(`(() => { ${source}\nreturn { ${exportNames.join(', ')} }; })()`, { React: (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default()), ...importValues });
|
|
102265
102455
|
Object.assign(scope, evaluatedExports);
|
|
102266
102456
|
}
|
|
102267
102457
|
catch (error) {
|
|
@@ -102327,15 +102517,17 @@ const evalExpression = (expression, scope) => {
|
|
|
102327
102517
|
|
|
102328
102518
|
|
|
102329
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);
|
|
102330
102522
|
/** Given the type of the expression result, create the corresponding mdast node. */
|
|
102331
102523
|
const createEvaluatedNode = (result, position) => {
|
|
102332
102524
|
if (result === null || result === undefined) {
|
|
102333
102525
|
return { type: 'text', value: '', position };
|
|
102334
102526
|
}
|
|
102335
|
-
else if (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().isValidElement(result)) {
|
|
102336
|
-
// Convert react elements to
|
|
102337
|
-
// This must come before the object check as
|
|
102338
|
-
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 };
|
|
102339
102531
|
}
|
|
102340
102532
|
else if (typeof result === 'object') {
|
|
102341
102533
|
return { type: 'text', value: JSON.stringify(result), position };
|
|
@@ -102375,6 +102567,47 @@ const evaluateExpressions = () => (tree, file) => {
|
|
|
102375
102567
|
};
|
|
102376
102568
|
/* harmony default export */ const evaluate_expressions = (evaluateExpressions);
|
|
102377
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
|
+
|
|
102378
102611
|
;// ./processor/transform/mdxish/heading-slugs.ts
|
|
102379
102612
|
|
|
102380
102613
|
|
|
@@ -104215,219 +104448,100 @@ const normalizeMdxJsxNodes = () => tree => {
|
|
|
104215
104448
|
*/
|
|
104216
104449
|
const JSX_COMMENT_REGEX = /\{\/\*[^*]*(?:\*(?!\/)[^*]*)*\*\/\}/g;
|
|
104217
104450
|
|
|
104218
|
-
;// ./processor/transform/mdxish/
|
|
104219
|
-
|
|
104451
|
+
;// ./processor/transform/mdxish/remove-jsx-comments.ts
|
|
104220
104452
|
|
|
104221
104453
|
/**
|
|
104222
104454
|
* Removes JSX-style comments (e.g., { /* comment *\/ }) from content.
|
|
104223
104455
|
*
|
|
104224
|
-
*
|
|
104225
|
-
*
|
|
104226
|
-
*
|
|
104456
|
+
* `@param` content
|
|
104457
|
+
* `@returns` Content with JSX comments removed
|
|
104458
|
+
* `@example`
|
|
104227
104459
|
* ```typescript
|
|
104228
|
-
* removeJSXComments('Text {
|
|
104229
|
-
* // Returns: 'Text more text'
|
|
104460
|
+
* removeJSXComments('Text {/* comment *\/} more text') // => 'Text more text'
|
|
104230
104461
|
* ```
|
|
104231
104462
|
*/
|
|
104232
104463
|
function removeJSXComments(content) {
|
|
104233
104464
|
return content.replace(JSX_COMMENT_REGEX, '');
|
|
104234
104465
|
}
|
|
104235
|
-
|
|
104236
|
-
|
|
104237
|
-
|
|
104238
|
-
// Allows optional leading indentation and lazily matches until the same closing tag.
|
|
104239
|
-
const BLOCK_HTML_RE = /(?<=^|\n)[ \t]*<([a-z][a-zA-Z0-9]*)(?:\s[^>]*)?>[\s\S]*?<\/\1>[ \t]*(?=\n|$)/g;
|
|
104240
|
-
/**
|
|
104241
|
-
* Hides line-anchored HTML elements from the brace-escaping pass so we don't leak `\{`
|
|
104242
|
-
* into rendered output (rehypeRaw renders the `\` literally, e.g. `<div>{foo</div>`).
|
|
104243
|
-
*
|
|
104244
|
-
* One carve-out: if an interior line at column 0 has bare text containing `{`, mdxish
|
|
104245
|
-
* parses that line as a paragraph and the mdxExpression step would throw without an
|
|
104246
|
-
* escape — so we leave that case to the brace balancer.
|
|
104247
|
-
*/
|
|
104248
|
-
function protectHTMLElements(content) {
|
|
104249
|
-
const htmlElements = [];
|
|
104250
|
-
const protectedContent = content.replace(BLOCK_HTML_RE, match => {
|
|
104251
|
-
// Look at the lines between the open and close tags. If any of them starts
|
|
104252
|
-
// at column 0 with bare text (not whitespace, not another tag) and contains
|
|
104253
|
-
// `{`, mdxish will parse that line as a paragraph and the brace as an MDX
|
|
104254
|
-
// expression, which would throw an error. So we let the brace balancer escape it.
|
|
104255
|
-
// Otherwise, we need to extract the sequence to protect it from the brace escaping.
|
|
104256
|
-
const interior = match.split('\n').slice(1, -1);
|
|
104257
|
-
const hazard = interior.some(line => line.length > 0 && line[0] !== ' ' && line[0] !== '\t' && line[0] !== '<' && line.includes('{'));
|
|
104258
|
-
if (hazard)
|
|
104259
|
-
return match;
|
|
104260
|
-
htmlElements.push(match);
|
|
104261
|
-
return `${HTML_ELEM_PLACEHOLDER_PREFIX}${htmlElements.length - 1}___`;
|
|
104262
|
-
});
|
|
104263
|
-
return { htmlElements, protectedContent };
|
|
104264
|
-
}
|
|
104265
|
-
function restoreHTMLElements(content, htmlElements) {
|
|
104266
|
-
if (htmlElements.length === 0)
|
|
104267
|
-
return content;
|
|
104268
|
-
return content.replace(HTML_ELEM_PLACEHOLDER, (_m, idx) => htmlElements[parseInt(idx, 10)]);
|
|
104269
|
-
}
|
|
104270
|
-
const ESM_DECLARATION_START = /^(?:export|import)\b/;
|
|
104466
|
+
|
|
104467
|
+
;// ./processor/transform/mdxish/style-object-to-css.ts
|
|
104468
|
+
|
|
104271
104469
|
/**
|
|
104272
|
-
*
|
|
104273
|
-
*
|
|
104274
|
-
*
|
|
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
|
|
104275
104473
|
*/
|
|
104276
|
-
|
|
104277
|
-
|
|
104278
|
-
|
|
104279
|
-
|
|
104280
|
-
|
|
104281
|
-
|
|
104282
|
-
|
|
104283
|
-
|
|
104284
|
-
|
|
104285
|
-
|
|
104286
|
-
|
|
104287
|
-
|
|
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}`;
|
|
104288
104525
|
/**
|
|
104289
|
-
*
|
|
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.
|
|
104290
104528
|
*/
|
|
104291
|
-
|
|
104292
|
-
const { htmlElements, protectedContent } = protectHTMLElements(content);
|
|
104293
|
-
let strDelim = null;
|
|
104294
|
-
let strEscaped = false;
|
|
104295
|
-
// Track position of last newline (outside strings) to detect blank lines
|
|
104296
|
-
// -2 means no recent newline
|
|
104297
|
-
let lastNewlinePos = -2;
|
|
104298
|
-
// Character state machine trackers
|
|
104299
|
-
const toEscape = new Set();
|
|
104300
|
-
// Convert to array of Unicode code points so that emojis and multi-byte characters are correctly tracked
|
|
104301
|
-
const chars = Array.from(protectedContent);
|
|
104302
|
-
const openStack = [];
|
|
104303
|
-
// Whether the current top-level statement is an `export`/`import` declaration.
|
|
104304
|
-
let insideEsmDeclaration = false;
|
|
104305
|
-
for (let i = 0; i < chars.length; i += 1) {
|
|
104306
|
-
const ch = chars[i];
|
|
104307
|
-
// At a top-level (brace depth 0) line start, decide whether we're inside an
|
|
104308
|
-
// ESM declaration. The flag persists across the declaration's own lines.
|
|
104309
|
-
if (openStack.length === 0 && (i === 0 || chars[i - 1] === '\n')) {
|
|
104310
|
-
if (startsEsmDeclaration(chars, i))
|
|
104311
|
-
insideEsmDeclaration = true;
|
|
104312
|
-
else if (isBlankLine(chars, i))
|
|
104313
|
-
insideEsmDeclaration = false;
|
|
104314
|
-
}
|
|
104315
|
-
// Track string delimiters inside expressions to ignore braces within them
|
|
104316
|
-
if (openStack.length > 0) {
|
|
104317
|
-
if (strDelim) {
|
|
104318
|
-
if (strEscaped)
|
|
104319
|
-
strEscaped = false;
|
|
104320
|
-
else if (ch === '\\')
|
|
104321
|
-
strEscaped = true;
|
|
104322
|
-
else if (ch === strDelim)
|
|
104323
|
-
strDelim = null;
|
|
104324
|
-
// eslint-disable-next-line no-continue
|
|
104325
|
-
continue;
|
|
104326
|
-
}
|
|
104327
|
-
if (ch === '"' || ch === "'" || ch === '`') {
|
|
104328
|
-
strDelim = ch;
|
|
104329
|
-
// eslint-disable-next-line no-continue
|
|
104330
|
-
continue;
|
|
104331
|
-
}
|
|
104332
|
-
if (ch === '\n') {
|
|
104333
|
-
if (lastNewlinePos >= 0) {
|
|
104334
|
-
const between = chars.slice(lastNewlinePos + 1, i).join('');
|
|
104335
|
-
if (/^[ \t]*$/.test(between)) {
|
|
104336
|
-
openStack.forEach(entry => { entry.hasBlankLine = true; });
|
|
104337
|
-
}
|
|
104338
|
-
}
|
|
104339
|
-
lastNewlinePos = i;
|
|
104340
|
-
}
|
|
104341
|
-
}
|
|
104342
|
-
// Skip already-escaped braces (odd run of preceding backslashes).
|
|
104343
|
-
if (ch === '{' || ch === '}') {
|
|
104344
|
-
let bs = 0;
|
|
104345
|
-
for (let j = i - 1; j >= 0 && chars[j] === '\\'; j -= 1)
|
|
104346
|
-
bs += 1;
|
|
104347
|
-
if (bs % 2 === 1) {
|
|
104348
|
-
// eslint-disable-next-line no-continue
|
|
104349
|
-
continue;
|
|
104350
|
-
}
|
|
104351
|
-
}
|
|
104352
|
-
if (ch === '{') {
|
|
104353
|
-
// `=` (after whitespace) before `{` ⇒ JSX attribute expression. The
|
|
104354
|
-
// mdxComponent tokenizer captures the whole component, so blank lines
|
|
104355
|
-
// inside attribute values are harmless. Nested `{` inherits the flag.
|
|
104356
|
-
let isAttrExpr = false;
|
|
104357
|
-
for (let j = i - 1; j >= 0; j -= 1) {
|
|
104358
|
-
const pc = chars[j];
|
|
104359
|
-
if (pc === '=') {
|
|
104360
|
-
isAttrExpr = true;
|
|
104361
|
-
break;
|
|
104362
|
-
}
|
|
104363
|
-
if (pc !== ' ' && pc !== '\t')
|
|
104364
|
-
break;
|
|
104365
|
-
}
|
|
104366
|
-
// Nested `{ ... }` inside an attribute value (e.g. `data={[{ ... }]}` or
|
|
104367
|
-
// `data={{ a: { b: 1 } }}`) must inherit the same exemption; only the
|
|
104368
|
-
// outer `{` is directly after `=`.
|
|
104369
|
-
if (!isAttrExpr && openStack.length > 0 && openStack[openStack.length - 1].isAttrExpr) {
|
|
104370
|
-
isAttrExpr = true;
|
|
104371
|
-
}
|
|
104372
|
-
openStack.push({ pos: i, hasBlankLine: false, isAttrExpr, isEsmDeclaration: insideEsmDeclaration });
|
|
104373
|
-
lastNewlinePos = -2;
|
|
104374
|
-
}
|
|
104375
|
-
else if (ch === '}') {
|
|
104376
|
-
if (openStack.length > 0) {
|
|
104377
|
-
const entry = openStack.pop();
|
|
104378
|
-
// The declaration's braces are closed; later top-level braces are not ESM.
|
|
104379
|
-
if (openStack.length === 0)
|
|
104380
|
-
insideEsmDeclaration = false;
|
|
104381
|
-
// Pure `{/* ... */}` comments are handled downstream by the jsxComment
|
|
104382
|
-
// tokenizer — escaping their braces would prevent it from running.
|
|
104383
|
-
const isPureJsxComment = chars[entry.pos + 1] === '/' &&
|
|
104384
|
-
chars[entry.pos + 2] === '*' &&
|
|
104385
|
-
chars[i - 1] === '/' &&
|
|
104386
|
-
chars[i - 2] === '*';
|
|
104387
|
-
if (entry.hasBlankLine && !isPureJsxComment && !entry.isAttrExpr && !entry.isEsmDeclaration) {
|
|
104388
|
-
toEscape.add(entry.pos);
|
|
104389
|
-
toEscape.add(i);
|
|
104390
|
-
}
|
|
104391
|
-
}
|
|
104392
|
-
else {
|
|
104393
|
-
toEscape.add(i);
|
|
104394
|
-
}
|
|
104395
|
-
}
|
|
104396
|
-
else if (ch === ';' && openStack.length === 0) {
|
|
104397
|
-
// A top-level `;` ends the current statement, ESM or otherwise.
|
|
104398
|
-
insideEsmDeclaration = false;
|
|
104399
|
-
}
|
|
104400
|
-
}
|
|
104401
|
-
// Anything still open is unbalanced.
|
|
104402
|
-
openStack.forEach(entry => {
|
|
104403
|
-
if (!entry.isEsmDeclaration)
|
|
104404
|
-
toEscape.add(entry.pos);
|
|
104405
|
-
});
|
|
104406
|
-
// Reconstruct the content with the escaped braces.
|
|
104407
|
-
const escapedContent = toEscape.size === 0 ? protectedContent : chars.map((ch, i) => (toEscape.has(i) ? `\\${ch}` : ch)).join('');
|
|
104408
|
-
return restoreHTMLElements(escapedContent, htmlElements);
|
|
104409
|
-
}
|
|
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);
|
|
104410
104530
|
/**
|
|
104411
|
-
*
|
|
104412
|
-
*
|
|
104413
|
-
*
|
|
104414
|
-
* they flow through the tokenizer as `mdxJsxAttributeValueExpression` nodes
|
|
104415
|
-
* and are evaluated at the hast handler step.
|
|
104416
|
-
*
|
|
104417
|
-
* @param content
|
|
104418
|
-
* @returns Preprocessed content ready for markdown parsing
|
|
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.
|
|
104419
104534
|
*/
|
|
104420
|
-
|
|
104421
|
-
|
|
104422
|
-
|
|
104423
|
-
|
|
104424
|
-
return processed;
|
|
104425
|
-
}
|
|
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(';');
|
|
104426
104539
|
|
|
104427
104540
|
;// ./processor/transform/mdxish/resolve-deferred-attribute-expression-props.ts
|
|
104428
104541
|
|
|
104429
104542
|
|
|
104430
104543
|
|
|
104544
|
+
|
|
104431
104545
|
/**
|
|
104432
104546
|
* Resolve attribute expressions that `mdxJsxElementHandler` deferred.
|
|
104433
104547
|
*
|
|
@@ -104449,7 +104563,10 @@ const resolveDeferredAttributeExpressionProps = () => (tree, file) => {
|
|
|
104449
104563
|
const properties = node.properties;
|
|
104450
104564
|
Object.entries(deferredExpressions).forEach(([name, source]) => {
|
|
104451
104565
|
try {
|
|
104452
|
-
|
|
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;
|
|
104453
104570
|
}
|
|
104454
104571
|
catch {
|
|
104455
104572
|
// Evaluation failed — fall back to the raw expression source so the attribute
|
|
@@ -104769,13 +104886,13 @@ function normalizeTableSeparator(content) {
|
|
|
104769
104886
|
;// ./processor/transform/mdxish/terminate-html-flow-blocks.ts
|
|
104770
104887
|
|
|
104771
104888
|
|
|
104889
|
+
|
|
104772
104890
|
const STANDALONE_HTML_LINE_REGEX = /^(<[a-z][^<>]*>|<\/[a-z][^<>]*>)+\s*$/;
|
|
104773
104891
|
const HTML_LINE_WITH_CONTENT_REGEX = /^<[a-z][^<>]*>.*<\/[a-z][^<>]*>(?:[^<]*)$/;
|
|
104774
|
-
const terminate_html_flow_blocks_TABLE_STRUCTURE_TAGS = ['table', 'thead', 'tbody', 'tfoot', 'tr', 'td', 'th', 'caption', 'colgroup'];
|
|
104775
104892
|
// Tags whose contents must be preserved as is, inserting a blank line after the
|
|
104776
104893
|
// opener corrupts the payload.
|
|
104777
104894
|
// htmlRawNames here refer to <pre>, <textarea>, <script>, <style>
|
|
104778
|
-
const RAW_CONTENT_TAGS = [...htmlRawNames, ...
|
|
104895
|
+
const RAW_CONTENT_TAGS = [...htmlRawNames, ...HTML_TABLE_STRUCTURE_TAGS];
|
|
104779
104896
|
// The `(?=[\s/>])` lookahead avoids false matches on lookalike names like `<script-foo>`.
|
|
104780
104897
|
const RAW_CONTENT_TAG_MATCHERS = RAW_CONTENT_TAGS.map(tag => ({
|
|
104781
104898
|
open: new RegExp(`<${tag}(?=[\\s/>])[^>]*?(?<!/)>`, 'gi'),
|
|
@@ -105397,6 +105514,85 @@ function jsxTable() {
|
|
|
105397
105514
|
;// ./lib/micromark/jsx-table/index.ts
|
|
105398
105515
|
|
|
105399
105516
|
|
|
105517
|
+
;// ./lib/micromark/mdx-expression-lenient/syntax.ts
|
|
105518
|
+
|
|
105519
|
+
|
|
105520
|
+
/**
|
|
105521
|
+
* Lenient MDX text-expression tokenizer (agnostic / no acorn).
|
|
105522
|
+
*
|
|
105523
|
+
* Matches a balanced `{ ... }` run — tracking nested braces and spanning soft
|
|
105524
|
+
* line breaks — and emits the standard `mdxTextExpression*` tokens so the
|
|
105525
|
+
* upstream `mdxExpressionFromMarkdown()` builds the node.
|
|
105526
|
+
*
|
|
105527
|
+
* Reimplements the official micromark mdxExpression, but an unbalanced brace that
|
|
105528
|
+
* reaches end of input returns `nok` instead of throwing: micromark rolls back
|
|
105529
|
+
* and the `{` renders as literal text, making the pipeline forgiving of stray
|
|
105530
|
+
* braces that upstream would hard-error on.
|
|
105531
|
+
*/
|
|
105532
|
+
function tokenizeTextExpression(effects, ok, nok) {
|
|
105533
|
+
let depth = 0;
|
|
105534
|
+
return start;
|
|
105535
|
+
function start(code) {
|
|
105536
|
+
if (code !== codes.leftCurlyBrace)
|
|
105537
|
+
return nok(code);
|
|
105538
|
+
effects.enter('mdxTextExpression');
|
|
105539
|
+
effects.enter('mdxTextExpressionMarker');
|
|
105540
|
+
effects.consume(code);
|
|
105541
|
+
effects.exit('mdxTextExpressionMarker');
|
|
105542
|
+
return before;
|
|
105543
|
+
}
|
|
105544
|
+
function before(code) {
|
|
105545
|
+
if (code === codes.eof) {
|
|
105546
|
+
effects.exit('mdxTextExpression');
|
|
105547
|
+
return nok(code);
|
|
105548
|
+
}
|
|
105549
|
+
if (markdownLineEnding(code)) {
|
|
105550
|
+
effects.enter('lineEnding');
|
|
105551
|
+
effects.consume(code);
|
|
105552
|
+
effects.exit('lineEnding');
|
|
105553
|
+
return before;
|
|
105554
|
+
}
|
|
105555
|
+
if (code === codes.rightCurlyBrace && depth === 0) {
|
|
105556
|
+
return close(code);
|
|
105557
|
+
}
|
|
105558
|
+
effects.enter('mdxTextExpressionChunk');
|
|
105559
|
+
return inside(code);
|
|
105560
|
+
}
|
|
105561
|
+
function inside(code) {
|
|
105562
|
+
if (code === codes.eof || markdownLineEnding(code)) {
|
|
105563
|
+
effects.exit('mdxTextExpressionChunk');
|
|
105564
|
+
return before(code);
|
|
105565
|
+
}
|
|
105566
|
+
if (code === codes.rightCurlyBrace && depth === 0) {
|
|
105567
|
+
effects.exit('mdxTextExpressionChunk');
|
|
105568
|
+
return close(code);
|
|
105569
|
+
}
|
|
105570
|
+
if (code === codes.leftCurlyBrace)
|
|
105571
|
+
depth += 1;
|
|
105572
|
+
else if (code === codes.rightCurlyBrace)
|
|
105573
|
+
depth -= 1;
|
|
105574
|
+
effects.consume(code);
|
|
105575
|
+
return inside;
|
|
105576
|
+
}
|
|
105577
|
+
function close(code) {
|
|
105578
|
+
effects.enter('mdxTextExpressionMarker');
|
|
105579
|
+
effects.consume(code);
|
|
105580
|
+
effects.exit('mdxTextExpressionMarker');
|
|
105581
|
+
effects.exit('mdxTextExpression');
|
|
105582
|
+
return ok;
|
|
105583
|
+
}
|
|
105584
|
+
}
|
|
105585
|
+
function mdxExpressionLenient() {
|
|
105586
|
+
return {
|
|
105587
|
+
text: {
|
|
105588
|
+
[codes.leftCurlyBrace]: {
|
|
105589
|
+
name: 'mdxTextExpression',
|
|
105590
|
+
tokenize: tokenizeTextExpression,
|
|
105591
|
+
},
|
|
105592
|
+
},
|
|
105593
|
+
};
|
|
105594
|
+
}
|
|
105595
|
+
|
|
105400
105596
|
;// ./lib/utils/mdxish/mdxish-load-components.ts
|
|
105401
105597
|
|
|
105402
105598
|
|
|
@@ -105494,6 +105690,7 @@ function loadComponents() {
|
|
|
105494
105690
|
|
|
105495
105691
|
|
|
105496
105692
|
|
|
105693
|
+
|
|
105497
105694
|
|
|
105498
105695
|
|
|
105499
105696
|
const defaultTransformers = [
|
|
@@ -105509,7 +105706,7 @@ const defaultTransformers = [
|
|
|
105509
105706
|
* 1. Normalize malformed table separator syntax (e.g., `|: ---` → `| :---`)
|
|
105510
105707
|
* 2. Terminate HTML flow blocks so subsequent content isn't swallowed
|
|
105511
105708
|
* 3. Close invalid "self-closing" HTML tags (e.g., `<i />` → `<i></i>`)
|
|
105512
|
-
* 4.
|
|
105709
|
+
* 4. Normalize compact ATX headings (e.g., `#Heading` → `# Heading`)
|
|
105513
105710
|
* 5. Replace snake_case component names with parser-safe placeholders
|
|
105514
105711
|
*/
|
|
105515
105712
|
function preprocessContent(content, opts) {
|
|
@@ -105518,7 +105715,6 @@ function preprocessContent(content, opts) {
|
|
|
105518
105715
|
result = terminateHtmlFlowBlocks(result);
|
|
105519
105716
|
result = closeSelfClosingHtmlTags(result);
|
|
105520
105717
|
result = normalizeCompactHeadings(result);
|
|
105521
|
-
result = preprocessJSXExpressions(result);
|
|
105522
105718
|
return processSnakeCaseComponent(result, { knownComponents });
|
|
105523
105719
|
}
|
|
105524
105720
|
function mdxishAstProcessor(mdContent, opts = {}) {
|
|
@@ -105535,12 +105731,8 @@ function mdxishAstProcessor(mdContent, opts = {}) {
|
|
|
105535
105731
|
acc[key] = String(value);
|
|
105536
105732
|
return acc;
|
|
105537
105733
|
}, {});
|
|
105538
|
-
//
|
|
105539
|
-
|
|
105540
|
-
const mdxExprExt = mdxExpression({ allowEmpty: true });
|
|
105541
|
-
const mdxExprTextOnly = {
|
|
105542
|
-
text: mdxExprExt.text,
|
|
105543
|
-
};
|
|
105734
|
+
// Parser extension for MDX expressions {}
|
|
105735
|
+
const mdxExprTextOnly = mdxExpressionLenient();
|
|
105544
105736
|
const micromarkExts = [
|
|
105545
105737
|
jsxTable(),
|
|
105546
105738
|
magicBlock(),
|
|
@@ -105649,6 +105841,7 @@ function mdxish(mdContent, opts = {}) {
|
|
|
105649
105841
|
.use(safeMode ? undefined : evaluate_exports) // Evaluate `export const/function` and stash scope on file.data.mdxishScope
|
|
105650
105842
|
.use(remarkBreaks) // Must precede evaluateExpressions to avoid splitting the \n in an evaluated template literal into a <br> node
|
|
105651
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
|
|
105652
105845
|
.use(variables_code, { variables }) // Resolve <<...>> and {user.*} inside code and inline code nodes
|
|
105653
105846
|
.use(remarkRehype, { allowDangerousHtml: true, handlers: mdxComponentHandlers })
|
|
105654
105847
|
.use(preserveBooleanProperties) // RehypeRaw converts boolean properties to empty strings
|