most basic html formatter
This commit is contained in:
parent
e098f4bcf7
commit
19966f0fc6
|
@ -0,0 +1,68 @@
|
||||||
|
package format
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"html"
|
||||||
|
|
||||||
|
"ewintr.nl/adoc"
|
||||||
|
"ewintr.nl/adoc/element"
|
||||||
|
"ewintr.nl/go-kit/slugify"
|
||||||
|
)
|
||||||
|
|
||||||
|
const pageTemplate = `<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>%s</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
%s</body>
|
||||||
|
</html>
|
||||||
|
`
|
||||||
|
|
||||||
|
func HTML(doc *adoc.ADoc) string {
|
||||||
|
return fmt.Sprintf(pageTemplate, html.EscapeString(doc.Title), HTMLFragment(doc.Content...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func HTMLFragment(els ...element.Element) string {
|
||||||
|
var html string
|
||||||
|
for _, el := range els {
|
||||||
|
html += htmlElement(el)
|
||||||
|
}
|
||||||
|
|
||||||
|
return html
|
||||||
|
}
|
||||||
|
|
||||||
|
func htmlElement(el element.Element) string {
|
||||||
|
switch v := el.(type) {
|
||||||
|
case element.SubTitle:
|
||||||
|
return fmt.Sprintf("<h2 id=%q>%s</h2>\n", slugify.Slugify(v.Text()), html.EscapeString(v.Text()))
|
||||||
|
case element.SubSubTitle:
|
||||||
|
return fmt.Sprintf("<h3 id=%q>%s</h3>\n", slugify.Slugify(v.Text()), html.EscapeString(v.Text()))
|
||||||
|
case element.List:
|
||||||
|
var items []element.Element
|
||||||
|
for _, i := range v {
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("<ul>\n%s</ul>\n", HTMLFragment(items...))
|
||||||
|
case element.ListItem:
|
||||||
|
return fmt.Sprintf("<li>%s</li>\n", HTMLFragment(v...))
|
||||||
|
case element.CodeBlock:
|
||||||
|
return fmt.Sprintf("<pre><code>%s</code></pre>", v.Text())
|
||||||
|
case element.Paragraph:
|
||||||
|
return fmt.Sprintf("<p>%s</p>\n", HTMLFragment(v.Elements...))
|
||||||
|
case element.Strong:
|
||||||
|
return fmt.Sprintf("<strong>%s</strong>", HTMLFragment(v...))
|
||||||
|
case element.Emphasis:
|
||||||
|
return fmt.Sprintf("<em>%s</em>", HTMLFragment(v...))
|
||||||
|
case element.Code:
|
||||||
|
return fmt.Sprintf("<code>%s</code>", HTMLFragment(v...))
|
||||||
|
case element.Link:
|
||||||
|
return fmt.Sprintf("<a href=%q>%s</a>", v.URL, html.EscapeString(v.Title))
|
||||||
|
case element.Word:
|
||||||
|
return html.EscapeString(v.Text())
|
||||||
|
case element.WhiteSpace:
|
||||||
|
return " "
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,166 @@
|
||||||
|
package format_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"ewintr.nl/adoc/element"
|
||||||
|
"ewintr.nl/adoc/format"
|
||||||
|
"ewintr.nl/adoc/parser"
|
||||||
|
"ewintr.nl/go-kit/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHTML(t *testing.T) {
|
||||||
|
input := `= A Title
|
||||||
|
|
||||||
|
Some document
|
||||||
|
|
||||||
|
With some text.`
|
||||||
|
|
||||||
|
exp := `<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>A Title</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>Some document</p>
|
||||||
|
<p>With some text.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`
|
||||||
|
doc := parser.New(strings.NewReader(input)).Parse()
|
||||||
|
test.Equals(t, exp, format.HTML(doc))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHTMLFragment(t *testing.T) {
|
||||||
|
for _, tc := range []struct {
|
||||||
|
name string
|
||||||
|
input element.Element
|
||||||
|
exp string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "whitespace",
|
||||||
|
input: element.WhiteSpace("\n"),
|
||||||
|
exp: " ",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "word",
|
||||||
|
input: element.Word("word"),
|
||||||
|
exp: "word",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "word with html",
|
||||||
|
input: element.Word("<h1>hi</h1>"),
|
||||||
|
exp: "<h1>hi</h1>",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pararaphs",
|
||||||
|
input: element.Paragraph{
|
||||||
|
Elements: []element.Element{
|
||||||
|
element.Word("a"),
|
||||||
|
element.WhiteSpace(" "),
|
||||||
|
element.Word("word"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
exp: "<p>a word</p>\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "strong",
|
||||||
|
input: element.Strong{
|
||||||
|
element.Word("something"),
|
||||||
|
element.WhiteSpace(" "),
|
||||||
|
element.Word("strong"),
|
||||||
|
},
|
||||||
|
exp: "<strong>something strong</strong>",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "nested",
|
||||||
|
input: element.Paragraph{
|
||||||
|
Elements: []element.Element{
|
||||||
|
element.Word("normal"),
|
||||||
|
element.WhiteSpace(" "),
|
||||||
|
element.Word("text"),
|
||||||
|
element.Strong{
|
||||||
|
element.WhiteSpace(" "),
|
||||||
|
element.Word("and"),
|
||||||
|
element.WhiteSpace(" "),
|
||||||
|
element.Word("strong"),
|
||||||
|
},
|
||||||
|
element.WhiteSpace(" "),
|
||||||
|
element.Word("too"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
exp: "<p>normal text<strong> and strong</strong> too</p>\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "emphasis",
|
||||||
|
input: element.Emphasis{
|
||||||
|
element.Word("yes"),
|
||||||
|
},
|
||||||
|
exp: "<em>yes</em>",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "code",
|
||||||
|
input: element.Code{
|
||||||
|
element.Word("simple"),
|
||||||
|
},
|
||||||
|
exp: "<code>simple</code>",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "link",
|
||||||
|
input: element.Link{
|
||||||
|
URL: "http://example.com",
|
||||||
|
Title: "an example",
|
||||||
|
},
|
||||||
|
exp: `<a href="http://example.com">an example</a>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "list",
|
||||||
|
input: element.List{
|
||||||
|
element.ListItem{
|
||||||
|
element.Word("item"),
|
||||||
|
element.WhiteSpace(" "),
|
||||||
|
element.Word("1"),
|
||||||
|
},
|
||||||
|
element.ListItem{
|
||||||
|
element.Word("item"),
|
||||||
|
element.WhiteSpace(" "),
|
||||||
|
element.Word("2"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
exp: `<ul>
|
||||||
|
<li>item 1</li>
|
||||||
|
<li>item 2</li>
|
||||||
|
</ul>
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "code block",
|
||||||
|
input: element.CodeBlock{
|
||||||
|
element.Word("some"),
|
||||||
|
element.WhiteSpace(" "),
|
||||||
|
element.Word("text"),
|
||||||
|
element.WhiteSpace("\n"),
|
||||||
|
element.Word("with"),
|
||||||
|
element.WhiteSpace("\t"),
|
||||||
|
element.Word("formatting"),
|
||||||
|
},
|
||||||
|
exp: `<pre><code>some text
|
||||||
|
with formatting</code></pre>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "subtitle",
|
||||||
|
input: element.SubTitle("a subtitle"),
|
||||||
|
exp: "<h2 id=\"a-subtitle\">a subtitle</h2>\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "subsubtitle",
|
||||||
|
input: element.SubSubTitle("a subsubtitle"),
|
||||||
|
exp: "<h3 id=\"a-subsubtitle\">a subsubtitle</h3>\n",
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
test.Equals(t, tc.exp, format.HTMLFragment(tc.input))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,14 +12,15 @@ import (
|
||||||
func TestText(t *testing.T) {
|
func TestText(t *testing.T) {
|
||||||
input := `= A Title
|
input := `= A Title
|
||||||
|
|
||||||
Some Document
|
Some document
|
||||||
|
|
||||||
|
With some text.`
|
||||||
|
|
||||||
With some text`
|
|
||||||
exp := `A Title
|
exp := `A Title
|
||||||
|
|
||||||
Some Document
|
Some document
|
||||||
|
|
||||||
With some text
|
With some text.
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue