@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.js
CHANGED
|
@@ -12060,10 +12060,55 @@ const Columns = ({ children, layout = 'auto' }) => {
|
|
|
12060
12060
|
};
|
|
12061
12061
|
/* harmony default export */ const components_Columns = (Columns);
|
|
12062
12062
|
|
|
12063
|
+
;// ./components/Embed/normalizeYouTubeUrl.ts
|
|
12064
|
+
// YouTube watch/share URLs (youtube.com/watch?v=ID, youtu.be/ID) set X-Frame-Options
|
|
12065
|
+
// and refuse to be framed. The player only allows embedding via youtube.com/embed/ID.
|
|
12066
|
+
const YOUTUBE_HOSTS = new Set(['youtube.com', 'www.youtube.com', 'm.youtube.com', 'youtu.be', 'www.youtu.be', 'm.youtu.be']);
|
|
12067
|
+
// /embed/ accepts `start` (integer seconds), not the watch-page `t` value which may carry units (e.g. 596s, 1h2m3s).
|
|
12068
|
+
const toStartSeconds = (timestamp) => {
|
|
12069
|
+
const [, hours, minutes, seconds] = timestamp.match(/^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s?)?$/) ?? [];
|
|
12070
|
+
const total = (Number(hours) || 0) * 3600 + (Number(minutes) || 0) * 60 + (Number(seconds) || 0);
|
|
12071
|
+
return total > 0 ? String(total) : null;
|
|
12072
|
+
};
|
|
12073
|
+
const extractVideoId = (parsed) => {
|
|
12074
|
+
if (parsed.hostname.endsWith('youtu.be'))
|
|
12075
|
+
return parsed.pathname.slice(1).split('/')[0] || null;
|
|
12076
|
+
if (parsed.pathname.startsWith('/watch'))
|
|
12077
|
+
return parsed.searchParams.get('v');
|
|
12078
|
+
if (parsed.pathname.startsWith('/shorts/'))
|
|
12079
|
+
return parsed.pathname.slice('/shorts/'.length).split('/')[0] || null;
|
|
12080
|
+
return null;
|
|
12081
|
+
};
|
|
12082
|
+
// Most youtube links we get from the browser are watch URLs, like https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
12083
|
+
// These /watch URLs won't work in an iframe, so we need to convert them to the embed URL if iframe is used
|
|
12084
|
+
const normalizeYouTubeUrlToEmbedUrl = (url) => {
|
|
12085
|
+
let parsed;
|
|
12086
|
+
try {
|
|
12087
|
+
parsed = new URL(url);
|
|
12088
|
+
}
|
|
12089
|
+
catch {
|
|
12090
|
+
return url;
|
|
12091
|
+
}
|
|
12092
|
+
if (!YOUTUBE_HOSTS.has(parsed.hostname))
|
|
12093
|
+
return url;
|
|
12094
|
+
if (parsed.pathname.startsWith('/embed/'))
|
|
12095
|
+
return url;
|
|
12096
|
+
const videoId = extractVideoId(parsed);
|
|
12097
|
+
if (!videoId)
|
|
12098
|
+
return url;
|
|
12099
|
+
const embed = new URL(`https://www.youtube.com/embed/${videoId}`);
|
|
12100
|
+
const timestamp = parsed.searchParams.get('start') || parsed.searchParams.get('t');
|
|
12101
|
+
const start = timestamp ? toStartSeconds(timestamp) : null;
|
|
12102
|
+
if (start)
|
|
12103
|
+
embed.searchParams.set('start', start);
|
|
12104
|
+
return embed.toString();
|
|
12105
|
+
};
|
|
12106
|
+
|
|
12063
12107
|
;// ./components/Embed/index.tsx
|
|
12064
12108
|
/* eslint-disable no-param-reassign */
|
|
12065
12109
|
/* eslint-disable react/jsx-props-no-spreading */
|
|
12066
12110
|
|
|
12111
|
+
|
|
12067
12112
|
const Favicon = ({ src, alt = 'favicon', ...attr }) => (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("img", { ...attr, alt: alt, height: "14", src: src, width: "14" }));
|
|
12068
12113
|
const IFRAME_DERIVABLE_TYPES = new Set(['youtube', 'jsfiddle', 'pdf']);
|
|
12069
12114
|
// HTML width/height attrs accept bare numbers (interpreted as px), but CSS does not, convert.
|
|
@@ -12097,7 +12142,8 @@ const Embed = ({ lazy = true, url, html, providerName, providerUrl, title, ifram
|
|
|
12097
12142
|
// Fall back to a direct iframe for URL-derivable embed types when html is missing.
|
|
12098
12143
|
const renderTypeAsIframe = !html && !explicitOptOut && url && typeOfEmbed && IFRAME_DERIVABLE_TYPES.has(typeOfEmbed);
|
|
12099
12144
|
if (iframe || renderTypeAsIframe) {
|
|
12100
|
-
|
|
12145
|
+
const src = normalizeYouTubeUrlToEmbedUrl(url);
|
|
12146
|
+
return external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement("iframe", { ...spreadAttrs, src: src, style: iframeStyle, title: title });
|
|
12101
12147
|
}
|
|
12102
12148
|
if (!providerUrl && url)
|
|
12103
12149
|
providerUrl = new URL(url).hostname
|
|
@@ -100750,6 +100796,12 @@ const types_types = /** @type {const} */ ({
|
|
|
100750
100796
|
|
|
100751
100797
|
|
|
100752
100798
|
|
|
100799
|
+
|
|
100800
|
+
// Raw tags (type-1: pre/script/style/textarea) and block tags (type-6: div,
|
|
100801
|
+
// section, …) always start a block, so they stay flow even with trailing
|
|
100802
|
+
// content. Other lowercase tags (i, span, …) follow the type-7 rule and only
|
|
100803
|
+
// stay flow when nothing trails the close tag.
|
|
100804
|
+
const htmlFlowTagNames = new Set([...htmlRawNames, ...htmlBlockNames]);
|
|
100753
100805
|
const syntax_nonLazyContinuationStart = {
|
|
100754
100806
|
tokenize: syntax_tokenizeNonLazyContinuationStart,
|
|
100755
100807
|
partial: true,
|
|
@@ -100786,11 +100838,12 @@ const mdxComponentTextConstruct = {
|
|
|
100786
100838
|
* lowercase HTML tags that carry at least one `{…}` attribute expression.
|
|
100787
100839
|
* Multi-line, concrete, `afterClose` consumes the rest of the line.
|
|
100788
100840
|
*
|
|
100789
|
-
* **Text** — runs inside paragraphs / inline context. Claims
|
|
100790
|
-
*
|
|
100791
|
-
*
|
|
100792
|
-
*
|
|
100793
|
-
*
|
|
100841
|
+
* **Text** — runs inside paragraphs / inline context. Claims lowercase tags and
|
|
100842
|
+
* inline PascalCase components (`INLINE_COMPONENT_TAGS` — Anchor, Glossary), both
|
|
100843
|
+
* gated on at least one `{…}` brace attribute. All other PascalCase stays
|
|
100844
|
+
* flow-only, matching how ReadMe's custom components are authored. Aborts on line
|
|
100845
|
+
* endings (inline constructs don't span lines) and exits immediately after
|
|
100846
|
+
* `</tag>` so the paragraph's inline parser picks up the trailing text.
|
|
100794
100847
|
*/
|
|
100795
100848
|
function createTokenize(mode) {
|
|
100796
100849
|
const isFlow = mode === 'flow';
|
|
@@ -100802,8 +100855,9 @@ function createTokenize(mode) {
|
|
|
100802
100855
|
let closingTagName = '';
|
|
100803
100856
|
// For lowercase tags we only want to claim the block if it uses JSX
|
|
100804
100857
|
// attribute expression syntax (`attr={...}`). Plain HTML should fall
|
|
100805
|
-
// through to CommonMark html-flow.
|
|
100806
|
-
//
|
|
100858
|
+
// through to CommonMark html-flow. Flow mode claims any PascalCase block
|
|
100859
|
+
// component; text mode claims only inline PascalCase components
|
|
100860
|
+
// (INLINE_COMPONENT_TAGS — Anchor, Glossary), also brace-gated.
|
|
100807
100861
|
let isLowercaseTag = false;
|
|
100808
100862
|
let sawBraceAttr = false;
|
|
100809
100863
|
// Code span tracking
|
|
@@ -100814,6 +100868,9 @@ function createTokenize(mode) {
|
|
|
100814
100868
|
let fenceLength = 0;
|
|
100815
100869
|
let fenceCloseLength = 0;
|
|
100816
100870
|
let atLineStart = false;
|
|
100871
|
+
// True once this construct consumes any line ending; lets `afterClose`
|
|
100872
|
+
// treat only single-line lowercase tags as inline candidates.
|
|
100873
|
+
let sawLineEnding = false;
|
|
100817
100874
|
// Bail when the opener line has unmatched tag-like tokens in its body.
|
|
100818
100875
|
// `<Foo>_<Bar>.csv` leaves opens > closes; matched shapes like
|
|
100819
100876
|
// `<Callout>x <strong>y</strong>` balance to 0. Without this,
|
|
@@ -100964,13 +101021,13 @@ function createTokenize(mode) {
|
|
|
100964
101021
|
}
|
|
100965
101022
|
// ── Tag name parsing ───────────────────────────────────────────────────
|
|
100966
101023
|
function tagNameFirst(code) {
|
|
100967
|
-
// Uppercase A-Z → PascalCase MDX component. Flow
|
|
100968
|
-
// components
|
|
101024
|
+
// Uppercase A-Z → PascalCase MDX component. Flow mode claims block
|
|
101025
|
+
// components; text mode only claims inline components (Anchor, Glossary),
|
|
101026
|
+
// which is enforced once the full name is known in `tagNameRest`.
|
|
100969
101027
|
if (code !== null && code >= codes.uppercaseA && code <= codes.uppercaseZ) {
|
|
100970
|
-
if (!isFlow)
|
|
100971
|
-
return nok(code);
|
|
100972
101028
|
tagName = String.fromCharCode(code);
|
|
100973
101029
|
isLowercaseTag = false;
|
|
101030
|
+
sawBraceAttr = false;
|
|
100974
101031
|
effects.consume(code);
|
|
100975
101032
|
return tagNameRest;
|
|
100976
101033
|
}
|
|
@@ -100998,10 +101055,18 @@ function createTokenize(mode) {
|
|
|
100998
101055
|
effects.consume(code);
|
|
100999
101056
|
return tagNameRest;
|
|
101000
101057
|
}
|
|
101001
|
-
// Tag name complete —
|
|
101002
|
-
|
|
101058
|
+
// Tag name complete — decide whether this tokenizer claims the tag.
|
|
101059
|
+
// Three cases: lowercase tags are always candidates (brace-gated later in
|
|
101060
|
+
// `afterOpenTagName`); flow-mode PascalCase claims any block component
|
|
101061
|
+
// except those with a dedicated tokenizer; text-mode PascalCase claims
|
|
101062
|
+
// only inline components (Anchor, Glossary).
|
|
101063
|
+
const claimable = isLowercaseTag
|
|
101064
|
+
? true
|
|
101065
|
+
: isFlow
|
|
101066
|
+
? !TOKENIZER_MDX_COMPONENT_EXCLUDED_TAGS.has(tagName)
|
|
101067
|
+
: INLINE_COMPONENT_TAGS.has(tagName);
|
|
101068
|
+
if (!claimable)
|
|
101003
101069
|
return nok(code);
|
|
101004
|
-
}
|
|
101005
101070
|
depth = 1;
|
|
101006
101071
|
return afterOpenTagName(code);
|
|
101007
101072
|
}
|
|
@@ -101009,6 +101074,10 @@ function createTokenize(mode) {
|
|
|
101009
101074
|
function afterOpenTagName(code) {
|
|
101010
101075
|
if (code === null)
|
|
101011
101076
|
return nok(code);
|
|
101077
|
+
// Everything except a flow-mode PascalCase block component must carry a
|
|
101078
|
+
// `{…}` brace attribute to be claimed; plain HTML falls through to
|
|
101079
|
+
// CommonMark.
|
|
101080
|
+
const requiresBraceAttr = isLowercaseTag || !isFlow;
|
|
101012
101081
|
if (markdownLineEnding(code)) {
|
|
101013
101082
|
if (!isFlow)
|
|
101014
101083
|
return nok(code);
|
|
@@ -101017,14 +101086,14 @@ function createTokenize(mode) {
|
|
|
101017
101086
|
}
|
|
101018
101087
|
// Self-closing />
|
|
101019
101088
|
if (code === codes.slash) {
|
|
101020
|
-
if (
|
|
101089
|
+
if (requiresBraceAttr && !sawBraceAttr)
|
|
101021
101090
|
return nok(code);
|
|
101022
101091
|
effects.consume(code);
|
|
101023
101092
|
return selfCloseGt;
|
|
101024
101093
|
}
|
|
101025
101094
|
// End of opening tag
|
|
101026
101095
|
if (code === codes.greaterThan) {
|
|
101027
|
-
if (
|
|
101096
|
+
if (requiresBraceAttr && !sawBraceAttr)
|
|
101028
101097
|
return nok(code);
|
|
101029
101098
|
effects.consume(code);
|
|
101030
101099
|
onOpenerLine = isFlow;
|
|
@@ -101088,6 +101157,7 @@ function createTokenize(mode) {
|
|
|
101088
101157
|
return effects.check(syntax_nonLazyContinuationStart, openTagContinuationNonLazy, continuationAfter)(code);
|
|
101089
101158
|
}
|
|
101090
101159
|
function openTagContinuationNonLazy(code) {
|
|
101160
|
+
sawLineEnding = true;
|
|
101091
101161
|
effects.enter(types_types.lineEnding);
|
|
101092
101162
|
effects.consume(code);
|
|
101093
101163
|
effects.exit(types_types.lineEnding);
|
|
@@ -101211,6 +101281,7 @@ function createTokenize(mode) {
|
|
|
101211
101281
|
return effects.check(syntax_nonLazyContinuationStart, fencedCodeContinuationNonLazy, continuationAfter)(code);
|
|
101212
101282
|
}
|
|
101213
101283
|
function fencedCodeContinuationNonLazy(code) {
|
|
101284
|
+
sawLineEnding = true;
|
|
101214
101285
|
effects.enter(types_types.lineEnding);
|
|
101215
101286
|
effects.consume(code);
|
|
101216
101287
|
effects.exit(types_types.lineEnding);
|
|
@@ -101367,6 +101438,12 @@ function createTokenize(mode) {
|
|
|
101367
101438
|
effects.exit('mdxComponent');
|
|
101368
101439
|
return ok(code);
|
|
101369
101440
|
}
|
|
101441
|
+
// A single-line type-7 lowercase tag with content trailing its close is
|
|
101442
|
+
// inline, so `<i …></i> <a>…</a>` stays on one line instead of splitting
|
|
101443
|
+
// into separate blocks. Raw/block tags (pre, div, …) stay flow.
|
|
101444
|
+
if (isLowercaseTag && !sawLineEnding && !htmlFlowTagNames.has(tagName)) {
|
|
101445
|
+
return afterCloseInlineCandidate(code);
|
|
101446
|
+
}
|
|
101370
101447
|
if (code === null || markdownLineEnding(code)) {
|
|
101371
101448
|
effects.exit('mdxComponentData');
|
|
101372
101449
|
effects.exit('mdxComponent');
|
|
@@ -101377,11 +101454,26 @@ function createTokenize(mode) {
|
|
|
101377
101454
|
effects.consume(code);
|
|
101378
101455
|
return afterClose;
|
|
101379
101456
|
}
|
|
101457
|
+
// Whitespace-only to the line ending keeps the flow block; any other
|
|
101458
|
+
// trailing char means inline content, so refuse and let inline parsing run.
|
|
101459
|
+
function afterCloseInlineCandidate(code) {
|
|
101460
|
+
if (code === null || markdownLineEnding(code)) {
|
|
101461
|
+
effects.exit('mdxComponentData');
|
|
101462
|
+
effects.exit('mdxComponent');
|
|
101463
|
+
return ok(code);
|
|
101464
|
+
}
|
|
101465
|
+
if (markdownSpace(code)) {
|
|
101466
|
+
effects.consume(code);
|
|
101467
|
+
return afterCloseInlineCandidate;
|
|
101468
|
+
}
|
|
101469
|
+
return nok(code);
|
|
101470
|
+
}
|
|
101380
101471
|
// ── Body continuation (line endings) ───────────────────────────────────
|
|
101381
101472
|
function bodyContinuationStart(code) {
|
|
101382
101473
|
return effects.check(syntax_nonLazyContinuationStart, bodyContinuationNonLazy, continuationAfter)(code);
|
|
101383
101474
|
}
|
|
101384
101475
|
function bodyContinuationNonLazy(code) {
|
|
101476
|
+
sawLineEnding = true;
|
|
101385
101477
|
effects.enter(types_types.lineEnding);
|
|
101386
101478
|
effects.consume(code);
|
|
101387
101479
|
effects.exit(types_types.lineEnding);
|
|
@@ -101451,12 +101543,13 @@ function syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
|
|
|
101451
101543
|
* self-closing `<Component />`). Prevents CommonMark from fragmenting them
|
|
101452
101544
|
* across multiple HTML / paragraph nodes.
|
|
101453
101545
|
*
|
|
101454
|
-
* **Text (inline)** — registers
|
|
101455
|
-
* (
|
|
101456
|
-
*
|
|
101457
|
-
*
|
|
101458
|
-
*
|
|
101459
|
-
*
|
|
101546
|
+
* **Text (inline)** — registers for lowercase tags and inline PascalCase
|
|
101547
|
+
* components (Anchor, Glossary) that carry brace attrs (e.g.
|
|
101548
|
+
* `Start <a href={url}>here</a> end`, `<Anchor href={url}>x</Anchor>`). Picks
|
|
101549
|
+
* them up during inline parsing so they render inline inside their paragraph,
|
|
101550
|
+
* then are rewritten to `mdxJsxTextElement` by the `components/inline-html`
|
|
101551
|
+
* transformer. All other PascalCase is flow-only; ReadMe's custom components
|
|
101552
|
+
* are authored as block-level elements.
|
|
101460
101553
|
*
|
|
101461
101554
|
* Excludes tags handled by dedicated tokenizers: Table, HTMLBlock, Glossary,
|
|
101462
101555
|
* Anchor.
|
|
@@ -101575,12 +101668,12 @@ const parsePhrasingChildren = (value, safeMode) => {
|
|
|
101575
101668
|
return first?.type === 'paragraph' ? first.children : [];
|
|
101576
101669
|
};
|
|
101577
101670
|
/**
|
|
101578
|
-
* Attempt to promote
|
|
101579
|
-
* `
|
|
101580
|
-
*
|
|
101581
|
-
*
|
|
101582
|
-
* `mdxishComponentBlocks` so they remain `mdxJsxFlowElement`,
|
|
101583
|
-
* ReadMe's flow-level component authoring model.
|
|
101671
|
+
* Attempt to promote an inline `html` node to an `mdxJsxTextElement`. Scope
|
|
101672
|
+
* mirrors what the `mdxComponent` text tokenizer claims: lowercase tags and
|
|
101673
|
+
* inline PascalCase components (`INLINE_COMPONENT_TAGS` — Anchor, Glossary),
|
|
101674
|
+
* both carrying `{…}` attribute expressions. All other PascalCase components
|
|
101675
|
+
* stay with `mdxishComponentBlocks` so they remain `mdxJsxFlowElement`,
|
|
101676
|
+
* matching ReadMe's flow-level component authoring model.
|
|
101584
101677
|
*
|
|
101585
101678
|
* Returns the original node unchanged when it doesn't qualify.
|
|
101586
101679
|
*/
|
|
@@ -101589,12 +101682,11 @@ const promoteInlineHtml = (node, parseOpts, safeMode) => {
|
|
|
101589
101682
|
if (!parsed)
|
|
101590
101683
|
return node;
|
|
101591
101684
|
const { tag, attributes, selfClosing, contentAfterTag = '' } = parsed;
|
|
101592
|
-
// PascalCase stays flow-level
|
|
101593
|
-
|
|
101594
|
-
|
|
101595
|
-
//
|
|
101596
|
-
|
|
101597
|
-
if (GENERIC_MDX_COMPONENT_EXCLUDED_TAGS.has(tag))
|
|
101685
|
+
// Non-inline PascalCase stays flow-level (handled by mdxishComponentBlocks)
|
|
101686
|
+
// and dedicated tokenizers (Table, HTMLBlock) own their tags. Inline
|
|
101687
|
+
// components (Anchor, Glossary) with expression attrs are promoted here —
|
|
101688
|
+
// the text tokenizer captures them as a single html node.
|
|
101689
|
+
if (isPascalCase(tag) && !INLINE_COMPONENT_TAGS.has(tag))
|
|
101598
101690
|
return node;
|
|
101599
101691
|
// Plain inline HTML (no expressions) stays as an html node so rehype-raw
|
|
101600
101692
|
// parses it with parse5 as normal.
|
|
@@ -101618,14 +101710,15 @@ const promoteInlineHtml = (node, parseOpts, safeMode) => {
|
|
|
101618
101710
|
* Runs after `mdxishComponentBlocks`, which skips paragraph-parented html
|
|
101619
101711
|
* nodes and leaves them for this pass. Two producers put html nodes inside
|
|
101620
101712
|
* paragraphs:
|
|
101621
|
-
* 1. The `mdxComponent` text tokenizer, for lowercase tags
|
|
101622
|
-
*
|
|
101713
|
+
* 1. The `mdxComponent` text tokenizer, for lowercase tags and inline
|
|
101714
|
+
* PascalCase components (Anchor, Glossary) with `{…}` attribute
|
|
101715
|
+
* expressions (e.g. `<a href={url}>here</a>`, `<Anchor href={url}>x</Anchor>`).
|
|
101623
101716
|
* 2. CommonMark's built-in html-text tokenizer, for PascalCase components
|
|
101624
101717
|
* (e.g. a single html node for self-closing `<C />`).
|
|
101625
101718
|
*
|
|
101626
|
-
* Eligibility mirrors `mdxishComponentBlocks`:
|
|
101627
|
-
*
|
|
101628
|
-
* `<a href="x">` stays as an html node for rehype-raw.
|
|
101719
|
+
* Eligibility mirrors `mdxishComponentBlocks`: a tag only promotes when it
|
|
101720
|
+
* carries an expression attribute and isn't a non-inline PascalCase component;
|
|
101721
|
+
* plain inline HTML like `<a href="x">` stays as an html node for rehype-raw.
|
|
101629
101722
|
*/
|
|
101630
101723
|
const mdxishInlineMdxHtmlBlocks = (opts = {}) => tree => {
|
|
101631
101724
|
const safeMode = !!opts.safeMode;
|
|
@@ -102073,12 +102166,60 @@ function restoreSnakeCase(placeholderName, mapping) {
|
|
|
102073
102166
|
return matchingKey ? mapping[matchingKey] : placeholderName;
|
|
102074
102167
|
}
|
|
102075
102168
|
|
|
102169
|
+
;// ./processor/transform/mdxish/resolve-esm-imports.ts
|
|
102170
|
+
|
|
102171
|
+
// We provide React as a default module so that components can use hooks
|
|
102172
|
+
// and it's a common use case. Add other common libraries here.
|
|
102173
|
+
const defaultModuleRegistry = { react: (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default()) };
|
|
102174
|
+
const isRecord = (value) => typeof value === 'object' && value !== null;
|
|
102175
|
+
// Get the value of a named export from a module
|
|
102176
|
+
const getModuleExport = (module, importedName) => isRecord(module) && importedName in module ? module[importedName] : undefined;
|
|
102177
|
+
/**
|
|
102178
|
+
* Turn `import` declarations into a flat map of binding → value.
|
|
102179
|
+
*
|
|
102180
|
+
* A "binding" is a mapping of a local name to the value of it in the module exports
|
|
102181
|
+
* Example: `import { useState } from 'react'` yields `{ useState: React.useState }`.
|
|
102182
|
+
*
|
|
102183
|
+
* Unsupported specifiers are skipped with a warning rather than throwing, so a
|
|
102184
|
+
* single unknown import can't break the rest of the document.
|
|
102185
|
+
*/
|
|
102186
|
+
const collectImportValues = (importDeclarations, registry = defaultModuleRegistry) => {
|
|
102187
|
+
const importValues = {};
|
|
102188
|
+
importDeclarations.forEach(declaration => {
|
|
102189
|
+
const libraryName = declaration.source.value;
|
|
102190
|
+
if (typeof libraryName !== 'string')
|
|
102191
|
+
return;
|
|
102192
|
+
if (!(libraryName in registry)) {
|
|
102193
|
+
// eslint-disable-next-line no-console
|
|
102194
|
+
console.warn(`[WARNING] Cannot resolve import "${libraryName}"; it is not a supported library.`);
|
|
102195
|
+
return;
|
|
102196
|
+
}
|
|
102197
|
+
const module = registry[libraryName];
|
|
102198
|
+
declaration.specifiers.forEach(spec => {
|
|
102199
|
+
// Default (`import React`) and namespace (`import * as React`) both bind
|
|
102200
|
+
// the whole module under the local name.
|
|
102201
|
+
if (spec.type === 'ImportDefaultSpecifier' || spec.type === 'ImportNamespaceSpecifier') {
|
|
102202
|
+
importValues[spec.local.name] = module;
|
|
102203
|
+
}
|
|
102204
|
+
else if (spec.type === 'ImportSpecifier') {
|
|
102205
|
+
// Named imports (e.g. `import { useState } from 'react'`, useState is the import name)
|
|
102206
|
+
const importName = spec.imported.type === 'Identifier' ? spec.imported.name : spec.imported.value;
|
|
102207
|
+
if (typeof importName === 'string') {
|
|
102208
|
+
importValues[spec.local.name] = getModuleExport(module, importName);
|
|
102209
|
+
}
|
|
102210
|
+
}
|
|
102211
|
+
});
|
|
102212
|
+
});
|
|
102213
|
+
return importValues;
|
|
102214
|
+
};
|
|
102215
|
+
|
|
102076
102216
|
;// ./processor/transform/mdxish/evaluate-exports.ts
|
|
102077
102217
|
|
|
102078
102218
|
|
|
102079
102219
|
|
|
102080
102220
|
|
|
102081
102221
|
|
|
102222
|
+
|
|
102082
102223
|
/**
|
|
102083
102224
|
* Recursively extract all identifier names introduced by a binding pattern.
|
|
102084
102225
|
* Handles destructuring (`{ a, b }`, `[x, y]`), rest elements (`...rest`),
|
|
@@ -102126,6 +102267,7 @@ const collectExportNames = (declaration) => {
|
|
|
102126
102267
|
const evaluateExports = () => (tree, file) => {
|
|
102127
102268
|
const programBody = [];
|
|
102128
102269
|
const exportNames = [];
|
|
102270
|
+
const importDeclarations = [];
|
|
102129
102271
|
const nodesToRemove = [];
|
|
102130
102272
|
visit(tree, isMDXEsm, (node, index, parent) => {
|
|
102131
102273
|
if (parent && typeof index === 'number') {
|
|
@@ -102139,6 +102281,10 @@ const evaluateExports = () => (tree, file) => {
|
|
|
102139
102281
|
// handled the same as a named export — the inner declaration carries the
|
|
102140
102282
|
// binding name
|
|
102141
102283
|
estreeBody.forEach(statement => {
|
|
102284
|
+
if (statement.type === 'ImportDeclaration') {
|
|
102285
|
+
importDeclarations.push(statement);
|
|
102286
|
+
return;
|
|
102287
|
+
}
|
|
102142
102288
|
let declaration = null;
|
|
102143
102289
|
if (statement.type === 'ExportNamedDeclaration' && statement.declaration) {
|
|
102144
102290
|
declaration = statement.declaration;
|
|
@@ -102166,9 +102312,11 @@ const evaluateExports = () => (tree, file) => {
|
|
|
102166
102312
|
const program = { type: 'Program', sourceType: 'module', body: programBody };
|
|
102167
102313
|
buildJsx(program, { runtime: 'classic', pragma: 'React.createElement', pragmaFrag: 'React.Fragment' });
|
|
102168
102314
|
const { value: source } = toJs(program);
|
|
102315
|
+
// Make sure import values are available in the scope
|
|
102316
|
+
const importValues = collectImportValues(importDeclarations);
|
|
102169
102317
|
// Evaluate and build on the expression source
|
|
102170
102318
|
// Use react to compile JSX codes
|
|
102171
|
-
const evaluatedExports = evaluate(`(() => { ${source}\nreturn { ${exportNames.join(', ')} }; })()`, { React: (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default()) });
|
|
102319
|
+
const evaluatedExports = evaluate(`(() => { ${source}\nreturn { ${exportNames.join(', ')} }; })()`, { React: (external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default()), ...importValues });
|
|
102172
102320
|
Object.assign(scope, evaluatedExports);
|
|
102173
102321
|
}
|
|
102174
102322
|
catch (error) {
|
|
@@ -104122,214 +104270,21 @@ const normalizeMdxJsxNodes = () => tree => {
|
|
|
104122
104270
|
*/
|
|
104123
104271
|
const JSX_COMMENT_REGEX = /\{\/\*[^*]*(?:\*(?!\/)[^*]*)*\*\/\}/g;
|
|
104124
104272
|
|
|
104125
|
-
;// ./processor/transform/mdxish/
|
|
104126
|
-
|
|
104273
|
+
;// ./processor/transform/mdxish/remove-jsx-comments.ts
|
|
104127
104274
|
|
|
104128
104275
|
/**
|
|
104129
104276
|
* Removes JSX-style comments (e.g., { /* comment *\/ }) from content.
|
|
104130
104277
|
*
|
|
104131
|
-
*
|
|
104132
|
-
*
|
|
104133
|
-
*
|
|
104278
|
+
* `@param` content
|
|
104279
|
+
* `@returns` Content with JSX comments removed
|
|
104280
|
+
* `@example`
|
|
104134
104281
|
* ```typescript
|
|
104135
|
-
* removeJSXComments('Text {
|
|
104136
|
-
* // Returns: 'Text more text'
|
|
104282
|
+
* removeJSXComments('Text {/* comment *\/} more text') // => 'Text more text'
|
|
104137
104283
|
* ```
|
|
104138
104284
|
*/
|
|
104139
104285
|
function removeJSXComments(content) {
|
|
104140
104286
|
return content.replace(JSX_COMMENT_REGEX, '');
|
|
104141
104287
|
}
|
|
104142
|
-
const HTML_ELEM_PLACEHOLDER_PREFIX = '___MDXISH_HTML_ELEM_';
|
|
104143
|
-
const HTML_ELEM_PLACEHOLDER = new RegExp(`${HTML_ELEM_PLACEHOLDER_PREFIX}(\\d+)___`, 'g');
|
|
104144
|
-
// Matches an HTML element that starts at a line boundary and ends at a line boundary.
|
|
104145
|
-
// Allows optional leading indentation and lazily matches until the same closing tag.
|
|
104146
|
-
const BLOCK_HTML_RE = /(?<=^|\n)[ \t]*<([a-z][a-zA-Z0-9]*)(?:\s[^>]*)?>[\s\S]*?<\/\1>[ \t]*(?=\n|$)/g;
|
|
104147
|
-
/**
|
|
104148
|
-
* Hides line-anchored HTML elements from the brace-escaping pass so we don't leak `\{`
|
|
104149
|
-
* into rendered output (rehypeRaw renders the `\` literally, e.g. `<div>{foo</div>`).
|
|
104150
|
-
*
|
|
104151
|
-
* One carve-out: if an interior line at column 0 has bare text containing `{`, mdxish
|
|
104152
|
-
* parses that line as a paragraph and the mdxExpression step would throw without an
|
|
104153
|
-
* escape — so we leave that case to the brace balancer.
|
|
104154
|
-
*/
|
|
104155
|
-
function protectHTMLElements(content) {
|
|
104156
|
-
const htmlElements = [];
|
|
104157
|
-
const protectedContent = content.replace(BLOCK_HTML_RE, match => {
|
|
104158
|
-
// Look at the lines between the open and close tags. If any of them starts
|
|
104159
|
-
// at column 0 with bare text (not whitespace, not another tag) and contains
|
|
104160
|
-
// `{`, mdxish will parse that line as a paragraph and the brace as an MDX
|
|
104161
|
-
// expression, which would throw an error. So we let the brace balancer escape it.
|
|
104162
|
-
// Otherwise, we need to extract the sequence to protect it from the brace escaping.
|
|
104163
|
-
const interior = match.split('\n').slice(1, -1);
|
|
104164
|
-
const hazard = interior.some(line => line.length > 0 && line[0] !== ' ' && line[0] !== '\t' && line[0] !== '<' && line.includes('{'));
|
|
104165
|
-
if (hazard)
|
|
104166
|
-
return match;
|
|
104167
|
-
htmlElements.push(match);
|
|
104168
|
-
return `${HTML_ELEM_PLACEHOLDER_PREFIX}${htmlElements.length - 1}___`;
|
|
104169
|
-
});
|
|
104170
|
-
return { htmlElements, protectedContent };
|
|
104171
|
-
}
|
|
104172
|
-
function restoreHTMLElements(content, htmlElements) {
|
|
104173
|
-
if (htmlElements.length === 0)
|
|
104174
|
-
return content;
|
|
104175
|
-
return content.replace(HTML_ELEM_PLACEHOLDER, (_m, idx) => htmlElements[parseInt(idx, 10)]);
|
|
104176
|
-
}
|
|
104177
|
-
const ESM_DECLARATION_START = /^(?:export|import)\b/;
|
|
104178
|
-
/**
|
|
104179
|
-
* Whether a line begins a top-level `export`/`import` declaration. Its braces
|
|
104180
|
-
* are valid JS owned by the mdxjsEsm tokenizer (which tolerates blank lines),
|
|
104181
|
-
* so escaping them would corrupt the source and break acorn parsing.
|
|
104182
|
-
*/
|
|
104183
|
-
function startsEsmDeclaration(chars, lineStart) {
|
|
104184
|
-
return ESM_DECLARATION_START.test(chars.slice(lineStart, lineStart + 7).join(''));
|
|
104185
|
-
}
|
|
104186
|
-
function isBlankLine(chars, lineStart) {
|
|
104187
|
-
for (let i = lineStart; i < chars.length; i += 1) {
|
|
104188
|
-
if (chars[i] === '\n')
|
|
104189
|
-
return true;
|
|
104190
|
-
if (chars[i] !== ' ' && chars[i] !== '\t')
|
|
104191
|
-
return false;
|
|
104192
|
-
}
|
|
104193
|
-
return true;
|
|
104194
|
-
}
|
|
104195
|
-
/**
|
|
104196
|
-
* Escapes unbalanced and paragraph-spanning braces so MDX doesn't trip on them.
|
|
104197
|
-
*/
|
|
104198
|
-
function escapeProblematicBraces(content) {
|
|
104199
|
-
const { htmlElements, protectedContent } = protectHTMLElements(content);
|
|
104200
|
-
let strDelim = null;
|
|
104201
|
-
let strEscaped = false;
|
|
104202
|
-
// Track position of last newline (outside strings) to detect blank lines
|
|
104203
|
-
// -2 means no recent newline
|
|
104204
|
-
let lastNewlinePos = -2;
|
|
104205
|
-
// Character state machine trackers
|
|
104206
|
-
const toEscape = new Set();
|
|
104207
|
-
// Convert to array of Unicode code points so that emojis and multi-byte characters are correctly tracked
|
|
104208
|
-
const chars = Array.from(protectedContent);
|
|
104209
|
-
const openStack = [];
|
|
104210
|
-
// Whether the current top-level statement is an `export`/`import` declaration.
|
|
104211
|
-
let insideEsmDeclaration = false;
|
|
104212
|
-
for (let i = 0; i < chars.length; i += 1) {
|
|
104213
|
-
const ch = chars[i];
|
|
104214
|
-
// At a top-level (brace depth 0) line start, decide whether we're inside an
|
|
104215
|
-
// ESM declaration. The flag persists across the declaration's own lines.
|
|
104216
|
-
if (openStack.length === 0 && (i === 0 || chars[i - 1] === '\n')) {
|
|
104217
|
-
if (startsEsmDeclaration(chars, i))
|
|
104218
|
-
insideEsmDeclaration = true;
|
|
104219
|
-
else if (isBlankLine(chars, i))
|
|
104220
|
-
insideEsmDeclaration = false;
|
|
104221
|
-
}
|
|
104222
|
-
// Track string delimiters inside expressions to ignore braces within them
|
|
104223
|
-
if (openStack.length > 0) {
|
|
104224
|
-
if (strDelim) {
|
|
104225
|
-
if (strEscaped)
|
|
104226
|
-
strEscaped = false;
|
|
104227
|
-
else if (ch === '\\')
|
|
104228
|
-
strEscaped = true;
|
|
104229
|
-
else if (ch === strDelim)
|
|
104230
|
-
strDelim = null;
|
|
104231
|
-
// eslint-disable-next-line no-continue
|
|
104232
|
-
continue;
|
|
104233
|
-
}
|
|
104234
|
-
if (ch === '"' || ch === "'" || ch === '`') {
|
|
104235
|
-
strDelim = ch;
|
|
104236
|
-
// eslint-disable-next-line no-continue
|
|
104237
|
-
continue;
|
|
104238
|
-
}
|
|
104239
|
-
if (ch === '\n') {
|
|
104240
|
-
if (lastNewlinePos >= 0) {
|
|
104241
|
-
const between = chars.slice(lastNewlinePos + 1, i).join('');
|
|
104242
|
-
if (/^[ \t]*$/.test(between)) {
|
|
104243
|
-
openStack.forEach(entry => { entry.hasBlankLine = true; });
|
|
104244
|
-
}
|
|
104245
|
-
}
|
|
104246
|
-
lastNewlinePos = i;
|
|
104247
|
-
}
|
|
104248
|
-
}
|
|
104249
|
-
// Skip already-escaped braces (odd run of preceding backslashes).
|
|
104250
|
-
if (ch === '{' || ch === '}') {
|
|
104251
|
-
let bs = 0;
|
|
104252
|
-
for (let j = i - 1; j >= 0 && chars[j] === '\\'; j -= 1)
|
|
104253
|
-
bs += 1;
|
|
104254
|
-
if (bs % 2 === 1) {
|
|
104255
|
-
// eslint-disable-next-line no-continue
|
|
104256
|
-
continue;
|
|
104257
|
-
}
|
|
104258
|
-
}
|
|
104259
|
-
if (ch === '{') {
|
|
104260
|
-
// `=` (after whitespace) before `{` ⇒ JSX attribute expression. The
|
|
104261
|
-
// mdxComponent tokenizer captures the whole component, so blank lines
|
|
104262
|
-
// inside attribute values are harmless. Nested `{` inherits the flag.
|
|
104263
|
-
let isAttrExpr = false;
|
|
104264
|
-
for (let j = i - 1; j >= 0; j -= 1) {
|
|
104265
|
-
const pc = chars[j];
|
|
104266
|
-
if (pc === '=') {
|
|
104267
|
-
isAttrExpr = true;
|
|
104268
|
-
break;
|
|
104269
|
-
}
|
|
104270
|
-
if (pc !== ' ' && pc !== '\t')
|
|
104271
|
-
break;
|
|
104272
|
-
}
|
|
104273
|
-
// Nested `{ ... }` inside an attribute value (e.g. `data={[{ ... }]}` or
|
|
104274
|
-
// `data={{ a: { b: 1 } }}`) must inherit the same exemption; only the
|
|
104275
|
-
// outer `{` is directly after `=`.
|
|
104276
|
-
if (!isAttrExpr && openStack.length > 0 && openStack[openStack.length - 1].isAttrExpr) {
|
|
104277
|
-
isAttrExpr = true;
|
|
104278
|
-
}
|
|
104279
|
-
openStack.push({ pos: i, hasBlankLine: false, isAttrExpr, isEsmDeclaration: insideEsmDeclaration });
|
|
104280
|
-
lastNewlinePos = -2;
|
|
104281
|
-
}
|
|
104282
|
-
else if (ch === '}') {
|
|
104283
|
-
if (openStack.length > 0) {
|
|
104284
|
-
const entry = openStack.pop();
|
|
104285
|
-
// The declaration's braces are closed; later top-level braces are not ESM.
|
|
104286
|
-
if (openStack.length === 0)
|
|
104287
|
-
insideEsmDeclaration = false;
|
|
104288
|
-
// Pure `{/* ... */}` comments are handled downstream by the jsxComment
|
|
104289
|
-
// tokenizer — escaping their braces would prevent it from running.
|
|
104290
|
-
const isPureJsxComment = chars[entry.pos + 1] === '/' &&
|
|
104291
|
-
chars[entry.pos + 2] === '*' &&
|
|
104292
|
-
chars[i - 1] === '/' &&
|
|
104293
|
-
chars[i - 2] === '*';
|
|
104294
|
-
if (entry.hasBlankLine && !isPureJsxComment && !entry.isAttrExpr && !entry.isEsmDeclaration) {
|
|
104295
|
-
toEscape.add(entry.pos);
|
|
104296
|
-
toEscape.add(i);
|
|
104297
|
-
}
|
|
104298
|
-
}
|
|
104299
|
-
else {
|
|
104300
|
-
toEscape.add(i);
|
|
104301
|
-
}
|
|
104302
|
-
}
|
|
104303
|
-
else if (ch === ';' && openStack.length === 0) {
|
|
104304
|
-
// A top-level `;` ends the current statement, ESM or otherwise.
|
|
104305
|
-
insideEsmDeclaration = false;
|
|
104306
|
-
}
|
|
104307
|
-
}
|
|
104308
|
-
// Anything still open is unbalanced.
|
|
104309
|
-
openStack.forEach(entry => {
|
|
104310
|
-
if (!entry.isEsmDeclaration)
|
|
104311
|
-
toEscape.add(entry.pos);
|
|
104312
|
-
});
|
|
104313
|
-
// Reconstruct the content with the escaped braces.
|
|
104314
|
-
const escapedContent = toEscape.size === 0 ? protectedContent : chars.map((ch, i) => (toEscape.has(i) ? `\\${ch}` : ch)).join('');
|
|
104315
|
-
return restoreHTMLElements(escapedContent, htmlElements);
|
|
104316
|
-
}
|
|
104317
|
-
/**
|
|
104318
|
-
* Preprocesses JSX-like markdown content before parsing.
|
|
104319
|
-
*
|
|
104320
|
-
* JSX attribute expressions (`href={baseUrl}`) are no longer rewritten here —
|
|
104321
|
-
* they flow through the tokenizer as `mdxJsxAttributeValueExpression` nodes
|
|
104322
|
-
* and are evaluated at the hast handler step.
|
|
104323
|
-
*
|
|
104324
|
-
* @param content
|
|
104325
|
-
* @returns Preprocessed content ready for markdown parsing
|
|
104326
|
-
*/
|
|
104327
|
-
function preprocessJSXExpressions(content) {
|
|
104328
|
-
const { protectedCode, protectedContent } = protectCodeBlocks(content);
|
|
104329
|
-
let processed = escapeProblematicBraces(protectedContent);
|
|
104330
|
-
processed = restoreCodeBlocks(processed, protectedCode);
|
|
104331
|
-
return processed;
|
|
104332
|
-
}
|
|
104333
104288
|
|
|
104334
104289
|
;// ./processor/transform/mdxish/resolve-deferred-attribute-expression-props.ts
|
|
104335
104290
|
|
|
@@ -105304,6 +105259,85 @@ function jsxTable() {
|
|
|
105304
105259
|
;// ./lib/micromark/jsx-table/index.ts
|
|
105305
105260
|
|
|
105306
105261
|
|
|
105262
|
+
;// ./lib/micromark/mdx-expression-lenient/syntax.ts
|
|
105263
|
+
|
|
105264
|
+
|
|
105265
|
+
/**
|
|
105266
|
+
* Lenient MDX text-expression tokenizer (agnostic / no acorn).
|
|
105267
|
+
*
|
|
105268
|
+
* Matches a balanced `{ ... }` run — tracking nested braces and spanning soft
|
|
105269
|
+
* line breaks — and emits the standard `mdxTextExpression*` tokens so the
|
|
105270
|
+
* upstream `mdxExpressionFromMarkdown()` builds the node.
|
|
105271
|
+
*
|
|
105272
|
+
* Reimplements the official micromark mdxExpression, but an unbalanced brace that
|
|
105273
|
+
* reaches end of input returns `nok` instead of throwing: micromark rolls back
|
|
105274
|
+
* and the `{` renders as literal text, making the pipeline forgiving of stray
|
|
105275
|
+
* braces that upstream would hard-error on.
|
|
105276
|
+
*/
|
|
105277
|
+
function tokenizeTextExpression(effects, ok, nok) {
|
|
105278
|
+
let depth = 0;
|
|
105279
|
+
return start;
|
|
105280
|
+
function start(code) {
|
|
105281
|
+
if (code !== codes.leftCurlyBrace)
|
|
105282
|
+
return nok(code);
|
|
105283
|
+
effects.enter('mdxTextExpression');
|
|
105284
|
+
effects.enter('mdxTextExpressionMarker');
|
|
105285
|
+
effects.consume(code);
|
|
105286
|
+
effects.exit('mdxTextExpressionMarker');
|
|
105287
|
+
return before;
|
|
105288
|
+
}
|
|
105289
|
+
function before(code) {
|
|
105290
|
+
if (code === codes.eof) {
|
|
105291
|
+
effects.exit('mdxTextExpression');
|
|
105292
|
+
return nok(code);
|
|
105293
|
+
}
|
|
105294
|
+
if (markdownLineEnding(code)) {
|
|
105295
|
+
effects.enter('lineEnding');
|
|
105296
|
+
effects.consume(code);
|
|
105297
|
+
effects.exit('lineEnding');
|
|
105298
|
+
return before;
|
|
105299
|
+
}
|
|
105300
|
+
if (code === codes.rightCurlyBrace && depth === 0) {
|
|
105301
|
+
return close(code);
|
|
105302
|
+
}
|
|
105303
|
+
effects.enter('mdxTextExpressionChunk');
|
|
105304
|
+
return inside(code);
|
|
105305
|
+
}
|
|
105306
|
+
function inside(code) {
|
|
105307
|
+
if (code === codes.eof || markdownLineEnding(code)) {
|
|
105308
|
+
effects.exit('mdxTextExpressionChunk');
|
|
105309
|
+
return before(code);
|
|
105310
|
+
}
|
|
105311
|
+
if (code === codes.rightCurlyBrace && depth === 0) {
|
|
105312
|
+
effects.exit('mdxTextExpressionChunk');
|
|
105313
|
+
return close(code);
|
|
105314
|
+
}
|
|
105315
|
+
if (code === codes.leftCurlyBrace)
|
|
105316
|
+
depth += 1;
|
|
105317
|
+
else if (code === codes.rightCurlyBrace)
|
|
105318
|
+
depth -= 1;
|
|
105319
|
+
effects.consume(code);
|
|
105320
|
+
return inside;
|
|
105321
|
+
}
|
|
105322
|
+
function close(code) {
|
|
105323
|
+
effects.enter('mdxTextExpressionMarker');
|
|
105324
|
+
effects.consume(code);
|
|
105325
|
+
effects.exit('mdxTextExpressionMarker');
|
|
105326
|
+
effects.exit('mdxTextExpression');
|
|
105327
|
+
return ok;
|
|
105328
|
+
}
|
|
105329
|
+
}
|
|
105330
|
+
function mdxExpressionLenient() {
|
|
105331
|
+
return {
|
|
105332
|
+
text: {
|
|
105333
|
+
[codes.leftCurlyBrace]: {
|
|
105334
|
+
name: 'mdxTextExpression',
|
|
105335
|
+
tokenize: tokenizeTextExpression,
|
|
105336
|
+
},
|
|
105337
|
+
},
|
|
105338
|
+
};
|
|
105339
|
+
}
|
|
105340
|
+
|
|
105307
105341
|
;// ./lib/utils/mdxish/mdxish-load-components.ts
|
|
105308
105342
|
|
|
105309
105343
|
|
|
@@ -105416,7 +105450,7 @@ const defaultTransformers = [
|
|
|
105416
105450
|
* 1. Normalize malformed table separator syntax (e.g., `|: ---` → `| :---`)
|
|
105417
105451
|
* 2. Terminate HTML flow blocks so subsequent content isn't swallowed
|
|
105418
105452
|
* 3. Close invalid "self-closing" HTML tags (e.g., `<i />` → `<i></i>`)
|
|
105419
|
-
* 4.
|
|
105453
|
+
* 4. Normalize compact ATX headings (e.g., `#Heading` → `# Heading`)
|
|
105420
105454
|
* 5. Replace snake_case component names with parser-safe placeholders
|
|
105421
105455
|
*/
|
|
105422
105456
|
function preprocessContent(content, opts) {
|
|
@@ -105425,7 +105459,6 @@ function preprocessContent(content, opts) {
|
|
|
105425
105459
|
result = terminateHtmlFlowBlocks(result);
|
|
105426
105460
|
result = closeSelfClosingHtmlTags(result);
|
|
105427
105461
|
result = normalizeCompactHeadings(result);
|
|
105428
|
-
result = preprocessJSXExpressions(result);
|
|
105429
105462
|
return processSnakeCaseComponent(result, { knownComponents });
|
|
105430
105463
|
}
|
|
105431
105464
|
function mdxishAstProcessor(mdContent, opts = {}) {
|
|
@@ -105442,12 +105475,8 @@ function mdxishAstProcessor(mdContent, opts = {}) {
|
|
|
105442
105475
|
acc[key] = String(value);
|
|
105443
105476
|
return acc;
|
|
105444
105477
|
}, {});
|
|
105445
|
-
//
|
|
105446
|
-
|
|
105447
|
-
const mdxExprExt = mdxExpression({ allowEmpty: true });
|
|
105448
|
-
const mdxExprTextOnly = {
|
|
105449
|
-
text: mdxExprExt.text,
|
|
105450
|
-
};
|
|
105478
|
+
// Parser extension for MDX expressions {}
|
|
105479
|
+
const mdxExprTextOnly = mdxExpressionLenient();
|
|
105451
105480
|
const micromarkExts = [
|
|
105452
105481
|
jsxTable(),
|
|
105453
105482
|
magicBlock(),
|