Skip to content

Comments panel discards <img> alt attribute, renders "Image: image" #8760

@nvignola

Description

@nvignola

Environment

  • VS Code: 1.122.0 (Universal), commit 6a49527b96e326fe62fbdb56f60e16877c9aa724
  • GitHub Pull Requests extension: 0.146.0
  • OS: macOS (Darwin arm64 25.4.0)
  • Electron: 39.8.8, Node.js: 22.22.1

Summary

When a PR comment body contains a raw <img> tag with a meaningful alt attribute, the VS Code Comments panel preview shows Image: image instead of Image: <alt>. The extension rewrites the <img> tag and overwrites the alt with the literal string image before VS Code ever sees it.

Only comments whose bodies contain raw HTML <img> tags are affected. Comments authored with markdown image syntax (![alt](src)) are unaffected, because they bypass the rewrite entirely. To reproduce this bug, the comment body must contain raw HTML <img alt="abc" src"...">.

The replaceImg function operates on the comment's raw markdown body, not on GitHub's server-rendered body_html. So a markdown ![P0](url) never matches IMG_EXPRESSION and passes through untouched, while a raw <img alt="P0" src="url"> matches, gets rewritten to ![image](url), and loses its alt.

Repro

  1. Post a PR review comment whose body is literally:

    <img src="https://example.com/anything.png" alt="P2"> hello world
    
  2. Open the PR in VS Code with this extension installed.

  3. Open the Comments panel (View → Comments).

Expected: preview reads Image: P2 hello world.
Actual: preview reads Image: image hello world.

See the attached screenshot: the top three rows are markdown-authored comments rendering correctly as Image: P0/P1/P2; the bottom rows are raw-HTML comments rendering as Image: image.

Image

Root cause

src/github/prComment.ts:354-358:

private replaceImg(body: string) {
    return body.replace(IMG_EXPRESSION, (_substring, _1, _2, _3, { src }) => {
        return `![image](${src})`;
    });
}

with IMG_EXPRESSION at line 218:

const IMG_EXPRESSION = /<img .*src=['"](?<src>.+?)['"].*?>/g;

The regex only captures src, the replacement template hardcodes image as the alt. Any pre-existing alt on the original tag is discarded.

Downstream, VS Code core does honor alt — see getRenderedComment in src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts in microsoft/vscode:

const images = renderedComment.element.getElementsByTagName('img');
for (let i = 0; i < images.length; i++) {
    const image = images[i];
    const textDescription = dom.$('');
    textDescription.textContent = image.alt ? nls.localize('imageWithLabel', "Image: {0}", image.alt) : nls.localize('image', "Image");
    image.replaceWith(textDescription);
}

So the rendering path is correct, only the extension's preprocessing needs to change.

Fix

Preserve the original alt when present and keep image as the fallback when missing or empty. Happy to send a PR.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions