@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
|
@@ -95894,6 +95894,18 @@ const tableTags = new Set([
|
|
|
95894
95894
|
'th',
|
|
95895
95895
|
'td',
|
|
95896
95896
|
]);
|
|
95897
|
+
/**
|
|
95898
|
+
* Replaces every paragraph node with its inline children. Used where paragraphs
|
|
95899
|
+
* are parser artifacts (remarkMdx wrapping inline JSX), not real content.
|
|
95900
|
+
*/
|
|
95901
|
+
const unwrapParagraphNodes = (children) => {
|
|
95902
|
+
return children.flatMap(child => {
|
|
95903
|
+
if (child.type === 'paragraph' && 'children' in child && Array.isArray(child.children)) {
|
|
95904
|
+
return child.children;
|
|
95905
|
+
}
|
|
95906
|
+
return [child];
|
|
95907
|
+
});
|
|
95908
|
+
};
|
|
95897
95909
|
/**
|
|
95898
95910
|
* If the cell has exactly one paragraph child, unwrap it so its inline children sit
|
|
95899
95911
|
* directly under the cell (matches GFM table cell shape and avoids stray `<p>` wrappers).
|
|
@@ -95905,12 +95917,7 @@ const unwrapSoleParagraph = (children) => {
|
|
|
95905
95917
|
const paragraphCount = children.filter(c => c.type === 'paragraph').length;
|
|
95906
95918
|
if (paragraphCount !== 1)
|
|
95907
95919
|
return children;
|
|
95908
|
-
return children
|
|
95909
|
-
if (child.type === 'paragraph' && 'children' in child && Array.isArray(child.children)) {
|
|
95910
|
-
return child.children;
|
|
95911
|
-
}
|
|
95912
|
-
return [child];
|
|
95913
|
-
});
|
|
95920
|
+
return unwrapParagraphNodes(children);
|
|
95914
95921
|
};
|
|
95915
95922
|
/**
|
|
95916
95923
|
* Splice each text into `html` at its offset. Inserts at the same offset
|
|
@@ -96260,6 +96267,23 @@ const RUNTIME_COMPONENT_TAGS = new Set(['Variable', 'variable', 'html-block', 'r
|
|
|
96260
96267
|
* Uses the html-tags package, converted to a Set<string> for efficient lookups.
|
|
96261
96268
|
*/
|
|
96262
96269
|
const STANDARD_HTML_TAGS = new Set(html_tags_namespaceObject);
|
|
96270
|
+
/**
|
|
96271
|
+
* Table structural tags. Blank lines inside these carry deliberate meaning for
|
|
96272
|
+
* `mdxishTables` (e.g. splitting cell content into paragraphs, or deciding
|
|
96273
|
+
* whether a table stays plain HTML vs a JSX `<Table>`), so transforms that
|
|
96274
|
+
* neutralize or claim across blank lines must leave them alone.
|
|
96275
|
+
*/
|
|
96276
|
+
const HTML_TABLE_STRUCTURE_TAGS = new Set([
|
|
96277
|
+
'table',
|
|
96278
|
+
'thead',
|
|
96279
|
+
'tbody',
|
|
96280
|
+
'tfoot',
|
|
96281
|
+
'tr',
|
|
96282
|
+
'td',
|
|
96283
|
+
'th',
|
|
96284
|
+
'caption',
|
|
96285
|
+
'colgroup',
|
|
96286
|
+
]);
|
|
96263
96287
|
/**
|
|
96264
96288
|
* HTML void elements — elements that have no closing tag and no children.
|
|
96265
96289
|
*
|
|
@@ -96571,18 +96595,17 @@ const processTableNode = (node, index, parent, documentPosition) => {
|
|
|
96571
96595
|
// same line as content becomes mdxJsxTextElement inside a paragraph).
|
|
96572
96596
|
// Unwrap these so <td>/<th> sit directly under <tr>, and strip
|
|
96573
96597
|
// whitespace-only text nodes to avoid rendering empty <p>/<br>.
|
|
96574
|
-
const
|
|
96575
|
-
.flatMap(child => {
|
|
96576
|
-
if (child.type === 'paragraph' && 'children' in child && Array.isArray(child.children)) {
|
|
96577
|
-
return child.children;
|
|
96578
|
-
}
|
|
96579
|
-
return [child];
|
|
96580
|
-
})
|
|
96581
|
-
.filter(child => !(child.type === 'text' && 'value' in child && typeof child.value === 'string' && !child.value.trim()));
|
|
96598
|
+
const removeWhitespaceOnlyTextNodes = (children) => children.filter(child => !(child.type === 'text' && 'value' in child && typeof child.value === 'string' && !child.value.trim()));
|
|
96582
96599
|
lib_visit(node, utils_isMDXElement, (el) => {
|
|
96583
|
-
if ('children' in el
|
|
96584
|
-
|
|
96585
|
-
|
|
96600
|
+
if (!('children' in el) || !Array.isArray(el.children))
|
|
96601
|
+
return;
|
|
96602
|
+
// Filtering transformers
|
|
96603
|
+
// A cell only unwraps a sole paragraph: multiple paragraphs are real
|
|
96604
|
+
// blank-line-separated content that must stay separated
|
|
96605
|
+
const unwrapped = isTableCell(el)
|
|
96606
|
+
? unwrapSoleParagraph(el.children)
|
|
96607
|
+
: unwrapParagraphNodes(el.children);
|
|
96608
|
+
el.children = removeWhitespaceOnlyTextNodes(unwrapped);
|
|
96586
96609
|
});
|
|
96587
96610
|
parent.children[index] = {
|
|
96588
96611
|
...node,
|
|
@@ -119552,15 +119575,26 @@ const types_types = /** @type {const} */ ({
|
|
|
119552
119575
|
|
|
119553
119576
|
|
|
119554
119577
|
|
|
119578
|
+
|
|
119555
119579
|
// Raw tags (type-1: pre/script/style/textarea) and block tags (type-6: div,
|
|
119556
119580
|
// section, …) always start a block, so they stay flow even with trailing
|
|
119557
119581
|
// content. Other lowercase tags (i, span, …) follow the type-7 rule and only
|
|
119558
119582
|
// stay flow when nothing trails the close tag.
|
|
119559
119583
|
const htmlFlowTagNames = new Set([...htmlRawNames, ...htmlBlockNames]);
|
|
119584
|
+
// Lowercase type-6 block tags claimable in flow even without a `{…}` attribute, so
|
|
119585
|
+
// blank lines between nested JSX siblings don't fragment the block. Excludes table
|
|
119586
|
+
// tags (mdxishTables owns their blank lines) and voids (never close).
|
|
119587
|
+
const plainBlockClaimTagNames = new Set([...htmlBlockNames].filter(tag => !HTML_TABLE_STRUCTURE_TAGS.has(tag) && !HTML_VOID_ELEMENTS.has(tag)));
|
|
119560
119588
|
const syntax_nonLazyContinuationStart = {
|
|
119561
119589
|
tokenize: syntax_tokenizeNonLazyContinuationStart,
|
|
119562
119590
|
partial: true,
|
|
119563
119591
|
};
|
|
119592
|
+
// Lookahead for `plainClaimLineStart`: is this line markup-only, or a paragraph
|
|
119593
|
+
// that merely starts with a tag? Run via `effects.check` so it never consumes.
|
|
119594
|
+
const markupOnlyContinuation = {
|
|
119595
|
+
tokenize: tokenizeMarkupOnlyContinuation,
|
|
119596
|
+
partial: true,
|
|
119597
|
+
};
|
|
119564
119598
|
function resolveToMdxComponent(events) {
|
|
119565
119599
|
let index = events.length;
|
|
119566
119600
|
while (index > 0) {
|
|
@@ -119615,6 +119649,10 @@ function createTokenize(mode) {
|
|
|
119615
119649
|
// (INLINE_COMPONENT_TAGS — Anchor, Glossary), also brace-gated.
|
|
119616
119650
|
let isLowercaseTag = false;
|
|
119617
119651
|
let sawBraceAttr = false;
|
|
119652
|
+
// A plain lowercase block tag claimed without a `{…}` attribute, gated by
|
|
119653
|
+
// `plainClaimLineStart`: after a blank line it may only continue on a tag line.
|
|
119654
|
+
let isPlainBlockClaim = false;
|
|
119655
|
+
let pendingBlankLine = false;
|
|
119618
119656
|
// Code span tracking
|
|
119619
119657
|
let codeSpanOpenSize = 0;
|
|
119620
119658
|
let codeSpanCloseSize = 0;
|
|
@@ -119848,8 +119886,13 @@ function createTokenize(mode) {
|
|
|
119848
119886
|
}
|
|
119849
119887
|
// End of opening tag
|
|
119850
119888
|
if (code === codes.greaterThan) {
|
|
119851
|
-
if (requiresBraceAttr && !sawBraceAttr)
|
|
119852
|
-
|
|
119889
|
+
if (requiresBraceAttr && !sawBraceAttr) {
|
|
119890
|
+
// Plain lowercase block tags stay claimable in flow, gated per line by
|
|
119891
|
+
// `plainClaimLineStart`; everything else falls through to CommonMark.
|
|
119892
|
+
if (!isFlow || !plainBlockClaimTagNames.has(tagName))
|
|
119893
|
+
return nok(code);
|
|
119894
|
+
isPlainBlockClaim = true;
|
|
119895
|
+
}
|
|
119853
119896
|
effects.consume(code);
|
|
119854
119897
|
onOpenerLine = isFlow;
|
|
119855
119898
|
return body;
|
|
@@ -119999,6 +120042,7 @@ function createTokenize(mode) {
|
|
|
119999
120042
|
if (atLineStart && codeSpanOpenSize >= 3) {
|
|
120000
120043
|
fenceChar = codes.graveAccent;
|
|
120001
120044
|
fenceLength = codeSpanOpenSize;
|
|
120045
|
+
atLineStart = false;
|
|
120002
120046
|
return inFencedCode(code);
|
|
120003
120047
|
}
|
|
120004
120048
|
return inCodeSpan(code);
|
|
@@ -120146,8 +120190,14 @@ function createTokenize(mode) {
|
|
|
120146
120190
|
effects.consume(code);
|
|
120147
120191
|
return nestedOpenTagName;
|
|
120148
120192
|
}
|
|
120149
|
-
//
|
|
120150
|
-
|
|
120193
|
+
// Same-name opener followed by a tag-end char bumps depth. A line ending
|
|
120194
|
+
// counts too: Prettier puts a newline right after the name (`<div\n …\n>`).
|
|
120195
|
+
if (closingTagName === tagName &&
|
|
120196
|
+
(code === codes.greaterThan ||
|
|
120197
|
+
code === codes.slash ||
|
|
120198
|
+
code === codes.space ||
|
|
120199
|
+
code === codes.horizontalTab ||
|
|
120200
|
+
markdownLineEnding(code))) {
|
|
120151
120201
|
depth += 1;
|
|
120152
120202
|
}
|
|
120153
120203
|
atLineStart = false;
|
|
@@ -120236,6 +120286,10 @@ function createTokenize(mode) {
|
|
|
120236
120286
|
}
|
|
120237
120287
|
function bodyContinuationBefore(code) {
|
|
120238
120288
|
if (code === null || markdownLineEnding(code)) {
|
|
120289
|
+
// Empty line: outside any `{…}` expression this is CommonMark's html-block
|
|
120290
|
+
// terminator, so a plain block claim must pass the guard below to continue.
|
|
120291
|
+
if (isPlainBlockClaim && braceDepth === 0)
|
|
120292
|
+
pendingBlankLine = true;
|
|
120239
120293
|
return bodyContinuationStart(code);
|
|
120240
120294
|
}
|
|
120241
120295
|
effects.enter('mdxComponentData');
|
|
@@ -120247,19 +120301,52 @@ function createTokenize(mode) {
|
|
|
120247
120301
|
return inBodyBraceString(code);
|
|
120248
120302
|
return inBodyBraceExpr(code);
|
|
120249
120303
|
}
|
|
120250
|
-
|
|
120251
|
-
|
|
120304
|
+
if (isPlainBlockClaim)
|
|
120305
|
+
return plainClaimLineStart(code);
|
|
120306
|
+
return bodyLineStart(code);
|
|
120307
|
+
}
|
|
120308
|
+
// Dispatch a non-blank continuation line: fenced code at line start, else body.
|
|
120309
|
+
function bodyLineStart(code) {
|
|
120310
|
+
if (atLineStart && code === codes.tilde)
|
|
120252
120311
|
return bodyAfterLineStart(code);
|
|
120253
|
-
}
|
|
120254
|
-
// Detect backtick fences at line start
|
|
120255
120312
|
if (atLineStart && code === codes.graveAccent) {
|
|
120256
120313
|
codeSpanOpenSize = 0;
|
|
120257
|
-
atLineStart
|
|
120314
|
+
// Leave `atLineStart` set — `countOpenTicks` needs it to tell a fence from an
|
|
120315
|
+
// inline code span once the run of backticks is fully counted; it's cleared once
|
|
120316
|
+
// that fence-vs-span decision has actually been made.
|
|
120258
120317
|
return countOpenTicks(code);
|
|
120259
120318
|
}
|
|
120260
120319
|
atLineStart = false;
|
|
120261
120320
|
return body(code);
|
|
120262
120321
|
}
|
|
120322
|
+
// Line-start gate for plain block claims. After a blank line the block may only
|
|
120323
|
+
// continue on a tag line (`<…`); any markdown island (`**bold**`, `[block:…]`, a
|
|
120324
|
+
// fence) refuses so CommonMark html-flow reparses it exactly as it does today.
|
|
120325
|
+
function plainClaimLineStart(code) {
|
|
120326
|
+
// Leading whitespace only → treat as a blank line, matching CommonMark.
|
|
120327
|
+
if (code === codes.space || code === codes.horizontalTab) {
|
|
120328
|
+
effects.consume(code);
|
|
120329
|
+
return plainClaimLineStart;
|
|
120330
|
+
}
|
|
120331
|
+
if (code === null || markdownLineEnding(code)) {
|
|
120332
|
+
pendingBlankLine = true;
|
|
120333
|
+
effects.exit('mdxComponentData');
|
|
120334
|
+
return bodyContinuationStart(code);
|
|
120335
|
+
}
|
|
120336
|
+
// Across a blank line the block only continues onto a markup-only line; a
|
|
120337
|
+
// paragraph that merely starts with a tag must fall back so its markdown
|
|
120338
|
+
// parses and rehype-raw re-nests it into the wrapper.
|
|
120339
|
+
if (pendingBlankLine) {
|
|
120340
|
+
if (code !== codes.lessThan)
|
|
120341
|
+
return nok(code);
|
|
120342
|
+
return effects.check(markupOnlyContinuation, plainClaimContinue, nok)(code);
|
|
120343
|
+
}
|
|
120344
|
+
return bodyLineStart(code);
|
|
120345
|
+
}
|
|
120346
|
+
function plainClaimContinue(code) {
|
|
120347
|
+
pendingBlankLine = false;
|
|
120348
|
+
return bodyLineStart(code);
|
|
120349
|
+
}
|
|
120263
120350
|
// ── Shared lazy continuation failure ───────────────────────────────────
|
|
120264
120351
|
function continuationAfter(code) {
|
|
120265
120352
|
if (code === null) {
|
|
@@ -120290,6 +120377,46 @@ function syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
|
|
|
120290
120377
|
return ok(code);
|
|
120291
120378
|
}
|
|
120292
120379
|
}
|
|
120380
|
+
// A markup-only line opens with a tag (`<x`/`</x`) and ends (ignoring trailing
|
|
120381
|
+
// spaces) at a `>`. That distinguishes a structural continuation like
|
|
120382
|
+
// `<span>b</span></div>` from a paragraph like `<b>Note:</b> read *this*`.
|
|
120383
|
+
function tokenizeMarkupOnlyContinuation(effects, ok, nok) {
|
|
120384
|
+
let lastNonSpace = null;
|
|
120385
|
+
return start;
|
|
120386
|
+
function start(code) {
|
|
120387
|
+
// Caller guarantees we are at `<` at the (already de-indented) line start.
|
|
120388
|
+
effects.enter(types_types.data);
|
|
120389
|
+
effects.consume(code);
|
|
120390
|
+
return afterLessThan;
|
|
120391
|
+
}
|
|
120392
|
+
function afterLessThan(code) {
|
|
120393
|
+
if (code === codes.slash) {
|
|
120394
|
+
effects.consume(code);
|
|
120395
|
+
return afterSlash;
|
|
120396
|
+
}
|
|
120397
|
+
return afterSlash(code);
|
|
120398
|
+
}
|
|
120399
|
+
// The `<` (or `</`) must introduce a real tag, not a stray `<` in prose.
|
|
120400
|
+
function afterSlash(code) {
|
|
120401
|
+
if (asciiAlpha(code)) {
|
|
120402
|
+
lastNonSpace = code;
|
|
120403
|
+
effects.consume(code);
|
|
120404
|
+
return scanToLineEnd;
|
|
120405
|
+
}
|
|
120406
|
+
effects.exit(types_types.data);
|
|
120407
|
+
return nok(code);
|
|
120408
|
+
}
|
|
120409
|
+
function scanToLineEnd(code) {
|
|
120410
|
+
if (code === null || markdownLineEnding(code)) {
|
|
120411
|
+
effects.exit(types_types.data);
|
|
120412
|
+
return lastNonSpace === codes.greaterThan ? ok(code) : nok(code);
|
|
120413
|
+
}
|
|
120414
|
+
if (!markdownSpace(code))
|
|
120415
|
+
lastNonSpace = code;
|
|
120416
|
+
effects.consume(code);
|
|
120417
|
+
return scanToLineEnd;
|
|
120418
|
+
}
|
|
120419
|
+
}
|
|
120293
120420
|
/**
|
|
120294
120421
|
* Micromark extension that tokenizes MDX-like components.
|
|
120295
120422
|
*
|
|
@@ -120536,6 +120663,8 @@ const mdxishInlineMdxComponents = () => tree => {
|
|
|
120536
120663
|
|
|
120537
120664
|
|
|
120538
120665
|
|
|
120666
|
+
/** Matches a JSX attribute expression (e.g. `key={i}`) anywhere in a string. */
|
|
120667
|
+
const NESTED_ATTR_EXPRESSION_RE = /[\w-]+\s*=\s*\{/;
|
|
120539
120668
|
/**
|
|
120540
120669
|
* Reduce leading whitespace on all lines just enough to prevent
|
|
120541
120670
|
* remark from treating indented content as code blocks (4+ spaces).
|
|
@@ -120695,10 +120824,16 @@ const mdx_blocks_mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
|
|
|
120695
120824
|
// inline, which is how ReadMe's custom components are modeled).
|
|
120696
120825
|
if (!isPascal && parent.type === 'paragraph')
|
|
120697
120826
|
return;
|
|
120698
|
-
// Lowercase HTML tags are
|
|
120699
|
-
//
|
|
120827
|
+
// Lowercase HTML tags are eligible when they (or a descendant tag in their
|
|
120828
|
+
// content, e.g. a `.map()` body returning JSX with `key={i}`) carry a
|
|
120829
|
+
// JSX-expression attribute. Without this, a wrapper `<div>` with only plain
|
|
120830
|
+
// attributes (or none) swallows its whole nested block — including any
|
|
120831
|
+
// `style={{...}}`/`.map()` JSX inside it — as literal HTML text, which
|
|
120832
|
+
// rehype-raw's parse5 pass then garbles (it has no notion of JS expressions).
|
|
120833
|
+
// Plain HTML with no expressions anywhere stays as an html node so
|
|
120700
120834
|
// rehype-raw handles it as normal.
|
|
120701
|
-
|
|
120835
|
+
const hasNestedExpressionAttr = !selfClosing && NESTED_ATTR_EXPRESSION_RE.test(contentAfterTag);
|
|
120836
|
+
if (!isPascal && !hasExpressionAttr(attributes) && !hasNestedExpressionAttr)
|
|
120702
120837
|
return;
|
|
120703
120838
|
const closingTagStr = `</${tag}>`;
|
|
120704
120839
|
// Case 1: Self-closing tag
|
|
@@ -120921,12 +121056,60 @@ function restoreSnakeCase(placeholderName, mapping) {
|
|
|
120921
121056
|
return matchingKey ? mapping[matchingKey] : placeholderName;
|
|
120922
121057
|
}
|
|
120923
121058
|
|
|
121059
|
+
;// ./processor/transform/mdxish/resolve-esm-imports.ts
|
|
121060
|
+
|
|
121061
|
+
// We provide React as a default module so that components can use hooks
|
|
121062
|
+
// and it's a common use case. Add other common libraries here.
|
|
121063
|
+
const defaultModuleRegistry = { react: (external_react_default()) };
|
|
121064
|
+
const isRecord = (value) => typeof value === 'object' && value !== null;
|
|
121065
|
+
// Get the value of a named export from a module
|
|
121066
|
+
const getModuleExport = (module, importedName) => isRecord(module) && importedName in module ? module[importedName] : undefined;
|
|
121067
|
+
/**
|
|
121068
|
+
* Turn `import` declarations into a flat map of binding → value.
|
|
121069
|
+
*
|
|
121070
|
+
* A "binding" is a mapping of a local name to the value of it in the module exports
|
|
121071
|
+
* Example: `import { useState } from 'react'` yields `{ useState: React.useState }`.
|
|
121072
|
+
*
|
|
121073
|
+
* Unsupported specifiers are skipped with a warning rather than throwing, so a
|
|
121074
|
+
* single unknown import can't break the rest of the document.
|
|
121075
|
+
*/
|
|
121076
|
+
const collectImportValues = (importDeclarations, registry = defaultModuleRegistry) => {
|
|
121077
|
+
const importValues = {};
|
|
121078
|
+
importDeclarations.forEach(declaration => {
|
|
121079
|
+
const libraryName = declaration.source.value;
|
|
121080
|
+
if (typeof libraryName !== 'string')
|
|
121081
|
+
return;
|
|
121082
|
+
if (!(libraryName in registry)) {
|
|
121083
|
+
// eslint-disable-next-line no-console
|
|
121084
|
+
console.warn(`[WARNING] Cannot resolve import "${libraryName}"; it is not a supported library.`);
|
|
121085
|
+
return;
|
|
121086
|
+
}
|
|
121087
|
+
const module = registry[libraryName];
|
|
121088
|
+
declaration.specifiers.forEach(spec => {
|
|
121089
|
+
// Default (`import React`) and namespace (`import * as React`) both bind
|
|
121090
|
+
// the whole module under the local name.
|
|
121091
|
+
if (spec.type === 'ImportDefaultSpecifier' || spec.type === 'ImportNamespaceSpecifier') {
|
|
121092
|
+
importValues[spec.local.name] = module;
|
|
121093
|
+
}
|
|
121094
|
+
else if (spec.type === 'ImportSpecifier') {
|
|
121095
|
+
// Named imports (e.g. `import { useState } from 'react'`, useState is the import name)
|
|
121096
|
+
const importName = spec.imported.type === 'Identifier' ? spec.imported.name : spec.imported.value;
|
|
121097
|
+
if (typeof importName === 'string') {
|
|
121098
|
+
importValues[spec.local.name] = getModuleExport(module, importName);
|
|
121099
|
+
}
|
|
121100
|
+
}
|
|
121101
|
+
});
|
|
121102
|
+
});
|
|
121103
|
+
return importValues;
|
|
121104
|
+
};
|
|
121105
|
+
|
|
120924
121106
|
;// ./processor/transform/mdxish/evaluate-exports.ts
|
|
120925
121107
|
|
|
120926
121108
|
|
|
120927
121109
|
|
|
120928
121110
|
|
|
120929
121111
|
|
|
121112
|
+
|
|
120930
121113
|
/**
|
|
120931
121114
|
* Recursively extract all identifier names introduced by a binding pattern.
|
|
120932
121115
|
* Handles destructuring (`{ a, b }`, `[x, y]`), rest elements (`...rest`),
|
|
@@ -120974,6 +121157,7 @@ const collectExportNames = (declaration) => {
|
|
|
120974
121157
|
const evaluateExports = () => (tree, file) => {
|
|
120975
121158
|
const programBody = [];
|
|
120976
121159
|
const exportNames = [];
|
|
121160
|
+
const importDeclarations = [];
|
|
120977
121161
|
const nodesToRemove = [];
|
|
120978
121162
|
lib_visit(tree, isMDXEsm, (node, index, parent) => {
|
|
120979
121163
|
if (parent && typeof index === 'number') {
|
|
@@ -120987,6 +121171,10 @@ const evaluateExports = () => (tree, file) => {
|
|
|
120987
121171
|
// handled the same as a named export — the inner declaration carries the
|
|
120988
121172
|
// binding name
|
|
120989
121173
|
estreeBody.forEach(statement => {
|
|
121174
|
+
if (statement.type === 'ImportDeclaration') {
|
|
121175
|
+
importDeclarations.push(statement);
|
|
121176
|
+
return;
|
|
121177
|
+
}
|
|
120990
121178
|
let declaration = null;
|
|
120991
121179
|
if (statement.type === 'ExportNamedDeclaration' && statement.declaration) {
|
|
120992
121180
|
declaration = statement.declaration;
|
|
@@ -121014,9 +121202,11 @@ const evaluateExports = () => (tree, file) => {
|
|
|
121014
121202
|
const program = { type: 'Program', sourceType: 'module', body: programBody };
|
|
121015
121203
|
buildJsx(program, { runtime: 'classic', pragma: 'React.createElement', pragmaFrag: 'React.Fragment' });
|
|
121016
121204
|
const { value: source } = toJs(program);
|
|
121205
|
+
// Make sure import values are available in the scope
|
|
121206
|
+
const importValues = collectImportValues(importDeclarations);
|
|
121017
121207
|
// Evaluate and build on the expression source
|
|
121018
121208
|
// Use react to compile JSX codes
|
|
121019
|
-
const evaluatedExports = evaluate(`(() => { ${source}\nreturn { ${exportNames.join(', ')} }; })()`, { React: (external_react_default()) });
|
|
121209
|
+
const evaluatedExports = evaluate(`(() => { ${source}\nreturn { ${exportNames.join(', ')} }; })()`, { React: (external_react_default()), ...importValues });
|
|
121020
121210
|
Object.assign(scope, evaluatedExports);
|
|
121021
121211
|
}
|
|
121022
121212
|
catch (error) {
|
|
@@ -121080,15 +121270,17 @@ const evalExpression = (expression, scope) => {
|
|
|
121080
121270
|
|
|
121081
121271
|
|
|
121082
121272
|
|
|
121273
|
+
/** True for an array containing at least one React element, e.g. the result of `.map()` returning JSX. */
|
|
121274
|
+
const isRenderableElementArray = (value) => Array.isArray(value) && value.some((external_react_default()).isValidElement);
|
|
121083
121275
|
/** Given the type of the expression result, create the corresponding mdast node. */
|
|
121084
121276
|
const createEvaluatedNode = (result, position) => {
|
|
121085
121277
|
if (result === null || result === undefined) {
|
|
121086
121278
|
return { type: 'text', value: '', position };
|
|
121087
121279
|
}
|
|
121088
|
-
else if (external_react_default().isValidElement(result)) {
|
|
121089
|
-
// Convert react elements to
|
|
121090
|
-
// This must come before the object check as
|
|
121091
|
-
return { type: 'html', value: (0,server_node/* renderToStaticMarkup */.qV)(result), position };
|
|
121280
|
+
else if (external_react_default().isValidElement(result) || isRenderableElementArray(result)) {
|
|
121281
|
+
// Convert react elements (or arrays of them, e.g. `.map()` returning JSX) to their HTML
|
|
121282
|
+
// representation. This must come before the object check as both are a subset of it.
|
|
121283
|
+
return { type: 'html', value: (0,server_node/* renderToStaticMarkup */.qV)(external_react_default().createElement((external_react_default()).Fragment, null, result)), position };
|
|
121092
121284
|
}
|
|
121093
121285
|
else if (typeof result === 'object') {
|
|
121094
121286
|
return { type: 'text', value: JSON.stringify(result), position };
|
|
@@ -121128,6 +121320,47 @@ const evaluateExpressions = () => (tree, file) => {
|
|
|
121128
121320
|
};
|
|
121129
121321
|
/* harmony default export */ const evaluate_expressions = (evaluateExpressions);
|
|
121130
121322
|
|
|
121323
|
+
;// ./processor/transform/mdxish/evaluate-style-block-expressions.ts
|
|
121324
|
+
|
|
121325
|
+
|
|
121326
|
+
|
|
121327
|
+
// Matches a standalone `<style ...>{ <expr> }</style>` block — the JSX shape MDX evaluates
|
|
121328
|
+
// (typically a template-literal-wrapped CSS string) but which mdxish otherwise leaves as
|
|
121329
|
+
// literal, invalid-CSS text (see CX-3646).
|
|
121330
|
+
const STYLE_EXPRESSION_RE = /^(<style\b[^>]*>)\s*\{([\s\S]*)\}\s*(<\/style>)$/i;
|
|
121331
|
+
/**
|
|
121332
|
+
* Evaluate the JSX expression wrapping a `<style>` tag's contents (typically a template
|
|
121333
|
+
* literal, e.g. `<style>{\`.foo { color: red; }\`}</style>`) so the tag ends up holding plain
|
|
121334
|
+
* CSS text instead of the literal `{`...`}` wrapper — which the browser treats as invalid CSS
|
|
121335
|
+
* and drops the entire stylesheet for.
|
|
121336
|
+
*
|
|
121337
|
+
* `<style>` is one of CommonMark's "raw text" HTML elements (along with script/pre/textarea):
|
|
121338
|
+
* its contents are captured verbatim as a single `html` mdast node with no inner tokenization,
|
|
121339
|
+
* so this expression never reaches the mdxFlowExpression tokenizer or `evaluateExpressions` —
|
|
121340
|
+
* it has to be matched and evaluated directly against the raw node's string value.
|
|
121341
|
+
*
|
|
121342
|
+
* Must run after `evaluateExports` (needs `file.data.mdxishScope`) and before `remarkRehype`
|
|
121343
|
+
* turns `html` mdast nodes into raw hast strings. Skipped in safeMode.
|
|
121344
|
+
*/
|
|
121345
|
+
const evaluateStyleBlockExpressions = () => (tree, file) => {
|
|
121346
|
+
const scope = { ...file.data.mdxishScope, React: (external_react_default()) };
|
|
121347
|
+
lib_visit(tree, 'html', (node) => {
|
|
121348
|
+
const match = node.value.trim().match(STYLE_EXPRESSION_RE);
|
|
121349
|
+
if (!match)
|
|
121350
|
+
return;
|
|
121351
|
+
const [, openTag, expression, closeTag] = match;
|
|
121352
|
+
try {
|
|
121353
|
+
const css = evalExpression(expression, scope);
|
|
121354
|
+
node.value = `${openTag}${String(css)}${closeTag}`;
|
|
121355
|
+
}
|
|
121356
|
+
catch {
|
|
121357
|
+
// Evaluation failed — leave the node untouched so it round-trips as literal text.
|
|
121358
|
+
}
|
|
121359
|
+
});
|
|
121360
|
+
return tree;
|
|
121361
|
+
};
|
|
121362
|
+
/* harmony default export */ const evaluate_style_block_expressions = (evaluateStyleBlockExpressions);
|
|
121363
|
+
|
|
121131
121364
|
;// ./processor/transform/mdxish/heading-slugs.ts
|
|
121132
121365
|
|
|
121133
121366
|
|
|
@@ -124388,219 +124621,100 @@ const normalizeMdxJsxNodes = () => tree => {
|
|
|
124388
124621
|
*/
|
|
124389
124622
|
const JSX_COMMENT_REGEX = /\{\/\*[^*]*(?:\*(?!\/)[^*]*)*\*\/\}/g;
|
|
124390
124623
|
|
|
124391
|
-
;// ./processor/transform/mdxish/
|
|
124392
|
-
|
|
124624
|
+
;// ./processor/transform/mdxish/remove-jsx-comments.ts
|
|
124393
124625
|
|
|
124394
124626
|
/**
|
|
124395
124627
|
* Removes JSX-style comments (e.g., { /* comment *\/ }) from content.
|
|
124396
124628
|
*
|
|
124397
|
-
*
|
|
124398
|
-
*
|
|
124399
|
-
*
|
|
124629
|
+
* `@param` content
|
|
124630
|
+
* `@returns` Content with JSX comments removed
|
|
124631
|
+
* `@example`
|
|
124400
124632
|
* ```typescript
|
|
124401
|
-
* removeJSXComments('Text {
|
|
124402
|
-
* // Returns: 'Text more text'
|
|
124633
|
+
* removeJSXComments('Text {/* comment *\/} more text') // => 'Text more text'
|
|
124403
124634
|
* ```
|
|
124404
124635
|
*/
|
|
124405
124636
|
function removeJSXComments(content) {
|
|
124406
124637
|
return content.replace(JSX_COMMENT_REGEX, '');
|
|
124407
124638
|
}
|
|
124408
|
-
|
|
124409
|
-
|
|
124410
|
-
|
|
124411
|
-
// Allows optional leading indentation and lazily matches until the same closing tag.
|
|
124412
|
-
const BLOCK_HTML_RE = /(?<=^|\n)[ \t]*<([a-z][a-zA-Z0-9]*)(?:\s[^>]*)?>[\s\S]*?<\/\1>[ \t]*(?=\n|$)/g;
|
|
124413
|
-
/**
|
|
124414
|
-
* Hides line-anchored HTML elements from the brace-escaping pass so we don't leak `\{`
|
|
124415
|
-
* into rendered output (rehypeRaw renders the `\` literally, e.g. `<div>{foo</div>`).
|
|
124416
|
-
*
|
|
124417
|
-
* One carve-out: if an interior line at column 0 has bare text containing `{`, mdxish
|
|
124418
|
-
* parses that line as a paragraph and the mdxExpression step would throw without an
|
|
124419
|
-
* escape — so we leave that case to the brace balancer.
|
|
124420
|
-
*/
|
|
124421
|
-
function protectHTMLElements(content) {
|
|
124422
|
-
const htmlElements = [];
|
|
124423
|
-
const protectedContent = content.replace(BLOCK_HTML_RE, match => {
|
|
124424
|
-
// Look at the lines between the open and close tags. If any of them starts
|
|
124425
|
-
// at column 0 with bare text (not whitespace, not another tag) and contains
|
|
124426
|
-
// `{`, mdxish will parse that line as a paragraph and the brace as an MDX
|
|
124427
|
-
// expression, which would throw an error. So we let the brace balancer escape it.
|
|
124428
|
-
// Otherwise, we need to extract the sequence to protect it from the brace escaping.
|
|
124429
|
-
const interior = match.split('\n').slice(1, -1);
|
|
124430
|
-
const hazard = interior.some(line => line.length > 0 && line[0] !== ' ' && line[0] !== '\t' && line[0] !== '<' && line.includes('{'));
|
|
124431
|
-
if (hazard)
|
|
124432
|
-
return match;
|
|
124433
|
-
htmlElements.push(match);
|
|
124434
|
-
return `${HTML_ELEM_PLACEHOLDER_PREFIX}${htmlElements.length - 1}___`;
|
|
124435
|
-
});
|
|
124436
|
-
return { htmlElements, protectedContent };
|
|
124437
|
-
}
|
|
124438
|
-
function restoreHTMLElements(content, htmlElements) {
|
|
124439
|
-
if (htmlElements.length === 0)
|
|
124440
|
-
return content;
|
|
124441
|
-
return content.replace(HTML_ELEM_PLACEHOLDER, (_m, idx) => htmlElements[parseInt(idx, 10)]);
|
|
124442
|
-
}
|
|
124443
|
-
const ESM_DECLARATION_START = /^(?:export|import)\b/;
|
|
124639
|
+
|
|
124640
|
+
;// ./processor/transform/mdxish/style-object-to-css.ts
|
|
124641
|
+
|
|
124444
124642
|
/**
|
|
124445
|
-
*
|
|
124446
|
-
*
|
|
124447
|
-
*
|
|
124643
|
+
* CSS properties React treats as unitless — a bare number stays as-is instead of
|
|
124644
|
+
* getting `px` appended. Mirrors React DOM's `isUnitlessNumber` whitelist.
|
|
124645
|
+
* @see https://github.com/facebook/react/blob/main/packages/react-dom-bindings/src/shared/CSSProperty.js
|
|
124448
124646
|
*/
|
|
124449
|
-
|
|
124450
|
-
|
|
124451
|
-
|
|
124452
|
-
|
|
124453
|
-
|
|
124454
|
-
|
|
124455
|
-
|
|
124456
|
-
|
|
124457
|
-
|
|
124458
|
-
|
|
124459
|
-
|
|
124460
|
-
|
|
124647
|
+
const UNITLESS_CSS_PROPERTIES = new Set([
|
|
124648
|
+
'animationIterationCount',
|
|
124649
|
+
'aspectRatio',
|
|
124650
|
+
'borderImageOutset',
|
|
124651
|
+
'borderImageSlice',
|
|
124652
|
+
'borderImageWidth',
|
|
124653
|
+
'boxFlex',
|
|
124654
|
+
'boxFlexGroup',
|
|
124655
|
+
'boxOrdinalGroup',
|
|
124656
|
+
'columnCount',
|
|
124657
|
+
'columns',
|
|
124658
|
+
'flex',
|
|
124659
|
+
'flexGrow',
|
|
124660
|
+
'flexPositive',
|
|
124661
|
+
'flexShrink',
|
|
124662
|
+
'flexNegative',
|
|
124663
|
+
'flexOrder',
|
|
124664
|
+
'gridArea',
|
|
124665
|
+
'gridRow',
|
|
124666
|
+
'gridRowEnd',
|
|
124667
|
+
'gridRowSpan',
|
|
124668
|
+
'gridRowStart',
|
|
124669
|
+
'gridColumn',
|
|
124670
|
+
'gridColumnEnd',
|
|
124671
|
+
'gridColumnSpan',
|
|
124672
|
+
'gridColumnStart',
|
|
124673
|
+
'fontWeight',
|
|
124674
|
+
'lineClamp',
|
|
124675
|
+
'lineHeight',
|
|
124676
|
+
'opacity',
|
|
124677
|
+
'order',
|
|
124678
|
+
'orphans',
|
|
124679
|
+
'tabSize',
|
|
124680
|
+
'widows',
|
|
124681
|
+
'zIndex',
|
|
124682
|
+
'zoom',
|
|
124683
|
+
'fillOpacity',
|
|
124684
|
+
'floodOpacity',
|
|
124685
|
+
'stopOpacity',
|
|
124686
|
+
'strokeDasharray',
|
|
124687
|
+
'strokeDashoffset',
|
|
124688
|
+
'strokeMiterlimit',
|
|
124689
|
+
'strokeOpacity',
|
|
124690
|
+
'strokeWidth',
|
|
124691
|
+
]);
|
|
124692
|
+
/** Convert a camelCase (or CSS custom property) key into its kebab-case CSS name. */
|
|
124693
|
+
const cssPropertyName = (key) => (key.startsWith('--') ? key : key.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`));
|
|
124694
|
+
/** React appends `px` to non-zero numeric values, except unitless and custom properties. */
|
|
124695
|
+
const cssPropertyValue = (key, value) => typeof value === 'number' && value !== 0 && !key.startsWith('--') && !UNITLESS_CSS_PROPERTIES.has(key)
|
|
124696
|
+
? `${value}px`
|
|
124697
|
+
: `${value}`;
|
|
124461
124698
|
/**
|
|
124462
|
-
*
|
|
124699
|
+
* True for a value that should be serialized as a style object rather than passed through
|
|
124700
|
+
* as an already-CSS string. React elements are excluded since they're valid objects too.
|
|
124463
124701
|
*/
|
|
124464
|
-
|
|
124465
|
-
const { htmlElements, protectedContent } = protectHTMLElements(content);
|
|
124466
|
-
let strDelim = null;
|
|
124467
|
-
let strEscaped = false;
|
|
124468
|
-
// Track position of last newline (outside strings) to detect blank lines
|
|
124469
|
-
// -2 means no recent newline
|
|
124470
|
-
let lastNewlinePos = -2;
|
|
124471
|
-
// Character state machine trackers
|
|
124472
|
-
const toEscape = new Set();
|
|
124473
|
-
// Convert to array of Unicode code points so that emojis and multi-byte characters are correctly tracked
|
|
124474
|
-
const chars = Array.from(protectedContent);
|
|
124475
|
-
const openStack = [];
|
|
124476
|
-
// Whether the current top-level statement is an `export`/`import` declaration.
|
|
124477
|
-
let insideEsmDeclaration = false;
|
|
124478
|
-
for (let i = 0; i < chars.length; i += 1) {
|
|
124479
|
-
const ch = chars[i];
|
|
124480
|
-
// At a top-level (brace depth 0) line start, decide whether we're inside an
|
|
124481
|
-
// ESM declaration. The flag persists across the declaration's own lines.
|
|
124482
|
-
if (openStack.length === 0 && (i === 0 || chars[i - 1] === '\n')) {
|
|
124483
|
-
if (startsEsmDeclaration(chars, i))
|
|
124484
|
-
insideEsmDeclaration = true;
|
|
124485
|
-
else if (isBlankLine(chars, i))
|
|
124486
|
-
insideEsmDeclaration = false;
|
|
124487
|
-
}
|
|
124488
|
-
// Track string delimiters inside expressions to ignore braces within them
|
|
124489
|
-
if (openStack.length > 0) {
|
|
124490
|
-
if (strDelim) {
|
|
124491
|
-
if (strEscaped)
|
|
124492
|
-
strEscaped = false;
|
|
124493
|
-
else if (ch === '\\')
|
|
124494
|
-
strEscaped = true;
|
|
124495
|
-
else if (ch === strDelim)
|
|
124496
|
-
strDelim = null;
|
|
124497
|
-
// eslint-disable-next-line no-continue
|
|
124498
|
-
continue;
|
|
124499
|
-
}
|
|
124500
|
-
if (ch === '"' || ch === "'" || ch === '`') {
|
|
124501
|
-
strDelim = ch;
|
|
124502
|
-
// eslint-disable-next-line no-continue
|
|
124503
|
-
continue;
|
|
124504
|
-
}
|
|
124505
|
-
if (ch === '\n') {
|
|
124506
|
-
if (lastNewlinePos >= 0) {
|
|
124507
|
-
const between = chars.slice(lastNewlinePos + 1, i).join('');
|
|
124508
|
-
if (/^[ \t]*$/.test(between)) {
|
|
124509
|
-
openStack.forEach(entry => { entry.hasBlankLine = true; });
|
|
124510
|
-
}
|
|
124511
|
-
}
|
|
124512
|
-
lastNewlinePos = i;
|
|
124513
|
-
}
|
|
124514
|
-
}
|
|
124515
|
-
// Skip already-escaped braces (odd run of preceding backslashes).
|
|
124516
|
-
if (ch === '{' || ch === '}') {
|
|
124517
|
-
let bs = 0;
|
|
124518
|
-
for (let j = i - 1; j >= 0 && chars[j] === '\\'; j -= 1)
|
|
124519
|
-
bs += 1;
|
|
124520
|
-
if (bs % 2 === 1) {
|
|
124521
|
-
// eslint-disable-next-line no-continue
|
|
124522
|
-
continue;
|
|
124523
|
-
}
|
|
124524
|
-
}
|
|
124525
|
-
if (ch === '{') {
|
|
124526
|
-
// `=` (after whitespace) before `{` ⇒ JSX attribute expression. The
|
|
124527
|
-
// mdxComponent tokenizer captures the whole component, so blank lines
|
|
124528
|
-
// inside attribute values are harmless. Nested `{` inherits the flag.
|
|
124529
|
-
let isAttrExpr = false;
|
|
124530
|
-
for (let j = i - 1; j >= 0; j -= 1) {
|
|
124531
|
-
const pc = chars[j];
|
|
124532
|
-
if (pc === '=') {
|
|
124533
|
-
isAttrExpr = true;
|
|
124534
|
-
break;
|
|
124535
|
-
}
|
|
124536
|
-
if (pc !== ' ' && pc !== '\t')
|
|
124537
|
-
break;
|
|
124538
|
-
}
|
|
124539
|
-
// Nested `{ ... }` inside an attribute value (e.g. `data={[{ ... }]}` or
|
|
124540
|
-
// `data={{ a: { b: 1 } }}`) must inherit the same exemption; only the
|
|
124541
|
-
// outer `{` is directly after `=`.
|
|
124542
|
-
if (!isAttrExpr && openStack.length > 0 && openStack[openStack.length - 1].isAttrExpr) {
|
|
124543
|
-
isAttrExpr = true;
|
|
124544
|
-
}
|
|
124545
|
-
openStack.push({ pos: i, hasBlankLine: false, isAttrExpr, isEsmDeclaration: insideEsmDeclaration });
|
|
124546
|
-
lastNewlinePos = -2;
|
|
124547
|
-
}
|
|
124548
|
-
else if (ch === '}') {
|
|
124549
|
-
if (openStack.length > 0) {
|
|
124550
|
-
const entry = openStack.pop();
|
|
124551
|
-
// The declaration's braces are closed; later top-level braces are not ESM.
|
|
124552
|
-
if (openStack.length === 0)
|
|
124553
|
-
insideEsmDeclaration = false;
|
|
124554
|
-
// Pure `{/* ... */}` comments are handled downstream by the jsxComment
|
|
124555
|
-
// tokenizer — escaping their braces would prevent it from running.
|
|
124556
|
-
const isPureJsxComment = chars[entry.pos + 1] === '/' &&
|
|
124557
|
-
chars[entry.pos + 2] === '*' &&
|
|
124558
|
-
chars[i - 1] === '/' &&
|
|
124559
|
-
chars[i - 2] === '*';
|
|
124560
|
-
if (entry.hasBlankLine && !isPureJsxComment && !entry.isAttrExpr && !entry.isEsmDeclaration) {
|
|
124561
|
-
toEscape.add(entry.pos);
|
|
124562
|
-
toEscape.add(i);
|
|
124563
|
-
}
|
|
124564
|
-
}
|
|
124565
|
-
else {
|
|
124566
|
-
toEscape.add(i);
|
|
124567
|
-
}
|
|
124568
|
-
}
|
|
124569
|
-
else if (ch === ';' && openStack.length === 0) {
|
|
124570
|
-
// A top-level `;` ends the current statement, ESM or otherwise.
|
|
124571
|
-
insideEsmDeclaration = false;
|
|
124572
|
-
}
|
|
124573
|
-
}
|
|
124574
|
-
// Anything still open is unbalanced.
|
|
124575
|
-
openStack.forEach(entry => {
|
|
124576
|
-
if (!entry.isEsmDeclaration)
|
|
124577
|
-
toEscape.add(entry.pos);
|
|
124578
|
-
});
|
|
124579
|
-
// Reconstruct the content with the escaped braces.
|
|
124580
|
-
const escapedContent = toEscape.size === 0 ? protectedContent : chars.map((ch, i) => (toEscape.has(i) ? `\\${ch}` : ch)).join('');
|
|
124581
|
-
return restoreHTMLElements(escapedContent, htmlElements);
|
|
124582
|
-
}
|
|
124702
|
+
const style_object_to_css_isPlainObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value) && !external_react_default().isValidElement(value);
|
|
124583
124703
|
/**
|
|
124584
|
-
*
|
|
124585
|
-
*
|
|
124586
|
-
*
|
|
124587
|
-
* they flow through the tokenizer as `mdxJsxAttributeValueExpression` nodes
|
|
124588
|
-
* and are evaluated at the hast handler step.
|
|
124589
|
-
*
|
|
124590
|
-
* @param content
|
|
124591
|
-
* @returns Preprocessed content ready for markdown parsing
|
|
124704
|
+
* Serialize a React-style inline style object (`{ color: "red", fontSize: 12 }`) into a
|
|
124705
|
+
* CSS declaration string (`color:red;font-size:12px`), the shape hast/HTML expects for a
|
|
124706
|
+
* `style` attribute. Empty (`undefined`/`null`/`''`) entries are dropped.
|
|
124592
124707
|
*/
|
|
124593
|
-
|
|
124594
|
-
|
|
124595
|
-
|
|
124596
|
-
|
|
124597
|
-
return processed;
|
|
124598
|
-
}
|
|
124708
|
+
const styleObjectToCssText = (style) => Object.entries(style)
|
|
124709
|
+
.filter(([, value]) => value !== undefined && value !== null && value !== '')
|
|
124710
|
+
.map(([key, value]) => `${cssPropertyName(key)}:${cssPropertyValue(key, value)}`)
|
|
124711
|
+
.join(';');
|
|
124599
124712
|
|
|
124600
124713
|
;// ./processor/transform/mdxish/resolve-deferred-attribute-expression-props.ts
|
|
124601
124714
|
|
|
124602
124715
|
|
|
124603
124716
|
|
|
124717
|
+
|
|
124604
124718
|
/**
|
|
124605
124719
|
* Resolve attribute expressions that `mdxJsxElementHandler` deferred.
|
|
124606
124720
|
*
|
|
@@ -124622,7 +124736,10 @@ const resolveDeferredAttributeExpressionProps = () => (tree, file) => {
|
|
|
124622
124736
|
const properties = node.properties;
|
|
124623
124737
|
Object.entries(deferredExpressions).forEach(([name, source]) => {
|
|
124624
124738
|
try {
|
|
124625
|
-
|
|
124739
|
+
const result = evalExpression(source, scope);
|
|
124740
|
+
// hast/HTML `style` is a plain CSS string; a `style={{...}}` expression evaluates to
|
|
124741
|
+
// a JS object, which must be serialized or it renders as the literal "[object Object]".
|
|
124742
|
+
properties[name] = name === 'style' && style_object_to_css_isPlainObject(result) ? styleObjectToCssText(result) : result;
|
|
124626
124743
|
}
|
|
124627
124744
|
catch {
|
|
124628
124745
|
// Evaluation failed — fall back to the raw expression source so the attribute
|
|
@@ -124942,13 +125059,13 @@ function normalizeTableSeparator(content) {
|
|
|
124942
125059
|
;// ./processor/transform/mdxish/terminate-html-flow-blocks.ts
|
|
124943
125060
|
|
|
124944
125061
|
|
|
125062
|
+
|
|
124945
125063
|
const STANDALONE_HTML_LINE_REGEX = /^(<[a-z][^<>]*>|<\/[a-z][^<>]*>)+\s*$/;
|
|
124946
125064
|
const HTML_LINE_WITH_CONTENT_REGEX = /^<[a-z][^<>]*>.*<\/[a-z][^<>]*>(?:[^<]*)$/;
|
|
124947
|
-
const terminate_html_flow_blocks_TABLE_STRUCTURE_TAGS = ['table', 'thead', 'tbody', 'tfoot', 'tr', 'td', 'th', 'caption', 'colgroup'];
|
|
124948
125065
|
// Tags whose contents must be preserved as is, inserting a blank line after the
|
|
124949
125066
|
// opener corrupts the payload.
|
|
124950
125067
|
// htmlRawNames here refer to <pre>, <textarea>, <script>, <style>
|
|
124951
|
-
const RAW_CONTENT_TAGS = [...htmlRawNames, ...
|
|
125068
|
+
const RAW_CONTENT_TAGS = [...htmlRawNames, ...HTML_TABLE_STRUCTURE_TAGS];
|
|
124952
125069
|
// The `(?=[\s/>])` lookahead avoids false matches on lookalike names like `<script-foo>`.
|
|
124953
125070
|
const RAW_CONTENT_TAG_MATCHERS = RAW_CONTENT_TAGS.map(tag => ({
|
|
124954
125071
|
open: new RegExp(`<${tag}(?=[\\s/>])[^>]*?(?<!/)>`, 'gi'),
|
|
@@ -125570,6 +125687,85 @@ function syntax_jsxTable() {
|
|
|
125570
125687
|
;// ./lib/micromark/jsx-table/index.ts
|
|
125571
125688
|
|
|
125572
125689
|
|
|
125690
|
+
;// ./lib/micromark/mdx-expression-lenient/syntax.ts
|
|
125691
|
+
|
|
125692
|
+
|
|
125693
|
+
/**
|
|
125694
|
+
* Lenient MDX text-expression tokenizer (agnostic / no acorn).
|
|
125695
|
+
*
|
|
125696
|
+
* Matches a balanced `{ ... }` run — tracking nested braces and spanning soft
|
|
125697
|
+
* line breaks — and emits the standard `mdxTextExpression*` tokens so the
|
|
125698
|
+
* upstream `mdxExpressionFromMarkdown()` builds the node.
|
|
125699
|
+
*
|
|
125700
|
+
* Reimplements the official micromark mdxExpression, but an unbalanced brace that
|
|
125701
|
+
* reaches end of input returns `nok` instead of throwing: micromark rolls back
|
|
125702
|
+
* and the `{` renders as literal text, making the pipeline forgiving of stray
|
|
125703
|
+
* braces that upstream would hard-error on.
|
|
125704
|
+
*/
|
|
125705
|
+
function tokenizeTextExpression(effects, ok, nok) {
|
|
125706
|
+
let depth = 0;
|
|
125707
|
+
return start;
|
|
125708
|
+
function start(code) {
|
|
125709
|
+
if (code !== codes.leftCurlyBrace)
|
|
125710
|
+
return nok(code);
|
|
125711
|
+
effects.enter('mdxTextExpression');
|
|
125712
|
+
effects.enter('mdxTextExpressionMarker');
|
|
125713
|
+
effects.consume(code);
|
|
125714
|
+
effects.exit('mdxTextExpressionMarker');
|
|
125715
|
+
return before;
|
|
125716
|
+
}
|
|
125717
|
+
function before(code) {
|
|
125718
|
+
if (code === codes.eof) {
|
|
125719
|
+
effects.exit('mdxTextExpression');
|
|
125720
|
+
return nok(code);
|
|
125721
|
+
}
|
|
125722
|
+
if (markdownLineEnding(code)) {
|
|
125723
|
+
effects.enter('lineEnding');
|
|
125724
|
+
effects.consume(code);
|
|
125725
|
+
effects.exit('lineEnding');
|
|
125726
|
+
return before;
|
|
125727
|
+
}
|
|
125728
|
+
if (code === codes.rightCurlyBrace && depth === 0) {
|
|
125729
|
+
return close(code);
|
|
125730
|
+
}
|
|
125731
|
+
effects.enter('mdxTextExpressionChunk');
|
|
125732
|
+
return inside(code);
|
|
125733
|
+
}
|
|
125734
|
+
function inside(code) {
|
|
125735
|
+
if (code === codes.eof || markdownLineEnding(code)) {
|
|
125736
|
+
effects.exit('mdxTextExpressionChunk');
|
|
125737
|
+
return before(code);
|
|
125738
|
+
}
|
|
125739
|
+
if (code === codes.rightCurlyBrace && depth === 0) {
|
|
125740
|
+
effects.exit('mdxTextExpressionChunk');
|
|
125741
|
+
return close(code);
|
|
125742
|
+
}
|
|
125743
|
+
if (code === codes.leftCurlyBrace)
|
|
125744
|
+
depth += 1;
|
|
125745
|
+
else if (code === codes.rightCurlyBrace)
|
|
125746
|
+
depth -= 1;
|
|
125747
|
+
effects.consume(code);
|
|
125748
|
+
return inside;
|
|
125749
|
+
}
|
|
125750
|
+
function close(code) {
|
|
125751
|
+
effects.enter('mdxTextExpressionMarker');
|
|
125752
|
+
effects.consume(code);
|
|
125753
|
+
effects.exit('mdxTextExpressionMarker');
|
|
125754
|
+
effects.exit('mdxTextExpression');
|
|
125755
|
+
return ok;
|
|
125756
|
+
}
|
|
125757
|
+
}
|
|
125758
|
+
function mdxExpressionLenient() {
|
|
125759
|
+
return {
|
|
125760
|
+
text: {
|
|
125761
|
+
[codes.leftCurlyBrace]: {
|
|
125762
|
+
name: 'mdxTextExpression',
|
|
125763
|
+
tokenize: tokenizeTextExpression,
|
|
125764
|
+
},
|
|
125765
|
+
},
|
|
125766
|
+
};
|
|
125767
|
+
}
|
|
125768
|
+
|
|
125573
125769
|
;// ./lib/utils/mdxish/mdxish-load-components.ts
|
|
125574
125770
|
|
|
125575
125771
|
|
|
@@ -125667,6 +125863,7 @@ function loadComponents() {
|
|
|
125667
125863
|
|
|
125668
125864
|
|
|
125669
125865
|
|
|
125866
|
+
|
|
125670
125867
|
|
|
125671
125868
|
|
|
125672
125869
|
const defaultTransformers = [
|
|
@@ -125682,7 +125879,7 @@ const defaultTransformers = [
|
|
|
125682
125879
|
* 1. Normalize malformed table separator syntax (e.g., `|: ---` → `| :---`)
|
|
125683
125880
|
* 2. Terminate HTML flow blocks so subsequent content isn't swallowed
|
|
125684
125881
|
* 3. Close invalid "self-closing" HTML tags (e.g., `<i />` → `<i></i>`)
|
|
125685
|
-
* 4.
|
|
125882
|
+
* 4. Normalize compact ATX headings (e.g., `#Heading` → `# Heading`)
|
|
125686
125883
|
* 5. Replace snake_case component names with parser-safe placeholders
|
|
125687
125884
|
*/
|
|
125688
125885
|
function preprocessContent(content, opts) {
|
|
@@ -125691,7 +125888,6 @@ function preprocessContent(content, opts) {
|
|
|
125691
125888
|
result = terminateHtmlFlowBlocks(result);
|
|
125692
125889
|
result = closeSelfClosingHtmlTags(result);
|
|
125693
125890
|
result = normalizeCompactHeadings(result);
|
|
125694
|
-
result = preprocessJSXExpressions(result);
|
|
125695
125891
|
return processSnakeCaseComponent(result, { knownComponents });
|
|
125696
125892
|
}
|
|
125697
125893
|
function mdxishAstProcessor(mdContent, opts = {}) {
|
|
@@ -125708,12 +125904,8 @@ function mdxishAstProcessor(mdContent, opts = {}) {
|
|
|
125708
125904
|
acc[key] = String(value);
|
|
125709
125905
|
return acc;
|
|
125710
125906
|
}, {});
|
|
125711
|
-
//
|
|
125712
|
-
|
|
125713
|
-
const mdxExprExt = syntax_mdxExpression({ allowEmpty: true });
|
|
125714
|
-
const mdxExprTextOnly = {
|
|
125715
|
-
text: mdxExprExt.text,
|
|
125716
|
-
};
|
|
125907
|
+
// Parser extension for MDX expressions {}
|
|
125908
|
+
const mdxExprTextOnly = mdxExpressionLenient();
|
|
125717
125909
|
const micromarkExts = [
|
|
125718
125910
|
syntax_jsxTable(),
|
|
125719
125911
|
syntax_magicBlock(),
|
|
@@ -125822,6 +126014,7 @@ function mdxish_mdxish(mdContent, opts = {}) {
|
|
|
125822
126014
|
.use(safeMode ? undefined : evaluate_exports) // Evaluate `export const/function` and stash scope on file.data.mdxishScope
|
|
125823
126015
|
.use(remarkBreaks) // Must precede evaluateExpressions to avoid splitting the \n in an evaluated template literal into a <br> node
|
|
125824
126016
|
.use(safeMode ? undefined : evaluate_expressions) // Evaluate self-contained MDX expressions (e.g. `{1+1}`)
|
|
126017
|
+
.use(safeMode ? undefined : evaluate_style_block_expressions) // Evaluate `<style>{`...`}</style>` template literals into plain CSS
|
|
125825
126018
|
.use(variables_code, { variables }) // Resolve <<...>> and {user.*} inside code and inline code nodes
|
|
125826
126019
|
.use(lib_remarkRehype, { allowDangerousHtml: true, handlers: mdxComponentHandlers })
|
|
125827
126020
|
.use(preserveBooleanProperties) // RehypeRaw converts boolean properties to empty strings
|