aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnhgelus Morhtuuzh <william@herges.fr>2025-12-13 18:09:40 +0100
committerAnhgelus Morhtuuzh <william@herges.fr>2025-12-13 18:09:48 +0100
commitaea07c141b3a2448ea367ad80ad5e12d04a78df7 (patch)
tree67031a6cfe4c5b42f9527410045f4d3793f32946
parentd695b39edf898e056a8de3724a020f15754fcea9 (diff)
refactor(markdown): use new dom package to create html
-rw-r--r--dom/css_class.go4
-rw-r--r--dom/html.go29
-rw-r--r--markdown/ast.go5
-rw-r--r--markdown/ast_code.go12
-rw-r--r--markdown/ast_external.go19
-rw-r--r--markdown/ast_external_test.go29
-rw-r--r--markdown/ast_heading.go (renamed from markdown/ast_header.go)9
-rw-r--r--markdown/ast_list.go13
-rw-r--r--markdown/ast_modifier.go4
-rw-r--r--markdown/ast_paragraph.go8
-rw-r--r--markdown/ast_paragraph_test.go9
-rw-r--r--markdown/ast_quote.go19
-rw-r--r--markdown/ast_test.go9
13 files changed, 89 insertions, 80 deletions
diff --git a/dom/css_class.go b/dom/css_class.go
index 633869e..998dd50 100644
--- a/dom/css_class.go
+++ b/dom/css_class.go
@@ -1,5 +1,7 @@
package dom
+import "strings"
+
type ClassList map[string]struct{}
func (cl ClassList) set(e Element) Element {
@@ -10,7 +12,7 @@ func (cl ClassList) set(e Element) Element {
for k := range cl {
classes += k + " "
}
- classes = classes[:len(cl)-1]
+ classes = strings.TrimSpace(classes)
return e.SetAttribute("class", classes)
}
diff --git a/dom/html.go b/dom/html.go
index 360a33b..a7dc434 100644
--- a/dom/html.go
+++ b/dom/html.go
@@ -2,7 +2,6 @@ package dom
import (
"fmt"
- "html"
"html/template"
)
@@ -25,12 +24,10 @@ type Element interface {
ClassList() ClassList
}
-type LiteralElement struct {
- Content string
-}
+type LiteralElement template.HTML
func (e LiteralElement) Render() template.HTML {
- return template.HTML(html.EscapeString(e.Content))
+ return template.HTML(e)
}
func (LiteralElement) HasAttribute(string) bool {
@@ -49,8 +46,8 @@ func (e LiteralElement) ClassList() ClassList {
return nil
}
-func NewLiteralElement(s string) LiteralElement {
- return LiteralElement{s}
+func NewLiteralElement(s template.HTML) LiteralElement {
+ return LiteralElement(s)
}
type VoidElement struct {
@@ -60,7 +57,7 @@ type VoidElement struct {
}
func (e VoidElement) Render() template.HTML {
- e = e.cl.set(e).(VoidElement)
+ e.cl.set(e)
return render(e.Tag, e.attributes, true)
}
@@ -88,7 +85,7 @@ func NewVoidElement(tag string) VoidElement {
}
func NewImg(src, alt string) Element {
- return NewVoidElement("img").SetAttribute("src", src).SetAttribute("alt", alt)
+ return NewVoidElement("img").SetAttribute("alt", alt).SetAttribute("src", src)
}
type ContentElement struct {
@@ -97,7 +94,7 @@ type ContentElement struct {
}
func (e ContentElement) Render() template.HTML {
- e = e.cl.set(e).(ContentElement)
+ e.cl.set(e)
base := render(e.Tag, e.attributes, false)
for _, el := range e.Contents {
base += el.Render()
@@ -109,6 +106,14 @@ func NewContentElement(tag string, contents []Element) ContentElement {
return ContentElement{NewVoidElement(tag), contents}
}
-func NewParagraph(content string) Element {
- return NewContentElement("p", []Element{NewLiteralElement(content)})
+func NewLiteralContentElement(tag string, content template.HTML) Element {
+ return NewContentElement(tag, []Element{NewLiteralElement(content)})
+}
+
+func NewParagraph(content template.HTML) Element {
+ return NewLiteralContentElement("p", content)
+}
+
+func NewHeading(level uint, content template.HTML) Element {
+ return NewLiteralContentElement(fmt.Sprintf("h%d", level), content)
}
diff --git a/markdown/ast.go b/markdown/ast.go
index 9c9816e..2e073ee 100644
--- a/markdown/ast.go
+++ b/markdown/ast.go
@@ -5,7 +5,6 @@ import (
"errors"
"fmt"
"html/template"
- "strings"
)
var ErrUnkownLexType = errors.New("unkown lex type")
@@ -107,7 +106,3 @@ func getBlock(lxs *lexers, newLine bool) (block, *ParseError) {
}
return b, err
}
-
-func trimSpace(s template.HTML) template.HTML {
- return template.HTML(strings.TrimSpace(string(s)))
-}
diff --git a/markdown/ast_code.go b/markdown/ast_code.go
index 6980f32..c83a984 100644
--- a/markdown/ast_code.go
+++ b/markdown/ast_code.go
@@ -2,8 +2,10 @@ package markdown
import (
"errors"
- "fmt"
+ "html"
"html/template"
+
+ "git.anhgelus.world/anhgelus/small-web/dom"
)
var (
@@ -26,11 +28,15 @@ type astCode struct {
}
func (a *astCode) Eval(_ *Option) (template.HTML, *ParseError) {
+ content := template.HTML(html.EscapeString(a.content))
switch a.codeType {
case codeOneLine:
- return template.HTML(fmt.Sprintf("<code>%s</code>", template.HTMLEscapeString(a.content))), nil
+ return dom.NewLiteralContentElement("code", content).Render(), nil
case codeMultiLine:
- return template.HTML(fmt.Sprintf("<pre><code>%s</code></pre>", template.HTMLEscapeString(a.content))), nil
+ pre := dom.NewContentElement("pre", make([]dom.Element, 1))
+ code := dom.NewContentElement("code", []dom.Element{dom.NewLiteralElement(content)})
+ pre.Contents[0] = code
+ return pre.Render(), nil
default:
return "", &ParseError{lxs: lexers{}, internal: ErrUnknownCodeType}
}
diff --git a/markdown/ast_external.go b/markdown/ast_external.go
index 8adeea1..4a1024a 100644
--- a/markdown/ast_external.go
+++ b/markdown/ast_external.go
@@ -1,9 +1,10 @@
package markdown
import (
- "fmt"
"html/template"
"regexp"
+
+ "git.anhgelus.world/anhgelus/small-web/dom"
)
var ExternalLink = regexp.MustCompile(`https?://`)
@@ -31,10 +32,12 @@ func (a *astLink) Eval(opt *Option) (template.HTML, *ParseError) {
}
func RenderLink(content, href string) template.HTML {
- if !ExternalLink.Match([]byte(href)) {
- return template.HTML(fmt.Sprintf(`<a href="%s">%s</a>`, href, content))
+ anchor := dom.NewLiteralContentElement("a", template.HTML(content))
+ anchor.SetAttribute("href", href)
+ if ExternalLink.MatchString(href) {
+ anchor.SetAttribute("target", "_blank").SetAttribute("rel", "noreferer")
}
- return template.HTML(fmt.Sprintf(`<a href="%s" target="_blank" rel="noreferer">%s</a>`, href, content))
+ return anchor.Render()
}
type astImage struct {
@@ -53,8 +56,10 @@ func (a *astImage) Eval(opt *Option) (template.HTML, *ParseError) {
return "", err
}
src = template.HTML(opt.ImageSource(string(src)))
+ img := dom.NewImg(string(src), string(alt))
+ figure := dom.NewContentElement("figure", []dom.Element{img})
if a.source == nil {
- return template.HTML(fmt.Sprintf(`<figure><img alt="%s" src="%s"></figure>`, alt, src)), nil
+ return figure.Render(), nil
}
var s template.HTML
for _, c := range a.source {
@@ -65,7 +70,9 @@ func (a *astImage) Eval(opt *Option) (template.HTML, *ParseError) {
s += ct + " "
}
s = s[:len(s)-1]
- return template.HTML(fmt.Sprintf(`<figure><img alt="%s" src="%s"><figcaption>%s</figcaption></figure>`, alt, src, s)), nil
+ figcaption := dom.NewLiteralContentElement("figcaption", s)
+ figure.Contents = append(figure.Contents, figcaption)
+ return figure.Render(), nil
}
func external(lxs *lexers) (block, *ParseError) {
diff --git a/markdown/ast_external_test.go b/markdown/ast_external_test.go
index 514cc89..c31c233 100644
--- a/markdown/ast_external_test.go
+++ b/markdown/ast_external_test.go
@@ -3,51 +3,34 @@ package markdown
import "testing"
func TestExternal(t *testing.T) {
- lxs := lex("[content](href)")
- tree, err := ast(lxs)
- if err != nil {
- t.Fatal(err)
- }
- got, err := tree.Eval(nil)
+ got, err := Parse("[content](href)", nil)
if err != nil {
t.Fatal(err)
}
if string(got) != `<p><a href="href">content</a></p>` {
t.Errorf("invalid value, got %s", got)
- t.Logf("lexer %s", lxs.String())
}
- lxs = lex("![image alt](image src)")
- tree, err = ast(lxs)
+ got, err = Parse("![image alt](image src)", nil)
if err != nil {
- t.Logf("lexer %s", lxs.String())
t.Fatal(err)
}
- got, err = tree.Eval(nil)
- if err != nil {
- t.Fatal(err)
- }
- if string(got) != `<figure><img alt="image alt" src="image src"></figure>` {
+ if string(got) != `<figure><img alt="image alt" src="image src" /></figure>` {
t.Errorf("invalid value, got %s", got)
}
- lxs = lex(`
+ got, err = Parse(`
Avant la source
![image alt](image src)
source 1
source 2
Hors de la source
-`)
- tree, err = ast(lxs)
- if err != nil {
- t.Fatal(err)
- }
- got, err = tree.Eval(nil)
+`, nil)
if err != nil {
t.Fatal(err)
}
- if string(got) != `<p>Avant la source</p><figure><img alt="image alt" src="image src"><figcaption>source 1 source 2</figcaption></figure><p>Hors de la source</p>` {
+ if string(got) != `<p>Avant la source</p><figure><img alt="image alt" src="image src" /><figcaption>source 1 source 2</figcaption></figure><p>Hors de la source</p>` {
t.Errorf("invalid value, got %s", got)
}
diff --git a/markdown/ast_header.go b/markdown/ast_heading.go
index 716a4a6..5ad7adb 100644
--- a/markdown/ast_header.go
+++ b/markdown/ast_heading.go
@@ -2,8 +2,10 @@ package markdown
import (
"errors"
- "fmt"
"html/template"
+ "strings"
+
+ "git.anhgelus.world/anhgelus/small-web/dom"
)
var ErrInvalidHeader = errors.New("invalid header")
@@ -22,7 +24,10 @@ func (a *astHeader) Eval(opt *Option) (template.HTML, *ParseError) {
if err != nil {
return "", err
}
- return template.HTML(fmt.Sprintf("<h%d>%s</h%d>", a.level, trimSpace(content), a.level)), nil
+ return dom.NewHeading(
+ a.level,
+ template.HTML(strings.TrimSpace(string(content))),
+ ).Render(), nil
}
func header(lxs *lexers) (*astHeader, *ParseError) {
diff --git a/markdown/ast_list.go b/markdown/ast_list.go
index b82df67..b07f013 100644
--- a/markdown/ast_list.go
+++ b/markdown/ast_list.go
@@ -1,9 +1,11 @@
package markdown
import (
- "fmt"
"html/template"
"regexp"
+ "strings"
+
+ "git.anhgelus.world/anhgelus/small-web/dom"
)
var regexOrdered = regexp.MustCompile(`\d+\.`)
@@ -21,15 +23,18 @@ type astList struct {
}
func (a *astList) Eval(opt *Option) (template.HTML, *ParseError) {
- var content template.HTML
+ list := dom.NewContentElement(string(a.tag), make([]dom.Element, 0))
for _, c := range a.content {
ct, err := c.Eval(opt)
if err != nil {
return "", err
}
- content += template.HTML(fmt.Sprintf("<li>%s</li>", trimSpace(ct)))
+ list.Contents = append(list.Contents, dom.NewLiteralContentElement(
+ "li",
+ template.HTML(strings.TrimSpace(string(ct))),
+ ))
}
- return template.HTML(fmt.Sprintf("<%s>%s</%s>", a.tag, content, a.tag)), nil
+ return list.Render(), nil
}
func list(lxs *lexers) (block, *ParseError) {
diff --git a/markdown/ast_modifier.go b/markdown/ast_modifier.go
index 909d25e..635fbc0 100644
--- a/markdown/ast_modifier.go
+++ b/markdown/ast_modifier.go
@@ -5,6 +5,8 @@ import (
"errors"
"fmt"
"html/template"
+
+ "git.anhgelus.world/anhgelus/small-web/dom"
)
var (
@@ -38,7 +40,7 @@ func (a *astModifier) Eval(opt *Option) (template.HTML, *ParseError) {
if a.super {
return content, nil
}
- return template.HTML(fmt.Sprintf("<%s>%s</%s>", a.tag, content, a.tag)), nil
+ return dom.NewLiteralContentElement(string(a.tag), content).Render(), nil
}
func (a *astModifier) String() string {
diff --git a/markdown/ast_paragraph.go b/markdown/ast_paragraph.go
index a6417e2..b945741 100644
--- a/markdown/ast_paragraph.go
+++ b/markdown/ast_paragraph.go
@@ -2,8 +2,10 @@ package markdown
import (
"errors"
- "fmt"
"html/template"
+ "strings"
+
+ "git.anhgelus.world/anhgelus/small-web/dom"
)
var (
@@ -27,7 +29,9 @@ func (a *astParagraph) Eval(opt *Option) (template.HTML, *ParseError) {
if a.oneLine {
return content, nil
}
- return template.HTML(fmt.Sprintf("<p>%s</p>", trimSpace(content))), nil
+ return dom.NewParagraph(
+ template.HTML(strings.TrimSpace(string(content))),
+ ).Render(), nil
}
func paragraph(lxs *lexers, oneLine bool) (*astParagraph, *ParseError) {
diff --git a/markdown/ast_paragraph_test.go b/markdown/ast_paragraph_test.go
index 9155a9b..46dd714 100644
--- a/markdown/ast_paragraph_test.go
+++ b/markdown/ast_paragraph_test.go
@@ -3,18 +3,11 @@ package markdown
import "testing"
func TestParagraph(t *testing.T) {
- content := "bonsoir"
- lxs := lex(content)
- tree, err := ast(lxs)
- if err != nil {
- t.Fatal(err)
- }
- c, err := tree.Eval(nil)
+ c, err := Parse("bonsoir", nil)
if err != nil {
t.Fatal(err)
}
if c != "<p>bonsoir</p>" {
t.Errorf("failed, got %s", c)
- t.Logf("lxs: %s\ntree: %s", lxs, tree)
}
}
diff --git a/markdown/ast_quote.go b/markdown/ast_quote.go
index fa3a878..96669c5 100644
--- a/markdown/ast_quote.go
+++ b/markdown/ast_quote.go
@@ -1,9 +1,10 @@
package markdown
import (
- "fmt"
"html/template"
"strings"
+
+ "git.anhgelus.world/anhgelus/small-web/dom"
)
type astQuote struct {
@@ -12,15 +13,18 @@ type astQuote struct {
}
func (a *astQuote) Eval(opt *Option) (template.HTML, *ParseError) {
- var quote template.HTML
+ var quoteContent template.HTML
for _, c := range a.quote {
ct, err := c.Eval(opt)
if err != nil {
return "", err
}
- quote += ct
+ quoteContent += ct
}
- quote = template.HTML(fmt.Sprintf("<blockquote>%s</blockquote>", trimSpace(quote)))
+ blockquote := dom.NewLiteralContentElement(
+ "blockquote",
+ template.HTML(strings.TrimSpace(string(quoteContent))),
+ )
var source template.HTML
for _, c := range a.source {
ct, err := c.Eval(opt)
@@ -30,10 +34,13 @@ func (a *astQuote) Eval(opt *Option) (template.HTML, *ParseError) {
source += ct
}
source = template.HTML(strings.TrimSpace(string(source)))
+ quote := dom.NewContentElement("div", make([]dom.Element, 0))
+ quote.ClassList().Add("quote")
+ quote.Contents = append(quote.Contents, blockquote)
if len(source) > 0 {
- return template.HTML(fmt.Sprintf(`<div class="quote">%s<p>%s</p></div>`, quote, source)), nil
+ quote.Contents = append(quote.Contents, dom.NewParagraph(source))
}
- return template.HTML(fmt.Sprintf(`<div class="quote">%s</div>`, quote)), nil
+ return quote.Render(), nil
}
func quote(lxs *lexers) (*astQuote, *ParseError) {
diff --git a/markdown/ast_test.go b/markdown/ast_test.go
index 45eb49d..8f701f4 100644
--- a/markdown/ast_test.go
+++ b/markdown/ast_test.go
@@ -40,18 +40,13 @@ var parsed = `
<ol><li>et maintenant</li><li>elle l&#39;est</li></ol>
<ul><li>hehe</li></ul>
<figure>
-<img alt="Ceci est ma pfp :3" src="https://cdn.anhgelus.world/pfp.jpg">
+<img alt="Ceci est ma pfp :3" src="https://cdn.anhgelus.world/pfp.jpg" />
<figcaption> <a href="https://now.anhgelus.world/" target="_blank" rel="noreferer">Ma pfp</a> hehe :D Elle est <b>magnifique</b>, n&#39;est-ce pas ?</figcaption>
</figure>
`
func TestAst(t *testing.T) {
- lxs := lex(raw)
- tree, err := ast(lxs)
- if err != nil {
- t.Fatal(err)
- }
- res, err := tree.Eval(nil)
+ res, err := Parse(raw, nil)
if err != nil {
t.Fatal(err)
}