diff --git a/packages/lexical-markdown/src/MarkdownExport.ts b/packages/lexical-markdown/src/MarkdownExport.ts index b61b4532a98..207c99e9f7d 100644 --- a/packages/lexical-markdown/src/MarkdownExport.ts +++ b/packages/lexical-markdown/src/MarkdownExport.ts @@ -203,13 +203,11 @@ function exportTextFormat( ): string { // This function handles the case of a string looking like this: " foo " // Where it would be invalid markdown to generate: "** foo **" - // If the node has no format, we use the original text. - // Otherwise, we escape leading and trailing whitespaces to their corresponding code points, - // ensuring the returned string maintains its original formatting, e.g., "** foo **". - let output = - node.getFormat() === 0 - ? textContent - : escapeLeadingAndTrailingWhitespaces(textContent); + // We instead want to trim the whitespace out, apply formatting, and then + // bring the whitespace back. So our returned string looks like this: " **foo** " + // However, we do not want to export any formatting if the string is just whitespace: " " + const frozenString = textContent.trim(); + let output = frozenString; if (!node.hasFormat('code')) { // Escape any markdown characters in the text content @@ -288,9 +286,9 @@ function exportTextFormat( break; } - output = openingTags + output + closingTagsAfter; + output = output ? openingTags + output + closingTagsAfter : output; // Replace trimmed version of textContent ensuring surrounding whitespace is not modified - return closingTagsBefore + output; + return closingTagsBefore + textContent.replace(frozenString, () => output); } function getTextSibling(node: TextNode, backward: boolean): TextNode | null { @@ -309,9 +307,3 @@ function hasFormat( ): boolean { return $isTextNode(node) && node.hasFormat(format); } - -function escapeLeadingAndTrailingWhitespaces(textContent: string) { - return textContent.replace(/^\s+|\s+$/g, (match) => { - return [...match].map((char) => '' + char.codePointAt(0) + ';').join(''); - }); -} diff --git a/packages/lexical-markdown/src/__tests__/unit/LexicalMarkdown.test.ts b/packages/lexical-markdown/src/__tests__/unit/LexicalMarkdown.test.ts index a5fc85f973a..6f02d7cf53a 100644 --- a/packages/lexical-markdown/src/__tests__/unit/LexicalMarkdown.test.ts +++ b/packages/lexical-markdown/src/__tests__/unit/LexicalMarkdown.test.ts @@ -409,17 +409,14 @@ describe('Markdown', () => { { html: '
Hello world!
Hello world!
Hello world!
', md: '*Hello **world**!*', - mdAfterExport: '*Hello **world**!*', }, { html: 'hello world
', @@ -602,28 +599,24 @@ describe('Markdown', () => { md: '**Bold** `[text](https://lexical.dev)` **Bold 3**', }, { - html: 'Text boldstart text boldend text
', - md: 'Text **boldstart [text](https://lexical.dev) boldend** text', - mdAfterExport: - 'Text **boldstart **[**text**](https://lexical.dev)** boldend** text', + html: 'Text boldstart text boldend text
', + md: 'Text **boldstart** [**text**](https://lexical.dev) **boldend** text', }, { - html: 'Text boldstart text boldend text
Text boldstart text boldend text
It works with links too
It works with links too
It works with links too!
It works with links too!
*Hello* world
', md: '\\*Hello\\* world', }, - { - html: '', - md: '** **', - }, { html: '', md: '[[h]ello](https://lexical.dev)[h[e]llo](https://lexical.dev)', @@ -720,7 +709,7 @@ describe('Markdown', () => { { html: '
text link
', md: '**text [link](https://lexical.dev)**', - mdAfterExport: '**text **[**link**](https://lexical.dev)', + mdAfterExport: '**text** [**link**](https://lexical.dev)', }, { html: 'texttext
', @@ -734,7 +723,7 @@ describe('Markdown', () => { { html: 'foo bar
', md: '**foo [*bar*](/url)**', - mdAfterExport: '**foo **[***bar***](/url)', + mdAfterExport: '**foo** [***bar***](/url)', }, { html: '*foo bar baz
', @@ -744,13 +733,18 @@ describe('Markdown', () => { { html: 'a * b x
_foo_bar
', md: '_foo_bar', mdAfterExport: '\\_foo\\_bar', }, + { + html: '', + md: ' ', + skipImport: true, + }, ]; for (const {