@readme/markdown 14.10.2 → 14.11.0
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/components/Embed/index.tsx +4 -1
- package/components/Embed/normalizeYouTubeUrl.ts +41 -0
- package/dist/components/Embed/normalizeYouTubeUrl.d.ts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/lib/index.d.ts +1 -0
- package/dist/lib/micromark/mdx-component/syntax.d.ts +7 -6
- 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 +276 -247
- package/dist/main.node.js +276 -247
- package/dist/main.node.js.map +1 -1
- package/dist/processor/transform/mdxish/components/inline-html.d.ts +6 -5
- 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/render-fixture.node.js +276 -247
- package/dist/render-fixture.node.js.map +1 -1
- package/package.json +2 -2
- package/dist/processor/transform/mdxish/preprocess-jsx-expressions.d.ts +0 -23
|
@@ -86655,10 +86655,55 @@ const Columns = ({ children, layout = 'auto' }) => {
|
|
|
86655
86655
|
};
|
|
86656
86656
|
/* harmony default export */ const components_Columns = (Columns);
|
|
86657
86657
|
|
|
86658
|
+
;// ./components/Embed/normalizeYouTubeUrl.ts
|
|
86659
|
+
// YouTube watch/share URLs (youtube.com/watch?v=ID, youtu.be/ID) set X-Frame-Options
|
|
86660
|
+
// and refuse to be framed. The player only allows embedding via youtube.com/embed/ID.
|
|
86661
|
+
const YOUTUBE_HOSTS = new Set(['youtube.com', 'www.youtube.com', 'm.youtube.com', 'youtu.be', 'www.youtu.be', 'm.youtu.be']);
|
|
86662
|
+
// /embed/ accepts `start` (integer seconds), not the watch-page `t` value which may carry units (e.g. 596s, 1h2m3s).
|
|
86663
|
+
const toStartSeconds = (timestamp) => {
|
|
86664
|
+
const [, hours, minutes, seconds] = timestamp.match(/^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s?)?$/) ?? [];
|
|
86665
|
+
const total = (Number(hours) || 0) * 3600 + (Number(minutes) || 0) * 60 + (Number(seconds) || 0);
|
|
86666
|
+
return total > 0 ? String(total) : null;
|
|
86667
|
+
};
|
|
86668
|
+
const extractVideoId = (parsed) => {
|
|
86669
|
+
if (parsed.hostname.endsWith('youtu.be'))
|
|
86670
|
+
return parsed.pathname.slice(1).split('/')[0] || null;
|
|
86671
|
+
if (parsed.pathname.startsWith('/watch'))
|
|
86672
|
+
return parsed.searchParams.get('v');
|
|
86673
|
+
if (parsed.pathname.startsWith('/shorts/'))
|
|
86674
|
+
return parsed.pathname.slice('/shorts/'.length).split('/')[0] || null;
|
|
86675
|
+
return null;
|
|
86676
|
+
};
|
|
86677
|
+
// Most youtube links we get from the browser are watch URLs, like https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
86678
|
+
// These /watch URLs won't work in an iframe, so we need to convert them to the embed URL if iframe is used
|
|
86679
|
+
const normalizeYouTubeUrlToEmbedUrl = (url) => {
|
|
86680
|
+
let parsed;
|
|
86681
|
+
try {
|
|
86682
|
+
parsed = new URL(url);
|
|
86683
|
+
}
|
|
86684
|
+
catch {
|
|
86685
|
+
return url;
|
|
86686
|
+
}
|
|
86687
|
+
if (!YOUTUBE_HOSTS.has(parsed.hostname))
|
|
86688
|
+
return url;
|
|
86689
|
+
if (parsed.pathname.startsWith('/embed/'))
|
|
86690
|
+
return url;
|
|
86691
|
+
const videoId = extractVideoId(parsed);
|
|
86692
|
+
if (!videoId)
|
|
86693
|
+
return url;
|
|
86694
|
+
const embed = new URL(`https://www.youtube.com/embed/${videoId}`);
|
|
86695
|
+
const timestamp = parsed.searchParams.get('start') || parsed.searchParams.get('t');
|
|
86696
|
+
const start = timestamp ? toStartSeconds(timestamp) : null;
|
|
86697
|
+
if (start)
|
|
86698
|
+
embed.searchParams.set('start', start);
|
|
86699
|
+
return embed.toString();
|
|
86700
|
+
};
|
|
86701
|
+
|
|
86658
86702
|
;// ./components/Embed/index.tsx
|
|
86659
86703
|
/* eslint-disable no-param-reassign */
|
|
86660
86704
|
/* eslint-disable react/jsx-props-no-spreading */
|
|
86661
86705
|
|
|
86706
|
+
|
|
86662
86707
|
const Favicon = ({ src, alt = 'favicon', ...attr }) => (external_react_default().createElement("img", { ...attr, alt: alt, height: "14", src: src, width: "14" }));
|
|
86663
86708
|
const IFRAME_DERIVABLE_TYPES = new Set(['youtube', 'jsfiddle', 'pdf']);
|
|
86664
86709
|
// HTML width/height attrs accept bare numbers (interpreted as px), but CSS does not, convert.
|
|
@@ -86692,7 +86737,8 @@ const Embed = ({ lazy = true, url, html, providerName, providerUrl, title, ifram
|
|
|
86692
86737
|
// Fall back to a direct iframe for URL-derivable embed types when html is missing.
|
|
86693
86738
|
const renderTypeAsIframe = !html && !explicitOptOut && url && typeOfEmbed && IFRAME_DERIVABLE_TYPES.has(typeOfEmbed);
|
|
86694
86739
|
if (iframe || renderTypeAsIframe) {
|
|
86695
|
-
|
|
86740
|
+
const src = normalizeYouTubeUrlToEmbedUrl(url);
|
|
86741
|
+
return external_react_default().createElement("iframe", { ...spreadAttrs, src: src, style: iframeStyle, title: title });
|
|
86696
86742
|
}
|
|
86697
86743
|
if (!providerUrl && url)
|
|
86698
86744
|
providerUrl = new URL(url).hostname
|
|
@@ -119505,6 +119551,12 @@ const types_types = /** @type {const} */ ({
|
|
|
119505
119551
|
|
|
119506
119552
|
|
|
119507
119553
|
|
|
119554
|
+
|
|
119555
|
+
// Raw tags (type-1: pre/script/style/textarea) and block tags (type-6: div,
|
|
119556
|
+
// section, …) always start a block, so they stay flow even with trailing
|
|
119557
|
+
// content. Other lowercase tags (i, span, …) follow the type-7 rule and only
|
|
119558
|
+
// stay flow when nothing trails the close tag.
|
|
119559
|
+
const htmlFlowTagNames = new Set([...htmlRawNames, ...htmlBlockNames]);
|
|
119508
119560
|
const syntax_nonLazyContinuationStart = {
|
|
119509
119561
|
tokenize: syntax_tokenizeNonLazyContinuationStart,
|
|
119510
119562
|
partial: true,
|
|
@@ -119541,11 +119593,12 @@ const mdxComponentTextConstruct = {
|
|
|
119541
119593
|
* lowercase HTML tags that carry at least one `{…}` attribute expression.
|
|
119542
119594
|
* Multi-line, concrete, `afterClose` consumes the rest of the line.
|
|
119543
119595
|
*
|
|
119544
|
-
* **Text** — runs inside paragraphs / inline context. Claims
|
|
119545
|
-
*
|
|
119546
|
-
*
|
|
119547
|
-
*
|
|
119548
|
-
*
|
|
119596
|
+
* **Text** — runs inside paragraphs / inline context. Claims lowercase tags and
|
|
119597
|
+
* inline PascalCase components (`INLINE_COMPONENT_TAGS` — Anchor, Glossary), both
|
|
119598
|
+
* gated on at least one `{…}` brace attribute. All other PascalCase stays
|
|
119599
|
+
* flow-only, matching how ReadMe's custom components are authored. Aborts on line
|
|
119600
|
+
* endings (inline constructs don't span lines) and exits immediately after
|
|
119601
|
+
* `</tag>` so the paragraph's inline parser picks up the trailing text.
|
|
119549
119602
|
*/
|
|
119550
119603
|
function createTokenize(mode) {
|
|
119551
119604
|
const isFlow = mode === 'flow';
|
|
@@ -119557,8 +119610,9 @@ function createTokenize(mode) {
|
|
|
119557
119610
|
let closingTagName = '';
|
|
119558
119611
|
// For lowercase tags we only want to claim the block if it uses JSX
|
|
119559
119612
|
// attribute expression syntax (`attr={...}`). Plain HTML should fall
|
|
119560
|
-
// through to CommonMark html-flow.
|
|
119561
|
-
//
|
|
119613
|
+
// through to CommonMark html-flow. Flow mode claims any PascalCase block
|
|
119614
|
+
// component; text mode claims only inline PascalCase components
|
|
119615
|
+
// (INLINE_COMPONENT_TAGS — Anchor, Glossary), also brace-gated.
|
|
119562
119616
|
let isLowercaseTag = false;
|
|
119563
119617
|
let sawBraceAttr = false;
|
|
119564
119618
|
// Code span tracking
|
|
@@ -119569,6 +119623,9 @@ function createTokenize(mode) {
|
|
|
119569
119623
|
let fenceLength = 0;
|
|
119570
119624
|
let fenceCloseLength = 0;
|
|
119571
119625
|
let atLineStart = false;
|
|
119626
|
+
// True once this construct consumes any line ending; lets `afterClose`
|
|
119627
|
+
// treat only single-line lowercase tags as inline candidates.
|
|
119628
|
+
let sawLineEnding = false;
|
|
119572
119629
|
// Bail when the opener line has unmatched tag-like tokens in its body.
|
|
119573
119630
|
// `<Foo>_<Bar>.csv` leaves opens > closes; matched shapes like
|
|
119574
119631
|
// `<Callout>x <strong>y</strong>` balance to 0. Without this,
|
|
@@ -119719,13 +119776,13 @@ function createTokenize(mode) {
|
|
|
119719
119776
|
}
|
|
119720
119777
|
// ── Tag name parsing ───────────────────────────────────────────────────
|
|
119721
119778
|
function tagNameFirst(code) {
|
|
119722
|
-
// Uppercase A-Z → PascalCase MDX component. Flow
|
|
119723
|
-
// components
|
|
119779
|
+
// Uppercase A-Z → PascalCase MDX component. Flow mode claims block
|
|
119780
|
+
// components; text mode only claims inline components (Anchor, Glossary),
|
|
119781
|
+
// which is enforced once the full name is known in `tagNameRest`.
|
|
119724
119782
|
if (code !== null && code >= codes.uppercaseA && code <= codes.uppercaseZ) {
|
|
119725
|
-
if (!isFlow)
|
|
119726
|
-
return nok(code);
|
|
119727
119783
|
tagName = String.fromCharCode(code);
|
|
119728
119784
|
isLowercaseTag = false;
|
|
119785
|
+
sawBraceAttr = false;
|
|
119729
119786
|
effects.consume(code);
|
|
119730
119787
|
return tagNameRest;
|
|
119731
119788
|
}
|
|
@@ -119753,10 +119810,18 @@ function createTokenize(mode) {
|
|
|
119753
119810
|
effects.consume(code);
|
|
119754
119811
|
return tagNameRest;
|
|
119755
119812
|
}
|
|
119756
|
-
// Tag name complete —
|
|
119757
|
-
|
|
119813
|
+
// Tag name complete — decide whether this tokenizer claims the tag.
|
|
119814
|
+
// Three cases: lowercase tags are always candidates (brace-gated later in
|
|
119815
|
+
// `afterOpenTagName`); flow-mode PascalCase claims any block component
|
|
119816
|
+
// except those with a dedicated tokenizer; text-mode PascalCase claims
|
|
119817
|
+
// only inline components (Anchor, Glossary).
|
|
119818
|
+
const claimable = isLowercaseTag
|
|
119819
|
+
? true
|
|
119820
|
+
: isFlow
|
|
119821
|
+
? !TOKENIZER_MDX_COMPONENT_EXCLUDED_TAGS.has(tagName)
|
|
119822
|
+
: INLINE_COMPONENT_TAGS.has(tagName);
|
|
119823
|
+
if (!claimable)
|
|
119758
119824
|
return nok(code);
|
|
119759
|
-
}
|
|
119760
119825
|
depth = 1;
|
|
119761
119826
|
return afterOpenTagName(code);
|
|
119762
119827
|
}
|
|
@@ -119764,6 +119829,10 @@ function createTokenize(mode) {
|
|
|
119764
119829
|
function afterOpenTagName(code) {
|
|
119765
119830
|
if (code === null)
|
|
119766
119831
|
return nok(code);
|
|
119832
|
+
// Everything except a flow-mode PascalCase block component must carry a
|
|
119833
|
+
// `{…}` brace attribute to be claimed; plain HTML falls through to
|
|
119834
|
+
// CommonMark.
|
|
119835
|
+
const requiresBraceAttr = isLowercaseTag || !isFlow;
|
|
119767
119836
|
if (markdownLineEnding(code)) {
|
|
119768
119837
|
if (!isFlow)
|
|
119769
119838
|
return nok(code);
|
|
@@ -119772,14 +119841,14 @@ function createTokenize(mode) {
|
|
|
119772
119841
|
}
|
|
119773
119842
|
// Self-closing />
|
|
119774
119843
|
if (code === codes.slash) {
|
|
119775
|
-
if (
|
|
119844
|
+
if (requiresBraceAttr && !sawBraceAttr)
|
|
119776
119845
|
return nok(code);
|
|
119777
119846
|
effects.consume(code);
|
|
119778
119847
|
return selfCloseGt;
|
|
119779
119848
|
}
|
|
119780
119849
|
// End of opening tag
|
|
119781
119850
|
if (code === codes.greaterThan) {
|
|
119782
|
-
if (
|
|
119851
|
+
if (requiresBraceAttr && !sawBraceAttr)
|
|
119783
119852
|
return nok(code);
|
|
119784
119853
|
effects.consume(code);
|
|
119785
119854
|
onOpenerLine = isFlow;
|
|
@@ -119843,6 +119912,7 @@ function createTokenize(mode) {
|
|
|
119843
119912
|
return effects.check(syntax_nonLazyContinuationStart, openTagContinuationNonLazy, continuationAfter)(code);
|
|
119844
119913
|
}
|
|
119845
119914
|
function openTagContinuationNonLazy(code) {
|
|
119915
|
+
sawLineEnding = true;
|
|
119846
119916
|
effects.enter(types_types.lineEnding);
|
|
119847
119917
|
effects.consume(code);
|
|
119848
119918
|
effects.exit(types_types.lineEnding);
|
|
@@ -119966,6 +120036,7 @@ function createTokenize(mode) {
|
|
|
119966
120036
|
return effects.check(syntax_nonLazyContinuationStart, fencedCodeContinuationNonLazy, continuationAfter)(code);
|
|
119967
120037
|
}
|
|
119968
120038
|
function fencedCodeContinuationNonLazy(code) {
|
|
120039
|
+
sawLineEnding = true;
|
|
119969
120040
|
effects.enter(types_types.lineEnding);
|
|
119970
120041
|
effects.consume(code);
|
|
119971
120042
|
effects.exit(types_types.lineEnding);
|
|
@@ -120122,6 +120193,12 @@ function createTokenize(mode) {
|
|
|
120122
120193
|
effects.exit('mdxComponent');
|
|
120123
120194
|
return ok(code);
|
|
120124
120195
|
}
|
|
120196
|
+
// A single-line type-7 lowercase tag with content trailing its close is
|
|
120197
|
+
// inline, so `<i …></i> <a>…</a>` stays on one line instead of splitting
|
|
120198
|
+
// into separate blocks. Raw/block tags (pre, div, …) stay flow.
|
|
120199
|
+
if (isLowercaseTag && !sawLineEnding && !htmlFlowTagNames.has(tagName)) {
|
|
120200
|
+
return afterCloseInlineCandidate(code);
|
|
120201
|
+
}
|
|
120125
120202
|
if (code === null || markdownLineEnding(code)) {
|
|
120126
120203
|
effects.exit('mdxComponentData');
|
|
120127
120204
|
effects.exit('mdxComponent');
|
|
@@ -120132,11 +120209,26 @@ function createTokenize(mode) {
|
|
|
120132
120209
|
effects.consume(code);
|
|
120133
120210
|
return afterClose;
|
|
120134
120211
|
}
|
|
120212
|
+
// Whitespace-only to the line ending keeps the flow block; any other
|
|
120213
|
+
// trailing char means inline content, so refuse and let inline parsing run.
|
|
120214
|
+
function afterCloseInlineCandidate(code) {
|
|
120215
|
+
if (code === null || markdownLineEnding(code)) {
|
|
120216
|
+
effects.exit('mdxComponentData');
|
|
120217
|
+
effects.exit('mdxComponent');
|
|
120218
|
+
return ok(code);
|
|
120219
|
+
}
|
|
120220
|
+
if (markdownSpace(code)) {
|
|
120221
|
+
effects.consume(code);
|
|
120222
|
+
return afterCloseInlineCandidate;
|
|
120223
|
+
}
|
|
120224
|
+
return nok(code);
|
|
120225
|
+
}
|
|
120135
120226
|
// ── Body continuation (line endings) ───────────────────────────────────
|
|
120136
120227
|
function bodyContinuationStart(code) {
|
|
120137
120228
|
return effects.check(syntax_nonLazyContinuationStart, bodyContinuationNonLazy, continuationAfter)(code);
|
|
120138
120229
|
}
|
|
120139
120230
|
function bodyContinuationNonLazy(code) {
|
|
120231
|
+
sawLineEnding = true;
|
|
120140
120232
|
effects.enter(types_types.lineEnding);
|
|
120141
120233
|
effects.consume(code);
|
|
120142
120234
|
effects.exit(types_types.lineEnding);
|
|
@@ -120206,12 +120298,13 @@ function syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
|
|
|
120206
120298
|
* self-closing `<Component />`). Prevents CommonMark from fragmenting them
|
|
120207
120299
|
* across multiple HTML / paragraph nodes.
|
|
120208
120300
|
*
|
|
120209
|
-
* **Text (inline)** — registers
|
|
120210
|
-
* (
|
|
120211
|
-
*
|
|
120212
|
-
*
|
|
120213
|
-
*
|
|
120214
|
-
*
|
|
120301
|
+
* **Text (inline)** — registers for lowercase tags and inline PascalCase
|
|
120302
|
+
* components (Anchor, Glossary) that carry brace attrs (e.g.
|
|
120303
|
+
* `Start <a href={url}>here</a> end`, `<Anchor href={url}>x</Anchor>`). Picks
|
|
120304
|
+
* them up during inline parsing so they render inline inside their paragraph,
|
|
120305
|
+
* then are rewritten to `mdxJsxTextElement` by the `components/inline-html`
|
|
120306
|
+
* transformer. All other PascalCase is flow-only; ReadMe's custom components
|
|
120307
|
+
* are authored as block-level elements.
|
|
120215
120308
|
*
|
|
120216
120309
|
* Excludes tags handled by dedicated tokenizers: Table, HTMLBlock, Glossary,
|
|
120217
120310
|
* Anchor.
|
|
@@ -120330,12 +120423,12 @@ const parsePhrasingChildren = (value, safeMode) => {
|
|
|
120330
120423
|
return first?.type === 'paragraph' ? first.children : [];
|
|
120331
120424
|
};
|
|
120332
120425
|
/**
|
|
120333
|
-
* Attempt to promote
|
|
120334
|
-
* `
|
|
120335
|
-
*
|
|
120336
|
-
*
|
|
120337
|
-
* `mdxishComponentBlocks` so they remain `mdxJsxFlowElement`,
|
|
120338
|
-
* ReadMe's flow-level component authoring model.
|
|
120426
|
+
* Attempt to promote an inline `html` node to an `mdxJsxTextElement`. Scope
|
|
120427
|
+
* mirrors what the `mdxComponent` text tokenizer claims: lowercase tags and
|
|
120428
|
+
* inline PascalCase components (`INLINE_COMPONENT_TAGS` — Anchor, Glossary),
|
|
120429
|
+
* both carrying `{…}` attribute expressions. All other PascalCase components
|
|
120430
|
+
* stay with `mdxishComponentBlocks` so they remain `mdxJsxFlowElement`,
|
|
120431
|
+
* matching ReadMe's flow-level component authoring model.
|
|
120339
120432
|
*
|
|
120340
120433
|
* Returns the original node unchanged when it doesn't qualify.
|
|
120341
120434
|
*/
|
|
@@ -120344,12 +120437,11 @@ const promoteInlineHtml = (node, parseOpts, safeMode) => {
|
|
|
120344
120437
|
if (!parsed)
|
|
120345
120438
|
return node;
|
|
120346
120439
|
const { tag, attributes, selfClosing, contentAfterTag = '' } = parsed;
|
|
120347
|
-
// PascalCase stays flow-level
|
|
120348
|
-
|
|
120349
|
-
|
|
120350
|
-
//
|
|
120351
|
-
|
|
120352
|
-
if (GENERIC_MDX_COMPONENT_EXCLUDED_TAGS.has(tag))
|
|
120440
|
+
// Non-inline PascalCase stays flow-level (handled by mdxishComponentBlocks)
|
|
120441
|
+
// and dedicated tokenizers (Table, HTMLBlock) own their tags. Inline
|
|
120442
|
+
// components (Anchor, Glossary) with expression attrs are promoted here —
|
|
120443
|
+
// the text tokenizer captures them as a single html node.
|
|
120444
|
+
if (isPascalCase(tag) && !INLINE_COMPONENT_TAGS.has(tag))
|
|
120353
120445
|
return node;
|
|
120354
120446
|
// Plain inline HTML (no expressions) stays as an html node so rehype-raw
|
|
120355
120447
|
// parses it with parse5 as normal.
|
|
@@ -120373,14 +120465,15 @@ const promoteInlineHtml = (node, parseOpts, safeMode) => {
|
|
|
120373
120465
|
* Runs after `mdxishComponentBlocks`, which skips paragraph-parented html
|
|
120374
120466
|
* nodes and leaves them for this pass. Two producers put html nodes inside
|
|
120375
120467
|
* paragraphs:
|
|
120376
|
-
* 1. The `mdxComponent` text tokenizer, for lowercase tags
|
|
120377
|
-
*
|
|
120468
|
+
* 1. The `mdxComponent` text tokenizer, for lowercase tags and inline
|
|
120469
|
+
* PascalCase components (Anchor, Glossary) with `{…}` attribute
|
|
120470
|
+
* expressions (e.g. `<a href={url}>here</a>`, `<Anchor href={url}>x</Anchor>`).
|
|
120378
120471
|
* 2. CommonMark's built-in html-text tokenizer, for PascalCase components
|
|
120379
120472
|
* (e.g. a single html node for self-closing `<C />`).
|
|
120380
120473
|
*
|
|
120381
|
-
* Eligibility mirrors `mdxishComponentBlocks`:
|
|
120382
|
-
*
|
|
120383
|
-
* `<a href="x">` stays as an html node for rehype-raw.
|
|
120474
|
+
* Eligibility mirrors `mdxishComponentBlocks`: a tag only promotes when it
|
|
120475
|
+
* carries an expression attribute and isn't a non-inline PascalCase component;
|
|
120476
|
+
* plain inline HTML like `<a href="x">` stays as an html node for rehype-raw.
|
|
120384
120477
|
*/
|
|
120385
120478
|
const mdxishInlineMdxHtmlBlocks = (opts = {}) => tree => {
|
|
120386
120479
|
const safeMode = !!opts.safeMode;
|
|
@@ -120828,12 +120921,60 @@ function restoreSnakeCase(placeholderName, mapping) {
|
|
|
120828
120921
|
return matchingKey ? mapping[matchingKey] : placeholderName;
|
|
120829
120922
|
}
|
|
120830
120923
|
|
|
120924
|
+
;// ./processor/transform/mdxish/resolve-esm-imports.ts
|
|
120925
|
+
|
|
120926
|
+
// We provide React as a default module so that components can use hooks
|
|
120927
|
+
// and it's a common use case. Add other common libraries here.
|
|
120928
|
+
const defaultModuleRegistry = { react: (external_react_default()) };
|
|
120929
|
+
const isRecord = (value) => typeof value === 'object' && value !== null;
|
|
120930
|
+
// Get the value of a named export from a module
|
|
120931
|
+
const getModuleExport = (module, importedName) => isRecord(module) && importedName in module ? module[importedName] : undefined;
|
|
120932
|
+
/**
|
|
120933
|
+
* Turn `import` declarations into a flat map of binding → value.
|
|
120934
|
+
*
|
|
120935
|
+
* A "binding" is a mapping of a local name to the value of it in the module exports
|
|
120936
|
+
* Example: `import { useState } from 'react'` yields `{ useState: React.useState }`.
|
|
120937
|
+
*
|
|
120938
|
+
* Unsupported specifiers are skipped with a warning rather than throwing, so a
|
|
120939
|
+
* single unknown import can't break the rest of the document.
|
|
120940
|
+
*/
|
|
120941
|
+
const collectImportValues = (importDeclarations, registry = defaultModuleRegistry) => {
|
|
120942
|
+
const importValues = {};
|
|
120943
|
+
importDeclarations.forEach(declaration => {
|
|
120944
|
+
const libraryName = declaration.source.value;
|
|
120945
|
+
if (typeof libraryName !== 'string')
|
|
120946
|
+
return;
|
|
120947
|
+
if (!(libraryName in registry)) {
|
|
120948
|
+
// eslint-disable-next-line no-console
|
|
120949
|
+
console.warn(`[WARNING] Cannot resolve import "${libraryName}"; it is not a supported library.`);
|
|
120950
|
+
return;
|
|
120951
|
+
}
|
|
120952
|
+
const module = registry[libraryName];
|
|
120953
|
+
declaration.specifiers.forEach(spec => {
|
|
120954
|
+
// Default (`import React`) and namespace (`import * as React`) both bind
|
|
120955
|
+
// the whole module under the local name.
|
|
120956
|
+
if (spec.type === 'ImportDefaultSpecifier' || spec.type === 'ImportNamespaceSpecifier') {
|
|
120957
|
+
importValues[spec.local.name] = module;
|
|
120958
|
+
}
|
|
120959
|
+
else if (spec.type === 'ImportSpecifier') {
|
|
120960
|
+
// Named imports (e.g. `import { useState } from 'react'`, useState is the import name)
|
|
120961
|
+
const importName = spec.imported.type === 'Identifier' ? spec.imported.name : spec.imported.value;
|
|
120962
|
+
if (typeof importName === 'string') {
|
|
120963
|
+
importValues[spec.local.name] = getModuleExport(module, importName);
|
|
120964
|
+
}
|
|
120965
|
+
}
|
|
120966
|
+
});
|
|
120967
|
+
});
|
|
120968
|
+
return importValues;
|
|
120969
|
+
};
|
|
120970
|
+
|
|
120831
120971
|
;// ./processor/transform/mdxish/evaluate-exports.ts
|
|
120832
120972
|
|
|
120833
120973
|
|
|
120834
120974
|
|
|
120835
120975
|
|
|
120836
120976
|
|
|
120977
|
+
|
|
120837
120978
|
/**
|
|
120838
120979
|
* Recursively extract all identifier names introduced by a binding pattern.
|
|
120839
120980
|
* Handles destructuring (`{ a, b }`, `[x, y]`), rest elements (`...rest`),
|
|
@@ -120881,6 +121022,7 @@ const collectExportNames = (declaration) => {
|
|
|
120881
121022
|
const evaluateExports = () => (tree, file) => {
|
|
120882
121023
|
const programBody = [];
|
|
120883
121024
|
const exportNames = [];
|
|
121025
|
+
const importDeclarations = [];
|
|
120884
121026
|
const nodesToRemove = [];
|
|
120885
121027
|
lib_visit(tree, isMDXEsm, (node, index, parent) => {
|
|
120886
121028
|
if (parent && typeof index === 'number') {
|
|
@@ -120894,6 +121036,10 @@ const evaluateExports = () => (tree, file) => {
|
|
|
120894
121036
|
// handled the same as a named export — the inner declaration carries the
|
|
120895
121037
|
// binding name
|
|
120896
121038
|
estreeBody.forEach(statement => {
|
|
121039
|
+
if (statement.type === 'ImportDeclaration') {
|
|
121040
|
+
importDeclarations.push(statement);
|
|
121041
|
+
return;
|
|
121042
|
+
}
|
|
120897
121043
|
let declaration = null;
|
|
120898
121044
|
if (statement.type === 'ExportNamedDeclaration' && statement.declaration) {
|
|
120899
121045
|
declaration = statement.declaration;
|
|
@@ -120921,9 +121067,11 @@ const evaluateExports = () => (tree, file) => {
|
|
|
120921
121067
|
const program = { type: 'Program', sourceType: 'module', body: programBody };
|
|
120922
121068
|
buildJsx(program, { runtime: 'classic', pragma: 'React.createElement', pragmaFrag: 'React.Fragment' });
|
|
120923
121069
|
const { value: source } = toJs(program);
|
|
121070
|
+
// Make sure import values are available in the scope
|
|
121071
|
+
const importValues = collectImportValues(importDeclarations);
|
|
120924
121072
|
// Evaluate and build on the expression source
|
|
120925
121073
|
// Use react to compile JSX codes
|
|
120926
|
-
const evaluatedExports = evaluate(`(() => { ${source}\nreturn { ${exportNames.join(', ')} }; })()`, { React: (external_react_default()) });
|
|
121074
|
+
const evaluatedExports = evaluate(`(() => { ${source}\nreturn { ${exportNames.join(', ')} }; })()`, { React: (external_react_default()), ...importValues });
|
|
120927
121075
|
Object.assign(scope, evaluatedExports);
|
|
120928
121076
|
}
|
|
120929
121077
|
catch (error) {
|
|
@@ -124295,214 +124443,21 @@ const normalizeMdxJsxNodes = () => tree => {
|
|
|
124295
124443
|
*/
|
|
124296
124444
|
const JSX_COMMENT_REGEX = /\{\/\*[^*]*(?:\*(?!\/)[^*]*)*\*\/\}/g;
|
|
124297
124445
|
|
|
124298
|
-
;// ./processor/transform/mdxish/
|
|
124299
|
-
|
|
124446
|
+
;// ./processor/transform/mdxish/remove-jsx-comments.ts
|
|
124300
124447
|
|
|
124301
124448
|
/**
|
|
124302
124449
|
* Removes JSX-style comments (e.g., { /* comment *\/ }) from content.
|
|
124303
124450
|
*
|
|
124304
|
-
*
|
|
124305
|
-
*
|
|
124306
|
-
*
|
|
124451
|
+
* `@param` content
|
|
124452
|
+
* `@returns` Content with JSX comments removed
|
|
124453
|
+
* `@example`
|
|
124307
124454
|
* ```typescript
|
|
124308
|
-
* removeJSXComments('Text {
|
|
124309
|
-
* // Returns: 'Text more text'
|
|
124455
|
+
* removeJSXComments('Text {/* comment *\/} more text') // => 'Text more text'
|
|
124310
124456
|
* ```
|
|
124311
124457
|
*/
|
|
124312
124458
|
function removeJSXComments(content) {
|
|
124313
124459
|
return content.replace(JSX_COMMENT_REGEX, '');
|
|
124314
124460
|
}
|
|
124315
|
-
const HTML_ELEM_PLACEHOLDER_PREFIX = '___MDXISH_HTML_ELEM_';
|
|
124316
|
-
const HTML_ELEM_PLACEHOLDER = new RegExp(`${HTML_ELEM_PLACEHOLDER_PREFIX}(\\d+)___`, 'g');
|
|
124317
|
-
// Matches an HTML element that starts at a line boundary and ends at a line boundary.
|
|
124318
|
-
// Allows optional leading indentation and lazily matches until the same closing tag.
|
|
124319
|
-
const BLOCK_HTML_RE = /(?<=^|\n)[ \t]*<([a-z][a-zA-Z0-9]*)(?:\s[^>]*)?>[\s\S]*?<\/\1>[ \t]*(?=\n|$)/g;
|
|
124320
|
-
/**
|
|
124321
|
-
* Hides line-anchored HTML elements from the brace-escaping pass so we don't leak `\{`
|
|
124322
|
-
* into rendered output (rehypeRaw renders the `\` literally, e.g. `<div>{foo</div>`).
|
|
124323
|
-
*
|
|
124324
|
-
* One carve-out: if an interior line at column 0 has bare text containing `{`, mdxish
|
|
124325
|
-
* parses that line as a paragraph and the mdxExpression step would throw without an
|
|
124326
|
-
* escape — so we leave that case to the brace balancer.
|
|
124327
|
-
*/
|
|
124328
|
-
function protectHTMLElements(content) {
|
|
124329
|
-
const htmlElements = [];
|
|
124330
|
-
const protectedContent = content.replace(BLOCK_HTML_RE, match => {
|
|
124331
|
-
// Look at the lines between the open and close tags. If any of them starts
|
|
124332
|
-
// at column 0 with bare text (not whitespace, not another tag) and contains
|
|
124333
|
-
// `{`, mdxish will parse that line as a paragraph and the brace as an MDX
|
|
124334
|
-
// expression, which would throw an error. So we let the brace balancer escape it.
|
|
124335
|
-
// Otherwise, we need to extract the sequence to protect it from the brace escaping.
|
|
124336
|
-
const interior = match.split('\n').slice(1, -1);
|
|
124337
|
-
const hazard = interior.some(line => line.length > 0 && line[0] !== ' ' && line[0] !== '\t' && line[0] !== '<' && line.includes('{'));
|
|
124338
|
-
if (hazard)
|
|
124339
|
-
return match;
|
|
124340
|
-
htmlElements.push(match);
|
|
124341
|
-
return `${HTML_ELEM_PLACEHOLDER_PREFIX}${htmlElements.length - 1}___`;
|
|
124342
|
-
});
|
|
124343
|
-
return { htmlElements, protectedContent };
|
|
124344
|
-
}
|
|
124345
|
-
function restoreHTMLElements(content, htmlElements) {
|
|
124346
|
-
if (htmlElements.length === 0)
|
|
124347
|
-
return content;
|
|
124348
|
-
return content.replace(HTML_ELEM_PLACEHOLDER, (_m, idx) => htmlElements[parseInt(idx, 10)]);
|
|
124349
|
-
}
|
|
124350
|
-
const ESM_DECLARATION_START = /^(?:export|import)\b/;
|
|
124351
|
-
/**
|
|
124352
|
-
* Whether a line begins a top-level `export`/`import` declaration. Its braces
|
|
124353
|
-
* are valid JS owned by the mdxjsEsm tokenizer (which tolerates blank lines),
|
|
124354
|
-
* so escaping them would corrupt the source and break acorn parsing.
|
|
124355
|
-
*/
|
|
124356
|
-
function startsEsmDeclaration(chars, lineStart) {
|
|
124357
|
-
return ESM_DECLARATION_START.test(chars.slice(lineStart, lineStart + 7).join(''));
|
|
124358
|
-
}
|
|
124359
|
-
function isBlankLine(chars, lineStart) {
|
|
124360
|
-
for (let i = lineStart; i < chars.length; i += 1) {
|
|
124361
|
-
if (chars[i] === '\n')
|
|
124362
|
-
return true;
|
|
124363
|
-
if (chars[i] !== ' ' && chars[i] !== '\t')
|
|
124364
|
-
return false;
|
|
124365
|
-
}
|
|
124366
|
-
return true;
|
|
124367
|
-
}
|
|
124368
|
-
/**
|
|
124369
|
-
* Escapes unbalanced and paragraph-spanning braces so MDX doesn't trip on them.
|
|
124370
|
-
*/
|
|
124371
|
-
function escapeProblematicBraces(content) {
|
|
124372
|
-
const { htmlElements, protectedContent } = protectHTMLElements(content);
|
|
124373
|
-
let strDelim = null;
|
|
124374
|
-
let strEscaped = false;
|
|
124375
|
-
// Track position of last newline (outside strings) to detect blank lines
|
|
124376
|
-
// -2 means no recent newline
|
|
124377
|
-
let lastNewlinePos = -2;
|
|
124378
|
-
// Character state machine trackers
|
|
124379
|
-
const toEscape = new Set();
|
|
124380
|
-
// Convert to array of Unicode code points so that emojis and multi-byte characters are correctly tracked
|
|
124381
|
-
const chars = Array.from(protectedContent);
|
|
124382
|
-
const openStack = [];
|
|
124383
|
-
// Whether the current top-level statement is an `export`/`import` declaration.
|
|
124384
|
-
let insideEsmDeclaration = false;
|
|
124385
|
-
for (let i = 0; i < chars.length; i += 1) {
|
|
124386
|
-
const ch = chars[i];
|
|
124387
|
-
// At a top-level (brace depth 0) line start, decide whether we're inside an
|
|
124388
|
-
// ESM declaration. The flag persists across the declaration's own lines.
|
|
124389
|
-
if (openStack.length === 0 && (i === 0 || chars[i - 1] === '\n')) {
|
|
124390
|
-
if (startsEsmDeclaration(chars, i))
|
|
124391
|
-
insideEsmDeclaration = true;
|
|
124392
|
-
else if (isBlankLine(chars, i))
|
|
124393
|
-
insideEsmDeclaration = false;
|
|
124394
|
-
}
|
|
124395
|
-
// Track string delimiters inside expressions to ignore braces within them
|
|
124396
|
-
if (openStack.length > 0) {
|
|
124397
|
-
if (strDelim) {
|
|
124398
|
-
if (strEscaped)
|
|
124399
|
-
strEscaped = false;
|
|
124400
|
-
else if (ch === '\\')
|
|
124401
|
-
strEscaped = true;
|
|
124402
|
-
else if (ch === strDelim)
|
|
124403
|
-
strDelim = null;
|
|
124404
|
-
// eslint-disable-next-line no-continue
|
|
124405
|
-
continue;
|
|
124406
|
-
}
|
|
124407
|
-
if (ch === '"' || ch === "'" || ch === '`') {
|
|
124408
|
-
strDelim = ch;
|
|
124409
|
-
// eslint-disable-next-line no-continue
|
|
124410
|
-
continue;
|
|
124411
|
-
}
|
|
124412
|
-
if (ch === '\n') {
|
|
124413
|
-
if (lastNewlinePos >= 0) {
|
|
124414
|
-
const between = chars.slice(lastNewlinePos + 1, i).join('');
|
|
124415
|
-
if (/^[ \t]*$/.test(between)) {
|
|
124416
|
-
openStack.forEach(entry => { entry.hasBlankLine = true; });
|
|
124417
|
-
}
|
|
124418
|
-
}
|
|
124419
|
-
lastNewlinePos = i;
|
|
124420
|
-
}
|
|
124421
|
-
}
|
|
124422
|
-
// Skip already-escaped braces (odd run of preceding backslashes).
|
|
124423
|
-
if (ch === '{' || ch === '}') {
|
|
124424
|
-
let bs = 0;
|
|
124425
|
-
for (let j = i - 1; j >= 0 && chars[j] === '\\'; j -= 1)
|
|
124426
|
-
bs += 1;
|
|
124427
|
-
if (bs % 2 === 1) {
|
|
124428
|
-
// eslint-disable-next-line no-continue
|
|
124429
|
-
continue;
|
|
124430
|
-
}
|
|
124431
|
-
}
|
|
124432
|
-
if (ch === '{') {
|
|
124433
|
-
// `=` (after whitespace) before `{` ⇒ JSX attribute expression. The
|
|
124434
|
-
// mdxComponent tokenizer captures the whole component, so blank lines
|
|
124435
|
-
// inside attribute values are harmless. Nested `{` inherits the flag.
|
|
124436
|
-
let isAttrExpr = false;
|
|
124437
|
-
for (let j = i - 1; j >= 0; j -= 1) {
|
|
124438
|
-
const pc = chars[j];
|
|
124439
|
-
if (pc === '=') {
|
|
124440
|
-
isAttrExpr = true;
|
|
124441
|
-
break;
|
|
124442
|
-
}
|
|
124443
|
-
if (pc !== ' ' && pc !== '\t')
|
|
124444
|
-
break;
|
|
124445
|
-
}
|
|
124446
|
-
// Nested `{ ... }` inside an attribute value (e.g. `data={[{ ... }]}` or
|
|
124447
|
-
// `data={{ a: { b: 1 } }}`) must inherit the same exemption; only the
|
|
124448
|
-
// outer `{` is directly after `=`.
|
|
124449
|
-
if (!isAttrExpr && openStack.length > 0 && openStack[openStack.length - 1].isAttrExpr) {
|
|
124450
|
-
isAttrExpr = true;
|
|
124451
|
-
}
|
|
124452
|
-
openStack.push({ pos: i, hasBlankLine: false, isAttrExpr, isEsmDeclaration: insideEsmDeclaration });
|
|
124453
|
-
lastNewlinePos = -2;
|
|
124454
|
-
}
|
|
124455
|
-
else if (ch === '}') {
|
|
124456
|
-
if (openStack.length > 0) {
|
|
124457
|
-
const entry = openStack.pop();
|
|
124458
|
-
// The declaration's braces are closed; later top-level braces are not ESM.
|
|
124459
|
-
if (openStack.length === 0)
|
|
124460
|
-
insideEsmDeclaration = false;
|
|
124461
|
-
// Pure `{/* ... */}` comments are handled downstream by the jsxComment
|
|
124462
|
-
// tokenizer — escaping their braces would prevent it from running.
|
|
124463
|
-
const isPureJsxComment = chars[entry.pos + 1] === '/' &&
|
|
124464
|
-
chars[entry.pos + 2] === '*' &&
|
|
124465
|
-
chars[i - 1] === '/' &&
|
|
124466
|
-
chars[i - 2] === '*';
|
|
124467
|
-
if (entry.hasBlankLine && !isPureJsxComment && !entry.isAttrExpr && !entry.isEsmDeclaration) {
|
|
124468
|
-
toEscape.add(entry.pos);
|
|
124469
|
-
toEscape.add(i);
|
|
124470
|
-
}
|
|
124471
|
-
}
|
|
124472
|
-
else {
|
|
124473
|
-
toEscape.add(i);
|
|
124474
|
-
}
|
|
124475
|
-
}
|
|
124476
|
-
else if (ch === ';' && openStack.length === 0) {
|
|
124477
|
-
// A top-level `;` ends the current statement, ESM or otherwise.
|
|
124478
|
-
insideEsmDeclaration = false;
|
|
124479
|
-
}
|
|
124480
|
-
}
|
|
124481
|
-
// Anything still open is unbalanced.
|
|
124482
|
-
openStack.forEach(entry => {
|
|
124483
|
-
if (!entry.isEsmDeclaration)
|
|
124484
|
-
toEscape.add(entry.pos);
|
|
124485
|
-
});
|
|
124486
|
-
// Reconstruct the content with the escaped braces.
|
|
124487
|
-
const escapedContent = toEscape.size === 0 ? protectedContent : chars.map((ch, i) => (toEscape.has(i) ? `\\${ch}` : ch)).join('');
|
|
124488
|
-
return restoreHTMLElements(escapedContent, htmlElements);
|
|
124489
|
-
}
|
|
124490
|
-
/**
|
|
124491
|
-
* Preprocesses JSX-like markdown content before parsing.
|
|
124492
|
-
*
|
|
124493
|
-
* JSX attribute expressions (`href={baseUrl}`) are no longer rewritten here —
|
|
124494
|
-
* they flow through the tokenizer as `mdxJsxAttributeValueExpression` nodes
|
|
124495
|
-
* and are evaluated at the hast handler step.
|
|
124496
|
-
*
|
|
124497
|
-
* @param content
|
|
124498
|
-
* @returns Preprocessed content ready for markdown parsing
|
|
124499
|
-
*/
|
|
124500
|
-
function preprocessJSXExpressions(content) {
|
|
124501
|
-
const { protectedCode, protectedContent } = protectCodeBlocks(content);
|
|
124502
|
-
let processed = escapeProblematicBraces(protectedContent);
|
|
124503
|
-
processed = restoreCodeBlocks(processed, protectedCode);
|
|
124504
|
-
return processed;
|
|
124505
|
-
}
|
|
124506
124461
|
|
|
124507
124462
|
;// ./processor/transform/mdxish/resolve-deferred-attribute-expression-props.ts
|
|
124508
124463
|
|
|
@@ -125477,6 +125432,85 @@ function syntax_jsxTable() {
|
|
|
125477
125432
|
;// ./lib/micromark/jsx-table/index.ts
|
|
125478
125433
|
|
|
125479
125434
|
|
|
125435
|
+
;// ./lib/micromark/mdx-expression-lenient/syntax.ts
|
|
125436
|
+
|
|
125437
|
+
|
|
125438
|
+
/**
|
|
125439
|
+
* Lenient MDX text-expression tokenizer (agnostic / no acorn).
|
|
125440
|
+
*
|
|
125441
|
+
* Matches a balanced `{ ... }` run — tracking nested braces and spanning soft
|
|
125442
|
+
* line breaks — and emits the standard `mdxTextExpression*` tokens so the
|
|
125443
|
+
* upstream `mdxExpressionFromMarkdown()` builds the node.
|
|
125444
|
+
*
|
|
125445
|
+
* Reimplements the official micromark mdxExpression, but an unbalanced brace that
|
|
125446
|
+
* reaches end of input returns `nok` instead of throwing: micromark rolls back
|
|
125447
|
+
* and the `{` renders as literal text, making the pipeline forgiving of stray
|
|
125448
|
+
* braces that upstream would hard-error on.
|
|
125449
|
+
*/
|
|
125450
|
+
function tokenizeTextExpression(effects, ok, nok) {
|
|
125451
|
+
let depth = 0;
|
|
125452
|
+
return start;
|
|
125453
|
+
function start(code) {
|
|
125454
|
+
if (code !== codes.leftCurlyBrace)
|
|
125455
|
+
return nok(code);
|
|
125456
|
+
effects.enter('mdxTextExpression');
|
|
125457
|
+
effects.enter('mdxTextExpressionMarker');
|
|
125458
|
+
effects.consume(code);
|
|
125459
|
+
effects.exit('mdxTextExpressionMarker');
|
|
125460
|
+
return before;
|
|
125461
|
+
}
|
|
125462
|
+
function before(code) {
|
|
125463
|
+
if (code === codes.eof) {
|
|
125464
|
+
effects.exit('mdxTextExpression');
|
|
125465
|
+
return nok(code);
|
|
125466
|
+
}
|
|
125467
|
+
if (markdownLineEnding(code)) {
|
|
125468
|
+
effects.enter('lineEnding');
|
|
125469
|
+
effects.consume(code);
|
|
125470
|
+
effects.exit('lineEnding');
|
|
125471
|
+
return before;
|
|
125472
|
+
}
|
|
125473
|
+
if (code === codes.rightCurlyBrace && depth === 0) {
|
|
125474
|
+
return close(code);
|
|
125475
|
+
}
|
|
125476
|
+
effects.enter('mdxTextExpressionChunk');
|
|
125477
|
+
return inside(code);
|
|
125478
|
+
}
|
|
125479
|
+
function inside(code) {
|
|
125480
|
+
if (code === codes.eof || markdownLineEnding(code)) {
|
|
125481
|
+
effects.exit('mdxTextExpressionChunk');
|
|
125482
|
+
return before(code);
|
|
125483
|
+
}
|
|
125484
|
+
if (code === codes.rightCurlyBrace && depth === 0) {
|
|
125485
|
+
effects.exit('mdxTextExpressionChunk');
|
|
125486
|
+
return close(code);
|
|
125487
|
+
}
|
|
125488
|
+
if (code === codes.leftCurlyBrace)
|
|
125489
|
+
depth += 1;
|
|
125490
|
+
else if (code === codes.rightCurlyBrace)
|
|
125491
|
+
depth -= 1;
|
|
125492
|
+
effects.consume(code);
|
|
125493
|
+
return inside;
|
|
125494
|
+
}
|
|
125495
|
+
function close(code) {
|
|
125496
|
+
effects.enter('mdxTextExpressionMarker');
|
|
125497
|
+
effects.consume(code);
|
|
125498
|
+
effects.exit('mdxTextExpressionMarker');
|
|
125499
|
+
effects.exit('mdxTextExpression');
|
|
125500
|
+
return ok;
|
|
125501
|
+
}
|
|
125502
|
+
}
|
|
125503
|
+
function mdxExpressionLenient() {
|
|
125504
|
+
return {
|
|
125505
|
+
text: {
|
|
125506
|
+
[codes.leftCurlyBrace]: {
|
|
125507
|
+
name: 'mdxTextExpression',
|
|
125508
|
+
tokenize: tokenizeTextExpression,
|
|
125509
|
+
},
|
|
125510
|
+
},
|
|
125511
|
+
};
|
|
125512
|
+
}
|
|
125513
|
+
|
|
125480
125514
|
;// ./lib/utils/mdxish/mdxish-load-components.ts
|
|
125481
125515
|
|
|
125482
125516
|
|
|
@@ -125589,7 +125623,7 @@ const defaultTransformers = [
|
|
|
125589
125623
|
* 1. Normalize malformed table separator syntax (e.g., `|: ---` → `| :---`)
|
|
125590
125624
|
* 2. Terminate HTML flow blocks so subsequent content isn't swallowed
|
|
125591
125625
|
* 3. Close invalid "self-closing" HTML tags (e.g., `<i />` → `<i></i>`)
|
|
125592
|
-
* 4.
|
|
125626
|
+
* 4. Normalize compact ATX headings (e.g., `#Heading` → `# Heading`)
|
|
125593
125627
|
* 5. Replace snake_case component names with parser-safe placeholders
|
|
125594
125628
|
*/
|
|
125595
125629
|
function preprocessContent(content, opts) {
|
|
@@ -125598,7 +125632,6 @@ function preprocessContent(content, opts) {
|
|
|
125598
125632
|
result = terminateHtmlFlowBlocks(result);
|
|
125599
125633
|
result = closeSelfClosingHtmlTags(result);
|
|
125600
125634
|
result = normalizeCompactHeadings(result);
|
|
125601
|
-
result = preprocessJSXExpressions(result);
|
|
125602
125635
|
return processSnakeCaseComponent(result, { knownComponents });
|
|
125603
125636
|
}
|
|
125604
125637
|
function mdxishAstProcessor(mdContent, opts = {}) {
|
|
@@ -125615,12 +125648,8 @@ function mdxishAstProcessor(mdContent, opts = {}) {
|
|
|
125615
125648
|
acc[key] = String(value);
|
|
125616
125649
|
return acc;
|
|
125617
125650
|
}, {});
|
|
125618
|
-
//
|
|
125619
|
-
|
|
125620
|
-
const mdxExprExt = syntax_mdxExpression({ allowEmpty: true });
|
|
125621
|
-
const mdxExprTextOnly = {
|
|
125622
|
-
text: mdxExprExt.text,
|
|
125623
|
-
};
|
|
125651
|
+
// Parser extension for MDX expressions {}
|
|
125652
|
+
const mdxExprTextOnly = mdxExpressionLenient();
|
|
125624
125653
|
const micromarkExts = [
|
|
125625
125654
|
syntax_jsxTable(),
|
|
125626
125655
|
syntax_magicBlock(),
|