@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
package/dist/main.node.js
CHANGED
|
@@ -19744,10 +19744,55 @@ const Columns = ({ children, layout = 'auto' }) => {
|
|
|
19744
19744
|
};
|
|
19745
19745
|
/* harmony default export */ const components_Columns = (Columns);
|
|
19746
19746
|
|
|
19747
|
+
;// ./components/Embed/normalizeYouTubeUrl.ts
|
|
19748
|
+
// YouTube watch/share URLs (youtube.com/watch?v=ID, youtu.be/ID) set X-Frame-Options
|
|
19749
|
+
// and refuse to be framed. The player only allows embedding via youtube.com/embed/ID.
|
|
19750
|
+
const YOUTUBE_HOSTS = new Set(['youtube.com', 'www.youtube.com', 'm.youtube.com', 'youtu.be', 'www.youtu.be', 'm.youtu.be']);
|
|
19751
|
+
// /embed/ accepts `start` (integer seconds), not the watch-page `t` value which may carry units (e.g. 596s, 1h2m3s).
|
|
19752
|
+
const toStartSeconds = (timestamp) => {
|
|
19753
|
+
const [, hours, minutes, seconds] = timestamp.match(/^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s?)?$/) ?? [];
|
|
19754
|
+
const total = (Number(hours) || 0) * 3600 + (Number(minutes) || 0) * 60 + (Number(seconds) || 0);
|
|
19755
|
+
return total > 0 ? String(total) : null;
|
|
19756
|
+
};
|
|
19757
|
+
const extractVideoId = (parsed) => {
|
|
19758
|
+
if (parsed.hostname.endsWith('youtu.be'))
|
|
19759
|
+
return parsed.pathname.slice(1).split('/')[0] || null;
|
|
19760
|
+
if (parsed.pathname.startsWith('/watch'))
|
|
19761
|
+
return parsed.searchParams.get('v');
|
|
19762
|
+
if (parsed.pathname.startsWith('/shorts/'))
|
|
19763
|
+
return parsed.pathname.slice('/shorts/'.length).split('/')[0] || null;
|
|
19764
|
+
return null;
|
|
19765
|
+
};
|
|
19766
|
+
// Most youtube links we get from the browser are watch URLs, like https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
19767
|
+
// These /watch URLs won't work in an iframe, so we need to convert them to the embed URL if iframe is used
|
|
19768
|
+
const normalizeYouTubeUrlToEmbedUrl = (url) => {
|
|
19769
|
+
let parsed;
|
|
19770
|
+
try {
|
|
19771
|
+
parsed = new URL(url);
|
|
19772
|
+
}
|
|
19773
|
+
catch {
|
|
19774
|
+
return url;
|
|
19775
|
+
}
|
|
19776
|
+
if (!YOUTUBE_HOSTS.has(parsed.hostname))
|
|
19777
|
+
return url;
|
|
19778
|
+
if (parsed.pathname.startsWith('/embed/'))
|
|
19779
|
+
return url;
|
|
19780
|
+
const videoId = extractVideoId(parsed);
|
|
19781
|
+
if (!videoId)
|
|
19782
|
+
return url;
|
|
19783
|
+
const embed = new URL(`https://www.youtube.com/embed/${videoId}`);
|
|
19784
|
+
const timestamp = parsed.searchParams.get('start') || parsed.searchParams.get('t');
|
|
19785
|
+
const start = timestamp ? toStartSeconds(timestamp) : null;
|
|
19786
|
+
if (start)
|
|
19787
|
+
embed.searchParams.set('start', start);
|
|
19788
|
+
return embed.toString();
|
|
19789
|
+
};
|
|
19790
|
+
|
|
19747
19791
|
;// ./components/Embed/index.tsx
|
|
19748
19792
|
/* eslint-disable no-param-reassign */
|
|
19749
19793
|
/* eslint-disable react/jsx-props-no-spreading */
|
|
19750
19794
|
|
|
19795
|
+
|
|
19751
19796
|
const Favicon = ({ src, alt = 'favicon', ...attr }) => (external_react_default().createElement("img", { ...attr, alt: alt, height: "14", src: src, width: "14" }));
|
|
19752
19797
|
const IFRAME_DERIVABLE_TYPES = new Set(['youtube', 'jsfiddle', 'pdf']);
|
|
19753
19798
|
// HTML width/height attrs accept bare numbers (interpreted as px), but CSS does not, convert.
|
|
@@ -19781,7 +19826,8 @@ const Embed = ({ lazy = true, url, html, providerName, providerUrl, title, ifram
|
|
|
19781
19826
|
// Fall back to a direct iframe for URL-derivable embed types when html is missing.
|
|
19782
19827
|
const renderTypeAsIframe = !html && !explicitOptOut && url && typeOfEmbed && IFRAME_DERIVABLE_TYPES.has(typeOfEmbed);
|
|
19783
19828
|
if (iframe || renderTypeAsIframe) {
|
|
19784
|
-
|
|
19829
|
+
const src = normalizeYouTubeUrlToEmbedUrl(url);
|
|
19830
|
+
return external_react_default().createElement("iframe", { ...spreadAttrs, src: src, style: iframeStyle, title: title });
|
|
19785
19831
|
}
|
|
19786
19832
|
if (!providerUrl && url)
|
|
19787
19833
|
providerUrl = new URL(url).hostname
|
|
@@ -120974,6 +121020,12 @@ const types_types = /** @type {const} */ ({
|
|
|
120974
121020
|
|
|
120975
121021
|
|
|
120976
121022
|
|
|
121023
|
+
|
|
121024
|
+
// Raw tags (type-1: pre/script/style/textarea) and block tags (type-6: div,
|
|
121025
|
+
// section, …) always start a block, so they stay flow even with trailing
|
|
121026
|
+
// content. Other lowercase tags (i, span, …) follow the type-7 rule and only
|
|
121027
|
+
// stay flow when nothing trails the close tag.
|
|
121028
|
+
const htmlFlowTagNames = new Set([...htmlRawNames, ...htmlBlockNames]);
|
|
120977
121029
|
const syntax_nonLazyContinuationStart = {
|
|
120978
121030
|
tokenize: syntax_tokenizeNonLazyContinuationStart,
|
|
120979
121031
|
partial: true,
|
|
@@ -121010,11 +121062,12 @@ const mdxComponentTextConstruct = {
|
|
|
121010
121062
|
* lowercase HTML tags that carry at least one `{…}` attribute expression.
|
|
121011
121063
|
* Multi-line, concrete, `afterClose` consumes the rest of the line.
|
|
121012
121064
|
*
|
|
121013
|
-
* **Text** — runs inside paragraphs / inline context. Claims
|
|
121014
|
-
*
|
|
121015
|
-
*
|
|
121016
|
-
*
|
|
121017
|
-
*
|
|
121065
|
+
* **Text** — runs inside paragraphs / inline context. Claims lowercase tags and
|
|
121066
|
+
* inline PascalCase components (`INLINE_COMPONENT_TAGS` — Anchor, Glossary), both
|
|
121067
|
+
* gated on at least one `{…}` brace attribute. All other PascalCase stays
|
|
121068
|
+
* flow-only, matching how ReadMe's custom components are authored. Aborts on line
|
|
121069
|
+
* endings (inline constructs don't span lines) and exits immediately after
|
|
121070
|
+
* `</tag>` so the paragraph's inline parser picks up the trailing text.
|
|
121018
121071
|
*/
|
|
121019
121072
|
function createTokenize(mode) {
|
|
121020
121073
|
const isFlow = mode === 'flow';
|
|
@@ -121026,8 +121079,9 @@ function createTokenize(mode) {
|
|
|
121026
121079
|
let closingTagName = '';
|
|
121027
121080
|
// For lowercase tags we only want to claim the block if it uses JSX
|
|
121028
121081
|
// attribute expression syntax (`attr={...}`). Plain HTML should fall
|
|
121029
|
-
// through to CommonMark html-flow.
|
|
121030
|
-
//
|
|
121082
|
+
// through to CommonMark html-flow. Flow mode claims any PascalCase block
|
|
121083
|
+
// component; text mode claims only inline PascalCase components
|
|
121084
|
+
// (INLINE_COMPONENT_TAGS — Anchor, Glossary), also brace-gated.
|
|
121031
121085
|
let isLowercaseTag = false;
|
|
121032
121086
|
let sawBraceAttr = false;
|
|
121033
121087
|
// Code span tracking
|
|
@@ -121038,6 +121092,9 @@ function createTokenize(mode) {
|
|
|
121038
121092
|
let fenceLength = 0;
|
|
121039
121093
|
let fenceCloseLength = 0;
|
|
121040
121094
|
let atLineStart = false;
|
|
121095
|
+
// True once this construct consumes any line ending; lets `afterClose`
|
|
121096
|
+
// treat only single-line lowercase tags as inline candidates.
|
|
121097
|
+
let sawLineEnding = false;
|
|
121041
121098
|
// Bail when the opener line has unmatched tag-like tokens in its body.
|
|
121042
121099
|
// `<Foo>_<Bar>.csv` leaves opens > closes; matched shapes like
|
|
121043
121100
|
// `<Callout>x <strong>y</strong>` balance to 0. Without this,
|
|
@@ -121188,13 +121245,13 @@ function createTokenize(mode) {
|
|
|
121188
121245
|
}
|
|
121189
121246
|
// ── Tag name parsing ───────────────────────────────────────────────────
|
|
121190
121247
|
function tagNameFirst(code) {
|
|
121191
|
-
// Uppercase A-Z → PascalCase MDX component. Flow
|
|
121192
|
-
// components
|
|
121248
|
+
// Uppercase A-Z → PascalCase MDX component. Flow mode claims block
|
|
121249
|
+
// components; text mode only claims inline components (Anchor, Glossary),
|
|
121250
|
+
// which is enforced once the full name is known in `tagNameRest`.
|
|
121193
121251
|
if (code !== null && code >= codes.uppercaseA && code <= codes.uppercaseZ) {
|
|
121194
|
-
if (!isFlow)
|
|
121195
|
-
return nok(code);
|
|
121196
121252
|
tagName = String.fromCharCode(code);
|
|
121197
121253
|
isLowercaseTag = false;
|
|
121254
|
+
sawBraceAttr = false;
|
|
121198
121255
|
effects.consume(code);
|
|
121199
121256
|
return tagNameRest;
|
|
121200
121257
|
}
|
|
@@ -121222,10 +121279,18 @@ function createTokenize(mode) {
|
|
|
121222
121279
|
effects.consume(code);
|
|
121223
121280
|
return tagNameRest;
|
|
121224
121281
|
}
|
|
121225
|
-
// Tag name complete —
|
|
121226
|
-
|
|
121282
|
+
// Tag name complete — decide whether this tokenizer claims the tag.
|
|
121283
|
+
// Three cases: lowercase tags are always candidates (brace-gated later in
|
|
121284
|
+
// `afterOpenTagName`); flow-mode PascalCase claims any block component
|
|
121285
|
+
// except those with a dedicated tokenizer; text-mode PascalCase claims
|
|
121286
|
+
// only inline components (Anchor, Glossary).
|
|
121287
|
+
const claimable = isLowercaseTag
|
|
121288
|
+
? true
|
|
121289
|
+
: isFlow
|
|
121290
|
+
? !TOKENIZER_MDX_COMPONENT_EXCLUDED_TAGS.has(tagName)
|
|
121291
|
+
: INLINE_COMPONENT_TAGS.has(tagName);
|
|
121292
|
+
if (!claimable)
|
|
121227
121293
|
return nok(code);
|
|
121228
|
-
}
|
|
121229
121294
|
depth = 1;
|
|
121230
121295
|
return afterOpenTagName(code);
|
|
121231
121296
|
}
|
|
@@ -121233,6 +121298,10 @@ function createTokenize(mode) {
|
|
|
121233
121298
|
function afterOpenTagName(code) {
|
|
121234
121299
|
if (code === null)
|
|
121235
121300
|
return nok(code);
|
|
121301
|
+
// Everything except a flow-mode PascalCase block component must carry a
|
|
121302
|
+
// `{…}` brace attribute to be claimed; plain HTML falls through to
|
|
121303
|
+
// CommonMark.
|
|
121304
|
+
const requiresBraceAttr = isLowercaseTag || !isFlow;
|
|
121236
121305
|
if (markdownLineEnding(code)) {
|
|
121237
121306
|
if (!isFlow)
|
|
121238
121307
|
return nok(code);
|
|
@@ -121241,14 +121310,14 @@ function createTokenize(mode) {
|
|
|
121241
121310
|
}
|
|
121242
121311
|
// Self-closing />
|
|
121243
121312
|
if (code === codes.slash) {
|
|
121244
|
-
if (
|
|
121313
|
+
if (requiresBraceAttr && !sawBraceAttr)
|
|
121245
121314
|
return nok(code);
|
|
121246
121315
|
effects.consume(code);
|
|
121247
121316
|
return selfCloseGt;
|
|
121248
121317
|
}
|
|
121249
121318
|
// End of opening tag
|
|
121250
121319
|
if (code === codes.greaterThan) {
|
|
121251
|
-
if (
|
|
121320
|
+
if (requiresBraceAttr && !sawBraceAttr)
|
|
121252
121321
|
return nok(code);
|
|
121253
121322
|
effects.consume(code);
|
|
121254
121323
|
onOpenerLine = isFlow;
|
|
@@ -121312,6 +121381,7 @@ function createTokenize(mode) {
|
|
|
121312
121381
|
return effects.check(syntax_nonLazyContinuationStart, openTagContinuationNonLazy, continuationAfter)(code);
|
|
121313
121382
|
}
|
|
121314
121383
|
function openTagContinuationNonLazy(code) {
|
|
121384
|
+
sawLineEnding = true;
|
|
121315
121385
|
effects.enter(types_types.lineEnding);
|
|
121316
121386
|
effects.consume(code);
|
|
121317
121387
|
effects.exit(types_types.lineEnding);
|
|
@@ -121435,6 +121505,7 @@ function createTokenize(mode) {
|
|
|
121435
121505
|
return effects.check(syntax_nonLazyContinuationStart, fencedCodeContinuationNonLazy, continuationAfter)(code);
|
|
121436
121506
|
}
|
|
121437
121507
|
function fencedCodeContinuationNonLazy(code) {
|
|
121508
|
+
sawLineEnding = true;
|
|
121438
121509
|
effects.enter(types_types.lineEnding);
|
|
121439
121510
|
effects.consume(code);
|
|
121440
121511
|
effects.exit(types_types.lineEnding);
|
|
@@ -121591,6 +121662,12 @@ function createTokenize(mode) {
|
|
|
121591
121662
|
effects.exit('mdxComponent');
|
|
121592
121663
|
return ok(code);
|
|
121593
121664
|
}
|
|
121665
|
+
// A single-line type-7 lowercase tag with content trailing its close is
|
|
121666
|
+
// inline, so `<i …></i> <a>…</a>` stays on one line instead of splitting
|
|
121667
|
+
// into separate blocks. Raw/block tags (pre, div, …) stay flow.
|
|
121668
|
+
if (isLowercaseTag && !sawLineEnding && !htmlFlowTagNames.has(tagName)) {
|
|
121669
|
+
return afterCloseInlineCandidate(code);
|
|
121670
|
+
}
|
|
121594
121671
|
if (code === null || markdownLineEnding(code)) {
|
|
121595
121672
|
effects.exit('mdxComponentData');
|
|
121596
121673
|
effects.exit('mdxComponent');
|
|
@@ -121601,11 +121678,26 @@ function createTokenize(mode) {
|
|
|
121601
121678
|
effects.consume(code);
|
|
121602
121679
|
return afterClose;
|
|
121603
121680
|
}
|
|
121681
|
+
// Whitespace-only to the line ending keeps the flow block; any other
|
|
121682
|
+
// trailing char means inline content, so refuse and let inline parsing run.
|
|
121683
|
+
function afterCloseInlineCandidate(code) {
|
|
121684
|
+
if (code === null || markdownLineEnding(code)) {
|
|
121685
|
+
effects.exit('mdxComponentData');
|
|
121686
|
+
effects.exit('mdxComponent');
|
|
121687
|
+
return ok(code);
|
|
121688
|
+
}
|
|
121689
|
+
if (markdownSpace(code)) {
|
|
121690
|
+
effects.consume(code);
|
|
121691
|
+
return afterCloseInlineCandidate;
|
|
121692
|
+
}
|
|
121693
|
+
return nok(code);
|
|
121694
|
+
}
|
|
121604
121695
|
// ── Body continuation (line endings) ───────────────────────────────────
|
|
121605
121696
|
function bodyContinuationStart(code) {
|
|
121606
121697
|
return effects.check(syntax_nonLazyContinuationStart, bodyContinuationNonLazy, continuationAfter)(code);
|
|
121607
121698
|
}
|
|
121608
121699
|
function bodyContinuationNonLazy(code) {
|
|
121700
|
+
sawLineEnding = true;
|
|
121609
121701
|
effects.enter(types_types.lineEnding);
|
|
121610
121702
|
effects.consume(code);
|
|
121611
121703
|
effects.exit(types_types.lineEnding);
|
|
@@ -121675,12 +121767,13 @@ function syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
|
|
|
121675
121767
|
* self-closing `<Component />`). Prevents CommonMark from fragmenting them
|
|
121676
121768
|
* across multiple HTML / paragraph nodes.
|
|
121677
121769
|
*
|
|
121678
|
-
* **Text (inline)** — registers
|
|
121679
|
-
* (
|
|
121680
|
-
*
|
|
121681
|
-
*
|
|
121682
|
-
*
|
|
121683
|
-
*
|
|
121770
|
+
* **Text (inline)** — registers for lowercase tags and inline PascalCase
|
|
121771
|
+
* components (Anchor, Glossary) that carry brace attrs (e.g.
|
|
121772
|
+
* `Start <a href={url}>here</a> end`, `<Anchor href={url}>x</Anchor>`). Picks
|
|
121773
|
+
* them up during inline parsing so they render inline inside their paragraph,
|
|
121774
|
+
* then are rewritten to `mdxJsxTextElement` by the `components/inline-html`
|
|
121775
|
+
* transformer. All other PascalCase is flow-only; ReadMe's custom components
|
|
121776
|
+
* are authored as block-level elements.
|
|
121684
121777
|
*
|
|
121685
121778
|
* Excludes tags handled by dedicated tokenizers: Table, HTMLBlock, Glossary,
|
|
121686
121779
|
* Anchor.
|
|
@@ -121799,12 +121892,12 @@ const parsePhrasingChildren = (value, safeMode) => {
|
|
|
121799
121892
|
return first?.type === 'paragraph' ? first.children : [];
|
|
121800
121893
|
};
|
|
121801
121894
|
/**
|
|
121802
|
-
* Attempt to promote
|
|
121803
|
-
* `
|
|
121804
|
-
*
|
|
121805
|
-
*
|
|
121806
|
-
* `mdxishComponentBlocks` so they remain `mdxJsxFlowElement`,
|
|
121807
|
-
* ReadMe's flow-level component authoring model.
|
|
121895
|
+
* Attempt to promote an inline `html` node to an `mdxJsxTextElement`. Scope
|
|
121896
|
+
* mirrors what the `mdxComponent` text tokenizer claims: lowercase tags and
|
|
121897
|
+
* inline PascalCase components (`INLINE_COMPONENT_TAGS` — Anchor, Glossary),
|
|
121898
|
+
* both carrying `{…}` attribute expressions. All other PascalCase components
|
|
121899
|
+
* stay with `mdxishComponentBlocks` so they remain `mdxJsxFlowElement`,
|
|
121900
|
+
* matching ReadMe's flow-level component authoring model.
|
|
121808
121901
|
*
|
|
121809
121902
|
* Returns the original node unchanged when it doesn't qualify.
|
|
121810
121903
|
*/
|
|
@@ -121813,12 +121906,11 @@ const promoteInlineHtml = (node, parseOpts, safeMode) => {
|
|
|
121813
121906
|
if (!parsed)
|
|
121814
121907
|
return node;
|
|
121815
121908
|
const { tag, attributes, selfClosing, contentAfterTag = '' } = parsed;
|
|
121816
|
-
// PascalCase stays flow-level
|
|
121817
|
-
|
|
121818
|
-
|
|
121819
|
-
//
|
|
121820
|
-
|
|
121821
|
-
if (GENERIC_MDX_COMPONENT_EXCLUDED_TAGS.has(tag))
|
|
121909
|
+
// Non-inline PascalCase stays flow-level (handled by mdxishComponentBlocks)
|
|
121910
|
+
// and dedicated tokenizers (Table, HTMLBlock) own their tags. Inline
|
|
121911
|
+
// components (Anchor, Glossary) with expression attrs are promoted here —
|
|
121912
|
+
// the text tokenizer captures them as a single html node.
|
|
121913
|
+
if (isPascalCase(tag) && !INLINE_COMPONENT_TAGS.has(tag))
|
|
121822
121914
|
return node;
|
|
121823
121915
|
// Plain inline HTML (no expressions) stays as an html node so rehype-raw
|
|
121824
121916
|
// parses it with parse5 as normal.
|
|
@@ -121842,14 +121934,15 @@ const promoteInlineHtml = (node, parseOpts, safeMode) => {
|
|
|
121842
121934
|
* Runs after `mdxishComponentBlocks`, which skips paragraph-parented html
|
|
121843
121935
|
* nodes and leaves them for this pass. Two producers put html nodes inside
|
|
121844
121936
|
* paragraphs:
|
|
121845
|
-
* 1. The `mdxComponent` text tokenizer, for lowercase tags
|
|
121846
|
-
*
|
|
121937
|
+
* 1. The `mdxComponent` text tokenizer, for lowercase tags and inline
|
|
121938
|
+
* PascalCase components (Anchor, Glossary) with `{…}` attribute
|
|
121939
|
+
* expressions (e.g. `<a href={url}>here</a>`, `<Anchor href={url}>x</Anchor>`).
|
|
121847
121940
|
* 2. CommonMark's built-in html-text tokenizer, for PascalCase components
|
|
121848
121941
|
* (e.g. a single html node for self-closing `<C />`).
|
|
121849
121942
|
*
|
|
121850
|
-
* Eligibility mirrors `mdxishComponentBlocks`:
|
|
121851
|
-
*
|
|
121852
|
-
* `<a href="x">` stays as an html node for rehype-raw.
|
|
121943
|
+
* Eligibility mirrors `mdxishComponentBlocks`: a tag only promotes when it
|
|
121944
|
+
* carries an expression attribute and isn't a non-inline PascalCase component;
|
|
121945
|
+
* plain inline HTML like `<a href="x">` stays as an html node for rehype-raw.
|
|
121853
121946
|
*/
|
|
121854
121947
|
const mdxishInlineMdxHtmlBlocks = (opts = {}) => tree => {
|
|
121855
121948
|
const safeMode = !!opts.safeMode;
|
|
@@ -122297,12 +122390,60 @@ function restoreSnakeCase(placeholderName, mapping) {
|
|
|
122297
122390
|
return matchingKey ? mapping[matchingKey] : placeholderName;
|
|
122298
122391
|
}
|
|
122299
122392
|
|
|
122393
|
+
;// ./processor/transform/mdxish/resolve-esm-imports.ts
|
|
122394
|
+
|
|
122395
|
+
// We provide React as a default module so that components can use hooks
|
|
122396
|
+
// and it's a common use case. Add other common libraries here.
|
|
122397
|
+
const defaultModuleRegistry = { react: (external_react_default()) };
|
|
122398
|
+
const isRecord = (value) => typeof value === 'object' && value !== null;
|
|
122399
|
+
// Get the value of a named export from a module
|
|
122400
|
+
const getModuleExport = (module, importedName) => isRecord(module) && importedName in module ? module[importedName] : undefined;
|
|
122401
|
+
/**
|
|
122402
|
+
* Turn `import` declarations into a flat map of binding → value.
|
|
122403
|
+
*
|
|
122404
|
+
* A "binding" is a mapping of a local name to the value of it in the module exports
|
|
122405
|
+
* Example: `import { useState } from 'react'` yields `{ useState: React.useState }`.
|
|
122406
|
+
*
|
|
122407
|
+
* Unsupported specifiers are skipped with a warning rather than throwing, so a
|
|
122408
|
+
* single unknown import can't break the rest of the document.
|
|
122409
|
+
*/
|
|
122410
|
+
const collectImportValues = (importDeclarations, registry = defaultModuleRegistry) => {
|
|
122411
|
+
const importValues = {};
|
|
122412
|
+
importDeclarations.forEach(declaration => {
|
|
122413
|
+
const libraryName = declaration.source.value;
|
|
122414
|
+
if (typeof libraryName !== 'string')
|
|
122415
|
+
return;
|
|
122416
|
+
if (!(libraryName in registry)) {
|
|
122417
|
+
// eslint-disable-next-line no-console
|
|
122418
|
+
console.warn(`[WARNING] Cannot resolve import "${libraryName}"; it is not a supported library.`);
|
|
122419
|
+
return;
|
|
122420
|
+
}
|
|
122421
|
+
const module = registry[libraryName];
|
|
122422
|
+
declaration.specifiers.forEach(spec => {
|
|
122423
|
+
// Default (`import React`) and namespace (`import * as React`) both bind
|
|
122424
|
+
// the whole module under the local name.
|
|
122425
|
+
if (spec.type === 'ImportDefaultSpecifier' || spec.type === 'ImportNamespaceSpecifier') {
|
|
122426
|
+
importValues[spec.local.name] = module;
|
|
122427
|
+
}
|
|
122428
|
+
else if (spec.type === 'ImportSpecifier') {
|
|
122429
|
+
// Named imports (e.g. `import { useState } from 'react'`, useState is the import name)
|
|
122430
|
+
const importName = spec.imported.type === 'Identifier' ? spec.imported.name : spec.imported.value;
|
|
122431
|
+
if (typeof importName === 'string') {
|
|
122432
|
+
importValues[spec.local.name] = getModuleExport(module, importName);
|
|
122433
|
+
}
|
|
122434
|
+
}
|
|
122435
|
+
});
|
|
122436
|
+
});
|
|
122437
|
+
return importValues;
|
|
122438
|
+
};
|
|
122439
|
+
|
|
122300
122440
|
;// ./processor/transform/mdxish/evaluate-exports.ts
|
|
122301
122441
|
|
|
122302
122442
|
|
|
122303
122443
|
|
|
122304
122444
|
|
|
122305
122445
|
|
|
122446
|
+
|
|
122306
122447
|
/**
|
|
122307
122448
|
* Recursively extract all identifier names introduced by a binding pattern.
|
|
122308
122449
|
* Handles destructuring (`{ a, b }`, `[x, y]`), rest elements (`...rest`),
|
|
@@ -122350,6 +122491,7 @@ const collectExportNames = (declaration) => {
|
|
|
122350
122491
|
const evaluateExports = () => (tree, file) => {
|
|
122351
122492
|
const programBody = [];
|
|
122352
122493
|
const exportNames = [];
|
|
122494
|
+
const importDeclarations = [];
|
|
122353
122495
|
const nodesToRemove = [];
|
|
122354
122496
|
visit(tree, isMDXEsm, (node, index, parent) => {
|
|
122355
122497
|
if (parent && typeof index === 'number') {
|
|
@@ -122363,6 +122505,10 @@ const evaluateExports = () => (tree, file) => {
|
|
|
122363
122505
|
// handled the same as a named export — the inner declaration carries the
|
|
122364
122506
|
// binding name
|
|
122365
122507
|
estreeBody.forEach(statement => {
|
|
122508
|
+
if (statement.type === 'ImportDeclaration') {
|
|
122509
|
+
importDeclarations.push(statement);
|
|
122510
|
+
return;
|
|
122511
|
+
}
|
|
122366
122512
|
let declaration = null;
|
|
122367
122513
|
if (statement.type === 'ExportNamedDeclaration' && statement.declaration) {
|
|
122368
122514
|
declaration = statement.declaration;
|
|
@@ -122390,9 +122536,11 @@ const evaluateExports = () => (tree, file) => {
|
|
|
122390
122536
|
const program = { type: 'Program', sourceType: 'module', body: programBody };
|
|
122391
122537
|
buildJsx(program, { runtime: 'classic', pragma: 'React.createElement', pragmaFrag: 'React.Fragment' });
|
|
122392
122538
|
const { value: source } = toJs(program);
|
|
122539
|
+
// Make sure import values are available in the scope
|
|
122540
|
+
const importValues = collectImportValues(importDeclarations);
|
|
122393
122541
|
// Evaluate and build on the expression source
|
|
122394
122542
|
// Use react to compile JSX codes
|
|
122395
|
-
const evaluatedExports = evaluate(`(() => { ${source}\nreturn { ${exportNames.join(', ')} }; })()`, { React: (external_react_default()) });
|
|
122543
|
+
const evaluatedExports = evaluate(`(() => { ${source}\nreturn { ${exportNames.join(', ')} }; })()`, { React: (external_react_default()), ...importValues });
|
|
122396
122544
|
Object.assign(scope, evaluatedExports);
|
|
122397
122545
|
}
|
|
122398
122546
|
catch (error) {
|
|
@@ -124346,214 +124494,21 @@ const normalizeMdxJsxNodes = () => tree => {
|
|
|
124346
124494
|
*/
|
|
124347
124495
|
const JSX_COMMENT_REGEX = /\{\/\*[^*]*(?:\*(?!\/)[^*]*)*\*\/\}/g;
|
|
124348
124496
|
|
|
124349
|
-
;// ./processor/transform/mdxish/
|
|
124350
|
-
|
|
124497
|
+
;// ./processor/transform/mdxish/remove-jsx-comments.ts
|
|
124351
124498
|
|
|
124352
124499
|
/**
|
|
124353
124500
|
* Removes JSX-style comments (e.g., { /* comment *\/ }) from content.
|
|
124354
124501
|
*
|
|
124355
|
-
*
|
|
124356
|
-
*
|
|
124357
|
-
*
|
|
124502
|
+
* `@param` content
|
|
124503
|
+
* `@returns` Content with JSX comments removed
|
|
124504
|
+
* `@example`
|
|
124358
124505
|
* ```typescript
|
|
124359
|
-
* removeJSXComments('Text {
|
|
124360
|
-
* // Returns: 'Text more text'
|
|
124506
|
+
* removeJSXComments('Text {/* comment *\/} more text') // => 'Text more text'
|
|
124361
124507
|
* ```
|
|
124362
124508
|
*/
|
|
124363
124509
|
function removeJSXComments(content) {
|
|
124364
124510
|
return content.replace(JSX_COMMENT_REGEX, '');
|
|
124365
124511
|
}
|
|
124366
|
-
const HTML_ELEM_PLACEHOLDER_PREFIX = '___MDXISH_HTML_ELEM_';
|
|
124367
|
-
const HTML_ELEM_PLACEHOLDER = new RegExp(`${HTML_ELEM_PLACEHOLDER_PREFIX}(\\d+)___`, 'g');
|
|
124368
|
-
// Matches an HTML element that starts at a line boundary and ends at a line boundary.
|
|
124369
|
-
// Allows optional leading indentation and lazily matches until the same closing tag.
|
|
124370
|
-
const BLOCK_HTML_RE = /(?<=^|\n)[ \t]*<([a-z][a-zA-Z0-9]*)(?:\s[^>]*)?>[\s\S]*?<\/\1>[ \t]*(?=\n|$)/g;
|
|
124371
|
-
/**
|
|
124372
|
-
* Hides line-anchored HTML elements from the brace-escaping pass so we don't leak `\{`
|
|
124373
|
-
* into rendered output (rehypeRaw renders the `\` literally, e.g. `<div>{foo</div>`).
|
|
124374
|
-
*
|
|
124375
|
-
* One carve-out: if an interior line at column 0 has bare text containing `{`, mdxish
|
|
124376
|
-
* parses that line as a paragraph and the mdxExpression step would throw without an
|
|
124377
|
-
* escape — so we leave that case to the brace balancer.
|
|
124378
|
-
*/
|
|
124379
|
-
function protectHTMLElements(content) {
|
|
124380
|
-
const htmlElements = [];
|
|
124381
|
-
const protectedContent = content.replace(BLOCK_HTML_RE, match => {
|
|
124382
|
-
// Look at the lines between the open and close tags. If any of them starts
|
|
124383
|
-
// at column 0 with bare text (not whitespace, not another tag) and contains
|
|
124384
|
-
// `{`, mdxish will parse that line as a paragraph and the brace as an MDX
|
|
124385
|
-
// expression, which would throw an error. So we let the brace balancer escape it.
|
|
124386
|
-
// Otherwise, we need to extract the sequence to protect it from the brace escaping.
|
|
124387
|
-
const interior = match.split('\n').slice(1, -1);
|
|
124388
|
-
const hazard = interior.some(line => line.length > 0 && line[0] !== ' ' && line[0] !== '\t' && line[0] !== '<' && line.includes('{'));
|
|
124389
|
-
if (hazard)
|
|
124390
|
-
return match;
|
|
124391
|
-
htmlElements.push(match);
|
|
124392
|
-
return `${HTML_ELEM_PLACEHOLDER_PREFIX}${htmlElements.length - 1}___`;
|
|
124393
|
-
});
|
|
124394
|
-
return { htmlElements, protectedContent };
|
|
124395
|
-
}
|
|
124396
|
-
function restoreHTMLElements(content, htmlElements) {
|
|
124397
|
-
if (htmlElements.length === 0)
|
|
124398
|
-
return content;
|
|
124399
|
-
return content.replace(HTML_ELEM_PLACEHOLDER, (_m, idx) => htmlElements[parseInt(idx, 10)]);
|
|
124400
|
-
}
|
|
124401
|
-
const ESM_DECLARATION_START = /^(?:export|import)\b/;
|
|
124402
|
-
/**
|
|
124403
|
-
* Whether a line begins a top-level `export`/`import` declaration. Its braces
|
|
124404
|
-
* are valid JS owned by the mdxjsEsm tokenizer (which tolerates blank lines),
|
|
124405
|
-
* so escaping them would corrupt the source and break acorn parsing.
|
|
124406
|
-
*/
|
|
124407
|
-
function startsEsmDeclaration(chars, lineStart) {
|
|
124408
|
-
return ESM_DECLARATION_START.test(chars.slice(lineStart, lineStart + 7).join(''));
|
|
124409
|
-
}
|
|
124410
|
-
function isBlankLine(chars, lineStart) {
|
|
124411
|
-
for (let i = lineStart; i < chars.length; i += 1) {
|
|
124412
|
-
if (chars[i] === '\n')
|
|
124413
|
-
return true;
|
|
124414
|
-
if (chars[i] !== ' ' && chars[i] !== '\t')
|
|
124415
|
-
return false;
|
|
124416
|
-
}
|
|
124417
|
-
return true;
|
|
124418
|
-
}
|
|
124419
|
-
/**
|
|
124420
|
-
* Escapes unbalanced and paragraph-spanning braces so MDX doesn't trip on them.
|
|
124421
|
-
*/
|
|
124422
|
-
function escapeProblematicBraces(content) {
|
|
124423
|
-
const { htmlElements, protectedContent } = protectHTMLElements(content);
|
|
124424
|
-
let strDelim = null;
|
|
124425
|
-
let strEscaped = false;
|
|
124426
|
-
// Track position of last newline (outside strings) to detect blank lines
|
|
124427
|
-
// -2 means no recent newline
|
|
124428
|
-
let lastNewlinePos = -2;
|
|
124429
|
-
// Character state machine trackers
|
|
124430
|
-
const toEscape = new Set();
|
|
124431
|
-
// Convert to array of Unicode code points so that emojis and multi-byte characters are correctly tracked
|
|
124432
|
-
const chars = Array.from(protectedContent);
|
|
124433
|
-
const openStack = [];
|
|
124434
|
-
// Whether the current top-level statement is an `export`/`import` declaration.
|
|
124435
|
-
let insideEsmDeclaration = false;
|
|
124436
|
-
for (let i = 0; i < chars.length; i += 1) {
|
|
124437
|
-
const ch = chars[i];
|
|
124438
|
-
// At a top-level (brace depth 0) line start, decide whether we're inside an
|
|
124439
|
-
// ESM declaration. The flag persists across the declaration's own lines.
|
|
124440
|
-
if (openStack.length === 0 && (i === 0 || chars[i - 1] === '\n')) {
|
|
124441
|
-
if (startsEsmDeclaration(chars, i))
|
|
124442
|
-
insideEsmDeclaration = true;
|
|
124443
|
-
else if (isBlankLine(chars, i))
|
|
124444
|
-
insideEsmDeclaration = false;
|
|
124445
|
-
}
|
|
124446
|
-
// Track string delimiters inside expressions to ignore braces within them
|
|
124447
|
-
if (openStack.length > 0) {
|
|
124448
|
-
if (strDelim) {
|
|
124449
|
-
if (strEscaped)
|
|
124450
|
-
strEscaped = false;
|
|
124451
|
-
else if (ch === '\\')
|
|
124452
|
-
strEscaped = true;
|
|
124453
|
-
else if (ch === strDelim)
|
|
124454
|
-
strDelim = null;
|
|
124455
|
-
// eslint-disable-next-line no-continue
|
|
124456
|
-
continue;
|
|
124457
|
-
}
|
|
124458
|
-
if (ch === '"' || ch === "'" || ch === '`') {
|
|
124459
|
-
strDelim = ch;
|
|
124460
|
-
// eslint-disable-next-line no-continue
|
|
124461
|
-
continue;
|
|
124462
|
-
}
|
|
124463
|
-
if (ch === '\n') {
|
|
124464
|
-
if (lastNewlinePos >= 0) {
|
|
124465
|
-
const between = chars.slice(lastNewlinePos + 1, i).join('');
|
|
124466
|
-
if (/^[ \t]*$/.test(between)) {
|
|
124467
|
-
openStack.forEach(entry => { entry.hasBlankLine = true; });
|
|
124468
|
-
}
|
|
124469
|
-
}
|
|
124470
|
-
lastNewlinePos = i;
|
|
124471
|
-
}
|
|
124472
|
-
}
|
|
124473
|
-
// Skip already-escaped braces (odd run of preceding backslashes).
|
|
124474
|
-
if (ch === '{' || ch === '}') {
|
|
124475
|
-
let bs = 0;
|
|
124476
|
-
for (let j = i - 1; j >= 0 && chars[j] === '\\'; j -= 1)
|
|
124477
|
-
bs += 1;
|
|
124478
|
-
if (bs % 2 === 1) {
|
|
124479
|
-
// eslint-disable-next-line no-continue
|
|
124480
|
-
continue;
|
|
124481
|
-
}
|
|
124482
|
-
}
|
|
124483
|
-
if (ch === '{') {
|
|
124484
|
-
// `=` (after whitespace) before `{` ⇒ JSX attribute expression. The
|
|
124485
|
-
// mdxComponent tokenizer captures the whole component, so blank lines
|
|
124486
|
-
// inside attribute values are harmless. Nested `{` inherits the flag.
|
|
124487
|
-
let isAttrExpr = false;
|
|
124488
|
-
for (let j = i - 1; j >= 0; j -= 1) {
|
|
124489
|
-
const pc = chars[j];
|
|
124490
|
-
if (pc === '=') {
|
|
124491
|
-
isAttrExpr = true;
|
|
124492
|
-
break;
|
|
124493
|
-
}
|
|
124494
|
-
if (pc !== ' ' && pc !== '\t')
|
|
124495
|
-
break;
|
|
124496
|
-
}
|
|
124497
|
-
// Nested `{ ... }` inside an attribute value (e.g. `data={[{ ... }]}` or
|
|
124498
|
-
// `data={{ a: { b: 1 } }}`) must inherit the same exemption; only the
|
|
124499
|
-
// outer `{` is directly after `=`.
|
|
124500
|
-
if (!isAttrExpr && openStack.length > 0 && openStack[openStack.length - 1].isAttrExpr) {
|
|
124501
|
-
isAttrExpr = true;
|
|
124502
|
-
}
|
|
124503
|
-
openStack.push({ pos: i, hasBlankLine: false, isAttrExpr, isEsmDeclaration: insideEsmDeclaration });
|
|
124504
|
-
lastNewlinePos = -2;
|
|
124505
|
-
}
|
|
124506
|
-
else if (ch === '}') {
|
|
124507
|
-
if (openStack.length > 0) {
|
|
124508
|
-
const entry = openStack.pop();
|
|
124509
|
-
// The declaration's braces are closed; later top-level braces are not ESM.
|
|
124510
|
-
if (openStack.length === 0)
|
|
124511
|
-
insideEsmDeclaration = false;
|
|
124512
|
-
// Pure `{/* ... */}` comments are handled downstream by the jsxComment
|
|
124513
|
-
// tokenizer — escaping their braces would prevent it from running.
|
|
124514
|
-
const isPureJsxComment = chars[entry.pos + 1] === '/' &&
|
|
124515
|
-
chars[entry.pos + 2] === '*' &&
|
|
124516
|
-
chars[i - 1] === '/' &&
|
|
124517
|
-
chars[i - 2] === '*';
|
|
124518
|
-
if (entry.hasBlankLine && !isPureJsxComment && !entry.isAttrExpr && !entry.isEsmDeclaration) {
|
|
124519
|
-
toEscape.add(entry.pos);
|
|
124520
|
-
toEscape.add(i);
|
|
124521
|
-
}
|
|
124522
|
-
}
|
|
124523
|
-
else {
|
|
124524
|
-
toEscape.add(i);
|
|
124525
|
-
}
|
|
124526
|
-
}
|
|
124527
|
-
else if (ch === ';' && openStack.length === 0) {
|
|
124528
|
-
// A top-level `;` ends the current statement, ESM or otherwise.
|
|
124529
|
-
insideEsmDeclaration = false;
|
|
124530
|
-
}
|
|
124531
|
-
}
|
|
124532
|
-
// Anything still open is unbalanced.
|
|
124533
|
-
openStack.forEach(entry => {
|
|
124534
|
-
if (!entry.isEsmDeclaration)
|
|
124535
|
-
toEscape.add(entry.pos);
|
|
124536
|
-
});
|
|
124537
|
-
// Reconstruct the content with the escaped braces.
|
|
124538
|
-
const escapedContent = toEscape.size === 0 ? protectedContent : chars.map((ch, i) => (toEscape.has(i) ? `\\${ch}` : ch)).join('');
|
|
124539
|
-
return restoreHTMLElements(escapedContent, htmlElements);
|
|
124540
|
-
}
|
|
124541
|
-
/**
|
|
124542
|
-
* Preprocesses JSX-like markdown content before parsing.
|
|
124543
|
-
*
|
|
124544
|
-
* JSX attribute expressions (`href={baseUrl}`) are no longer rewritten here —
|
|
124545
|
-
* they flow through the tokenizer as `mdxJsxAttributeValueExpression` nodes
|
|
124546
|
-
* and are evaluated at the hast handler step.
|
|
124547
|
-
*
|
|
124548
|
-
* @param content
|
|
124549
|
-
* @returns Preprocessed content ready for markdown parsing
|
|
124550
|
-
*/
|
|
124551
|
-
function preprocessJSXExpressions(content) {
|
|
124552
|
-
const { protectedCode, protectedContent } = protectCodeBlocks(content);
|
|
124553
|
-
let processed = escapeProblematicBraces(protectedContent);
|
|
124554
|
-
processed = restoreCodeBlocks(processed, protectedCode);
|
|
124555
|
-
return processed;
|
|
124556
|
-
}
|
|
124557
124512
|
|
|
124558
124513
|
;// ./processor/transform/mdxish/resolve-deferred-attribute-expression-props.ts
|
|
124559
124514
|
|
|
@@ -125528,6 +125483,85 @@ function jsxTable() {
|
|
|
125528
125483
|
;// ./lib/micromark/jsx-table/index.ts
|
|
125529
125484
|
|
|
125530
125485
|
|
|
125486
|
+
;// ./lib/micromark/mdx-expression-lenient/syntax.ts
|
|
125487
|
+
|
|
125488
|
+
|
|
125489
|
+
/**
|
|
125490
|
+
* Lenient MDX text-expression tokenizer (agnostic / no acorn).
|
|
125491
|
+
*
|
|
125492
|
+
* Matches a balanced `{ ... }` run — tracking nested braces and spanning soft
|
|
125493
|
+
* line breaks — and emits the standard `mdxTextExpression*` tokens so the
|
|
125494
|
+
* upstream `mdxExpressionFromMarkdown()` builds the node.
|
|
125495
|
+
*
|
|
125496
|
+
* Reimplements the official micromark mdxExpression, but an unbalanced brace that
|
|
125497
|
+
* reaches end of input returns `nok` instead of throwing: micromark rolls back
|
|
125498
|
+
* and the `{` renders as literal text, making the pipeline forgiving of stray
|
|
125499
|
+
* braces that upstream would hard-error on.
|
|
125500
|
+
*/
|
|
125501
|
+
function tokenizeTextExpression(effects, ok, nok) {
|
|
125502
|
+
let depth = 0;
|
|
125503
|
+
return start;
|
|
125504
|
+
function start(code) {
|
|
125505
|
+
if (code !== codes.leftCurlyBrace)
|
|
125506
|
+
return nok(code);
|
|
125507
|
+
effects.enter('mdxTextExpression');
|
|
125508
|
+
effects.enter('mdxTextExpressionMarker');
|
|
125509
|
+
effects.consume(code);
|
|
125510
|
+
effects.exit('mdxTextExpressionMarker');
|
|
125511
|
+
return before;
|
|
125512
|
+
}
|
|
125513
|
+
function before(code) {
|
|
125514
|
+
if (code === codes.eof) {
|
|
125515
|
+
effects.exit('mdxTextExpression');
|
|
125516
|
+
return nok(code);
|
|
125517
|
+
}
|
|
125518
|
+
if (markdownLineEnding(code)) {
|
|
125519
|
+
effects.enter('lineEnding');
|
|
125520
|
+
effects.consume(code);
|
|
125521
|
+
effects.exit('lineEnding');
|
|
125522
|
+
return before;
|
|
125523
|
+
}
|
|
125524
|
+
if (code === codes.rightCurlyBrace && depth === 0) {
|
|
125525
|
+
return close(code);
|
|
125526
|
+
}
|
|
125527
|
+
effects.enter('mdxTextExpressionChunk');
|
|
125528
|
+
return inside(code);
|
|
125529
|
+
}
|
|
125530
|
+
function inside(code) {
|
|
125531
|
+
if (code === codes.eof || markdownLineEnding(code)) {
|
|
125532
|
+
effects.exit('mdxTextExpressionChunk');
|
|
125533
|
+
return before(code);
|
|
125534
|
+
}
|
|
125535
|
+
if (code === codes.rightCurlyBrace && depth === 0) {
|
|
125536
|
+
effects.exit('mdxTextExpressionChunk');
|
|
125537
|
+
return close(code);
|
|
125538
|
+
}
|
|
125539
|
+
if (code === codes.leftCurlyBrace)
|
|
125540
|
+
depth += 1;
|
|
125541
|
+
else if (code === codes.rightCurlyBrace)
|
|
125542
|
+
depth -= 1;
|
|
125543
|
+
effects.consume(code);
|
|
125544
|
+
return inside;
|
|
125545
|
+
}
|
|
125546
|
+
function close(code) {
|
|
125547
|
+
effects.enter('mdxTextExpressionMarker');
|
|
125548
|
+
effects.consume(code);
|
|
125549
|
+
effects.exit('mdxTextExpressionMarker');
|
|
125550
|
+
effects.exit('mdxTextExpression');
|
|
125551
|
+
return ok;
|
|
125552
|
+
}
|
|
125553
|
+
}
|
|
125554
|
+
function mdxExpressionLenient() {
|
|
125555
|
+
return {
|
|
125556
|
+
text: {
|
|
125557
|
+
[codes.leftCurlyBrace]: {
|
|
125558
|
+
name: 'mdxTextExpression',
|
|
125559
|
+
tokenize: tokenizeTextExpression,
|
|
125560
|
+
},
|
|
125561
|
+
},
|
|
125562
|
+
};
|
|
125563
|
+
}
|
|
125564
|
+
|
|
125531
125565
|
;// ./lib/utils/mdxish/mdxish-load-components.ts
|
|
125532
125566
|
|
|
125533
125567
|
|
|
@@ -125640,7 +125674,7 @@ const defaultTransformers = [
|
|
|
125640
125674
|
* 1. Normalize malformed table separator syntax (e.g., `|: ---` → `| :---`)
|
|
125641
125675
|
* 2. Terminate HTML flow blocks so subsequent content isn't swallowed
|
|
125642
125676
|
* 3. Close invalid "self-closing" HTML tags (e.g., `<i />` → `<i></i>`)
|
|
125643
|
-
* 4.
|
|
125677
|
+
* 4. Normalize compact ATX headings (e.g., `#Heading` → `# Heading`)
|
|
125644
125678
|
* 5. Replace snake_case component names with parser-safe placeholders
|
|
125645
125679
|
*/
|
|
125646
125680
|
function preprocessContent(content, opts) {
|
|
@@ -125649,7 +125683,6 @@ function preprocessContent(content, opts) {
|
|
|
125649
125683
|
result = terminateHtmlFlowBlocks(result);
|
|
125650
125684
|
result = closeSelfClosingHtmlTags(result);
|
|
125651
125685
|
result = normalizeCompactHeadings(result);
|
|
125652
|
-
result = preprocessJSXExpressions(result);
|
|
125653
125686
|
return processSnakeCaseComponent(result, { knownComponents });
|
|
125654
125687
|
}
|
|
125655
125688
|
function mdxishAstProcessor(mdContent, opts = {}) {
|
|
@@ -125666,12 +125699,8 @@ function mdxishAstProcessor(mdContent, opts = {}) {
|
|
|
125666
125699
|
acc[key] = String(value);
|
|
125667
125700
|
return acc;
|
|
125668
125701
|
}, {});
|
|
125669
|
-
//
|
|
125670
|
-
|
|
125671
|
-
const mdxExprExt = mdxExpression({ allowEmpty: true });
|
|
125672
|
-
const mdxExprTextOnly = {
|
|
125673
|
-
text: mdxExprExt.text,
|
|
125674
|
-
};
|
|
125702
|
+
// Parser extension for MDX expressions {}
|
|
125703
|
+
const mdxExprTextOnly = mdxExpressionLenient();
|
|
125675
125704
|
const micromarkExts = [
|
|
125676
125705
|
jsxTable(),
|
|
125677
125706
|
magicBlock(),
|