From aea07c141b3a2448ea367ad80ad5e12d04a78df7 Mon Sep 17 00:00:00 2001 From: Anhgelus Morhtuuzh Date: Sat, 13 Dec 2025 18:09:40 +0100 Subject: refactor(markdown): use new dom package to create html --- markdown/ast.go | 5 ----- markdown/ast_code.go | 12 +++++++++--- markdown/ast_external.go | 19 ++++++++++++------ markdown/ast_external_test.go | 29 ++++++---------------------- markdown/ast_header.go | 39 ------------------------------------- markdown/ast_heading.go | 44 ++++++++++++++++++++++++++++++++++++++++++ markdown/ast_list.go | 13 +++++++++---- markdown/ast_modifier.go | 4 +++- markdown/ast_paragraph.go | 8 ++++++-- markdown/ast_paragraph_test.go | 9 +-------- markdown/ast_quote.go | 19 ++++++++++++------ markdown/ast_test.go | 9 ++------- 12 files changed, 106 insertions(+), 104 deletions(-) delete mode 100644 markdown/ast_header.go create mode 100644 markdown/ast_heading.go (limited to 'markdown') 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("%s", template.HTMLEscapeString(a.content))), nil + return dom.NewLiteralContentElement("code", content).Render(), nil case codeMultiLine: - return template.HTML(fmt.Sprintf("
%s
", 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(`%s`, 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(`%s`, 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(`
%s
`, 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(`
%s
%s
`, 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) != `

content

` { 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) != `
image alt
` { + if string(got) != `
image alt
` { 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) != `

Avant la source

image alt
source 1 source 2

Hors de la source

` { + if string(got) != `

Avant la source

image alt
source 1 source 2

Hors de la source

` { t.Errorf("invalid value, got %s", got) } diff --git a/markdown/ast_header.go b/markdown/ast_header.go deleted file mode 100644 index 716a4a6..0000000 --- a/markdown/ast_header.go +++ /dev/null @@ -1,39 +0,0 @@ -package markdown - -import ( - "errors" - "fmt" - "html/template" -) - -var ErrInvalidHeader = errors.New("invalid header") - -type astHeader struct { - level uint - content *astParagraph -} - -func (a *astHeader) Eval(opt *Option) (template.HTML, *ParseError) { - if a.level > 6 { - return "", &ParseError{lxs: lexers{}, internal: ErrInvalidCodeFormat} - } - var content template.HTML - content, err := a.content.Eval(opt) - if err != nil { - return "", err - } - return template.HTML(fmt.Sprintf("%s", a.level, trimSpace(content), a.level)), nil -} - -func header(lxs *lexers) (*astHeader, *ParseError) { - b := &astHeader{level: uint(len(lxs.Current().Value))} - if !lxs.Next() { - return nil, &ParseError{lxs: *lxs, internal: ErrInvalidHeader} - } - var err *ParseError - b.content, err = paragraph(lxs, true) - if err != nil { - return nil, err - } - return b, nil -} diff --git a/markdown/ast_heading.go b/markdown/ast_heading.go new file mode 100644 index 0000000..5ad7adb --- /dev/null +++ b/markdown/ast_heading.go @@ -0,0 +1,44 @@ +package markdown + +import ( + "errors" + "html/template" + "strings" + + "git.anhgelus.world/anhgelus/small-web/dom" +) + +var ErrInvalidHeader = errors.New("invalid header") + +type astHeader struct { + level uint + content *astParagraph +} + +func (a *astHeader) Eval(opt *Option) (template.HTML, *ParseError) { + if a.level > 6 { + return "", &ParseError{lxs: lexers{}, internal: ErrInvalidCodeFormat} + } + var content template.HTML + content, err := a.content.Eval(opt) + if err != nil { + return "", err + } + return dom.NewHeading( + a.level, + template.HTML(strings.TrimSpace(string(content))), + ).Render(), nil +} + +func header(lxs *lexers) (*astHeader, *ParseError) { + b := &astHeader{level: uint(len(lxs.Current().Value))} + if !lxs.Next() { + return nil, &ParseError{lxs: *lxs, internal: ErrInvalidHeader} + } + var err *ParseError + b.content, err = paragraph(lxs, true) + if err != nil { + return nil, err + } + return b, nil +} 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("
  • %s
  • ", trimSpace(ct))) + list.Contents = append(list.Contents, dom.NewLiteralContentElement( + "li", + template.HTML(strings.TrimSpace(string(ct))), + )) } - return template.HTML(fmt.Sprintf("<%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", 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("

    %s

    ", 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 != "

    bonsoir

    " { 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("
    %s
    ", 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(`
    %s

    %s

    `, quote, source)), nil + quote.Contents = append(quote.Contents, dom.NewParagraph(source)) } - return template.HTML(fmt.Sprintf(`
    %s
    `, 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 = `
    1. et maintenant
    2. elle l'est
    -Ceci est ma pfp :3 +Ceci est ma pfp :3
    Ma pfp hehe :D Elle est magnifique, n'est-ce pas ?
    ` 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) } -- cgit v1.2.3 From 48311424ba2eaac254864c008b6d18e8510f827d Mon Sep 17 00:00:00 2001 From: Anhgelus Morhtuuzh Date: Sat, 13 Dec 2025 18:11:04 +0100 Subject: style(markdown): rename header into heading --- markdown/ast.go | 4 ++-- markdown/ast_heading.go | 8 ++++---- markdown/ast_modifier.go | 2 +- markdown/ast_paragraph.go | 2 +- markdown/lexer.go | 8 ++++---- 5 files changed, 12 insertions(+), 12 deletions(-) (limited to 'markdown') diff --git a/markdown/ast.go b/markdown/ast.go index 2e073ee..f409ccb 100644 --- a/markdown/ast.go +++ b/markdown/ast.go @@ -62,11 +62,11 @@ func getBlock(lxs *lexers, newLine bool) (block, *ParseError) { var b block var err *ParseError switch lxs.Current().Type { - case lexerHeader: + case lexerHeading: if !newLine { b, err = paragraph(lxs, false) } else { - b, err = header(lxs) + b, err = heading(lxs) } case lexerExternal: if newLine && lxs.Current().Value == "![" { diff --git a/markdown/ast_heading.go b/markdown/ast_heading.go index 5ad7adb..206ff94 100644 --- a/markdown/ast_heading.go +++ b/markdown/ast_heading.go @@ -10,12 +10,12 @@ import ( var ErrInvalidHeader = errors.New("invalid header") -type astHeader struct { +type astHeading struct { level uint content *astParagraph } -func (a *astHeader) Eval(opt *Option) (template.HTML, *ParseError) { +func (a *astHeading) Eval(opt *Option) (template.HTML, *ParseError) { if a.level > 6 { return "", &ParseError{lxs: lexers{}, internal: ErrInvalidCodeFormat} } @@ -30,8 +30,8 @@ func (a *astHeader) Eval(opt *Option) (template.HTML, *ParseError) { ).Render(), nil } -func header(lxs *lexers) (*astHeader, *ParseError) { - b := &astHeader{level: uint(len(lxs.Current().Value))} +func heading(lxs *lexers) (*astHeading, *ParseError) { + b := &astHeading{level: uint(len(lxs.Current().Value))} if !lxs.Next() { return nil, &ParseError{lxs: *lxs, internal: ErrInvalidHeader} } diff --git a/markdown/ast_modifier.go b/markdown/ast_modifier.go index 635fbc0..7672c0c 100644 --- a/markdown/ast_modifier.go +++ b/markdown/ast_modifier.go @@ -68,7 +68,7 @@ func modifier(lxs *lexers) (*astModifier, error) { var s string for lxs.Next() { switch lxs.Current().Type { - case lexerLiteral, lexerHeader, lexerList: + case lexerLiteral, lexerHeading, lexerList: s += lxs.Current().Value case lexerModifier: if mod.super && []rune(mod.symbols)[0] == []rune(lxs.Current().Value)[0] && diff --git a/markdown/ast_paragraph.go b/markdown/ast_paragraph.go index b945741..eddba0a 100644 --- a/markdown/ast_paragraph.go +++ b/markdown/ast_paragraph.go @@ -53,7 +53,7 @@ func paragraph(lxs *lexers, oneLine bool) (*astParagraph, *ParseError) { return tree, nil } tree.content = append(tree.content, astLiteral(lxs.Current().Value)) - case lexerLiteral, lexerHeader: + case lexerLiteral, lexerHeading: s := lxs.Current().Value // replace line break by space if n > 0 && len(tree.content) != 0 { diff --git a/markdown/lexer.go b/markdown/lexer.go index 30587e4..b68bbf9 100644 --- a/markdown/lexer.go +++ b/markdown/lexer.go @@ -14,9 +14,9 @@ const ( lexerCode lexerType = "code" - lexerHeader lexerType = "header" - lexerQuote lexerType = "quote" - lexerList lexerType = "list" + lexerHeading lexerType = "header" + lexerQuote lexerType = "quote" + lexerList lexerType = "list" lexerExternal lexerType = "external" @@ -115,7 +115,7 @@ func lex(s string) *lexers { fn(c, lexerBreak, nil) case '#': newLine = false - fn(c, lexerHeader, nil) + fn(c, lexerHeading, nil) case '>': newLine = false fn(c, lexerQuote, nil) -- cgit v1.2.3