@readme/markdown 14.13.0 → 14.13.2
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/Accordion/style.scss +4 -0
- package/components/TailwindRoot/index.tsx +4 -0
- package/dist/example/components.d.ts +2 -0
- package/dist/lib/mdxish.d.ts +1 -1
- package/dist/lib/micromark/mdx-component/continuation-checks.d.ts +3 -0
- package/dist/lib/renderMdxish.d.ts +1 -1
- package/dist/main.css +2 -2
- package/dist/main.css.map +1 -1
- package/dist/main.js +243 -116
- package/dist/main.node.js +243 -116
- package/dist/main.node.js.map +1 -1
- package/dist/processor/plugin/mdxish-components.d.ts +1 -1
- package/dist/processor/transform/mdxish/components/mdx-blocks.d.ts +0 -31
- package/dist/render-fixture.css +1 -1
- package/dist/render-fixture.css.map +1 -1
- package/dist/render-fixture.node.js +243 -116
- package/dist/render-fixture.node.js.map +1 -1
- package/dist/utils/common-html-words.d.ts +9 -0
- package/package.json +1 -1
- package/styles/gfm.scss +15 -1
package/dist/main.js
CHANGED
|
@@ -12645,6 +12645,10 @@ const tailwindPrefix = 'readme-tailwind';
|
|
|
12645
12645
|
|
|
12646
12646
|
|
|
12647
12647
|
const TailwindRoot = ({ children, flow }) => {
|
|
12648
|
+
// `styles/gfm.scss` spaces the wrapped block children through this element and
|
|
12649
|
+
// relies on their margins collapsing through it. Keep it a plain block — no
|
|
12650
|
+
// border, padding, or block formatting context (overflow, display: flow-root/
|
|
12651
|
+
// flex/grid) — or the spacing breaks.
|
|
12648
12652
|
const Tag = flow ? 'div' : 'span';
|
|
12649
12653
|
return external_amd_react_commonjs_react_commonjs2_react_root_React_umd_react_default().createElement(Tag, { className: tailwindPrefix }, children);
|
|
12650
12654
|
};
|
|
@@ -76301,6 +76305,15 @@ const HTML_TABLE_STRUCTURE_TAGS = new Set([
|
|
|
76301
76305
|
'caption',
|
|
76302
76306
|
'colgroup',
|
|
76303
76307
|
]);
|
|
76308
|
+
/**
|
|
76309
|
+
* Tags whose bodies a later mdxish transform keeps raw and never re-parses as
|
|
76310
|
+
* markdown. Both layers depend on this property, not on the tags being figures:
|
|
76311
|
+
* the transformer treats them as non-promotable, and the tokenizer must not claim
|
|
76312
|
+
* markdown islands inside them (a claimed island would never be re-parsed and would
|
|
76313
|
+
* leak as literal text). Currently just the figure tags, whose bodies are owned by
|
|
76314
|
+
* the figure reassembly transform (`mdxishJsxToMdast`).
|
|
76315
|
+
*/
|
|
76316
|
+
const NON_REPARSED_BODY_TAGS = new Set(['figure', 'figcaption']);
|
|
76304
76317
|
/**
|
|
76305
76318
|
* The two HTML "foreign content" namespaces: SVG and MathML. Their descendants
|
|
76306
76319
|
* (`<path>`, `<mrow>`, …) are namespaced XML, not HTML tags or components. A closed
|
|
@@ -99098,7 +99111,7 @@ function normalizeProperties(node) {
|
|
|
99098
99111
|
* Identifies custom MDX components and recursively parses markdown children.
|
|
99099
99112
|
* Replaces tagName with PascalCase component name for React component resolution.
|
|
99100
99113
|
*
|
|
99101
|
-
* @see
|
|
99114
|
+
* @see .claude/context/MDXish/Processor Overview.md
|
|
99102
99115
|
* @param {Options} options - Configuration options
|
|
99103
99116
|
* @param {CustomComponents} options.components - Available custom components
|
|
99104
99117
|
* @param {Function} options.processMarkdown - Function to process markdown content
|
|
@@ -101498,12 +101511,95 @@ function tokenizeMagicBlockText(effects, ok, nok) {
|
|
|
101498
101511
|
*/
|
|
101499
101512
|
|
|
101500
101513
|
|
|
101514
|
+
;// ./lib/micromark/mdx-component/continuation-checks.ts
|
|
101515
|
+
|
|
101516
|
+
|
|
101517
|
+
/**
|
|
101518
|
+
* Partial constructs the `mdxComponent` tokenizer runs via `effects.check` to
|
|
101519
|
+
* decide whether the next line continues the block. They live here (not in
|
|
101520
|
+
* `syntax.ts`) because they hold none of `createTokenize`'s closure state — each
|
|
101521
|
+
* is a self-contained, single-line lookahead.
|
|
101522
|
+
*/
|
|
101523
|
+
function continuation_checks_tokenizeNonLazyContinuationStart(effects, ok, nok) {
|
|
101524
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
101525
|
+
const self = this;
|
|
101526
|
+
return start;
|
|
101527
|
+
function start(code) {
|
|
101528
|
+
if (markdownLineEnding(code)) {
|
|
101529
|
+
effects.enter(types_types.lineEnding);
|
|
101530
|
+
effects.consume(code);
|
|
101531
|
+
effects.exit(types_types.lineEnding);
|
|
101532
|
+
return after;
|
|
101533
|
+
}
|
|
101534
|
+
return nok(code);
|
|
101535
|
+
}
|
|
101536
|
+
function after(code) {
|
|
101537
|
+
if (self.parser.lazy[self.now().line]) {
|
|
101538
|
+
return nok(code);
|
|
101539
|
+
}
|
|
101540
|
+
return ok(code);
|
|
101541
|
+
}
|
|
101542
|
+
}
|
|
101543
|
+
// A markup-only line opens with a tag (`<x`/`</x`) and ends (ignoring trailing
|
|
101544
|
+
// spaces) at a `>`. That distinguishes a structural continuation like
|
|
101545
|
+
// `<span>b</span></div>` from a paragraph like `<b>Note:</b> read *this*`.
|
|
101546
|
+
function tokenizeMarkupOnlyContinuation(effects, ok, nok) {
|
|
101547
|
+
let lastNonSpace = null;
|
|
101548
|
+
return start;
|
|
101549
|
+
function start(code) {
|
|
101550
|
+
// Caller guarantees we are at `<` at the (already de-indented) line start.
|
|
101551
|
+
effects.enter(types_types.data);
|
|
101552
|
+
effects.consume(code);
|
|
101553
|
+
return afterLessThan;
|
|
101554
|
+
}
|
|
101555
|
+
function afterLessThan(code) {
|
|
101556
|
+
if (code === codes.slash) {
|
|
101557
|
+
effects.consume(code);
|
|
101558
|
+
return afterSlash;
|
|
101559
|
+
}
|
|
101560
|
+
return afterSlash(code);
|
|
101561
|
+
}
|
|
101562
|
+
// The `<` (or `</`) must introduce a real tag, not a stray `<` in prose.
|
|
101563
|
+
function afterSlash(code) {
|
|
101564
|
+
if (asciiAlpha(code)) {
|
|
101565
|
+
lastNonSpace = code;
|
|
101566
|
+
effects.consume(code);
|
|
101567
|
+
return scanToLineEnd;
|
|
101568
|
+
}
|
|
101569
|
+
effects.exit(types_types.data);
|
|
101570
|
+
return nok(code);
|
|
101571
|
+
}
|
|
101572
|
+
function scanToLineEnd(code) {
|
|
101573
|
+
if (code === null || markdownLineEnding(code)) {
|
|
101574
|
+
effects.exit(types_types.data);
|
|
101575
|
+
return lastNonSpace === codes.greaterThan ? ok(code) : nok(code);
|
|
101576
|
+
}
|
|
101577
|
+
if (!markdownSpace(code))
|
|
101578
|
+
lastNonSpace = code;
|
|
101579
|
+
effects.consume(code);
|
|
101580
|
+
return scanToLineEnd;
|
|
101581
|
+
}
|
|
101582
|
+
}
|
|
101583
|
+
// A line ending whose next line isn't a lazy paragraph continuation. Checked so a
|
|
101584
|
+
// component body's blank/continuation lines aren't stolen by an interrupted paragraph.
|
|
101585
|
+
const continuation_checks_nonLazyContinuationStart = {
|
|
101586
|
+
tokenize: continuation_checks_tokenizeNonLazyContinuationStart,
|
|
101587
|
+
partial: true,
|
|
101588
|
+
};
|
|
101589
|
+
// Lookahead for `plainClaimLineStart`: is this line markup-only, or a paragraph
|
|
101590
|
+
// that merely starts with a tag? Run via `effects.check` so it never consumes.
|
|
101591
|
+
const markupOnlyContinuation = {
|
|
101592
|
+
tokenize: tokenizeMarkupOnlyContinuation,
|
|
101593
|
+
partial: true,
|
|
101594
|
+
};
|
|
101595
|
+
|
|
101501
101596
|
;// ./lib/micromark/mdx-component/syntax.ts
|
|
101502
101597
|
|
|
101503
101598
|
|
|
101504
101599
|
|
|
101505
101600
|
|
|
101506
101601
|
|
|
101602
|
+
|
|
101507
101603
|
// Raw tags (type-1: pre/script/style/textarea) and block tags (type-6: div,
|
|
101508
101604
|
// section, …) always start a block, so they stay flow even with trailing
|
|
101509
101605
|
// content. Other lowercase tags (i, span, …) follow the type-7 rule and only
|
|
@@ -101513,16 +101609,19 @@ const htmlFlowTagNames = new Set([...htmlRawNames, ...htmlBlockNames]);
|
|
|
101513
101609
|
// blank lines between nested JSX siblings don't fragment the block. Excludes table
|
|
101514
101610
|
// tags (mdxishTables owns their blank lines) and voids (never close).
|
|
101515
101611
|
const plainBlockClaimTagNames = new Set([...htmlBlockNames].filter(tag => !HTML_TABLE_STRUCTURE_TAGS.has(tag) && !HTML_VOID_ELEMENTS.has(tag)));
|
|
101516
|
-
const
|
|
101517
|
-
|
|
101518
|
-
|
|
101519
|
-
|
|
101520
|
-
//
|
|
101521
|
-
//
|
|
101522
|
-
const
|
|
101523
|
-
|
|
101524
|
-
|
|
101525
|
-
|
|
101612
|
+
const foreignContentTags = new Set(FOREIGN_CONTENT_TAGS);
|
|
101613
|
+
// Type-7 lowercase tags (a, span, button, and unknown names): CommonMark ends their
|
|
101614
|
+
// block at a blank line, fragmenting 4+ column children into indented code. Claimable
|
|
101615
|
+
// only in block-wrapper shape (see `blockWrapperOpenerRest`); lookalike openers
|
|
101616
|
+
// (`<https://…>`) never find a closer, so their claim retreats cleanly to CommonMark.
|
|
101617
|
+
// Voids never close and raw/foreign-content bodies have dedicated owners.
|
|
101618
|
+
const isBlockWrapperClaimTagName = (tag) => !htmlFlowTagNames.has(tag) && !HTML_VOID_ELEMENTS.has(tag) && !foreignContentTags.has(tag);
|
|
101619
|
+
// Both are 4 columns per CommonMark, but they mean different things: a tab advances
|
|
101620
|
+
// to the next multiple of TAB_STOP_WIDTH, and INDENTED_CODE_MIN_COLUMNS is the depth
|
|
101621
|
+
// at which a line would fragment into indented code. Named separately so the two
|
|
101622
|
+
// concepts don't read as one incidental literal.
|
|
101623
|
+
const TAB_STOP_WIDTH = 4;
|
|
101624
|
+
const INDENTED_CODE_MIN_COLUMNS = 4;
|
|
101526
101625
|
function resolveToMdxComponent(events) {
|
|
101527
101626
|
let index = events.length;
|
|
101528
101627
|
while (index > 0) {
|
|
@@ -101581,6 +101680,23 @@ function createTokenize(mode) {
|
|
|
101581
101680
|
// `plainClaimLineStart`: after a blank line it may only continue on a tag line.
|
|
101582
101681
|
let isPlainBlockClaim = false;
|
|
101583
101682
|
let pendingBlankLine = false;
|
|
101683
|
+
// Type-7 tag claimed pending the block-wrapper (opener alone on its line) check.
|
|
101684
|
+
let pendingBlockWrapperClaim = false;
|
|
101685
|
+
// True once a block-wrapper claim is confirmed; relaxes the top-of-body island gate
|
|
101686
|
+
// below (type-7 fallback is the fragmentation bug, not intentional indented code).
|
|
101687
|
+
let isBlockWrapperClaim = false;
|
|
101688
|
+
// Leading indent columns of the current plain-claim line, reset per line; ≥4 is
|
|
101689
|
+
// where CommonMark would fragment the island as indented code. Tabs advance to the
|
|
101690
|
+
// next 4-column stop — the same rule `expandIndentToColumns`
|
|
101691
|
+
// (processor/transform/mdxish/indentation.ts) applies, kept in sync by hand since
|
|
101692
|
+
// this side works on a `Code` stream, not a string. NB: do NOT swap this for
|
|
101693
|
+
// `self.now().column`; micromark bumps the point column by 1 per `horizontalTab`
|
|
101694
|
+
// code (the trailing `virtualSpace` codes don't move it), so it measures a tab as
|
|
101695
|
+
// 1 column, reviving the tab-under-measurement bug this math exists to avoid.
|
|
101696
|
+
let plainClaimIndentColumns = 0;
|
|
101697
|
+
// True once a non-blank line follows the opener: a deep island below it is nested
|
|
101698
|
+
// (cosmetic indent), not top-of-body indented code.
|
|
101699
|
+
let sawPlainBlockBodyContent = false;
|
|
101584
101700
|
// Code span tracking
|
|
101585
101701
|
let codeSpanOpenSize = 0;
|
|
101586
101702
|
let codeSpanCloseSize = 0;
|
|
@@ -101814,16 +101930,11 @@ function createTokenize(mode) {
|
|
|
101814
101930
|
}
|
|
101815
101931
|
// End of opening tag
|
|
101816
101932
|
if (code === codes.greaterThan) {
|
|
101817
|
-
if (requiresBraceAttr && !sawBraceAttr)
|
|
101818
|
-
|
|
101819
|
-
// `plainClaimLineStart`; everything else falls through to CommonMark.
|
|
101820
|
-
if (!isFlow || !plainBlockClaimTagNames.has(tagName))
|
|
101821
|
-
return nok(code);
|
|
101822
|
-
isPlainBlockClaim = true;
|
|
101823
|
-
}
|
|
101933
|
+
if (requiresBraceAttr && !sawBraceAttr && !claimBraceLessTag())
|
|
101934
|
+
return nok(code);
|
|
101824
101935
|
effects.consume(code);
|
|
101825
101936
|
onOpenerLine = isFlow;
|
|
101826
|
-
return body;
|
|
101937
|
+
return pendingBlockWrapperClaim ? blockWrapperOpenerRest : body;
|
|
101827
101938
|
}
|
|
101828
101939
|
// Quoted attribute value
|
|
101829
101940
|
if (code === codes.quotationMark || code === codes.apostrophe) {
|
|
@@ -101878,9 +101989,38 @@ function createTokenize(mode) {
|
|
|
101878
101989
|
// `/ ` without `>` is just part of the attribute area
|
|
101879
101990
|
return afterOpenTagName(code);
|
|
101880
101991
|
}
|
|
101992
|
+
// Whether a brace-less lowercase flow tag is claimable: type-6 tags immediately,
|
|
101993
|
+
// type-7 tags pending the block-wrapper check; anything else is CommonMark's.
|
|
101994
|
+
function claimBraceLessTag() {
|
|
101995
|
+
if (!isFlow)
|
|
101996
|
+
return false;
|
|
101997
|
+
if (plainBlockClaimTagNames.has(tagName)) {
|
|
101998
|
+
isPlainBlockClaim = true;
|
|
101999
|
+
return true;
|
|
102000
|
+
}
|
|
102001
|
+
if (isBlockWrapperClaimTagName(tagName)) {
|
|
102002
|
+
pendingBlockWrapperClaim = true;
|
|
102003
|
+
return true;
|
|
102004
|
+
}
|
|
102005
|
+
return false;
|
|
102006
|
+
}
|
|
102007
|
+
// A type-7 tag is claimed only as a block wrapper: opener alone on its line
|
|
102008
|
+
// (trailing spaces ok). Inline content after the opener bails to CommonMark.
|
|
102009
|
+
function blockWrapperOpenerRest(code) {
|
|
102010
|
+
if (markdownSpace(code)) {
|
|
102011
|
+
effects.consume(code);
|
|
102012
|
+
return blockWrapperOpenerRest;
|
|
102013
|
+
}
|
|
102014
|
+
if (!markdownLineEnding(code))
|
|
102015
|
+
return nok(code);
|
|
102016
|
+
pendingBlockWrapperClaim = false;
|
|
102017
|
+
isPlainBlockClaim = true;
|
|
102018
|
+
isBlockWrapperClaim = true;
|
|
102019
|
+
return body(code);
|
|
102020
|
+
}
|
|
101881
102021
|
// Continuation for multi-line opening tags
|
|
101882
102022
|
function openTagContinuationStart(code) {
|
|
101883
|
-
return effects.check(
|
|
102023
|
+
return effects.check(continuation_checks_nonLazyContinuationStart, openTagContinuationNonLazy, continuationAfter)(code);
|
|
101884
102024
|
}
|
|
101885
102025
|
function openTagContinuationNonLazy(code) {
|
|
101886
102026
|
sawLineEnding = true;
|
|
@@ -101925,6 +102065,9 @@ function createTokenize(mode) {
|
|
|
101925
102065
|
}
|
|
101926
102066
|
if (code !== codes.space && code !== codes.horizontalTab) {
|
|
101927
102067
|
openerLineHasContent = true;
|
|
102068
|
+
// Continuation content marks a later deep island as nested, not indented code.
|
|
102069
|
+
if (!onOpenerLine)
|
|
102070
|
+
sawPlainBlockBodyContent = true;
|
|
101928
102071
|
}
|
|
101929
102072
|
if (code === codes.backslash) {
|
|
101930
102073
|
effects.consume(code);
|
|
@@ -102005,7 +102148,7 @@ function createTokenize(mode) {
|
|
|
102005
102148
|
return inFencedCode;
|
|
102006
102149
|
}
|
|
102007
102150
|
function fencedCodeContinuationStart(code) {
|
|
102008
|
-
return effects.check(
|
|
102151
|
+
return effects.check(continuation_checks_nonLazyContinuationStart, fencedCodeContinuationNonLazy, continuationAfter)(code);
|
|
102009
102152
|
}
|
|
102010
102153
|
function fencedCodeContinuationNonLazy(code) {
|
|
102011
102154
|
sawLineEnding = true;
|
|
@@ -102213,7 +102356,7 @@ function createTokenize(mode) {
|
|
|
102213
102356
|
}
|
|
102214
102357
|
// ── Body continuation (line endings) ───────────────────────────────────
|
|
102215
102358
|
function bodyContinuationStart(code) {
|
|
102216
|
-
return effects.check(
|
|
102359
|
+
return effects.check(continuation_checks_nonLazyContinuationStart, bodyContinuationNonLazy, continuationAfter)(code);
|
|
102217
102360
|
}
|
|
102218
102361
|
function bodyContinuationNonLazy(code) {
|
|
102219
102362
|
sawLineEnding = true;
|
|
@@ -102239,8 +102382,10 @@ function createTokenize(mode) {
|
|
|
102239
102382
|
return inBodyBraceString(code);
|
|
102240
102383
|
return inBodyBraceExpr(code);
|
|
102241
102384
|
}
|
|
102242
|
-
if (isPlainBlockClaim)
|
|
102385
|
+
if (isPlainBlockClaim) {
|
|
102386
|
+
plainClaimIndentColumns = 0;
|
|
102243
102387
|
return plainClaimLineStart(code);
|
|
102388
|
+
}
|
|
102244
102389
|
return bodyLineStart(code);
|
|
102245
102390
|
}
|
|
102246
102391
|
// Dispatch a non-blank continuation line: fenced code at line start, else body.
|
|
@@ -102268,8 +102413,16 @@ function createTokenize(mode) {
|
|
|
102268
102413
|
// continue on a tag line (`<…`); any markdown island (`**bold**`, `[block:…]`, a
|
|
102269
102414
|
// fence) refuses so CommonMark html-flow reparses it exactly as it does today.
|
|
102270
102415
|
function plainClaimLineStart(code) {
|
|
102271
|
-
// Leading whitespace only → treat as a blank line, matching CommonMark.
|
|
102272
|
-
|
|
102416
|
+
// Leading whitespace only → treat as a blank line, matching CommonMark. A tab
|
|
102417
|
+
// advances to the next stop; its trailing `virtualSpace` fillers add nothing
|
|
102418
|
+
// but must still be consumed or they'd read as line content below.
|
|
102419
|
+
if (markdownSpace(code)) {
|
|
102420
|
+
if (code === codes.horizontalTab) {
|
|
102421
|
+
plainClaimIndentColumns += TAB_STOP_WIDTH - (plainClaimIndentColumns % TAB_STOP_WIDTH);
|
|
102422
|
+
}
|
|
102423
|
+
else if (code === codes.space) {
|
|
102424
|
+
plainClaimIndentColumns += 1;
|
|
102425
|
+
}
|
|
102273
102426
|
effects.consume(code);
|
|
102274
102427
|
return plainClaimLineStart;
|
|
102275
102428
|
}
|
|
@@ -102278,10 +102431,19 @@ function createTokenize(mode) {
|
|
|
102278
102431
|
effects.exit('mdxComponentData');
|
|
102279
102432
|
return bodyContinuationStart(code);
|
|
102280
102433
|
}
|
|
102281
|
-
// Across a blank line the block only continues onto a markup-only line; a
|
|
102282
|
-
// paragraph that merely starts with a tag must fall back so its markdown
|
|
102283
|
-
// parses and rehype-raw re-nests it into the wrapper.
|
|
102284
102434
|
if (pendingBlankLine) {
|
|
102435
|
+
// A 4+ col island nested under other tags is cosmetic nesting indent, not code:
|
|
102436
|
+
// keep claiming so promotion dedents + re-parses it as markdown (RM-17560).
|
|
102437
|
+
// Block-wrapper claims extend this to top-of-body islands — their CommonMark
|
|
102438
|
+
// fallback is the fragmentation bug, not intentional indented code. Tags whose
|
|
102439
|
+
// bodies stay raw are excluded: a claimed island there would leak as literal text.
|
|
102440
|
+
if (plainClaimIndentColumns >= INDENTED_CODE_MIN_COLUMNS &&
|
|
102441
|
+
(sawPlainBlockBodyContent || isBlockWrapperClaim) &&
|
|
102442
|
+
!NON_REPARSED_BODY_TAGS.has(tagName)) {
|
|
102443
|
+
return plainClaimContinue(code);
|
|
102444
|
+
}
|
|
102445
|
+
// Otherwise only a markup-only tag line continues; markdown/prose falls back to
|
|
102446
|
+
// CommonMark so it parses and rehype-raw re-nests it into the wrapper.
|
|
102285
102447
|
if (code !== codes.lessThan)
|
|
102286
102448
|
return nok(code);
|
|
102287
102449
|
return effects.check(markupOnlyContinuation, plainClaimContinue, nok)(code);
|
|
@@ -102302,66 +102464,6 @@ function createTokenize(mode) {
|
|
|
102302
102464
|
}
|
|
102303
102465
|
};
|
|
102304
102466
|
}
|
|
102305
|
-
function mdx_component_syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
|
|
102306
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
102307
|
-
const self = this;
|
|
102308
|
-
return start;
|
|
102309
|
-
function start(code) {
|
|
102310
|
-
if (markdownLineEnding(code)) {
|
|
102311
|
-
effects.enter(types_types.lineEnding);
|
|
102312
|
-
effects.consume(code);
|
|
102313
|
-
effects.exit(types_types.lineEnding);
|
|
102314
|
-
return after;
|
|
102315
|
-
}
|
|
102316
|
-
return nok(code);
|
|
102317
|
-
}
|
|
102318
|
-
function after(code) {
|
|
102319
|
-
if (self.parser.lazy[self.now().line]) {
|
|
102320
|
-
return nok(code);
|
|
102321
|
-
}
|
|
102322
|
-
return ok(code);
|
|
102323
|
-
}
|
|
102324
|
-
}
|
|
102325
|
-
// A markup-only line opens with a tag (`<x`/`</x`) and ends (ignoring trailing
|
|
102326
|
-
// spaces) at a `>`. That distinguishes a structural continuation like
|
|
102327
|
-
// `<span>b</span></div>` from a paragraph like `<b>Note:</b> read *this*`.
|
|
102328
|
-
function tokenizeMarkupOnlyContinuation(effects, ok, nok) {
|
|
102329
|
-
let lastNonSpace = null;
|
|
102330
|
-
return start;
|
|
102331
|
-
function start(code) {
|
|
102332
|
-
// Caller guarantees we are at `<` at the (already de-indented) line start.
|
|
102333
|
-
effects.enter(types_types.data);
|
|
102334
|
-
effects.consume(code);
|
|
102335
|
-
return afterLessThan;
|
|
102336
|
-
}
|
|
102337
|
-
function afterLessThan(code) {
|
|
102338
|
-
if (code === codes.slash) {
|
|
102339
|
-
effects.consume(code);
|
|
102340
|
-
return afterSlash;
|
|
102341
|
-
}
|
|
102342
|
-
return afterSlash(code);
|
|
102343
|
-
}
|
|
102344
|
-
// The `<` (or `</`) must introduce a real tag, not a stray `<` in prose.
|
|
102345
|
-
function afterSlash(code) {
|
|
102346
|
-
if (asciiAlpha(code)) {
|
|
102347
|
-
lastNonSpace = code;
|
|
102348
|
-
effects.consume(code);
|
|
102349
|
-
return scanToLineEnd;
|
|
102350
|
-
}
|
|
102351
|
-
effects.exit(types_types.data);
|
|
102352
|
-
return nok(code);
|
|
102353
|
-
}
|
|
102354
|
-
function scanToLineEnd(code) {
|
|
102355
|
-
if (code === null || markdownLineEnding(code)) {
|
|
102356
|
-
effects.exit(types_types.data);
|
|
102357
|
-
return lastNonSpace === codes.greaterThan ? ok(code) : nok(code);
|
|
102358
|
-
}
|
|
102359
|
-
if (!markdownSpace(code))
|
|
102360
|
-
lastNonSpace = code;
|
|
102361
|
-
effects.consume(code);
|
|
102362
|
-
return scanToLineEnd;
|
|
102363
|
-
}
|
|
102364
|
-
}
|
|
102365
102467
|
/**
|
|
102366
102468
|
* Micromark extension that tokenizes MDX-like components.
|
|
102367
102469
|
*
|
|
@@ -102415,6 +102517,7 @@ function mdxComponent() {
|
|
|
102415
102517
|
|
|
102416
102518
|
|
|
102417
102519
|
|
|
102520
|
+
|
|
102418
102521
|
|
|
102419
102522
|
const buildInlineMdProcessor = (safeMode) => {
|
|
102420
102523
|
// `jsxTable` must be present so a `<Table>`/`<table>` nested in a component
|
|
@@ -102486,7 +102589,7 @@ const toMdxJsxTextElement = (name, attributes, children, position) => ({
|
|
|
102486
102589
|
// Raw-body tags (pre/script/style/textarea) must stay byte-exact; table
|
|
102487
102590
|
// structure (`table` + `tableTags`) is owned by `mdxishTables` and figures by
|
|
102488
102591
|
// `mdxishJsxToMdast`, both of which run later on raw html nodes.
|
|
102489
|
-
const NON_PROMOTABLE_PLAIN_TAGS = new Set([...htmlRawNames, ...tableTags, 'table',
|
|
102592
|
+
const NON_PROMOTABLE_PLAIN_TAGS = new Set([...htmlRawNames, ...tableTags, 'table', ...NON_REPARSED_BODY_TAGS]);
|
|
102490
102593
|
const NESTED_TABLE_RE = /<table[\s>]/i;
|
|
102491
102594
|
const isMarkdownPromotableHtmlTag = (tag) => !NON_PROMOTABLE_PLAIN_TAGS.has(tag);
|
|
102492
102595
|
// Expression nodes count as plain so `<div>{1+1}</div>` keeps its current
|
|
@@ -102845,15 +102948,22 @@ function safeDeindent(text) {
|
|
|
102845
102948
|
*/
|
|
102846
102949
|
const parseMdChildren = (value, safeMode) => {
|
|
102847
102950
|
const parsed = getInlineMdProcessor({ safeMode }).parse(terminateHtmlFlowBlocks(safeDeindent(value).trim()));
|
|
102951
|
+
// Promote nested wrappers bottom-up so an outer wrapper sees markdown buried in a
|
|
102952
|
+
// child claimed whole (e.g. `<li>` in `<ol>`) before its containsMarkdownConstruct check (RM-17560).
|
|
102953
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define -- mutually recursive; hoisted decl, safe at runtime
|
|
102954
|
+
promoteComponentBlocks(parsed, safeMode, null);
|
|
102848
102955
|
return parsed.children || [];
|
|
102849
102956
|
};
|
|
102850
|
-
//
|
|
102851
|
-
// components among them
|
|
102852
|
-
|
|
102957
|
+
// Splices trailing content in as sibling nodes. parseMdChildren has already
|
|
102958
|
+
// promoted any components nested among them (bottom-up); the main loop's
|
|
102959
|
+
// index-based walk then reaches these spliced siblings and the original children
|
|
102960
|
+
// they shift down, so no parent re-queue is needed. Each spliced subtree is marked
|
|
102961
|
+
// `promoted` so the walk doesn't redundantly re-descend into it (its html is gone).
|
|
102962
|
+
const parseSibling = (parent, index, sibling, safeMode, promoted) => {
|
|
102853
102963
|
const siblingNodes = parseMdChildren(sibling, safeMode);
|
|
102854
102964
|
if (siblingNodes.length > 0) {
|
|
102855
102965
|
parent.children.splice(index + 1, 0, ...siblingNodes);
|
|
102856
|
-
|
|
102966
|
+
siblingNodes.forEach(siblingNode => promoted.add(siblingNode));
|
|
102857
102967
|
}
|
|
102858
102968
|
};
|
|
102859
102969
|
// Ends the position at `consumedLength` so the component doesn't claim trailing
|
|
@@ -102919,16 +103029,19 @@ const substituteNodeWithMdxNode = (parent, index, mdxNode) => {
|
|
|
102919
103029
|
* The opening tag, content, and closing tag are all captured in one HTML node
|
|
102920
103030
|
* (guaranteed by the mdx-component tokenizer).
|
|
102921
103031
|
*/
|
|
102922
|
-
|
|
103032
|
+
function promoteComponentBlocks(tree, safeMode, source) {
|
|
102923
103033
|
const stack = [tree];
|
|
102924
|
-
const safeMode = !!opts.safeMode;
|
|
102925
|
-
const source = file?.value ? String(file.value) : null;
|
|
102926
103034
|
const parseOpts = { preserveExpressionsAsText: safeMode };
|
|
103035
|
+
// Subtrees a nested parseMdChildren already promoted wholesale (spliced siblings):
|
|
103036
|
+
// re-descending them finds no html to promote, so skip them.
|
|
103037
|
+
const promoted = new WeakSet();
|
|
102927
103038
|
const processChildNode = (parent, index) => {
|
|
102928
103039
|
const node = parent.children[index];
|
|
102929
103040
|
if (!node)
|
|
102930
103041
|
return;
|
|
102931
|
-
|
|
103042
|
+
// Descend into container nodes (lists, blockquotes, …) so their html children
|
|
103043
|
+
// are reached — unless the subtree was already promoted upstream.
|
|
103044
|
+
if ('children' in node && Array.isArray(node.children) && !promoted.has(node)) {
|
|
102932
103045
|
stack.push(node);
|
|
102933
103046
|
}
|
|
102934
103047
|
// Only html nodes can be an unparsed MDX component.
|
|
@@ -102983,7 +103096,7 @@ const mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
|
|
|
102983
103096
|
substituteNodeWithMdxNode(parent, index, componentNode);
|
|
102984
103097
|
const remainingContent = contentAfterTag.trim();
|
|
102985
103098
|
if (remainingContent) {
|
|
102986
|
-
parseSibling(
|
|
103099
|
+
parseSibling(parent, index, remainingContent, safeMode, promoted);
|
|
102987
103100
|
}
|
|
102988
103101
|
return;
|
|
102989
103102
|
}
|
|
@@ -103010,43 +103123,57 @@ const mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
|
|
|
103010
103123
|
return;
|
|
103011
103124
|
// Lowercase tags are usually inline; unwrap a sole paragraph so their
|
|
103012
103125
|
// phrasing content isn't spuriously block-wrapped.
|
|
103126
|
+
let unwrappedSoleParagraph = false;
|
|
103013
103127
|
if (!isPascal && parsedChildren.length === 1 && parsedChildren[0].type === 'paragraph') {
|
|
103014
103128
|
parsedChildren = parsedChildren[0].children;
|
|
103129
|
+
unwrappedSoleParagraph = true;
|
|
103130
|
+
}
|
|
103131
|
+
// Without trailing content the whole node position is correct. With it, end
|
|
103132
|
+
// precisely at the closing tag — preferring source offsets when available (the
|
|
103133
|
+
// node's value strips blockquote/list prefixes), else the consumed span.
|
|
103134
|
+
let endPosition = node.position;
|
|
103135
|
+
if (contentAfterClose) {
|
|
103136
|
+
endPosition = source
|
|
103137
|
+
? positionEndingAtClosingTagInSource(node.position, closingTagStr, source)
|
|
103138
|
+
: positionEndingAtConsumed(node.position, value, leadingWhitespace + openingTagEnd + closingTagIndex + closingTagStr.length);
|
|
103015
103139
|
}
|
|
103016
103140
|
const componentNode = createComponentNode({
|
|
103017
103141
|
tag,
|
|
103018
103142
|
attributes,
|
|
103019
103143
|
children: parsedChildren,
|
|
103020
103144
|
startPosition: node.position,
|
|
103021
|
-
|
|
103022
|
-
// offsets when available (the node's value strips blockquote/list
|
|
103023
|
-
// prefixes); otherwise fall back to the whole node position.
|
|
103024
|
-
endPosition: contentAfterClose
|
|
103025
|
-
? source
|
|
103026
|
-
? positionEndingAtClosingTagInSource(node.position, closingTagStr, source)
|
|
103027
|
-
: positionEndingAtConsumed(node.position, value, leadingWhitespace + openingTagEnd + closingTagIndex + closingTagStr.length)
|
|
103028
|
-
: node.position,
|
|
103145
|
+
endPosition,
|
|
103029
103146
|
});
|
|
103030
103147
|
substituteNodeWithMdxNode(parent, index, componentNode);
|
|
103031
|
-
//
|
|
103032
|
-
|
|
103033
|
-
|
|
103034
|
-
}
|
|
103035
|
-
else if (componentNode.children.length > 0) {
|
|
103148
|
+
// The unwrap reparented the children out of their paragraph, so re-walk them
|
|
103149
|
+
// since the children HTML may contain promotable syntax (e.g. `{…}`-attr tags)
|
|
103150
|
+
if (unwrappedSoleParagraph) {
|
|
103036
103151
|
stack.push(componentNode);
|
|
103037
103152
|
}
|
|
103153
|
+
// Trailing content after the close becomes siblings; parseMdChildren has
|
|
103154
|
+
// already promoted any components nested inside both sides, so the promoted
|
|
103155
|
+
// subtree itself needs no re-queue.
|
|
103156
|
+
if (contentAfterClose) {
|
|
103157
|
+
parseSibling(parent, index, contentAfterClose, safeMode, promoted);
|
|
103158
|
+
}
|
|
103038
103159
|
}
|
|
103039
103160
|
};
|
|
103040
|
-
// Depth-first so nodes keep their source order.
|
|
103161
|
+
// Depth-first so nodes keep their source order. Index-based (not forEach) and
|
|
103162
|
+
// re-reading length each step: parseSibling splices siblings in mid-iteration, and
|
|
103163
|
+
// those — plus the original children they shift down — must all stay eligible.
|
|
103041
103164
|
while (stack.length) {
|
|
103042
103165
|
const parent = stack.pop();
|
|
103043
103166
|
if (parent?.children) {
|
|
103044
|
-
parent.children.
|
|
103167
|
+
for (let index = 0; index < parent.children.length; index += 1) {
|
|
103045
103168
|
processChildNode(parent, index);
|
|
103046
|
-
}
|
|
103169
|
+
}
|
|
103047
103170
|
}
|
|
103048
103171
|
}
|
|
103049
103172
|
return tree;
|
|
103173
|
+
}
|
|
103174
|
+
const mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
|
|
103175
|
+
const source = file?.value ? String(file.value) : null;
|
|
103176
|
+
return promoteComponentBlocks(tree, !!opts.safeMode, source);
|
|
103050
103177
|
};
|
|
103051
103178
|
/* harmony default export */ const mdx_blocks = (mdxishMdxComponentBlocks);
|
|
103052
103179
|
|
|
@@ -106800,7 +106927,7 @@ function mdxishMdastToMd(mdast) {
|
|
|
106800
106927
|
* Processes markdown content with MDX syntax support and returns a HAST.
|
|
106801
106928
|
* Detects and renders custom component tags from the components hash.
|
|
106802
106929
|
*
|
|
106803
|
-
* @see
|
|
106930
|
+
* @see .claude/context/MDXish/Processor Overview.md
|
|
106804
106931
|
*/
|
|
106805
106932
|
function mdxish(mdContent, opts = {}) {
|
|
106806
106933
|
const { components: userComponents = {}, safeMode = false, variables } = opts;
|
|
@@ -107140,7 +107267,7 @@ function buildRMDXModule(content, headings, tocHast, opts) {
|
|
|
107140
107267
|
* @param opts - The options for the render
|
|
107141
107268
|
* @returns The React component
|
|
107142
107269
|
*
|
|
107143
|
-
* @see
|
|
107270
|
+
* @see .claude/context/MDXish/Processor Overview.md
|
|
107144
107271
|
*/
|
|
107145
107272
|
const renderMdxish = (tree, opts = {}) => {
|
|
107146
107273
|
const { components: userComponents = {}, variables, ...contextOpts } = opts;
|