Skip to content

Commit 00d1ea6

Browse files
committed
fix: enhance link parser to correctly handle nested brackets and add test cases for image links
1 parent d1583ab commit 00d1ea6

2 files changed

Lines changed: 39 additions & 5 deletions

File tree

parser/internal/link.go

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,28 @@ func NewLinkParser() *LinkParser {
1111
return &LinkParser{}
1212
}
1313

14+
// findMatchingRightSquareBracket finds the index of the closing ] that matches the opening [
15+
// It handles nested brackets by tracking bracket depth
16+
func findMatchingRightSquareBracket(tokens []*tokenizer.Token) int {
17+
depth := 0
18+
for i, token := range tokens {
19+
// Skip escaped brackets
20+
if i > 0 && tokens[i-1].Type == tokenizer.Backslash {
21+
continue
22+
}
23+
24+
if token.Type == tokenizer.LeftSquareBracket {
25+
depth++
26+
} else if token.Type == tokenizer.RightSquareBracket {
27+
if depth == 0 {
28+
return i
29+
}
30+
depth--
31+
}
32+
}
33+
return -1
34+
}
35+
1436
func (*LinkParser) Match(tokens []*tokenizer.Token) (ast.Node, int) {
1537
matchedTokens := tokenizer.GetFirstLine(tokens)
1638
if len(matchedTokens) < 5 {
@@ -20,14 +42,12 @@ func (*LinkParser) Match(tokens []*tokenizer.Token) (ast.Node, int) {
2042
return nil, 0
2143
}
2244

23-
rightSquareBracketIndex := tokenizer.FindUnescaped(matchedTokens[1:], tokenizer.RightSquareBracket)
45+
rightSquareBracketIndex := findMatchingRightSquareBracket(matchedTokens[1:])
2446
if rightSquareBracketIndex == -1 {
2547
return nil, 0
2648
}
2749
contentTokens := matchedTokens[1 : rightSquareBracketIndex+1]
28-
if tokenizer.FindUnescaped(contentTokens, tokenizer.LeftSquareBracket) != -1 {
29-
return nil, 0
30-
}
50+
3151
if len(contentTokens)+4 >= len(matchedTokens) {
3252
return nil, 0
3353
}
@@ -49,7 +69,7 @@ func (*LinkParser) Match(tokens []*tokenizer.Token) (ast.Node, int) {
4969
return nil, 0
5070
}
5171

52-
contentNodes, err := ParseInlineWithParsers(contentTokens, []InlineParser{NewEscapingCharacterParser(), NewTextParser()})
72+
contentNodes, err := ParseInlineWithParsers(contentTokens, []InlineParser{NewImageParser(), NewEscapingCharacterParser(), NewTextParser()})
5373
if err != nil {
5474
return nil, 0
5575
}

parser/tests/link_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,20 @@ func TestLinkParser(t *testing.T) {
5757
URL: "https://example.com",
5858
},
5959
},
60+
{
61+
text: "[![alt text](https://example.com/image.png)](https://example.com)",
62+
node: &ast.Link{
63+
Content: []ast.Node{&ast.Image{AltText: "alt text", URL: "https://example.com/image.png"}},
64+
URL: "https://example.com",
65+
},
66+
},
67+
{
68+
text: "[![](https://example.com/image.png)](https://example.com)",
69+
node: &ast.Link{
70+
Content: []ast.Node{&ast.Image{AltText: "", URL: "https://example.com/image.png"}},
71+
URL: "https://example.com",
72+
},
73+
},
6074
}
6175
for _, test := range tests {
6276
tokens := tokenizer.Tokenize(test.text)

0 commit comments

Comments
 (0)