fix(editor): rewrite local images in markdown runs of the split renderer
Every .md preview renders through MarkdownDocument (htmlInfo is ungated), but its markdown segments passed the raw source into MarkdownText, whose chat-security stance drops non-http(s) image destinations — so local markdown-syntax images (, reference-style definitions) always fell back to alt text. Only HTML <img src> tags were rewritten (postProcessSanitized). Apply rewriteLocalImageUrls to each markdown run (segment + appended reference definitions) inside MarkdownDocument's prepared memo, through the same media trust fence the sanitized HTML leaves already use. Idempotent for already-absolute media URLs; remote destinations untouched. Also correct the stale "non-null only for HTML documents" comment on TextEditor's htmlInfo.
This commit is contained in:
@@ -175,3 +175,51 @@ describe('MarkdownDocument (inline pass)', () => {
|
||||
await unmount(root)
|
||||
})
|
||||
})
|
||||
|
||||
describe('MarkdownDocument (local markdown images)', () => {
|
||||
it('renders markdown-syntax local images through the /sidebar/file route', async () => {
|
||||
const { container, root } = await renderDocument([
|
||||
'# Title',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'![logo][logo]',
|
||||
'',
|
||||
'[logo]: ./logo.png',
|
||||
].join('\n'))
|
||||
const imgs = [...container.querySelectorAll('img')]
|
||||
expect(imgs.length, 'both local images must render as <img>, not alt fallback').toBe(2)
|
||||
expect(imgs[0]?.getAttribute('src')).toBe('http://gui.origin/sidebar/file?sessionId=s1&path=%2Fws%2Fdocs%2Fassets%2Ficon.svg&cwd=%2Fws')
|
||||
expect(imgs[0]?.getAttribute('alt')).toBe('icon')
|
||||
expect(imgs[1]?.getAttribute('src')).toBe('http://gui.origin/sidebar/file?sessionId=s1&path=%2Fws%2Fdocs%2Flogo.png&cwd=%2Fws')
|
||||
expect(imgs[1]?.getAttribute('alt')).toBe('logo')
|
||||
await unmount(root)
|
||||
})
|
||||
|
||||
it('renders local markdown images in HTML-mixed documents (the production path)', async () => {
|
||||
const { container, root } = await renderDocument([
|
||||
'<div align="center">badges</div>',
|
||||
'',
|
||||
'',
|
||||
].join('\n'))
|
||||
const img = container.querySelector('img')
|
||||
expect(img, 'the markdown-syntax image after an HTML run must render').not.toBeNull()
|
||||
expect(img?.getAttribute('src')).toBe('http://gui.origin/sidebar/file?sessionId=s1&path=%2Fws%2Fdocs%2Fimg.png&cwd=%2Fws')
|
||||
await unmount(root)
|
||||
})
|
||||
|
||||
it('keeps remote image destinations untouched', async () => {
|
||||
const { container, root } = await renderDocument('')
|
||||
const img = container.querySelector('img')
|
||||
expect(img?.getAttribute('src')).toBe('https://example.com/x.png')
|
||||
await unmount(root)
|
||||
})
|
||||
|
||||
it('is idempotent for already-rewritten media URLs', async () => {
|
||||
const url = 'http://gui.origin/sidebar/file?sessionId=s1&path=%2Fws%2Fdocs%2Fimg.png&cwd=%2Fws'
|
||||
const { container, root } = await renderDocument(``)
|
||||
const img = container.querySelector('img')
|
||||
expect(img?.getAttribute('src')).toBe(url)
|
||||
await unmount(root)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user