diff --git a/README.md b/README.md
index 4c65a88..c19ffd8 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,7 @@ A markdown renderer that supports only a subset of the CommonMark spec in order
- Italic
- Links
- Lists
+- Images
- Headers
- Paragraphs
- Quotes
@@ -38,6 +39,7 @@ PASS: TestItalic
PASS: TestBold
PASS: TestStrike
PASS: TestLink
+PASS: TestImage
PASS: TestList
PASS: TestTables
PASS: TestCode
@@ -51,9 +53,9 @@ coverage: 100.0% of statements
## Benchmarks
```
-BenchmarkSmall-12 5836533 205.3 ns/op 32 B/op 1 allocs/op
-BenchmarkMedium-12 967740 1103 ns/op 512 B/op 1 allocs/op
-BenchmarkLarge-12 277908 4099 ns/op 2560 B/op 2 allocs/op
+BenchmarkSmall-12 5884641 201.5 ns/op 32 B/op 1 allocs/op
+BenchmarkMedium-12 938371 1124 ns/op 512 B/op 1 allocs/op
+BenchmarkLarge-12 277065 4115 ns/op 2560 B/op 2 allocs/op
```
## License
diff --git a/Render.go b/Render.go
index eeae870..15aad80 100644
--- a/Render.go
+++ b/Render.go
@@ -279,6 +279,7 @@ func (r *renderer) writeText(markdown string) {
searchStart = 0
linkTextStart = -1
linkTextEnd = -1
+ linkIsImage = false
emStart = -1
strongStart = -1
strikeStart = -1
@@ -286,7 +287,7 @@ func (r *renderer) writeText(markdown string) {
begin:
for {
- i := strings.IndexAny(markdown[searchStart:], "[]()`*_~")
+ i := strings.IndexAny(markdown[searchStart:], "[]()`*_~!")
if i == -1 {
r.WriteString(html.EscapeString(markdown[tokenStart:]))
@@ -332,11 +333,19 @@ begin:
linkText := markdown[linkTextStart+1 : linkTextEnd]
linkURL := markdown[i+1 : urlEnd]
- r.WriteString("")
- r.WriteString(html.EscapeString(linkText))
- r.WriteString("")
+ if linkIsImage {
+ r.WriteString("")
+ } else {
+ r.WriteString("")
+ r.WriteString(html.EscapeString(linkText))
+ r.WriteString("")
+ }
linkTextStart = -1
linkTextEnd = -1
@@ -402,6 +411,17 @@ begin:
tokenStart = i
strikeStart = i + 2
}
+
+ case '!':
+ if i+1 >= len(markdown) || markdown[i+1] != '[' {
+ continue
+ }
+
+ r.WriteString(html.EscapeString(markdown[tokenStart:i]))
+ tokenStart = i
+ linkTextStart = i + 1
+ searchStart++
+ linkIsImage = true
}
}
}
diff --git a/Render_test.go b/Render_test.go
index db81fd4..c71d402 100644
--- a/Render_test.go
+++ b/Render_test.go
@@ -45,13 +45,22 @@ func TestStrike(t *testing.T) {
}
func TestLink(t *testing.T) {
- assert.Equal(t, markdown.Render("[text](https://example.com/)"), "
[text](https://example.com/
") - assert.Equal(t, markdown.Render("[text]https://example.com/)"), "[text]https://example.com/)
") - assert.Equal(t, markdown.Render("[text(https://example.com/)"), "[text(https://example.com/)
") - assert.Equal(t, markdown.Render("text](https://example.com/)"), "text](https://example.com/)
") - assert.Equal(t, markdown.Render("[text](https://example.com/_test_)"), "") - assert.Equal(t, markdown.Render("Prefix [text](https://example.com/) suffix."), "Prefix text suffix.
") + assert.Equal(t, markdown.Render("[text](https://example.com/)"), ``) + assert.Equal(t, markdown.Render("[text](https://example.com/"), `[text](https://example.com/
`) + assert.Equal(t, markdown.Render("[text]https://example.com/)"), `[text]https://example.com/)
`) + assert.Equal(t, markdown.Render("[text(https://example.com/)"), `[text(https://example.com/)
`) + assert.Equal(t, markdown.Render("text](https://example.com/)"), `text](https://example.com/)
`) + assert.Equal(t, markdown.Render("[text](https://example.com/_test_)"), ``) + assert.Equal(t, markdown.Render("Prefix [text](https://example.com/) suffix."), `Prefix text suffix.
`) +} + +func TestImage(t *testing.T) { + assert.Equal(t, markdown.Render("!"), `!
`) + assert.Equal(t, markdown.Render("!["), `![
`) + assert.Equal(t, markdown.Render("![]"), `![]
`) + assert.Equal(t, markdown.Render(", ` + assert.Equal(t, markdown.Render("![]()"), `Line 1.
") - assert.Equal(t, markdown.Render("# Header\nLine 1.\nLine 2.\nLine 3."), "Line 1. Line 2. Line 3.
") - assert.Equal(t, markdown.Render("# Header 1\nLine 1.\n# Header 2\nLine 2."), "Line 1.
Line 2.
") - assert.Equal(t, markdown.Render("# [Header Link](https://example.com/)"), "Text.
") - assert.Equal(t, markdown.Render("- Entry\n# Header"), "") - assert.Equal(t, markdown.Render("> **bold** and *italic* text."), "
- Entry
Header
") - assert.Equal(t, markdown.Render("> __bold__ and _italic_ text."), "bold and italic text.
") + assert.Equal(t, markdown.Render("# Header\n\nLine 1."), `bold and italic text.
Line 1.
`) + assert.Equal(t, markdown.Render("# Header\nLine 1.\nLine 2.\nLine 3."), `Line 1. Line 2. Line 3.
`) + assert.Equal(t, markdown.Render("# Header 1\nLine 1.\n# Header 2\nLine 2."), `Line 1.
Line 2.
`) + assert.Equal(t, markdown.Render("# [Header Link](https://example.com/)"), `Text.
`) + assert.Equal(t, markdown.Render("- Entry\n# Header"), ``) + assert.Equal(t, markdown.Render("> **bold** and *italic* text."), `
- Entry
Header
`) + assert.Equal(t, markdown.Render("> __bold__ and _italic_ text."), `bold and italic text.
`) } func TestSecurity(t *testing.T) { - assert.Equal(t, markdown.Render("[text](javascript:alert(\"xss\"))"), "") - assert.Equal(t, markdown.Render("[text](javAscRipt:alert(\"xss\"))"), "") - assert.Equal(t, markdown.Render("[text]( javascript:alert(\"xss\"))"), "") - assert.Equal(t, markdown.Render("[text]('javAscRipt:alert(\"xss\")')"), "") - assert.Equal(t, markdown.Render("[text](\">)"), "") - assert.Equal(t, markdown.Render("[]()"), "") + assert.Equal(t, markdown.Render(`[text](javascript:alert("xss"))`), ``) + assert.Equal(t, markdown.Render(`[text](javAscRipt:alert("xss"))`), ``) + assert.Equal(t, markdown.Render(`[text]( javascript:alert("xss"))`), ``) + assert.Equal(t, markdown.Render(`[text]('javAscRipt:alert("xss")')`), ``) + assert.Equal(t, markdown.Render(`[text](">)`), ``) + assert.Equal(t, markdown.Render(`[]()`), ``) }bold and italic text.