diff --git a/src/markdown.ts b/src/markdown.ts index db9c09603..c5c5d528b 100644 --- a/src/markdown.ts +++ b/src/markdown.ts @@ -640,12 +640,15 @@ export function createMarkdownContent(content: string, url: string) { || ''; const code = codeElement.textContent || ''; - // Clean up the content and escape backticks - const cleanCode = code - .trim() - .replace(/`/g, '\\`'); - - return `\n\`\`\`${language}\n${cleanCode}\n\`\`\`\n`; + // Backslash escapes are literal inside a fence, so escaping backticks here would + // corrupt the code. Only a line-leading run of three or more backticks can close + // the block, so grow the fence past the longest such run instead. + const cleanCode = code.trim(); + const fenceSize = (cleanCode.match(/^`{3,}/gm) || []) + .reduce((size, run) => Math.max(size, run.length + 1), 3); + const fence = '`'.repeat(fenceSize); + + return `\n${fence}${language}\n${cleanCode}\n${fence}\n`; } }); diff --git a/tests/expected/general--obsidian.md-blog-verify-obsidian-sync-encryption.md b/tests/expected/general--obsidian.md-blog-verify-obsidian-sync-encryption.md index 46e29df67..8670e6bd1 100644 --- a/tests/expected/general--obsidian.md-blog-verify-obsidian-sync-encryption.md +++ b/tests/expected/general--obsidian.md-blog-verify-obsidian-sync-encryption.md @@ -38,7 +38,7 @@ First, get the salt used to derive your encryption key by following these steps: let data = await (await fetch('https://api.obsidian.md/vault/list', {method:'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({token: JSON.parse(localStorage.getItem('obsidian-account')).token})})).json(); let vaults = [].concat(data.shared, data.vaults); let vault = vaults.find(v => v.id === app.internalPlugins.getEnabledPluginById('sync').vaultId); -console.log(\`The salt of your vault ${vault.name} is: "${vault.salt}" with encryptionVersion ${vault.encryption_version}\`); +console.log(`The salt of your vault ${vault.name} is: "${vault.salt}" with encryptionVersion ${vault.encryption_version}`); ``` You should see a message containing your salt and encryption version: diff --git a/tests/markdown.test.ts b/tests/markdown.test.ts index 9ac581bd1..21d9af41a 100644 --- a/tests/markdown.test.ts +++ b/tests/markdown.test.ts @@ -294,4 +294,43 @@ describe('Markdown conversion', () => { expect(markdown).not.toContain('\\begin{aligned}'); }); }); + + describe('fenced code blocks', () => { + test('should not escape backticks inside a code block', () => { + const markdown = createMarkdownContent( + '
res.write(`data: ${payload}`);
', + 'https://example.com' + ); + + expect(markdown).toContain('res.write(`data: ${payload}`);'); + expect(markdown).not.toContain('\\`'); + }); + + test('should lengthen the fence when the code contains a fence line', () => { + const markdown = createMarkdownContent( + '
```js\nconst a = 1;\n```
', + 'https://example.com' + ); + + expect(markdown).toContain('````markdown\n```js\nconst a = 1;\n```\n````'); + }); + + test('should size the fence past the longest fence line in the code', () => { + const markdown = createMarkdownContent( + '
a\n`````\nb
', + 'https://example.com' + ); + + expect(markdown).toContain('``````\na\n`````\nb\n``````'); + }); + + test('should keep the standard fence for code without backticks', () => { + const markdown = createMarkdownContent( + '
print("hi")
', + 'https://example.com' + ); + + expect(markdown).toContain('```python\nprint("hi")\n```'); + }); + }); });