Skip to content

fix: keep the Markdown an image description was written with - #347

Merged
Azganoth merged 1 commit into
mainfrom
bug/image-description-authored-form
Sep 1, 2026
Merged

fix: keep the Markdown an image description was written with#347
Azganoth merged 1 commit into
mainfrom
bug/image-description-authored-form

Conversation

@Azganoth

@Azganoth Azganoth commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Summary

An image description holds inline content and the parser keeps only the text it spells, so ![Alt with *emphasis*](leaf.svg) opened as Alt with emphasis and saved that way, and ![Outer ![inner](inner.svg)](leaf.svg) lost the inner image's destination from the file on the first save with nothing in the document able to recover it.

The image node now carries the description's source beside the alt text the parser derived, on the pattern an authored destination and a title marker already use. The source is recovered in the pass that walks the tree against the file it was read from, and reaches the file as it stands rather than through the label escaping that would turn its markers into characters. The alt text is unchanged, so the rendered image is still named by the text its description spells.

Holding the description as document content was the alternative, and nothing delivers it: the mdast image node carries no children to build inline content from, and the node view's whole editing surface is a raw Markdown input, so a description rich in the schema would still be edited as text. That trade and its consequences are recorded in docs/decisions.md.

Two things follow from the same place:

  • The reference image form has the same defect and takes the same treatment. That also reaches the collapsed and shortcut forms of a described reference: mdast-util-to-markdown keeps those forms only while the description it writes still matches the label, which a flattened description does not, so ![*em*] needed the description back before it could stay a shortcut.
  • The raw image Markdown a focused image exposes is now the source the file holds rather than the text the description spells. Editing the destination or the title leaves the description standing; editing the description writes it as the text typed there, because reading its markers back as inline content is the parse that input does not run.

A description is carried only where it says more than the alt text does. Escapes and character references are differences the alt text answers for on its own, so a description spelling only those is left exactly as it was.

The source is read from the file slice, and a code span binds more tightly than the brackets around a description, so the reading is confirmed against the destination or the reference label the node holds and declined where they disagree. A description whose brackets a code span interrupts is left to its text rather than written from a reading that ended early.

Related Issue

Closes #259

Verification

imageDescription.test.ts is new. Each row opens a source, saves it, and reopens the result, asserting the saved bytes, the node attributes, and that the document the reopened file gives back is the document that was saved. The document assertion is the one that matters here: a flattened description converges perfectly, so the corpus guard is green on this defect either way, which is the trap #251 records. The rows cover emphasis with inline code, strong with strikethrough, a link, a title, an image in a link label, the three reference forms, a nested image, a description holding only escapes, and a description a code span interrupts. The nested-image row asserts the outer node keeps Outer inner as its alt text while carrying Outer ![inner](../assets/inner.svg) as its description.

imageView.test.ts gains two rows: editing the destination through the raw image Markdown keeps the description the file holds, and editing the description writes it as text, so ![Alt with *markers*](./assets/icon.png) saves as ![Alt with \*markers\*](./assets/icon.png). sourceProjectionImageLink.test.ts gains one: a link label holding a described image projects that image's authored source and restores the identical document when the caret leaves it. imageMarkdown.test.ts covers the input's serialize and parse for a description holding a nested image, and for a shortcut reference whose description spells its label.

Measured by driving the editor mount across ten image forms before and after the change, comparing the saved bytes and the document each time. The five flattening rows move to byte identity: emphasis with inline code, strong with strikethrough, a link in a description, a nested image, and a reference image. Nothing else in the set moves — an escaped description, a bracketed one, an entity one, a linked image, and a titled image are all written exactly as before.

pnpm check:frontend passes. The backend is untouched, so pnpm check:backend was not run.

Not verified: the manual pass over corpus/ in the running application, which covers rendering, interaction, and navigator behavior beyond the automated round-trip.

Notes

A character reference in a description still decodes on save, so ![& entity](x.png) is still written ![& entity](x.png). Carrying the source only where it says more than the alt text is what keeps that difference with #262, which owns it, rather than fixing it as collateral here.

A copy through the DOM carries no authored attributes, so an image pasted from outside the editing session falls back to the text its description spells, exactly as an edited description does. That is the fallback the authored destination and title marker already take.

corpus/commonmark/links-and-images.md is unchanged. Both forms the issue names were already in it, under Inline and reference image forms and Linked and nested images, and both now round-trip byte-identically.

@Azganoth Azganoth added the Bug Something isn't working label Sep 1, 2026
@Azganoth Azganoth self-assigned this Sep 1, 2026
@Azganoth
Azganoth enabled auto-merge (squash) September 1, 2026 09:12
@Azganoth
Azganoth merged commit c0bfd5b into main Sep 1, 2026
3 checks passed
@Azganoth
Azganoth deleted the bug/image-description-authored-form branch September 1, 2026 09:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Formatting and nested images inside an image description are destroyed on save

1 participant