@readme/markdown 11.11.0 → 11.12.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
CHANGED
|
@@ -70584,77 +70584,197 @@ const mdxToHast = () => tree => {
|
|
|
70584
70584
|
;// ./processor/transform/mdxish/mdxish-component-blocks.ts
|
|
70585
70585
|
|
|
70586
70586
|
|
|
70587
|
-
const
|
|
70588
|
-
const
|
|
70587
|
+
const pascalCaseTagPattern = /^<([A-Z][A-Za-z0-9_]*)([^>]*?)(\/?)>([\s\S]*)?$/;
|
|
70588
|
+
const tagAttributePattern = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*("[^"]*"|'[^']*'|[^\s"'>]+))?/g;
|
|
70589
|
+
/**
|
|
70590
|
+
* Maximum number of siblings to scan forward when looking for a closing tag
|
|
70591
|
+
* to avoid scanning too far and degrading performance
|
|
70592
|
+
*/
|
|
70593
|
+
const MAX_LOOKAHEAD = 30;
|
|
70594
|
+
/**
|
|
70595
|
+
* Tags that have dedicated transformers and should NOT be handled by this plugin.
|
|
70596
|
+
* These components have special parsing requirements that the generic component
|
|
70597
|
+
* block transformer cannot handle correctly.
|
|
70598
|
+
*/
|
|
70599
|
+
const EXCLUDED_TAGS = new Set(['HTMLBlock', 'Table']);
|
|
70589
70600
|
const inlineMdProcessor = unified().use(remarkParse);
|
|
70590
70601
|
const isClosingTag = (value, tag) => value.trim() === `</${tag}>`;
|
|
70591
|
-
|
|
70592
|
-
|
|
70593
|
-
|
|
70594
|
-
return { paragraph: node, found: false };
|
|
70595
|
-
const children = [...node.children];
|
|
70596
|
-
const closingIndex = children.findIndex(child => child.type === 'html' && isClosingTag(child.value || '', tag));
|
|
70597
|
-
if (closingIndex === -1)
|
|
70598
|
-
return { paragraph: node, found: false };
|
|
70599
|
-
children.splice(closingIndex, 1);
|
|
70600
|
-
return {
|
|
70601
|
-
paragraph: { ...node, children },
|
|
70602
|
-
found: true,
|
|
70603
|
-
};
|
|
70604
|
-
};
|
|
70605
|
-
// Replace two child nodes (opening HTML tag + paragraph) with a single replacement node
|
|
70606
|
-
const replaceChild = (parent, index, replacement) => {
|
|
70607
|
-
parent.children.splice(index, 2, replacement);
|
|
70608
|
-
};
|
|
70609
|
-
// Parse markdown inside a component's inline content into mdast children.
|
|
70602
|
+
/**
|
|
70603
|
+
* Parse markdown content into mdast children nodes.
|
|
70604
|
+
*/
|
|
70610
70605
|
const parseMdChildren = (value) => {
|
|
70611
70606
|
const parsed = inlineMdProcessor.parse(value);
|
|
70612
70607
|
return parsed.children || [];
|
|
70613
70608
|
};
|
|
70614
|
-
|
|
70615
|
-
|
|
70609
|
+
/**
|
|
70610
|
+
* Convert raw attribute string into mdxJsxAttribute entries.
|
|
70611
|
+
* Handles both key-value attributes (theme="info") and boolean attributes (empty).
|
|
70612
|
+
*/
|
|
70616
70613
|
const parseAttributes = (raw) => {
|
|
70617
70614
|
const attributes = [];
|
|
70618
70615
|
const attrString = raw.trim();
|
|
70619
70616
|
if (!attrString)
|
|
70620
70617
|
return attributes;
|
|
70621
|
-
|
|
70622
|
-
|
|
70623
|
-
let match = attributePattern.exec(attrString);
|
|
70618
|
+
tagAttributePattern.lastIndex = 0;
|
|
70619
|
+
let match = tagAttributePattern.exec(attrString);
|
|
70624
70620
|
while (match !== null) {
|
|
70625
70621
|
const [, attrName, attrValue] = match;
|
|
70626
|
-
// Boolean attribute (no value) -> set to null
|
|
70627
|
-
// Attribute with value -> clean and set string value
|
|
70628
|
-
// Note: Attribute value types can't directly be numbers & booleans. String, nulls, undefined are supported.
|
|
70629
70622
|
const value = attrValue ? attrValue.replace(/^['"]|['"]$/g, '') : null;
|
|
70630
|
-
attributes.push({
|
|
70631
|
-
|
|
70632
|
-
name: attrName,
|
|
70633
|
-
value,
|
|
70634
|
-
});
|
|
70635
|
-
match = attributePattern.exec(attrString);
|
|
70623
|
+
attributes.push({ type: 'mdxJsxAttribute', name: attrName, value });
|
|
70624
|
+
match = tagAttributePattern.exec(attrString);
|
|
70636
70625
|
}
|
|
70637
70626
|
return attributes;
|
|
70638
70627
|
};
|
|
70639
|
-
|
|
70628
|
+
/**
|
|
70629
|
+
* Parse an HTML tag string into structured data.
|
|
70630
|
+
*/
|
|
70640
70631
|
const parseTag = (value) => {
|
|
70641
|
-
const match = value.match(
|
|
70632
|
+
const match = value.match(pascalCaseTagPattern);
|
|
70642
70633
|
if (!match)
|
|
70643
70634
|
return null;
|
|
70644
|
-
const [, tag, attrString = '', selfClosing = '',
|
|
70645
|
-
const attributes = parseAttributes(attrString);
|
|
70635
|
+
const [, tag, attrString = '', selfClosing = '', contentAfterTag = ''] = match;
|
|
70646
70636
|
return {
|
|
70647
70637
|
tag,
|
|
70648
|
-
attributes,
|
|
70638
|
+
attributes: parseAttributes(attrString),
|
|
70649
70639
|
selfClosing: !!selfClosing,
|
|
70650
|
-
|
|
70640
|
+
contentAfterTag,
|
|
70651
70641
|
};
|
|
70652
70642
|
};
|
|
70653
|
-
|
|
70654
|
-
|
|
70643
|
+
/**
|
|
70644
|
+
* Create an MdxJsxFlowElement node from component data.
|
|
70645
|
+
*/
|
|
70646
|
+
const createComponentNode = ({ tag, attributes, children, startPosition, endPosition }) => ({
|
|
70647
|
+
type: 'mdxJsxFlowElement',
|
|
70648
|
+
name: tag,
|
|
70649
|
+
attributes,
|
|
70650
|
+
children,
|
|
70651
|
+
position: {
|
|
70652
|
+
start: startPosition?.start,
|
|
70653
|
+
end: endPosition?.end ?? startPosition?.end,
|
|
70654
|
+
},
|
|
70655
|
+
});
|
|
70656
|
+
/**
|
|
70657
|
+
* Remove a closing tag from a paragraph's children and return the updated paragraph.
|
|
70658
|
+
*/
|
|
70659
|
+
const stripClosingTagFromParagraph = (node, tag) => {
|
|
70660
|
+
if (!Array.isArray(node.children))
|
|
70661
|
+
return { paragraph: node, found: false };
|
|
70662
|
+
const children = [...node.children];
|
|
70663
|
+
const closingIndex = children.findIndex(child => child.type === 'html' && isClosingTag(child.value || '', tag));
|
|
70664
|
+
if (closingIndex === -1)
|
|
70665
|
+
return { paragraph: node, found: false };
|
|
70666
|
+
children.splice(closingIndex, 1);
|
|
70667
|
+
return { paragraph: { ...node, children }, found: true };
|
|
70668
|
+
};
|
|
70669
|
+
/**
|
|
70670
|
+
* Scan forward through siblings to find a closing tag.
|
|
70671
|
+
* Handles:
|
|
70672
|
+
* - Exact match HTML siblings (e.g., `</Tag>`)
|
|
70673
|
+
* - HTML siblings with embedded closing tag (e.g., `...\n</Tag>`)
|
|
70674
|
+
* - Paragraph siblings containing the closing tag as a child
|
|
70675
|
+
*
|
|
70676
|
+
* Returns null if not found within MAX_LOOKAHEAD siblings
|
|
70677
|
+
*/
|
|
70678
|
+
const scanForClosingTag = (parent, startIndex, tag) => {
|
|
70679
|
+
const closingTagStr = `</${tag}>`;
|
|
70680
|
+
const maxIndex = Math.min(startIndex + MAX_LOOKAHEAD, parent.children.length);
|
|
70681
|
+
let i = startIndex + 1;
|
|
70682
|
+
for (; i < maxIndex; i += 1) {
|
|
70683
|
+
const sibling = parent.children[i];
|
|
70684
|
+
// Check HTML siblings
|
|
70685
|
+
if (sibling.type === 'html') {
|
|
70686
|
+
const siblingValue = sibling.value || '';
|
|
70687
|
+
// Exact match (standalone closing tag)
|
|
70688
|
+
if (isClosingTag(siblingValue, tag)) {
|
|
70689
|
+
return { closingIndex: i, extraClosingChildren: [] };
|
|
70690
|
+
}
|
|
70691
|
+
// Embedded closing tag (closing tag at end of HTML block content)
|
|
70692
|
+
if (siblingValue.includes(closingTagStr)) {
|
|
70693
|
+
const contentBeforeClose = siblingValue.substring(0, siblingValue.lastIndexOf(closingTagStr)).trim();
|
|
70694
|
+
const extraChildren = contentBeforeClose
|
|
70695
|
+
? parseMdChildren(contentBeforeClose)
|
|
70696
|
+
: [];
|
|
70697
|
+
return { closingIndex: i, extraClosingChildren: extraChildren };
|
|
70698
|
+
}
|
|
70699
|
+
}
|
|
70700
|
+
// Check paragraph siblings
|
|
70701
|
+
if (sibling.type === 'paragraph') {
|
|
70702
|
+
const { paragraph, found } = stripClosingTagFromParagraph(sibling, tag);
|
|
70703
|
+
if (found) {
|
|
70704
|
+
return { closingIndex: i, extraClosingChildren: [], strippedParagraph: paragraph };
|
|
70705
|
+
}
|
|
70706
|
+
}
|
|
70707
|
+
}
|
|
70708
|
+
if (i < parent.children.length) {
|
|
70709
|
+
// eslint-disable-next-line no-console
|
|
70710
|
+
console.warn(`Closing tag </${tag}> not found within ${MAX_LOOKAHEAD} siblings, stopping scan`);
|
|
70711
|
+
}
|
|
70712
|
+
return null;
|
|
70713
|
+
};
|
|
70714
|
+
const substituteNodeWithMdxNode = (parent, index, mdxNode) => {
|
|
70715
|
+
parent.children.splice(index, 1, mdxNode);
|
|
70716
|
+
};
|
|
70717
|
+
/**
|
|
70718
|
+
* Transform PascalCase HTML nodes into mdxJsxFlowElement nodes.
|
|
70719
|
+
*
|
|
70720
|
+
* Remark parses unknown/custom component tags as raw HTML nodes.
|
|
70721
|
+
* These are the custom readme MDX syntax for components.
|
|
70722
|
+
* This transformer identifies these patterns and converts them to proper MDX JSX elements so they
|
|
70723
|
+
* can be accurately recognized and rendered later with their component definition code.
|
|
70724
|
+
* Though for some tags, we need to handle them specially
|
|
70725
|
+
*
|
|
70726
|
+
* ## Supported HTML Structures
|
|
70727
|
+
*
|
|
70728
|
+
* ### 1. Self-closing tags
|
|
70729
|
+
* ```
|
|
70730
|
+
* <Component />
|
|
70731
|
+
* ```
|
|
70732
|
+
* Parsed as: `html: "<Component />"`
|
|
70733
|
+
*
|
|
70734
|
+
* ### 2. Self-contained blocks (entire component in single HTML node)
|
|
70735
|
+
* ```
|
|
70736
|
+
* <Button>Click me</Button>
|
|
70737
|
+
* ```
|
|
70738
|
+
* ```
|
|
70739
|
+
* <Component>
|
|
70740
|
+
* <h2>Title</h2>
|
|
70741
|
+
* <p>Content</p>
|
|
70742
|
+
* </Component>
|
|
70743
|
+
* ```
|
|
70744
|
+
* Parsed as: `html: "<Component>\n <h2>Title</h2>\n <p>Content</p>\n</Component>"`
|
|
70745
|
+
* The opening tag, content, and closing tag are all captured in one HTML node.
|
|
70746
|
+
*
|
|
70747
|
+
* ### 3. Multi-sibling components (closing tag in a following sibling)
|
|
70748
|
+
* Handles various structures where the closing tag is in a later sibling, such as:
|
|
70749
|
+
*
|
|
70750
|
+
* #### 3a. Block components (closing tag in sibling paragraph)
|
|
70751
|
+
* ```
|
|
70752
|
+
* <Callout>
|
|
70753
|
+
* Some **markdown** content
|
|
70754
|
+
* </Callout>
|
|
70755
|
+
* ```
|
|
70756
|
+
*
|
|
70757
|
+
* #### 3b. Multi-paragraph components (closing tag several siblings away)
|
|
70758
|
+
* ```
|
|
70759
|
+
* <Callout>
|
|
70760
|
+
*
|
|
70761
|
+
* First paragraph
|
|
70762
|
+
*
|
|
70763
|
+
* Second paragraph
|
|
70764
|
+
* </Callout>
|
|
70765
|
+
* ```
|
|
70766
|
+
*
|
|
70767
|
+
* #### 3c. Nested components split by blank lines (closing tag embedded in HTML sibling)
|
|
70768
|
+
* ```
|
|
70769
|
+
* <Outer>
|
|
70770
|
+
* <Inner>content</Inner>
|
|
70771
|
+
*
|
|
70772
|
+
* <Inner>content</Inner>
|
|
70773
|
+
* </Outer>
|
|
70774
|
+
* ```
|
|
70775
|
+
*/
|
|
70655
70776
|
const mdxishComponentBlocks = () => tree => {
|
|
70656
70777
|
const stack = [tree];
|
|
70657
|
-
// Process children depth-first, rewriting opening/closing component HTML pairs
|
|
70658
70778
|
const processChildNode = (parent, index) => {
|
|
70659
70779
|
const node = parent.children[index];
|
|
70660
70780
|
if (!node)
|
|
@@ -70662,46 +70782,66 @@ const mdxishComponentBlocks = () => tree => {
|
|
|
70662
70782
|
if ('children' in node && Array.isArray(node.children)) {
|
|
70663
70783
|
stack.push(node);
|
|
70664
70784
|
}
|
|
70785
|
+
// Only visit HTML nodes with an actual html tag
|
|
70665
70786
|
const value = node.value;
|
|
70666
70787
|
if (node.type !== 'html' || typeof value !== 'string')
|
|
70667
70788
|
return;
|
|
70668
70789
|
const parsed = parseTag(value);
|
|
70669
70790
|
if (!parsed)
|
|
70670
70791
|
return;
|
|
70671
|
-
const { tag, attributes, selfClosing,
|
|
70672
|
-
|
|
70792
|
+
const { tag, attributes, selfClosing, contentAfterTag = '' } = parsed;
|
|
70793
|
+
// Skip tags that have dedicated transformers
|
|
70794
|
+
if (EXCLUDED_TAGS.has(tag))
|
|
70795
|
+
return;
|
|
70796
|
+
const closingTagStr = `</${tag}>`;
|
|
70797
|
+
// Case 1: Self-closing tag
|
|
70673
70798
|
if (selfClosing) {
|
|
70674
|
-
const componentNode = {
|
|
70675
|
-
|
|
70676
|
-
name: tag,
|
|
70799
|
+
const componentNode = createComponentNode({
|
|
70800
|
+
tag,
|
|
70677
70801
|
attributes,
|
|
70678
70802
|
children: [],
|
|
70679
|
-
|
|
70680
|
-
};
|
|
70681
|
-
parent
|
|
70803
|
+
startPosition: node.position,
|
|
70804
|
+
});
|
|
70805
|
+
substituteNodeWithMdxNode(parent, index, componentNode);
|
|
70682
70806
|
return;
|
|
70683
70807
|
}
|
|
70684
|
-
|
|
70685
|
-
if (
|
|
70808
|
+
// Case 2: Self-contained block (closing tag in content)
|
|
70809
|
+
if (contentAfterTag.includes(closingTagStr)) {
|
|
70810
|
+
const componentInnerContent = contentAfterTag.substring(0, contentAfterTag.lastIndexOf(closingTagStr)).trim();
|
|
70811
|
+
const componentNode = createComponentNode({
|
|
70812
|
+
tag,
|
|
70813
|
+
attributes,
|
|
70814
|
+
children: componentInnerContent ? parseMdChildren(componentInnerContent) : [],
|
|
70815
|
+
startPosition: node.position,
|
|
70816
|
+
});
|
|
70817
|
+
substituteNodeWithMdxNode(parent, index, componentNode);
|
|
70686
70818
|
return;
|
|
70687
|
-
|
|
70688
|
-
|
|
70819
|
+
}
|
|
70820
|
+
// Case 3: Multi-sibling component (closing tag in a following sibling)
|
|
70821
|
+
// Scans forward through siblings to find closing tag in HTML or paragraph nodes
|
|
70822
|
+
const scanResult = scanForClosingTag(parent, index, tag);
|
|
70823
|
+
if (!scanResult)
|
|
70689
70824
|
return;
|
|
70690
|
-
const
|
|
70691
|
-
|
|
70692
|
-
|
|
70825
|
+
const { closingIndex, extraClosingChildren, strippedParagraph } = scanResult;
|
|
70826
|
+
const extraChildren = contentAfterTag ? parseMdChildren(contentAfterTag.trimStart()) : [];
|
|
70827
|
+
// Collect all intermediate siblings between opening tag and closing tag
|
|
70828
|
+
const intermediateChildren = parent.children.slice(index + 1, closingIndex);
|
|
70829
|
+
// For paragraph siblings, include the paragraph's children (with closing tag stripped)
|
|
70830
|
+
// For HTML siblings, include any content parsed from before the closing tag
|
|
70831
|
+
const closingChildren = strippedParagraph
|
|
70832
|
+
? strippedParagraph.children
|
|
70833
|
+
: extraClosingChildren;
|
|
70834
|
+
const componentNode = createComponentNode({
|
|
70835
|
+
tag,
|
|
70693
70836
|
attributes,
|
|
70694
|
-
children: [
|
|
70695
|
-
|
|
70696
|
-
|
|
70697
|
-
|
|
70698
|
-
|
|
70699
|
-
|
|
70700
|
-
end: next.position?.end,
|
|
70701
|
-
},
|
|
70702
|
-
};
|
|
70703
|
-
replaceChild(parent, index, componentNode);
|
|
70837
|
+
children: [...extraChildren, ...intermediateChildren, ...closingChildren],
|
|
70838
|
+
startPosition: node.position,
|
|
70839
|
+
endPosition: parent.children[closingIndex]?.position,
|
|
70840
|
+
});
|
|
70841
|
+
// Remove all nodes from opening tag to closing tag (inclusive) and replace with component node
|
|
70842
|
+
parent.children.splice(index, closingIndex - index + 1, componentNode);
|
|
70704
70843
|
};
|
|
70844
|
+
// Travel the tree depth-first
|
|
70705
70845
|
while (stack.length) {
|
|
70706
70846
|
const parent = stack.pop();
|
|
70707
70847
|
if (parent?.children) {
|
|
@@ -92845,8 +92985,11 @@ function smartCamelCase(str) {
|
|
|
92845
92985
|
}
|
|
92846
92986
|
// Sort by length (longest first) to prevent shorter matches (e.g., "column" in "columns")
|
|
92847
92987
|
const sortedBoundaries = [...allBoundaries].sort((a, b) => b.length - a.length);
|
|
92988
|
+
// Use case-sensitive matching ('g' not 'gi') so that once a letter is
|
|
92989
|
+
// capitalized by a longer boundary, shorter boundaries won't re-match it.
|
|
92990
|
+
// This prevents issues like 'iconcolor' becoming 'iconColOr' instead of 'iconColor'.
|
|
92848
92991
|
return sortedBoundaries.reduce((res, word) => {
|
|
92849
|
-
const regex = new RegExp(`(${word})([a-z])`, '
|
|
92992
|
+
const regex = new RegExp(`(${word})([a-z])`, 'g');
|
|
92850
92993
|
return res.replace(regex, (_, prefix, nextChar) => prefix.toLowerCase() + nextChar.toUpperCase());
|
|
92851
92994
|
}, str);
|
|
92852
92995
|
}
|
|
@@ -92972,7 +93115,21 @@ const htmlBlockHandler = (_state, node) => {
|
|
|
92972
93115
|
children: [],
|
|
92973
93116
|
};
|
|
92974
93117
|
};
|
|
93118
|
+
// Convert embed magic blocks to Embed components
|
|
93119
|
+
const embedHandler = (state, node) => {
|
|
93120
|
+
// Assert to get the minimum properties we need
|
|
93121
|
+
const { data } = node;
|
|
93122
|
+
return {
|
|
93123
|
+
type: 'element',
|
|
93124
|
+
// To differentiate between regular embeds and magic block embeds,
|
|
93125
|
+
// magic block embeds have a certain hName
|
|
93126
|
+
tagName: data?.hName === NodeTypes.embedBlock ? 'Embed' : 'embed',
|
|
93127
|
+
properties: data?.hProperties,
|
|
93128
|
+
children: state.all(node),
|
|
93129
|
+
};
|
|
93130
|
+
};
|
|
92975
93131
|
const mdxComponentHandlers = {
|
|
93132
|
+
embed: embedHandler,
|
|
92976
93133
|
mdxFlowExpression: mdxExpressionHandler,
|
|
92977
93134
|
mdxJsxFlowElement: mdxJsxElementHandler,
|
|
92978
93135
|
mdxJsxTextElement: mdxJsxElementHandler,
|
|
@@ -93676,6 +93833,10 @@ const parseInline = (text) => {
|
|
|
93676
93833
|
if (!text.trim())
|
|
93677
93834
|
return [{ type: 'text', value: '' }];
|
|
93678
93835
|
const tree = cellParser.runSync(cellParser.parse(text));
|
|
93836
|
+
// If there are multiple block-level nodes, keep them as-is to preserve the document structure and spacing
|
|
93837
|
+
if (tree.children.length > 1) {
|
|
93838
|
+
return tree.children;
|
|
93839
|
+
}
|
|
93679
93840
|
return tree.children.flatMap(n =>
|
|
93680
93841
|
// This unwraps the extra p node that might appear & wrapping the content
|
|
93681
93842
|
n.type === 'paragraph' && 'children' in n ? n.children : [n]);
|
|
@@ -93813,14 +93974,17 @@ function parseMagicBlock(raw, options = {}) {
|
|
|
93813
93974
|
else {
|
|
93814
93975
|
children.push(...titleBlocks, ...bodyBlocks);
|
|
93815
93976
|
}
|
|
93977
|
+
// If there is no title or title is empty
|
|
93978
|
+
const empty = !titleBlocks.length || !titleBlocks[0].children[0]?.value;
|
|
93816
93979
|
// Create mdxJsxFlowElement directly for mdxish
|
|
93817
93980
|
const calloutElement = {
|
|
93818
93981
|
type: 'mdxJsxFlowElement',
|
|
93819
93982
|
name: 'Callout',
|
|
93820
|
-
attributes: toAttributes({ icon, theme: theme || 'default', type: theme || 'default' }, [
|
|
93983
|
+
attributes: toAttributes({ icon, theme: theme || 'default', type: theme || 'default', empty }, [
|
|
93821
93984
|
'icon',
|
|
93822
93985
|
'theme',
|
|
93823
93986
|
'type',
|
|
93987
|
+
'empty',
|
|
93824
93988
|
]),
|
|
93825
93989
|
children: children,
|
|
93826
93990
|
};
|
|
@@ -93878,9 +94042,9 @@ function parseMagicBlock(raw, options = {}) {
|
|
|
93878
94042
|
return [
|
|
93879
94043
|
wrapPinnedBlocks({
|
|
93880
94044
|
children: [
|
|
93881
|
-
{ children: [{ type: 'text', value: title ||
|
|
94045
|
+
{ children: [{ type: 'text', value: title || '' }], title: embedJson.provider, type: 'link', url },
|
|
93882
94046
|
],
|
|
93883
|
-
data: { hName: '
|
|
94047
|
+
data: { hName: 'embed-block', hProperties: { ...embedJson, href: url, html, title, url } },
|
|
93884
94048
|
type: 'embed',
|
|
93885
94049
|
}, json),
|
|
93886
94050
|
];
|
|
@@ -93898,6 +94062,25 @@ function parseMagicBlock(raw, options = {}) {
|
|
|
93898
94062
|
}, json),
|
|
93899
94063
|
];
|
|
93900
94064
|
}
|
|
94065
|
+
// Recipe/TutorialTile: renders as Recipe component
|
|
94066
|
+
case 'recipe':
|
|
94067
|
+
case 'tutorial-tile': {
|
|
94068
|
+
const recipeJson = json;
|
|
94069
|
+
if (!recipeJson.slug || !recipeJson.title)
|
|
94070
|
+
return [];
|
|
94071
|
+
// Create mdxJsxFlowElement directly for mdxish flow
|
|
94072
|
+
// Note: Don't wrap in pinned blocks for mdxish - rehypeMdxishComponents handles component resolution
|
|
94073
|
+
// The node structure matches what mdxishComponentBlocks creates for JSX tags
|
|
94074
|
+
const recipeNode = {
|
|
94075
|
+
type: 'mdxJsxFlowElement',
|
|
94076
|
+
name: 'Recipe',
|
|
94077
|
+
attributes: toAttributes(recipeJson, ['slug', 'title']),
|
|
94078
|
+
children: [],
|
|
94079
|
+
// Position is optional but helps with debugging
|
|
94080
|
+
position: undefined,
|
|
94081
|
+
};
|
|
94082
|
+
return [recipeNode];
|
|
94083
|
+
}
|
|
93901
94084
|
// Unknown block types: render as generic div with JSON properties
|
|
93902
94085
|
default: {
|
|
93903
94086
|
const text = json.text || json.html || '';
|
|
@@ -94191,6 +94374,45 @@ const restoreSnakeCaseComponentNames = (options) => {
|
|
|
94191
94374
|
};
|
|
94192
94375
|
/* harmony default export */ const restore_snake_case_component_name = (restoreSnakeCaseComponentNames);
|
|
94193
94376
|
|
|
94377
|
+
;// ./processor/transform/mdxish/retain-boolean-attributes.ts
|
|
94378
|
+
|
|
94379
|
+
// Private Use Area character (U+E000) which is extremely unlikely to appear in real content.
|
|
94380
|
+
const TEMP_TRUE_BOOLEAN_VALUE = 'readme-this-is-a-temporary-boolean-attribute-\uE000';
|
|
94381
|
+
const TEMP_FALSE_BOOLEAN_VALUE = 'readme-this-is-a-temporary-boolean-attribute-\uE001';
|
|
94382
|
+
/**
|
|
94383
|
+
* Preserves boolean properties when passed to rehypeRaw because
|
|
94384
|
+
* rehypeRaw converts boolean properties in nodes to strings (e.g. true -> ""),
|
|
94385
|
+
* which can change the truthiness of the property. Hence we need to preserve the boolean properties.
|
|
94386
|
+
*/
|
|
94387
|
+
const preserveBooleanProperties = () => tree => {
|
|
94388
|
+
visit(tree, 'element', (node) => {
|
|
94389
|
+
if (!node.properties)
|
|
94390
|
+
return;
|
|
94391
|
+
Object.entries(node.properties).forEach(([key, value]) => {
|
|
94392
|
+
if (typeof value === 'boolean') {
|
|
94393
|
+
node.properties[key] = value ? TEMP_TRUE_BOOLEAN_VALUE : TEMP_FALSE_BOOLEAN_VALUE;
|
|
94394
|
+
}
|
|
94395
|
+
});
|
|
94396
|
+
});
|
|
94397
|
+
return tree;
|
|
94398
|
+
};
|
|
94399
|
+
const restoreBooleanProperties = () => tree => {
|
|
94400
|
+
visit(tree, 'element', (node) => {
|
|
94401
|
+
if (!node.properties)
|
|
94402
|
+
return;
|
|
94403
|
+
Object.entries(node.properties).forEach(([key, value]) => {
|
|
94404
|
+
if (value === TEMP_TRUE_BOOLEAN_VALUE) {
|
|
94405
|
+
node.properties[key] = true;
|
|
94406
|
+
}
|
|
94407
|
+
else if (value === TEMP_FALSE_BOOLEAN_VALUE) {
|
|
94408
|
+
node.properties[key] = false;
|
|
94409
|
+
}
|
|
94410
|
+
});
|
|
94411
|
+
});
|
|
94412
|
+
return tree;
|
|
94413
|
+
};
|
|
94414
|
+
|
|
94415
|
+
|
|
94194
94416
|
;// ./processor/transform/mdxish/variables-text.ts
|
|
94195
94417
|
|
|
94196
94418
|
|
|
@@ -94218,6 +94440,8 @@ const variablesTextTransformer = () => tree => {
|
|
|
94218
94440
|
if (parent.type === 'inlineCode')
|
|
94219
94441
|
return;
|
|
94220
94442
|
const text = node.value;
|
|
94443
|
+
if (typeof text !== 'string' || !text.trim())
|
|
94444
|
+
return;
|
|
94221
94445
|
if (!text.includes('{user.') && !text.includes('{user['))
|
|
94222
94446
|
return;
|
|
94223
94447
|
const matches = [...text.matchAll(USER_VAR_REGEX)];
|
|
@@ -94370,6 +94594,7 @@ function loadComponents() {
|
|
|
94370
94594
|
|
|
94371
94595
|
|
|
94372
94596
|
|
|
94597
|
+
|
|
94373
94598
|
|
|
94374
94599
|
|
|
94375
94600
|
const defaultTransformers = [callouts, code_tabs, gemoji_, transform_embeds];
|
|
@@ -94416,7 +94641,9 @@ function mdxish(mdContent, opts = {}) {
|
|
|
94416
94641
|
.use(useTailwind ? transform_tailwind : undefined, { components: tempComponentsMap })
|
|
94417
94642
|
.use(remarkGfm)
|
|
94418
94643
|
.use(remarkRehype, { allowDangerousHtml: true, handlers: mdxComponentHandlers })
|
|
94644
|
+
.use(preserveBooleanProperties) // RehypeRaw converts boolean properties to empty strings
|
|
94419
94645
|
.use(rehypeRaw, { passThrough: ['html-block'] })
|
|
94646
|
+
.use(restoreBooleanProperties)
|
|
94420
94647
|
.use(rehypeSlug)
|
|
94421
94648
|
.use(rehypeMdxishComponents, {
|
|
94422
94649
|
components,
|