Skip to content

Preserve literal ampersands in Markdown links and images - #468

Open
PHJ2000 wants to merge 1 commit into
commonmark:mainfrom
PHJ2000:fix-markdown-link-ampersands
Open

PHJ2000 wants to merge 1 commit into
commonmark:mainfrom
PHJ2000:fix-markdown-link-ampersands

Conversation

@PHJ2000

@PHJ2000 PHJ2000 commented Oct 23, 2026

Copy link
Copy Markdown

Rendering a Link or Image whose destination/title contains literal entity-like text (for example © or A) writes an unescaped ampersand. Parsing that Markdown again turns the text into a character, changing the AST value.

For example:

import org.commonmark.node.*;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.markdown.MarkdownRenderer;

public class CommonmarkAmpersandProbe {
    public static void main(String[] args) {
        Link link = new Link("/url?value=©", "literal A");
        link.appendChild(new Text("example"));
        String markdown = MarkdownRenderer.builder().build().render(link);
        Link reparsed = (Link) Parser.builder().build().parse(markdown).getFirstChild().getFirstChild();
        if (!link.getDestination().equals(reparsed.getDestination())
                || !link.getTitle().equals(reparsed.getTitle())) {
            throw new AssertionError("Changed to: " + reparsed.getDestination() + " / " + reparsed.getTitle());
        }
        System.out.println(markdown);
        System.out.println("Literal destination and title preserved");
    }
}

Use the existing MarkdownWriter escaping for ampersands in bare/angle-bracket destinations and quoted titles. The regression tests cover links and images, named/decimal/hex entities, angle-bracket destinations, and ordinary ampersands. Ordinary query separators are also escaped in the Markdown output, while the parsed values stay the same; the renderer does not promise identical Markdown syntax.

Validation:

  • Baseline: 14 of the 18 new parameter cases fail; the four ordinary-ampersand controls pass.
  • JDK 21: focused renderer and spec tests pass; ./mvnw clean verify javadoc:javadoc spotless:check succeeds (4,603 test entries, 1 skipped, no failures/errors). Javadoc emits nonfatal missing sibling target/apidocs link messages; generation completes.
  • Actual JDK 11: a standalone destination/title round-trip example compiles and runs. The separate Android project was not run.
  • A separate AI review reproduced the 14 baseline failures and passing focused tests. It did not repeat the full reactor or JDK 11 probe.

AI disclosure: OpenAI Codex assisted with investigation, implementation, tests, and this description. The separate review was also performed by an AI session, not a human reviewer.

Escape entity-like values in destinations and titles through the existing
MarkdownWriter path so parsing the output preserves the AST values.

Generated-by: OpenAI Codex

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant