@readme/markdown 15.2.1 → 15.3.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/README.md +1 -0
- package/dist/lib/mdxish.d.ts +9 -0
- package/dist/main.js +63 -28
- package/dist/main.node.js +63 -28
- package/dist/main.node.js.map +1 -1
- package/dist/processor/transform/mdxish/magic-blocks/patterns.d.ts +3 -0
- package/dist/processor/transform/mdxish/magic-blocks/types.d.ts +1 -0
- package/dist/render-fixture.node.js +63 -28
- package/dist/render-fixture.node.js.map +1 -1
- package/dist/utils/common-html-words.d.ts +9 -2
- package/package.json +2 -1
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
export declare const HTML_TAG_RE: RegExp;
|
|
3
3
|
/** Matches an HTML element from its opening tag to the matching closing tag. */
|
|
4
4
|
export declare const HTML_ELEMENT_BLOCK_RE: RegExp;
|
|
5
|
+
export declare const NEWLINE_RE: RegExp;
|
|
5
6
|
/** Matches a newline with surrounding horizontal whitespace. */
|
|
6
7
|
export declare const NEWLINE_WITH_WHITESPACE_RE: RegExp;
|
|
8
|
+
/** Matches a run of two or more newlines (a blank line) with surrounding horizontal whitespace. */
|
|
9
|
+
export declare const BLANK_LINE_RE: RegExp;
|
|
7
10
|
/** Matches a closing block-level tag followed by non-tag text or by a newline then non-blank content. */
|
|
8
11
|
export declare const CLOSE_BLOCK_TAG_BOUNDARY_RE: RegExp;
|
|
9
12
|
/** Strips HTML open/close tags. Used to detect non-tag inner text content. */
|
|
@@ -95928,6 +95928,7 @@ var allCSS2RNProps = __webpack_unused_export__ = flatten([allProps, CSS2RNProps]
|
|
|
95928
95928
|
|
|
95929
95929
|
|
|
95930
95930
|
|
|
95931
|
+
|
|
95931
95932
|
/**
|
|
95932
95933
|
* Extract word boundaries from camelCase strings (e.g., "borderWidth" -> ["border", "width"])
|
|
95933
95934
|
*/
|
|
@@ -96007,10 +96008,43 @@ const CUSTOM_PROP_BOUNDARIES = [
|
|
|
96007
96008
|
*/
|
|
96008
96009
|
const RUNTIME_COMPONENT_TAGS = new Set(['Variable', 'variable', 'html-block', 'rdme-pin']);
|
|
96009
96010
|
/**
|
|
96010
|
-
*
|
|
96011
|
-
*
|
|
96011
|
+
* Elements that are not actually standard HTML tags, or those that we intentionally
|
|
96012
|
+
* don't want to treat as one & is mute to check with. These include:
|
|
96013
|
+
* - SVG/MathML descendants
|
|
96014
|
+
* - Namespaced foreign content
|
|
96015
|
+
* - `image`, which the HTML tree builder rewrites to `img`
|
|
96016
|
+
* Most of these are bundled in parse5's `TAG_NAMES` set, but we can also add a few more.
|
|
96012
96017
|
*/
|
|
96013
|
-
const
|
|
96018
|
+
const NON_STANDARD_TAGS = new Set([
|
|
96019
|
+
'annotation-xml',
|
|
96020
|
+
'desc',
|
|
96021
|
+
'foreignObject',
|
|
96022
|
+
'image',
|
|
96023
|
+
'malignmark',
|
|
96024
|
+
'mglyph',
|
|
96025
|
+
'mi',
|
|
96026
|
+
'mn',
|
|
96027
|
+
'mo',
|
|
96028
|
+
'ms',
|
|
96029
|
+
'mtext',
|
|
96030
|
+
]);
|
|
96031
|
+
/**
|
|
96032
|
+
* Standard HTML tags list.
|
|
96033
|
+
* A use case of this is to differentiate custom components tag vs standard HTML tags.
|
|
96034
|
+
*
|
|
96035
|
+
* Unioned from:
|
|
96036
|
+
* - `html-tags`: All modern spec HTML elements
|
|
96037
|
+
* - parse5's `TAG_NAMES`: Elements the HTML tree-construction algorithm has to special-case
|
|
96038
|
+
* This includes obsolete tags that are still rendered by browsers.
|
|
96039
|
+
* - NON_STANDARD_TAGS: We've had to filter because currently parse5's `TAG_NAMES` set over-enumerates
|
|
96040
|
+
* tags that are not actually standard HTML tags. It also allows custom tags to be filtered out.
|
|
96041
|
+
*/
|
|
96042
|
+
const STANDARD_HTML_TAGS = new Set([
|
|
96043
|
+
...html_tags_namespaceObject,
|
|
96044
|
+
...Object.values(TAG_NAMES),
|
|
96045
|
+
'acronym', // Obselete tag not included either of the above sources. Add here if we have missed any.
|
|
96046
|
+
'blink',
|
|
96047
|
+
].filter(tag => !NON_STANDARD_TAGS.has(tag)));
|
|
96014
96048
|
/**
|
|
96015
96049
|
* Table structural tags. Blank lines inside these carry deliberate meaning for
|
|
96016
96050
|
* `mdxishTables` (e.g. splitting cell content into paragraphs, or deciding
|
|
@@ -125298,8 +125332,11 @@ function rehypeStringify(options) {
|
|
|
125298
125332
|
const HTML_TAG_RE = /<\/?([a-zA-Z][a-zA-Z0-9-]*)((?:[^>"']*(?:"[^"]*"|'[^']*'))*[^>"']*)>/g;
|
|
125299
125333
|
/** Matches an HTML element from its opening tag to the matching closing tag. */
|
|
125300
125334
|
const HTML_ELEMENT_BLOCK_RE = /<([a-zA-Z][a-zA-Z0-9-]*)[\s>][\s\S]*?<\/\1>/g;
|
|
125335
|
+
const NEWLINE_RE = /\n/g;
|
|
125301
125336
|
/** Matches a newline with surrounding horizontal whitespace. */
|
|
125302
125337
|
const NEWLINE_WITH_WHITESPACE_RE = /[^\S\n]*\n[^\S\n]*/g;
|
|
125338
|
+
/** Matches a run of two or more newlines (a blank line) with surrounding horizontal whitespace. */
|
|
125339
|
+
const BLANK_LINE_RE = /[^\S\n]*\n(?:[^\S\n]*\n)+[^\S\n]*/g;
|
|
125303
125340
|
/** Matches a closing block-level tag followed by non-tag text or by a newline then non-blank content. */
|
|
125304
125341
|
const CLOSE_BLOCK_TAG_BOUNDARY_RE = /<\/([a-zA-Z][a-zA-Z0-9-]*)>\s*(?:(?!<)(\S)|\n([^\n]))/g;
|
|
125305
125342
|
/** Strips HTML open/close tags. Used to detect non-tag inner text content. */
|
|
@@ -125369,7 +125406,6 @@ const EMPTY_CODE_PLACEHOLDER = {
|
|
|
125369
125406
|
|
|
125370
125407
|
|
|
125371
125408
|
|
|
125372
|
-
|
|
125373
125409
|
/**
|
|
125374
125410
|
* Wraps a node in a "pinned" container if sidebar: true is set.
|
|
125375
125411
|
*/
|
|
@@ -125404,16 +125440,13 @@ const textToBlock = (text) => [{ children: textToInline(text), type: 'paragraph'
|
|
|
125404
125440
|
*/
|
|
125405
125441
|
const ensureLeadingBreaks = (text) => text.replace(/^\n+/, match => '<br>'.repeat(match.length));
|
|
125406
125442
|
/** Preprocesses magic block body content before parsing. */
|
|
125407
|
-
const preprocessBody = (text) =>
|
|
125408
|
-
return ensureLeadingBreaks(text);
|
|
125409
|
-
};
|
|
125443
|
+
const preprocessBody = (text, hardBreaks) => (hardBreaks ? ensureLeadingBreaks(text) : text);
|
|
125410
125444
|
const bodyExtensions = mdxishExtensions(FEATURES.magicBlockBody);
|
|
125411
125445
|
/** Markdown parser */
|
|
125412
125446
|
const contentParser = unified()
|
|
125413
125447
|
.data('micromarkExtensions', bodyExtensions.micromarkExtensions)
|
|
125414
125448
|
.data('fromMarkdownExtensions', bodyExtensions.fromMarkdownExtensions)
|
|
125415
125449
|
.use(remarkParse)
|
|
125416
|
-
.use(hard_breaks)
|
|
125417
125450
|
.use(remarkGfm)
|
|
125418
125451
|
.use(normalize_malformed_md_syntax);
|
|
125419
125452
|
/**
|
|
@@ -125510,17 +125543,21 @@ const processMarkdownInHtmlString = (html) => {
|
|
|
125510
125543
|
/**
|
|
125511
125544
|
* Separate a closing block-level tag from the content that follows it.
|
|
125512
125545
|
*
|
|
125513
|
-
*
|
|
125514
|
-
*
|
|
125515
|
-
* the following content as markdown.
|
|
125546
|
+
* A blank line (\n\n) is appended so CommonMark ends the HTML block and parses the
|
|
125547
|
+
* following content as markdown; with hard breaks each \n also becomes a <br> to keep its spacing.
|
|
125516
125548
|
*/
|
|
125517
|
-
const separateBlockTagFromContent = (match, tag, inlineChar, nextLineChar) => {
|
|
125549
|
+
const separateBlockTagFromContent = (hardBreaks, match, tag, inlineChar, nextLineChar) => {
|
|
125518
125550
|
if (!BLOCK_LEVEL_TAGS.has(tag.toLowerCase()))
|
|
125519
125551
|
return match;
|
|
125520
|
-
const newlineCount = (match.match(
|
|
125552
|
+
const newlineCount = hardBreaks ? (match.match(NEWLINE_RE) ?? []).length : 0;
|
|
125521
125553
|
const breaks = '<br>'.repeat(newlineCount);
|
|
125522
125554
|
return `</${tag}>${breaks}\n\n${inlineChar || nextLineChar}`;
|
|
125523
125555
|
};
|
|
125556
|
+
/**
|
|
125557
|
+
* Newlines inside an HTML block become <br> so CommonMark doesn't end the block on a blank
|
|
125558
|
+
* line. Without hard breaks only blank lines break, but they still have to be replaced.
|
|
125559
|
+
*/
|
|
125560
|
+
const collapseHtmlBlockNewlines = (html, hardBreaks) => html.replace(hardBreaks ? NEWLINE_WITH_WHITESPACE_RE : BLANK_LINE_RE, '<br>');
|
|
125524
125561
|
/** Escape a leading (possibly indented) `-`/`*`/`+` so cells don't become bullet lists. */
|
|
125525
125562
|
const escapeLeadingListMarkers = (text) => text.replace(/^([ \t]*)([-*+])(?=[ \t]|$)/gm, '$1\\$2');
|
|
125526
125563
|
/**
|
|
@@ -125528,15 +125565,13 @@ const escapeLeadingListMarkers = (text) => text.replace(/^([ \t]*)([-*+])(?=[ \t
|
|
|
125528
125565
|
* so `<ul><li>_text_</li></ul>` won't convert underscores to emphasis.
|
|
125529
125566
|
* We parse first, then visit html nodes and process their text content.
|
|
125530
125567
|
*/
|
|
125531
|
-
const parseTableCell = (text) => {
|
|
125568
|
+
const parseTableCell = (text, hardBreaks) => {
|
|
125532
125569
|
if (!text.trim())
|
|
125533
125570
|
return [{ type: 'text', value: '' }];
|
|
125534
|
-
// Convert \n (and surrounding whitespace) to <br> inside HTML blocks so
|
|
125535
|
-
// CommonMark doesn't split them on blank lines.
|
|
125536
125571
|
const escaped = processBackslashEscapes(text);
|
|
125537
125572
|
const normalized = escaped
|
|
125538
|
-
.replace(HTML_ELEMENT_BLOCK_RE, match => match
|
|
125539
|
-
.replace(CLOSE_BLOCK_TAG_BOUNDARY_RE, separateBlockTagFromContent);
|
|
125573
|
+
.replace(HTML_ELEMENT_BLOCK_RE, match => collapseHtmlBlockNewlines(match, hardBreaks))
|
|
125574
|
+
.replace(CLOSE_BLOCK_TAG_BOUNDARY_RE, (match, tag, inlineChar, nextLineChar) => separateBlockTagFromContent(hardBreaks, match, tag, inlineChar, nextLineChar));
|
|
125540
125575
|
const processed = escapeLeadingListMarkers(normalized);
|
|
125541
125576
|
const tree = contentParser.runSync(contentParser.parse(processed));
|
|
125542
125577
|
// Process markdown inside HTML blocks that have non-tag inner text (e.g. `<div>**x**`
|
|
@@ -125585,7 +125620,7 @@ const parseApiHeaderTitle = (text) => {
|
|
|
125585
125620
|
* Transform a magicBlock node into final MDAST nodes.
|
|
125586
125621
|
*/
|
|
125587
125622
|
function transformMagicBlock(blockType, data, rawValue, options = {}) {
|
|
125588
|
-
const { compatibilityMode = false, safeMode = false } = options;
|
|
125623
|
+
const { compatibilityMode = false, hardBreaks = true, safeMode = false } = options;
|
|
125589
125624
|
// Handle empty data by returning placeholder nodes for known block types
|
|
125590
125625
|
// This allows the editor to show appropriate placeholder UI instead of nothing
|
|
125591
125626
|
if (Object.keys(data).length < 1) {
|
|
@@ -125724,7 +125759,7 @@ function transformMagicBlock(blockType, data, rawValue, options = {}) {
|
|
|
125724
125759
|
});
|
|
125725
125760
|
}
|
|
125726
125761
|
if (hasBody) {
|
|
125727
|
-
const bodyBlocks = parseBlock(preprocessBody(calloutJson.body || ''));
|
|
125762
|
+
const bodyBlocks = parseBlock(preprocessBody(calloutJson.body || '', hardBreaks));
|
|
125728
125763
|
children.push(...bodyBlocks);
|
|
125729
125764
|
}
|
|
125730
125765
|
const calloutElement = {
|
|
@@ -125756,12 +125791,12 @@ function transformMagicBlock(blockType, data, rawValue, options = {}) {
|
|
|
125756
125791
|
mapped[rowIndex][colIndex] = v;
|
|
125757
125792
|
return mapped;
|
|
125758
125793
|
}, []);
|
|
125759
|
-
const tokenizeCell = compatibilityMode
|
|
125760
|
-
? textToBlock
|
|
125761
|
-
: parseTableCell;
|
|
125794
|
+
const tokenizeCell = compatibilityMode ? textToBlock : (text) => parseTableCell(text, hardBreaks);
|
|
125762
125795
|
const tableChildren = Array.from({ length: rows + 1 }, (_, y) => ({
|
|
125763
125796
|
children: Array.from({ length: cols }, (__, x) => ({
|
|
125764
|
-
children: sparseData[y]?.[x]
|
|
125797
|
+
children: sparseData[y]?.[x]
|
|
125798
|
+
? tokenizeCell(preprocessBody(sparseData[y][x], hardBreaks))
|
|
125799
|
+
: [{ type: 'text', value: '' }],
|
|
125765
125800
|
type: y === 0 ? 'tableHead' : 'tableCell',
|
|
125766
125801
|
})),
|
|
125767
125802
|
type: 'tableRow',
|
|
@@ -127618,7 +127653,7 @@ function preprocessContent(content, opts) {
|
|
|
127618
127653
|
return processSnakeCaseComponent(result, { knownComponents });
|
|
127619
127654
|
}
|
|
127620
127655
|
function mdxishAstProcessor(mdContent, opts = {}) {
|
|
127621
|
-
const { components: userComponents = {}, newEditorTypes = false, safeMode = false, useTailwind } = opts;
|
|
127656
|
+
const { components: userComponents = {}, hardBreaks: enableHardBreaks = true, newEditorTypes = false, safeMode = false, useTailwind, } = opts;
|
|
127622
127657
|
const components = {
|
|
127623
127658
|
...loadComponents(),
|
|
127624
127659
|
...userComponents,
|
|
@@ -127647,7 +127682,7 @@ function mdxishAstProcessor(mdContent, opts = {}) {
|
|
|
127647
127682
|
// The next few transformers must appear after mdxishMdxComponentBlocks
|
|
127648
127683
|
// so nodes produced by the inline re-parse of component bodies
|
|
127649
127684
|
// (e.g. code/image/embed inside <Tabs>) get visited too
|
|
127650
|
-
.use(magic_block_transformer)
|
|
127685
|
+
.use(magic_block_transformer, { hardBreaks: enableHardBreaks })
|
|
127651
127686
|
.use(transform_images, { isMdxish: true })
|
|
127652
127687
|
.use(defaultTransformers)
|
|
127653
127688
|
.use(newEditorTypes ? inline_mdx_blocks : undefined) // Merge inline html components (e.g. <Anchor>) into MDAST nodes
|
|
@@ -127704,7 +127739,7 @@ function mdxishMdastToMd(mdast) {
|
|
|
127704
127739
|
* @see .claude/context/MDXish/Processor Overview.md
|
|
127705
127740
|
*/
|
|
127706
127741
|
function mdxish(mdContent, opts = {}) {
|
|
127707
|
-
const { components: userComponents = {}, safeMode = false, variables } = opts;
|
|
127742
|
+
const { components: userComponents = {}, hardBreaks: enableHardBreaks = true, safeMode = false, variables } = opts;
|
|
127708
127743
|
const components = {
|
|
127709
127744
|
...loadComponents(),
|
|
127710
127745
|
...userComponents,
|
|
@@ -127716,7 +127751,7 @@ function mdxish(mdContent, opts = {}) {
|
|
|
127716
127751
|
const { processor, parserReadyContent } = mdxishAstProcessor(contentWithoutComments, opts);
|
|
127717
127752
|
processor
|
|
127718
127753
|
.use(safeMode ? undefined : evaluate_exports) // Evaluate `export const/function` and stash scope on file.data.mdxishScope
|
|
127719
|
-
.use(hard_breaks) // Must precede evaluateExpressions to avoid splitting the \n in an evaluated template literal into a <br> node
|
|
127754
|
+
.use(enableHardBreaks ? hard_breaks : undefined) // Must precede evaluateExpressions to avoid splitting the \n in an evaluated template literal into a <br> node
|
|
127720
127755
|
.use(safeMode ? undefined : evaluate_expressions) // Evaluate self-contained MDX expressions (e.g. `{1+1}`)
|
|
127721
127756
|
.use(safeMode ? undefined : evaluate_style_block_expressions) // Evaluate `<style>{`...`}</style>` template literals into plain CSS
|
|
127722
127757
|
.use(variables_code, { variables }) // Resolve <<...>> and {user.*} inside code and inline code nodes
|