Skip to content

Commit 1bf85c6

Browse files
authored
Merge pull request #318 from commonmark/issue-315
Fix link reference definition parsing with invalid title
2 parents 5ba9c78 + b570e1b commit 1bf85c6

File tree

4 files changed

+48
-2
lines changed

4 files changed

+48
-2
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
66
This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html),
77
with the exception that 0.x versions can break between minor versions.
88

9+
## Unreleased
10+
### Fixed
11+
- Fix parsing of link reference definitions where it looks like it has a title
12+
but it doesn't because it's followed by characters other than space/tab. In that
13+
case, the title was set to the partially-parsed title and the source spans were
14+
wrong (#315).
15+
916
## [0.22.0] - 2024-03-15
1017
### Added
1118
- New `MarkdownRenderer` for rendering nodes to Markdown (CommonMark)!

commonmark/src/main/java/org/commonmark/internal/LinkReferenceDefinitionParser.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
/**
1616
* Parser for link reference definitions at the beginning of a paragraph.
1717
*
18-
* @see <a href="https://spec.commonmark.org/0.29/#link-reference-definition">Link reference definitions</a>
18+
* @see <a href="https://spec.commonmark.org/0.31.2/#link-reference-definitions">Link reference definitions</a>
1919
*/
2020
public class LinkReferenceDefinitionParser {
2121

@@ -70,6 +70,9 @@ public void parse(SourceLine line) {
7070
// Parsing failed, which means we fall back to treating text as a paragraph.
7171
if (!success) {
7272
state = State.PARAGRAPH;
73+
// If parsing of the title part failed, we still have a valid reference that we can add, and we need to
74+
// do it before the source span for this line is added.
75+
finishReference();
7376
return;
7477
}
7578
}
@@ -218,7 +221,8 @@ private boolean startTitle(Scanner scanner) {
218221
private boolean title(Scanner scanner) {
219222
Position start = scanner.position();
220223
if (!LinkScanner.scanLinkTitleContent(scanner, titleDelimiter)) {
221-
// Invalid title, stop
224+
// Invalid title, stop. Title collected so far must not be used.
225+
title = null;
222226
return false;
223227
}
224228

@@ -235,6 +239,8 @@ private boolean title(Scanner scanner) {
235239
scanner.whitespace();
236240
if (scanner.hasNext()) {
237241
// spec: No further non-whitespace characters may occur on the line.
242+
// Title collected so far must not be used.
243+
title = null;
238244
return false;
239245
}
240246
referenceValid = true;

commonmark/src/test/java/org/commonmark/internal/LinkReferenceDefinitionParserTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,30 @@ public void testTitleMultiline2() {
145145
assertDef(parser.getDefinitions().get(0), "foo", "/url", "\ntitle");
146146
}
147147

148+
@Test
149+
public void testTitleMultiline3() {
150+
parse("[foo]: /url");
151+
assertEquals(State.START_TITLE, parser.getState());
152+
// Note that this looks like a valid title until we parse "bad", at which point we need to treat the whole line
153+
// as a paragraph line and discard any already parsed title.
154+
parse("\"title\" bad");
155+
assertEquals(State.PARAGRAPH, parser.getState());
156+
157+
assertDef(parser.getDefinitions().get(0), "foo", "/url", null);
158+
}
159+
160+
@Test
161+
public void testTitleMultiline4() {
162+
parse("[foo]: /url");
163+
assertEquals(State.START_TITLE, parser.getState());
164+
parse("(title");
165+
assertEquals(State.TITLE, parser.getState());
166+
parse("foo(");
167+
assertEquals(State.PARAGRAPH, parser.getState());
168+
169+
assertDef(parser.getDefinitions().get(0), "foo", "/url", null);
170+
}
171+
148172
@Test
149173
public void testTitleInvalid() {
150174
assertParagraph("[foo]: /url (invalid(");

commonmark/src/test/java/org/commonmark/test/SourceSpansTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,15 @@ public void linkReferenceDefinitionWithTitle() {
183183
assertEquals(List.of(SourceSpan.of(1, 0, 11)), def2.getSourceSpans());
184184
}
185185

186+
@Test
187+
public void linkReferenceDefinitionWithTitleInvalid() {
188+
var doc = PARSER.parse("[foo]: /url\n\"title\" ok\n");
189+
var def = Nodes.find(doc, LinkReferenceDefinition.class);
190+
var paragraph = Nodes.find(doc, Paragraph.class);
191+
assertEquals(List.of(SourceSpan.of(0, 0, 11)), def.getSourceSpans());
192+
assertEquals(List.of(SourceSpan.of(1, 0, 10)), paragraph.getSourceSpans());
193+
}
194+
186195
@Test
187196
public void linkReferenceDefinitionHeading() {
188197
// This is probably the trickiest because we have a link reference definition at the start of a paragraph

0 commit comments

Comments
 (0)