Implemented image links
This commit is contained in:
parent
463c8b4a85
commit
809b89d689
@ -9,6 +9,7 @@ A markdown renderer that supports only a subset of the CommonMark spec in order
|
|||||||
- Italic
|
- Italic
|
||||||
- Links
|
- Links
|
||||||
- Lists
|
- Lists
|
||||||
|
- Images
|
||||||
- Headers
|
- Headers
|
||||||
- Paragraphs
|
- Paragraphs
|
||||||
- Quotes
|
- Quotes
|
||||||
@ -38,6 +39,7 @@ PASS: TestItalic
|
|||||||
PASS: TestBold
|
PASS: TestBold
|
||||||
PASS: TestStrike
|
PASS: TestStrike
|
||||||
PASS: TestLink
|
PASS: TestLink
|
||||||
|
PASS: TestImage
|
||||||
PASS: TestList
|
PASS: TestList
|
||||||
PASS: TestTables
|
PASS: TestTables
|
||||||
PASS: TestCode
|
PASS: TestCode
|
||||||
@ -51,9 +53,9 @@ coverage: 100.0% of statements
|
|||||||
## Benchmarks
|
## Benchmarks
|
||||||
|
|
||||||
```
|
```
|
||||||
BenchmarkSmall-12 5836533 205.3 ns/op 32 B/op 1 allocs/op
|
BenchmarkSmall-12 5884641 201.5 ns/op 32 B/op 1 allocs/op
|
||||||
BenchmarkMedium-12 967740 1103 ns/op 512 B/op 1 allocs/op
|
BenchmarkMedium-12 938371 1124 ns/op 512 B/op 1 allocs/op
|
||||||
BenchmarkLarge-12 277908 4099 ns/op 2560 B/op 2 allocs/op
|
BenchmarkLarge-12 277065 4115 ns/op 2560 B/op 2 allocs/op
|
||||||
```
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
32
Render.go
32
Render.go
@ -279,6 +279,7 @@ func (r *renderer) writeText(markdown string) {
|
|||||||
searchStart = 0
|
searchStart = 0
|
||||||
linkTextStart = -1
|
linkTextStart = -1
|
||||||
linkTextEnd = -1
|
linkTextEnd = -1
|
||||||
|
linkIsImage = false
|
||||||
emStart = -1
|
emStart = -1
|
||||||
strongStart = -1
|
strongStart = -1
|
||||||
strikeStart = -1
|
strikeStart = -1
|
||||||
@ -286,7 +287,7 @@ func (r *renderer) writeText(markdown string) {
|
|||||||
|
|
||||||
begin:
|
begin:
|
||||||
for {
|
for {
|
||||||
i := strings.IndexAny(markdown[searchStart:], "[]()`*_~")
|
i := strings.IndexAny(markdown[searchStart:], "[]()`*_~!")
|
||||||
|
|
||||||
if i == -1 {
|
if i == -1 {
|
||||||
r.WriteString(html.EscapeString(markdown[tokenStart:]))
|
r.WriteString(html.EscapeString(markdown[tokenStart:]))
|
||||||
@ -332,11 +333,19 @@ begin:
|
|||||||
linkText := markdown[linkTextStart+1 : linkTextEnd]
|
linkText := markdown[linkTextStart+1 : linkTextEnd]
|
||||||
linkURL := markdown[i+1 : urlEnd]
|
linkURL := markdown[i+1 : urlEnd]
|
||||||
|
|
||||||
r.WriteString("<a href=\"")
|
if linkIsImage {
|
||||||
r.WriteString(sanitizeURL(linkURL))
|
r.WriteString("<img src=\"")
|
||||||
r.WriteString("\">")
|
r.WriteString(sanitizeURL(linkURL))
|
||||||
r.WriteString(html.EscapeString(linkText))
|
r.WriteString("\" alt=\"")
|
||||||
r.WriteString("</a>")
|
r.WriteString(html.EscapeString(linkText))
|
||||||
|
r.WriteString("\">")
|
||||||
|
} else {
|
||||||
|
r.WriteString("<a href=\"")
|
||||||
|
r.WriteString(sanitizeURL(linkURL))
|
||||||
|
r.WriteString("\">")
|
||||||
|
r.WriteString(html.EscapeString(linkText))
|
||||||
|
r.WriteString("</a>")
|
||||||
|
}
|
||||||
|
|
||||||
linkTextStart = -1
|
linkTextStart = -1
|
||||||
linkTextEnd = -1
|
linkTextEnd = -1
|
||||||
@ -402,6 +411,17 @@ begin:
|
|||||||
tokenStart = i
|
tokenStart = i
|
||||||
strikeStart = i + 2
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,13 +45,22 @@ func TestStrike(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLink(t *testing.T) {
|
func TestLink(t *testing.T) {
|
||||||
assert.Equal(t, markdown.Render("[text](https://example.com/)"), "<p><a href=\"https://example.com/\">text</a></p>")
|
assert.Equal(t, markdown.Render("[text](https://example.com/)"), `<p><a href="https://example.com/">text</a></p>`)
|
||||||
assert.Equal(t, markdown.Render("[text](https://example.com/"), "<p>[text](https://example.com/</p>")
|
assert.Equal(t, markdown.Render("[text](https://example.com/"), `<p>[text](https://example.com/</p>`)
|
||||||
assert.Equal(t, markdown.Render("[text]https://example.com/)"), "<p>[text]https://example.com/)</p>")
|
assert.Equal(t, markdown.Render("[text]https://example.com/)"), `<p>[text]https://example.com/)</p>`)
|
||||||
assert.Equal(t, markdown.Render("[text(https://example.com/)"), "<p>[text(https://example.com/)</p>")
|
assert.Equal(t, markdown.Render("[text(https://example.com/)"), `<p>[text(https://example.com/)</p>`)
|
||||||
assert.Equal(t, markdown.Render("text](https://example.com/)"), "<p>text](https://example.com/)</p>")
|
assert.Equal(t, markdown.Render("text](https://example.com/)"), `<p>text](https://example.com/)</p>`)
|
||||||
assert.Equal(t, markdown.Render("[text](https://example.com/_test_)"), "<p><a href=\"https://example.com/_test_\">text</a></p>")
|
assert.Equal(t, markdown.Render("[text](https://example.com/_test_)"), `<p><a href="https://example.com/_test_">text</a></p>`)
|
||||||
assert.Equal(t, markdown.Render("Prefix [text](https://example.com/) suffix."), "<p>Prefix <a href=\"https://example.com/\">text</a> suffix.</p>")
|
assert.Equal(t, markdown.Render("Prefix [text](https://example.com/) suffix."), `<p>Prefix <a href="https://example.com/">text</a> suffix.</p>`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestImage(t *testing.T) {
|
||||||
|
assert.Equal(t, markdown.Render("!"), `<p>!</p>`)
|
||||||
|
assert.Equal(t, markdown.Render("!["), `<p>![</p>`)
|
||||||
|
assert.Equal(t, markdown.Render("![]"), `<p>![]</p>`)
|
||||||
|
assert.Equal(t, markdown.Render("![]("), `<p>![](</p>`)
|
||||||
|
assert.Equal(t, markdown.Render("![]()"), `<p><img src="" alt=""></p>`)
|
||||||
|
assert.Equal(t, markdown.Render("![title](https://example.com/image.png)"), `<p><img src="https://example.com/image.png" alt="title"></p>`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestList(t *testing.T) {
|
func TestList(t *testing.T) {
|
||||||
@ -97,22 +106,22 @@ func TestSeparator(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCombined(t *testing.T) {
|
func TestCombined(t *testing.T) {
|
||||||
assert.Equal(t, markdown.Render("# Header\n\nLine 1."), "<h1>Header</h1><p>Line 1.</p>")
|
assert.Equal(t, markdown.Render("# Header\n\nLine 1."), `<h1>Header</h1><p>Line 1.</p>`)
|
||||||
assert.Equal(t, markdown.Render("# Header\nLine 1.\nLine 2.\nLine 3."), "<h1>Header</h1><p>Line 1. Line 2. Line 3.</p>")
|
assert.Equal(t, markdown.Render("# Header\nLine 1.\nLine 2.\nLine 3."), `<h1>Header</h1><p>Line 1. Line 2. Line 3.</p>`)
|
||||||
assert.Equal(t, markdown.Render("# Header 1\nLine 1.\n# Header 2\nLine 2."), "<h1>Header 1</h1><p>Line 1.</p><h1>Header 2</h1><p>Line 2.</p>")
|
assert.Equal(t, markdown.Render("# Header 1\nLine 1.\n# Header 2\nLine 2."), `<h1>Header 1</h1><p>Line 1.</p><h1>Header 2</h1><p>Line 2.</p>`)
|
||||||
assert.Equal(t, markdown.Render("# [Header Link](https://example.com/)"), "<h1><a href=\"https://example.com/\">Header Link</a></h1>")
|
assert.Equal(t, markdown.Render("# [Header Link](https://example.com/)"), `<h1><a href="https://example.com/">Header Link</a></h1>`)
|
||||||
assert.Equal(t, markdown.Render("# Title\n\n- Entry 1\n- Entry 2\n\nText."), "<h1>Title</h1><ul><li>Entry 1</li><li>Entry 2</li></ul><p>Text.</p>")
|
assert.Equal(t, markdown.Render("# Title\n\n- Entry 1\n- Entry 2\n\nText."), `<h1>Title</h1><ul><li>Entry 1</li><li>Entry 2</li></ul><p>Text.</p>`)
|
||||||
assert.Equal(t, markdown.Render("- Entry\n# Header"), "<ul><li>Entry</li></ul><h1>Header</h1>")
|
assert.Equal(t, markdown.Render("- Entry\n# Header"), `<ul><li>Entry</li></ul><h1>Header</h1>`)
|
||||||
assert.Equal(t, markdown.Render("> - Entry\n> # Header"), "<blockquote><ul><li>Entry</li></ul><h1>Header</h1></blockquote>")
|
assert.Equal(t, markdown.Render("> - Entry\n> # Header"), `<blockquote><ul><li>Entry</li></ul><h1>Header</h1></blockquote>`)
|
||||||
assert.Equal(t, markdown.Render("> **bold** and *italic* text."), "<blockquote><p><strong>bold</strong> and <em>italic</em> text.</p></blockquote>")
|
assert.Equal(t, markdown.Render("> **bold** and *italic* text."), `<blockquote><p><strong>bold</strong> and <em>italic</em> text.</p></blockquote>`)
|
||||||
assert.Equal(t, markdown.Render("> __bold__ and _italic_ text."), "<blockquote><p><strong>bold</strong> and <em>italic</em> text.</p></blockquote>")
|
assert.Equal(t, markdown.Render("> __bold__ and _italic_ text."), `<blockquote><p><strong>bold</strong> and <em>italic</em> text.</p></blockquote>`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSecurity(t *testing.T) {
|
func TestSecurity(t *testing.T) {
|
||||||
assert.Equal(t, markdown.Render("[text](javascript:alert(\"xss\"))"), "<p><a href=\"\">text</a></p>")
|
assert.Equal(t, markdown.Render(`[text](javascript:alert("xss"))`), `<p><a href="">text</a></p>`)
|
||||||
assert.Equal(t, markdown.Render("[text](javAscRipt:alert(\"xss\"))"), "<p><a href=\"\">text</a></p>")
|
assert.Equal(t, markdown.Render(`[text](javAscRipt:alert("xss"))`), `<p><a href="">text</a></p>`)
|
||||||
assert.Equal(t, markdown.Render("[text]( javascript:alert(\"xss\"))"), "<p><a href=\"\">text</a></p>")
|
assert.Equal(t, markdown.Render(`[text]( javascript:alert("xss"))`), `<p><a href="">text</a></p>`)
|
||||||
assert.Equal(t, markdown.Render("[text]('javAscRipt:alert(\"xss\")')"), "<p><a href=\"'javAscRipt:alert("xss")'\">text</a></p>")
|
assert.Equal(t, markdown.Render(`[text]('javAscRipt:alert("xss")')`), `<p><a href="'javAscRipt:alert("xss")'">text</a></p>`)
|
||||||
assert.Equal(t, markdown.Render("[text](\"><script>alert(123)</script>)"), "<p><a href=\""><script>alert(123)</script>\">text</a></p>")
|
assert.Equal(t, markdown.Render(`[text]("><script>alert(123)</script>)`), `<p><a href=""><script>alert(123)</script>">text</a></p>`)
|
||||||
assert.Equal(t, markdown.Render("[<script>alert(123)</script>]()"), "<p><a href=\"\"><script>alert(123)</script></a></p>")
|
assert.Equal(t, markdown.Render(`[<script>alert(123)</script>]()`), `<p><a href=""><script>alert(123)</script></a></p>`)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user