@readme/markdown 14.11.0 → 14.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +293 -36
- package/dist/main.node.js +293 -36
- package/dist/main.node.js.map +1 -1
- package/dist/processor/transform/mdxish/evaluate-style-block-expressions.d.ts +18 -0
- package/dist/processor/transform/mdxish/style-object-to-css.d.ts +11 -0
- package/dist/processor/transform/mdxish/tables/utils.d.ts +5 -0
- package/dist/render-fixture.node.js +293 -36
- package/dist/render-fixture.node.js.map +1 -1
- package/dist/utils/common-html-words.d.ts +7 -0
- package/package.json +1 -1
package/dist/main.node.js
CHANGED
|
@@ -95943,6 +95943,18 @@ const tableTags = new Set([
|
|
|
95943
95943
|
'th',
|
|
95944
95944
|
'td',
|
|
95945
95945
|
]);
|
|
95946
|
+
/**
|
|
95947
|
+
* Replaces every paragraph node with its inline children. Used where paragraphs
|
|
95948
|
+
* are parser artifacts (remarkMdx wrapping inline JSX), not real content.
|
|
95949
|
+
*/
|
|
95950
|
+
const unwrapParagraphNodes = (children) => {
|
|
95951
|
+
return children.flatMap(child => {
|
|
95952
|
+
if (child.type === 'paragraph' && 'children' in child && Array.isArray(child.children)) {
|
|
95953
|
+
return child.children;
|
|
95954
|
+
}
|
|
95955
|
+
return [child];
|
|
95956
|
+
});
|
|
95957
|
+
};
|
|
95946
95958
|
/**
|
|
95947
95959
|
* If the cell has exactly one paragraph child, unwrap it so its inline children sit
|
|
95948
95960
|
* directly under the cell (matches GFM table cell shape and avoids stray `<p>` wrappers).
|
|
@@ -95954,12 +95966,7 @@ const unwrapSoleParagraph = (children) => {
|
|
|
95954
95966
|
const paragraphCount = children.filter(c => c.type === 'paragraph').length;
|
|
95955
95967
|
if (paragraphCount !== 1)
|
|
95956
95968
|
return children;
|
|
95957
|
-
return children
|
|
95958
|
-
if (child.type === 'paragraph' && 'children' in child && Array.isArray(child.children)) {
|
|
95959
|
-
return child.children;
|
|
95960
|
-
}
|
|
95961
|
-
return [child];
|
|
95962
|
-
});
|
|
95969
|
+
return unwrapParagraphNodes(children);
|
|
95963
95970
|
};
|
|
95964
95971
|
/**
|
|
95965
95972
|
* Splice each text into `html` at its offset. Inserts at the same offset
|
|
@@ -96309,6 +96316,23 @@ const RUNTIME_COMPONENT_TAGS = new Set(['Variable', 'variable', 'html-block', 'r
|
|
|
96309
96316
|
* Uses the html-tags package, converted to a Set<string> for efficient lookups.
|
|
96310
96317
|
*/
|
|
96311
96318
|
const STANDARD_HTML_TAGS = new Set(html_tags_namespaceObject);
|
|
96319
|
+
/**
|
|
96320
|
+
* Table structural tags. Blank lines inside these carry deliberate meaning for
|
|
96321
|
+
* `mdxishTables` (e.g. splitting cell content into paragraphs, or deciding
|
|
96322
|
+
* whether a table stays plain HTML vs a JSX `<Table>`), so transforms that
|
|
96323
|
+
* neutralize or claim across blank lines must leave them alone.
|
|
96324
|
+
*/
|
|
96325
|
+
const HTML_TABLE_STRUCTURE_TAGS = new Set([
|
|
96326
|
+
'table',
|
|
96327
|
+
'thead',
|
|
96328
|
+
'tbody',
|
|
96329
|
+
'tfoot',
|
|
96330
|
+
'tr',
|
|
96331
|
+
'td',
|
|
96332
|
+
'th',
|
|
96333
|
+
'caption',
|
|
96334
|
+
'colgroup',
|
|
96335
|
+
]);
|
|
96312
96336
|
/**
|
|
96313
96337
|
* HTML void elements — elements that have no closing tag and no children.
|
|
96314
96338
|
*
|
|
@@ -96620,18 +96644,17 @@ const processTableNode = (node, index, parent, documentPosition) => {
|
|
|
96620
96644
|
// same line as content becomes mdxJsxTextElement inside a paragraph).
|
|
96621
96645
|
// Unwrap these so <td>/<th> sit directly under <tr>, and strip
|
|
96622
96646
|
// whitespace-only text nodes to avoid rendering empty <p>/<br>.
|
|
96623
|
-
const
|
|
96624
|
-
.flatMap(child => {
|
|
96625
|
-
if (child.type === 'paragraph' && 'children' in child && Array.isArray(child.children)) {
|
|
96626
|
-
return child.children;
|
|
96627
|
-
}
|
|
96628
|
-
return [child];
|
|
96629
|
-
})
|
|
96630
|
-
.filter(child => !(child.type === 'text' && 'value' in child && typeof child.value === 'string' && !child.value.trim()));
|
|
96647
|
+
const removeWhitespaceOnlyTextNodes = (children) => children.filter(child => !(child.type === 'text' && 'value' in child && typeof child.value === 'string' && !child.value.trim()));
|
|
96631
96648
|
visit(node, isMDXElement, (el) => {
|
|
96632
|
-
if ('children' in el
|
|
96633
|
-
|
|
96634
|
-
|
|
96649
|
+
if (!('children' in el) || !Array.isArray(el.children))
|
|
96650
|
+
return;
|
|
96651
|
+
// Filtering transformers
|
|
96652
|
+
// A cell only unwraps a sole paragraph: multiple paragraphs are real
|
|
96653
|
+
// blank-line-separated content that must stay separated
|
|
96654
|
+
const unwrapped = isTableCell(el)
|
|
96655
|
+
? unwrapSoleParagraph(el.children)
|
|
96656
|
+
: unwrapParagraphNodes(el.children);
|
|
96657
|
+
el.children = removeWhitespaceOnlyTextNodes(unwrapped);
|
|
96635
96658
|
});
|
|
96636
96659
|
parent.children[index] = {
|
|
96637
96660
|
...node,
|
|
@@ -121021,15 +121044,26 @@ const types_types = /** @type {const} */ ({
|
|
|
121021
121044
|
|
|
121022
121045
|
|
|
121023
121046
|
|
|
121047
|
+
|
|
121024
121048
|
// Raw tags (type-1: pre/script/style/textarea) and block tags (type-6: div,
|
|
121025
121049
|
// section, …) always start a block, so they stay flow even with trailing
|
|
121026
121050
|
// content. Other lowercase tags (i, span, …) follow the type-7 rule and only
|
|
121027
121051
|
// stay flow when nothing trails the close tag.
|
|
121028
121052
|
const htmlFlowTagNames = new Set([...htmlRawNames, ...htmlBlockNames]);
|
|
121053
|
+
// Lowercase type-6 block tags claimable in flow even without a `{…}` attribute, so
|
|
121054
|
+
// blank lines between nested JSX siblings don't fragment the block. Excludes table
|
|
121055
|
+
// tags (mdxishTables owns their blank lines) and voids (never close).
|
|
121056
|
+
const plainBlockClaimTagNames = new Set([...htmlBlockNames].filter(tag => !HTML_TABLE_STRUCTURE_TAGS.has(tag) && !HTML_VOID_ELEMENTS.has(tag)));
|
|
121029
121057
|
const syntax_nonLazyContinuationStart = {
|
|
121030
121058
|
tokenize: syntax_tokenizeNonLazyContinuationStart,
|
|
121031
121059
|
partial: true,
|
|
121032
121060
|
};
|
|
121061
|
+
// Lookahead for `plainClaimLineStart`: is this line markup-only, or a paragraph
|
|
121062
|
+
// that merely starts with a tag? Run via `effects.check` so it never consumes.
|
|
121063
|
+
const markupOnlyContinuation = {
|
|
121064
|
+
tokenize: tokenizeMarkupOnlyContinuation,
|
|
121065
|
+
partial: true,
|
|
121066
|
+
};
|
|
121033
121067
|
function resolveToMdxComponent(events) {
|
|
121034
121068
|
let index = events.length;
|
|
121035
121069
|
while (index > 0) {
|
|
@@ -121084,6 +121118,10 @@ function createTokenize(mode) {
|
|
|
121084
121118
|
// (INLINE_COMPONENT_TAGS — Anchor, Glossary), also brace-gated.
|
|
121085
121119
|
let isLowercaseTag = false;
|
|
121086
121120
|
let sawBraceAttr = false;
|
|
121121
|
+
// A plain lowercase block tag claimed without a `{…}` attribute, gated by
|
|
121122
|
+
// `plainClaimLineStart`: after a blank line it may only continue on a tag line.
|
|
121123
|
+
let isPlainBlockClaim = false;
|
|
121124
|
+
let pendingBlankLine = false;
|
|
121087
121125
|
// Code span tracking
|
|
121088
121126
|
let codeSpanOpenSize = 0;
|
|
121089
121127
|
let codeSpanCloseSize = 0;
|
|
@@ -121317,8 +121355,13 @@ function createTokenize(mode) {
|
|
|
121317
121355
|
}
|
|
121318
121356
|
// End of opening tag
|
|
121319
121357
|
if (code === codes.greaterThan) {
|
|
121320
|
-
if (requiresBraceAttr && !sawBraceAttr)
|
|
121321
|
-
|
|
121358
|
+
if (requiresBraceAttr && !sawBraceAttr) {
|
|
121359
|
+
// Plain lowercase block tags stay claimable in flow, gated per line by
|
|
121360
|
+
// `plainClaimLineStart`; everything else falls through to CommonMark.
|
|
121361
|
+
if (!isFlow || !plainBlockClaimTagNames.has(tagName))
|
|
121362
|
+
return nok(code);
|
|
121363
|
+
isPlainBlockClaim = true;
|
|
121364
|
+
}
|
|
121322
121365
|
effects.consume(code);
|
|
121323
121366
|
onOpenerLine = isFlow;
|
|
121324
121367
|
return body;
|
|
@@ -121468,6 +121511,7 @@ function createTokenize(mode) {
|
|
|
121468
121511
|
if (atLineStart && codeSpanOpenSize >= 3) {
|
|
121469
121512
|
fenceChar = codes.graveAccent;
|
|
121470
121513
|
fenceLength = codeSpanOpenSize;
|
|
121514
|
+
atLineStart = false;
|
|
121471
121515
|
return inFencedCode(code);
|
|
121472
121516
|
}
|
|
121473
121517
|
return inCodeSpan(code);
|
|
@@ -121615,8 +121659,14 @@ function createTokenize(mode) {
|
|
|
121615
121659
|
effects.consume(code);
|
|
121616
121660
|
return nestedOpenTagName;
|
|
121617
121661
|
}
|
|
121618
|
-
//
|
|
121619
|
-
|
|
121662
|
+
// Same-name opener followed by a tag-end char bumps depth. A line ending
|
|
121663
|
+
// counts too: Prettier puts a newline right after the name (`<div\n …\n>`).
|
|
121664
|
+
if (closingTagName === tagName &&
|
|
121665
|
+
(code === codes.greaterThan ||
|
|
121666
|
+
code === codes.slash ||
|
|
121667
|
+
code === codes.space ||
|
|
121668
|
+
code === codes.horizontalTab ||
|
|
121669
|
+
markdownLineEnding(code))) {
|
|
121620
121670
|
depth += 1;
|
|
121621
121671
|
}
|
|
121622
121672
|
atLineStart = false;
|
|
@@ -121705,6 +121755,10 @@ function createTokenize(mode) {
|
|
|
121705
121755
|
}
|
|
121706
121756
|
function bodyContinuationBefore(code) {
|
|
121707
121757
|
if (code === null || markdownLineEnding(code)) {
|
|
121758
|
+
// Empty line: outside any `{…}` expression this is CommonMark's html-block
|
|
121759
|
+
// terminator, so a plain block claim must pass the guard below to continue.
|
|
121760
|
+
if (isPlainBlockClaim && braceDepth === 0)
|
|
121761
|
+
pendingBlankLine = true;
|
|
121708
121762
|
return bodyContinuationStart(code);
|
|
121709
121763
|
}
|
|
121710
121764
|
effects.enter('mdxComponentData');
|
|
@@ -121716,19 +121770,52 @@ function createTokenize(mode) {
|
|
|
121716
121770
|
return inBodyBraceString(code);
|
|
121717
121771
|
return inBodyBraceExpr(code);
|
|
121718
121772
|
}
|
|
121719
|
-
|
|
121720
|
-
|
|
121773
|
+
if (isPlainBlockClaim)
|
|
121774
|
+
return plainClaimLineStart(code);
|
|
121775
|
+
return bodyLineStart(code);
|
|
121776
|
+
}
|
|
121777
|
+
// Dispatch a non-blank continuation line: fenced code at line start, else body.
|
|
121778
|
+
function bodyLineStart(code) {
|
|
121779
|
+
if (atLineStart && code === codes.tilde)
|
|
121721
121780
|
return bodyAfterLineStart(code);
|
|
121722
|
-
}
|
|
121723
|
-
// Detect backtick fences at line start
|
|
121724
121781
|
if (atLineStart && code === codes.graveAccent) {
|
|
121725
121782
|
codeSpanOpenSize = 0;
|
|
121726
|
-
atLineStart
|
|
121783
|
+
// Leave `atLineStart` set — `countOpenTicks` needs it to tell a fence from an
|
|
121784
|
+
// inline code span once the run of backticks is fully counted; it's cleared once
|
|
121785
|
+
// that fence-vs-span decision has actually been made.
|
|
121727
121786
|
return countOpenTicks(code);
|
|
121728
121787
|
}
|
|
121729
121788
|
atLineStart = false;
|
|
121730
121789
|
return body(code);
|
|
121731
121790
|
}
|
|
121791
|
+
// Line-start gate for plain block claims. After a blank line the block may only
|
|
121792
|
+
// continue on a tag line (`<…`); any markdown island (`**bold**`, `[block:…]`, a
|
|
121793
|
+
// fence) refuses so CommonMark html-flow reparses it exactly as it does today.
|
|
121794
|
+
function plainClaimLineStart(code) {
|
|
121795
|
+
// Leading whitespace only → treat as a blank line, matching CommonMark.
|
|
121796
|
+
if (code === codes.space || code === codes.horizontalTab) {
|
|
121797
|
+
effects.consume(code);
|
|
121798
|
+
return plainClaimLineStart;
|
|
121799
|
+
}
|
|
121800
|
+
if (code === null || markdownLineEnding(code)) {
|
|
121801
|
+
pendingBlankLine = true;
|
|
121802
|
+
effects.exit('mdxComponentData');
|
|
121803
|
+
return bodyContinuationStart(code);
|
|
121804
|
+
}
|
|
121805
|
+
// Across a blank line the block only continues onto a markup-only line; a
|
|
121806
|
+
// paragraph that merely starts with a tag must fall back so its markdown
|
|
121807
|
+
// parses and rehype-raw re-nests it into the wrapper.
|
|
121808
|
+
if (pendingBlankLine) {
|
|
121809
|
+
if (code !== codes.lessThan)
|
|
121810
|
+
return nok(code);
|
|
121811
|
+
return effects.check(markupOnlyContinuation, plainClaimContinue, nok)(code);
|
|
121812
|
+
}
|
|
121813
|
+
return bodyLineStart(code);
|
|
121814
|
+
}
|
|
121815
|
+
function plainClaimContinue(code) {
|
|
121816
|
+
pendingBlankLine = false;
|
|
121817
|
+
return bodyLineStart(code);
|
|
121818
|
+
}
|
|
121732
121819
|
// ── Shared lazy continuation failure ───────────────────────────────────
|
|
121733
121820
|
function continuationAfter(code) {
|
|
121734
121821
|
if (code === null) {
|
|
@@ -121759,6 +121846,46 @@ function syntax_tokenizeNonLazyContinuationStart(effects, ok, nok) {
|
|
|
121759
121846
|
return ok(code);
|
|
121760
121847
|
}
|
|
121761
121848
|
}
|
|
121849
|
+
// A markup-only line opens with a tag (`<x`/`</x`) and ends (ignoring trailing
|
|
121850
|
+
// spaces) at a `>`. That distinguishes a structural continuation like
|
|
121851
|
+
// `<span>b</span></div>` from a paragraph like `<b>Note:</b> read *this*`.
|
|
121852
|
+
function tokenizeMarkupOnlyContinuation(effects, ok, nok) {
|
|
121853
|
+
let lastNonSpace = null;
|
|
121854
|
+
return start;
|
|
121855
|
+
function start(code) {
|
|
121856
|
+
// Caller guarantees we are at `<` at the (already de-indented) line start.
|
|
121857
|
+
effects.enter(types_types.data);
|
|
121858
|
+
effects.consume(code);
|
|
121859
|
+
return afterLessThan;
|
|
121860
|
+
}
|
|
121861
|
+
function afterLessThan(code) {
|
|
121862
|
+
if (code === codes.slash) {
|
|
121863
|
+
effects.consume(code);
|
|
121864
|
+
return afterSlash;
|
|
121865
|
+
}
|
|
121866
|
+
return afterSlash(code);
|
|
121867
|
+
}
|
|
121868
|
+
// The `<` (or `</`) must introduce a real tag, not a stray `<` in prose.
|
|
121869
|
+
function afterSlash(code) {
|
|
121870
|
+
if (asciiAlpha(code)) {
|
|
121871
|
+
lastNonSpace = code;
|
|
121872
|
+
effects.consume(code);
|
|
121873
|
+
return scanToLineEnd;
|
|
121874
|
+
}
|
|
121875
|
+
effects.exit(types_types.data);
|
|
121876
|
+
return nok(code);
|
|
121877
|
+
}
|
|
121878
|
+
function scanToLineEnd(code) {
|
|
121879
|
+
if (code === null || markdownLineEnding(code)) {
|
|
121880
|
+
effects.exit(types_types.data);
|
|
121881
|
+
return lastNonSpace === codes.greaterThan ? ok(code) : nok(code);
|
|
121882
|
+
}
|
|
121883
|
+
if (!markdownSpace(code))
|
|
121884
|
+
lastNonSpace = code;
|
|
121885
|
+
effects.consume(code);
|
|
121886
|
+
return scanToLineEnd;
|
|
121887
|
+
}
|
|
121888
|
+
}
|
|
121762
121889
|
/**
|
|
121763
121890
|
* Micromark extension that tokenizes MDX-like components.
|
|
121764
121891
|
*
|
|
@@ -122005,6 +122132,8 @@ const mdxishInlineMdxComponents = () => tree => {
|
|
|
122005
122132
|
|
|
122006
122133
|
|
|
122007
122134
|
|
|
122135
|
+
/** Matches a JSX attribute expression (e.g. `key={i}`) anywhere in a string. */
|
|
122136
|
+
const NESTED_ATTR_EXPRESSION_RE = /[\w-]+\s*=\s*\{/;
|
|
122008
122137
|
/**
|
|
122009
122138
|
* Reduce leading whitespace on all lines just enough to prevent
|
|
122010
122139
|
* remark from treating indented content as code blocks (4+ spaces).
|
|
@@ -122164,10 +122293,16 @@ const mdxishMdxComponentBlocks = (opts = {}) => (tree, file) => {
|
|
|
122164
122293
|
// inline, which is how ReadMe's custom components are modeled).
|
|
122165
122294
|
if (!isPascal && parent.type === 'paragraph')
|
|
122166
122295
|
return;
|
|
122167
|
-
// Lowercase HTML tags are
|
|
122168
|
-
//
|
|
122296
|
+
// Lowercase HTML tags are eligible when they (or a descendant tag in their
|
|
122297
|
+
// content, e.g. a `.map()` body returning JSX with `key={i}`) carry a
|
|
122298
|
+
// JSX-expression attribute. Without this, a wrapper `<div>` with only plain
|
|
122299
|
+
// attributes (or none) swallows its whole nested block — including any
|
|
122300
|
+
// `style={{...}}`/`.map()` JSX inside it — as literal HTML text, which
|
|
122301
|
+
// rehype-raw's parse5 pass then garbles (it has no notion of JS expressions).
|
|
122302
|
+
// Plain HTML with no expressions anywhere stays as an html node so
|
|
122169
122303
|
// rehype-raw handles it as normal.
|
|
122170
|
-
|
|
122304
|
+
const hasNestedExpressionAttr = !selfClosing && NESTED_ATTR_EXPRESSION_RE.test(contentAfterTag);
|
|
122305
|
+
if (!isPascal && !hasExpressionAttr(attributes) && !hasNestedExpressionAttr)
|
|
122171
122306
|
return;
|
|
122172
122307
|
const closingTagStr = `</${tag}>`;
|
|
122173
122308
|
// Case 1: Self-closing tag
|
|
@@ -122606,15 +122741,17 @@ const evalExpression = (expression, scope) => {
|
|
|
122606
122741
|
|
|
122607
122742
|
|
|
122608
122743
|
|
|
122744
|
+
/** True for an array containing at least one React element, e.g. the result of `.map()` returning JSX. */
|
|
122745
|
+
const isRenderableElementArray = (value) => Array.isArray(value) && value.some((external_react_default()).isValidElement);
|
|
122609
122746
|
/** Given the type of the expression result, create the corresponding mdast node. */
|
|
122610
122747
|
const createEvaluatedNode = (result, position) => {
|
|
122611
122748
|
if (result === null || result === undefined) {
|
|
122612
122749
|
return { type: 'text', value: '', position };
|
|
122613
122750
|
}
|
|
122614
|
-
else if (external_react_default().isValidElement(result)) {
|
|
122615
|
-
// Convert react elements to
|
|
122616
|
-
// This must come before the object check as
|
|
122617
|
-
return { type: 'html', value: (0,server_node/* renderToStaticMarkup */.qV)(result), position };
|
|
122751
|
+
else if (external_react_default().isValidElement(result) || isRenderableElementArray(result)) {
|
|
122752
|
+
// Convert react elements (or arrays of them, e.g. `.map()` returning JSX) to their HTML
|
|
122753
|
+
// representation. This must come before the object check as both are a subset of it.
|
|
122754
|
+
return { type: 'html', value: (0,server_node/* renderToStaticMarkup */.qV)(external_react_default().createElement((external_react_default()).Fragment, null, result)), position };
|
|
122618
122755
|
}
|
|
122619
122756
|
else if (typeof result === 'object') {
|
|
122620
122757
|
return { type: 'text', value: JSON.stringify(result), position };
|
|
@@ -122654,6 +122791,47 @@ const evaluateExpressions = () => (tree, file) => {
|
|
|
122654
122791
|
};
|
|
122655
122792
|
/* harmony default export */ const evaluate_expressions = (evaluateExpressions);
|
|
122656
122793
|
|
|
122794
|
+
;// ./processor/transform/mdxish/evaluate-style-block-expressions.ts
|
|
122795
|
+
|
|
122796
|
+
|
|
122797
|
+
|
|
122798
|
+
// Matches a standalone `<style ...>{ <expr> }</style>` block — the JSX shape MDX evaluates
|
|
122799
|
+
// (typically a template-literal-wrapped CSS string) but which mdxish otherwise leaves as
|
|
122800
|
+
// literal, invalid-CSS text (see CX-3646).
|
|
122801
|
+
const STYLE_EXPRESSION_RE = /^(<style\b[^>]*>)\s*\{([\s\S]*)\}\s*(<\/style>)$/i;
|
|
122802
|
+
/**
|
|
122803
|
+
* Evaluate the JSX expression wrapping a `<style>` tag's contents (typically a template
|
|
122804
|
+
* literal, e.g. `<style>{\`.foo { color: red; }\`}</style>`) so the tag ends up holding plain
|
|
122805
|
+
* CSS text instead of the literal `{`...`}` wrapper — which the browser treats as invalid CSS
|
|
122806
|
+
* and drops the entire stylesheet for.
|
|
122807
|
+
*
|
|
122808
|
+
* `<style>` is one of CommonMark's "raw text" HTML elements (along with script/pre/textarea):
|
|
122809
|
+
* its contents are captured verbatim as a single `html` mdast node with no inner tokenization,
|
|
122810
|
+
* so this expression never reaches the mdxFlowExpression tokenizer or `evaluateExpressions` —
|
|
122811
|
+
* it has to be matched and evaluated directly against the raw node's string value.
|
|
122812
|
+
*
|
|
122813
|
+
* Must run after `evaluateExports` (needs `file.data.mdxishScope`) and before `remarkRehype`
|
|
122814
|
+
* turns `html` mdast nodes into raw hast strings. Skipped in safeMode.
|
|
122815
|
+
*/
|
|
122816
|
+
const evaluateStyleBlockExpressions = () => (tree, file) => {
|
|
122817
|
+
const scope = { ...file.data.mdxishScope, React: (external_react_default()) };
|
|
122818
|
+
visit(tree, 'html', (node) => {
|
|
122819
|
+
const match = node.value.trim().match(STYLE_EXPRESSION_RE);
|
|
122820
|
+
if (!match)
|
|
122821
|
+
return;
|
|
122822
|
+
const [, openTag, expression, closeTag] = match;
|
|
122823
|
+
try {
|
|
122824
|
+
const css = evalExpression(expression, scope);
|
|
122825
|
+
node.value = `${openTag}${String(css)}${closeTag}`;
|
|
122826
|
+
}
|
|
122827
|
+
catch {
|
|
122828
|
+
// Evaluation failed — leave the node untouched so it round-trips as literal text.
|
|
122829
|
+
}
|
|
122830
|
+
});
|
|
122831
|
+
return tree;
|
|
122832
|
+
};
|
|
122833
|
+
/* harmony default export */ const evaluate_style_block_expressions = (evaluateStyleBlockExpressions);
|
|
122834
|
+
|
|
122657
122835
|
;// ./processor/transform/mdxish/heading-slugs.ts
|
|
122658
122836
|
|
|
122659
122837
|
|
|
@@ -124510,10 +124688,84 @@ function removeJSXComments(content) {
|
|
|
124510
124688
|
return content.replace(JSX_COMMENT_REGEX, '');
|
|
124511
124689
|
}
|
|
124512
124690
|
|
|
124691
|
+
;// ./processor/transform/mdxish/style-object-to-css.ts
|
|
124692
|
+
|
|
124693
|
+
/**
|
|
124694
|
+
* CSS properties React treats as unitless — a bare number stays as-is instead of
|
|
124695
|
+
* getting `px` appended. Mirrors React DOM's `isUnitlessNumber` whitelist.
|
|
124696
|
+
* @see https://github.com/facebook/react/blob/main/packages/react-dom-bindings/src/shared/CSSProperty.js
|
|
124697
|
+
*/
|
|
124698
|
+
const UNITLESS_CSS_PROPERTIES = new Set([
|
|
124699
|
+
'animationIterationCount',
|
|
124700
|
+
'aspectRatio',
|
|
124701
|
+
'borderImageOutset',
|
|
124702
|
+
'borderImageSlice',
|
|
124703
|
+
'borderImageWidth',
|
|
124704
|
+
'boxFlex',
|
|
124705
|
+
'boxFlexGroup',
|
|
124706
|
+
'boxOrdinalGroup',
|
|
124707
|
+
'columnCount',
|
|
124708
|
+
'columns',
|
|
124709
|
+
'flex',
|
|
124710
|
+
'flexGrow',
|
|
124711
|
+
'flexPositive',
|
|
124712
|
+
'flexShrink',
|
|
124713
|
+
'flexNegative',
|
|
124714
|
+
'flexOrder',
|
|
124715
|
+
'gridArea',
|
|
124716
|
+
'gridRow',
|
|
124717
|
+
'gridRowEnd',
|
|
124718
|
+
'gridRowSpan',
|
|
124719
|
+
'gridRowStart',
|
|
124720
|
+
'gridColumn',
|
|
124721
|
+
'gridColumnEnd',
|
|
124722
|
+
'gridColumnSpan',
|
|
124723
|
+
'gridColumnStart',
|
|
124724
|
+
'fontWeight',
|
|
124725
|
+
'lineClamp',
|
|
124726
|
+
'lineHeight',
|
|
124727
|
+
'opacity',
|
|
124728
|
+
'order',
|
|
124729
|
+
'orphans',
|
|
124730
|
+
'tabSize',
|
|
124731
|
+
'widows',
|
|
124732
|
+
'zIndex',
|
|
124733
|
+
'zoom',
|
|
124734
|
+
'fillOpacity',
|
|
124735
|
+
'floodOpacity',
|
|
124736
|
+
'stopOpacity',
|
|
124737
|
+
'strokeDasharray',
|
|
124738
|
+
'strokeDashoffset',
|
|
124739
|
+
'strokeMiterlimit',
|
|
124740
|
+
'strokeOpacity',
|
|
124741
|
+
'strokeWidth',
|
|
124742
|
+
]);
|
|
124743
|
+
/** Convert a camelCase (or CSS custom property) key into its kebab-case CSS name. */
|
|
124744
|
+
const cssPropertyName = (key) => (key.startsWith('--') ? key : key.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`));
|
|
124745
|
+
/** React appends `px` to non-zero numeric values, except unitless and custom properties. */
|
|
124746
|
+
const cssPropertyValue = (key, value) => typeof value === 'number' && value !== 0 && !key.startsWith('--') && !UNITLESS_CSS_PROPERTIES.has(key)
|
|
124747
|
+
? `${value}px`
|
|
124748
|
+
: `${value}`;
|
|
124749
|
+
/**
|
|
124750
|
+
* True for a value that should be serialized as a style object rather than passed through
|
|
124751
|
+
* as an already-CSS string. React elements are excluded since they're valid objects too.
|
|
124752
|
+
*/
|
|
124753
|
+
const style_object_to_css_isPlainObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value) && !external_react_default().isValidElement(value);
|
|
124754
|
+
/**
|
|
124755
|
+
* Serialize a React-style inline style object (`{ color: "red", fontSize: 12 }`) into a
|
|
124756
|
+
* CSS declaration string (`color:red;font-size:12px`), the shape hast/HTML expects for a
|
|
124757
|
+
* `style` attribute. Empty (`undefined`/`null`/`''`) entries are dropped.
|
|
124758
|
+
*/
|
|
124759
|
+
const styleObjectToCssText = (style) => Object.entries(style)
|
|
124760
|
+
.filter(([, value]) => value !== undefined && value !== null && value !== '')
|
|
124761
|
+
.map(([key, value]) => `${cssPropertyName(key)}:${cssPropertyValue(key, value)}`)
|
|
124762
|
+
.join(';');
|
|
124763
|
+
|
|
124513
124764
|
;// ./processor/transform/mdxish/resolve-deferred-attribute-expression-props.ts
|
|
124514
124765
|
|
|
124515
124766
|
|
|
124516
124767
|
|
|
124768
|
+
|
|
124517
124769
|
/**
|
|
124518
124770
|
* Resolve attribute expressions that `mdxJsxElementHandler` deferred.
|
|
124519
124771
|
*
|
|
@@ -124535,7 +124787,10 @@ const resolveDeferredAttributeExpressionProps = () => (tree, file) => {
|
|
|
124535
124787
|
const properties = node.properties;
|
|
124536
124788
|
Object.entries(deferredExpressions).forEach(([name, source]) => {
|
|
124537
124789
|
try {
|
|
124538
|
-
|
|
124790
|
+
const result = evalExpression(source, scope);
|
|
124791
|
+
// hast/HTML `style` is a plain CSS string; a `style={{...}}` expression evaluates to
|
|
124792
|
+
// a JS object, which must be serialized or it renders as the literal "[object Object]".
|
|
124793
|
+
properties[name] = name === 'style' && style_object_to_css_isPlainObject(result) ? styleObjectToCssText(result) : result;
|
|
124539
124794
|
}
|
|
124540
124795
|
catch {
|
|
124541
124796
|
// Evaluation failed — fall back to the raw expression source so the attribute
|
|
@@ -124855,13 +125110,13 @@ function normalizeTableSeparator(content) {
|
|
|
124855
125110
|
;// ./processor/transform/mdxish/terminate-html-flow-blocks.ts
|
|
124856
125111
|
|
|
124857
125112
|
|
|
125113
|
+
|
|
124858
125114
|
const STANDALONE_HTML_LINE_REGEX = /^(<[a-z][^<>]*>|<\/[a-z][^<>]*>)+\s*$/;
|
|
124859
125115
|
const HTML_LINE_WITH_CONTENT_REGEX = /^<[a-z][^<>]*>.*<\/[a-z][^<>]*>(?:[^<]*)$/;
|
|
124860
|
-
const terminate_html_flow_blocks_TABLE_STRUCTURE_TAGS = ['table', 'thead', 'tbody', 'tfoot', 'tr', 'td', 'th', 'caption', 'colgroup'];
|
|
124861
125116
|
// Tags whose contents must be preserved as is, inserting a blank line after the
|
|
124862
125117
|
// opener corrupts the payload.
|
|
124863
125118
|
// htmlRawNames here refer to <pre>, <textarea>, <script>, <style>
|
|
124864
|
-
const RAW_CONTENT_TAGS = [...htmlRawNames, ...
|
|
125119
|
+
const RAW_CONTENT_TAGS = [...htmlRawNames, ...HTML_TABLE_STRUCTURE_TAGS];
|
|
124865
125120
|
// The `(?=[\s/>])` lookahead avoids false matches on lookalike names like `<script-foo>`.
|
|
124866
125121
|
const RAW_CONTENT_TAG_MATCHERS = RAW_CONTENT_TAGS.map(tag => ({
|
|
124867
125122
|
open: new RegExp(`<${tag}(?=[\\s/>])[^>]*?(?<!/)>`, 'gi'),
|
|
@@ -125659,6 +125914,7 @@ function loadComponents() {
|
|
|
125659
125914
|
|
|
125660
125915
|
|
|
125661
125916
|
|
|
125917
|
+
|
|
125662
125918
|
|
|
125663
125919
|
|
|
125664
125920
|
const defaultTransformers = [
|
|
@@ -125809,6 +126065,7 @@ function mdxish(mdContent, opts = {}) {
|
|
|
125809
126065
|
.use(safeMode ? undefined : evaluate_exports) // Evaluate `export const/function` and stash scope on file.data.mdxishScope
|
|
125810
126066
|
.use(remarkBreaks) // Must precede evaluateExpressions to avoid splitting the \n in an evaluated template literal into a <br> node
|
|
125811
126067
|
.use(safeMode ? undefined : evaluate_expressions) // Evaluate self-contained MDX expressions (e.g. `{1+1}`)
|
|
126068
|
+
.use(safeMode ? undefined : evaluate_style_block_expressions) // Evaluate `<style>{`...`}</style>` template literals into plain CSS
|
|
125812
126069
|
.use(variables_code, { variables }) // Resolve <<...>> and {user.*} inside code and inline code nodes
|
|
125813
126070
|
.use(remarkRehype, { allowDangerousHtml: true, handlers: mdxComponentHandlers })
|
|
125814
126071
|
.use(preserveBooleanProperties) // RehypeRaw converts boolean properties to empty strings
|