chore: rename renderer package

This commit is contained in:
Steven
2023-12-16 11:57:36 +08:00
parent e43a445c34
commit e8ca2ea5a0
8 changed files with 73 additions and 73 deletions

View File

@ -0,0 +1,208 @@
package html
import (
"bytes"
"fmt"
"github.com/usememos/memos/plugin/gomark/ast"
)
// HTMLRenderer is a simple renderer that converts AST to HTML.
type HTMLRenderer struct {
output *bytes.Buffer
context *RendererContext
}
type RendererContext struct {
}
// NewHTMLRenderer creates a new HTMLRender.
func NewHTMLRenderer() *HTMLRenderer {
return &HTMLRenderer{
output: new(bytes.Buffer),
context: &RendererContext{},
}
}
// RenderNode renders a single AST node to HTML.
func (r *HTMLRenderer) RenderNode(node ast.Node) {
switch n := node.(type) {
case *ast.LineBreak:
r.renderLineBreak(n)
case *ast.Paragraph:
r.renderParagraph(n)
case *ast.CodeBlock:
r.renderCodeBlock(n)
case *ast.Heading:
r.renderHeading(n)
case *ast.HorizontalRule:
r.renderHorizontalRule(n)
case *ast.Blockquote:
r.renderBlockquote(n)
case *ast.UnorderedList:
r.renderUnorderedList(n)
case *ast.OrderedList:
r.renderOrderedList(n)
case *ast.Bold:
r.renderBold(n)
case *ast.Italic:
r.renderItalic(n)
case *ast.BoldItalic:
r.renderBoldItalic(n)
case *ast.Code:
r.renderCode(n)
case *ast.Image:
r.renderImage(n)
case *ast.Link:
r.renderLink(n)
case *ast.Tag:
r.renderTag(n)
case *ast.Strikethrough:
r.renderStrikethrough(n)
case *ast.EscapingCharacter:
r.renderEscapingCharacter(n)
case *ast.Text:
r.renderText(n)
default:
// Handle other block types if needed.
}
}
// RenderNodes renders a slice of AST nodes to HTML.
func (r *HTMLRenderer) RenderNodes(nodes []ast.Node) {
for _, node := range nodes {
r.RenderNode(node)
}
}
// Render renders the AST to HTML.
func (r *HTMLRenderer) Render(astRoot []ast.Node) string {
r.RenderNodes(astRoot)
return r.output.String()
}
func (r *HTMLRenderer) renderLineBreak(_ *ast.LineBreak) {
r.output.WriteString("<br>")
}
func (r *HTMLRenderer) renderParagraph(node *ast.Paragraph) {
r.output.WriteString("<p>")
r.RenderNodes(node.Children)
r.output.WriteString("</p>")
}
func (r *HTMLRenderer) renderCodeBlock(node *ast.CodeBlock) {
r.output.WriteString("<pre><code>")
r.output.WriteString(node.Content)
r.output.WriteString("</code></pre>")
}
func (r *HTMLRenderer) renderHeading(node *ast.Heading) {
element := fmt.Sprintf("h%d", node.Level)
r.output.WriteString(fmt.Sprintf("<%s>", element))
r.RenderNodes(node.Children)
r.output.WriteString(fmt.Sprintf("</%s>", element))
}
func (r *HTMLRenderer) renderHorizontalRule(_ *ast.HorizontalRule) {
r.output.WriteString("<hr>")
}
func (r *HTMLRenderer) renderBlockquote(node *ast.Blockquote) {
prevSibling, nextSibling := node.PrevSibling(), node.NextSibling()
if prevSibling == nil || prevSibling.Type() != ast.BlockquoteNode {
r.output.WriteString("<blockquote>")
}
r.RenderNodes(node.Children)
if nextSibling == nil || nextSibling.Type() != ast.BlockquoteNode {
r.output.WriteString("</blockquote>")
}
}
func (r *HTMLRenderer) renderUnorderedList(node *ast.UnorderedList) {
prevSibling, nextSibling := node.PrevSibling(), node.NextSibling()
if prevSibling == nil || prevSibling.Type() != ast.UnorderedListNode {
r.output.WriteString("<ul>")
}
r.output.WriteString("<li>")
r.RenderNodes(node.Children)
r.output.WriteString("</li>")
if nextSibling == nil || nextSibling.Type() != ast.UnorderedListNode {
r.output.WriteString("</ul>")
}
}
func (r *HTMLRenderer) renderOrderedList(node *ast.OrderedList) {
prevSibling, nextSibling := node.PrevSibling(), node.NextSibling()
if prevSibling == nil || prevSibling.Type() != ast.OrderedListNode {
r.output.WriteString("<ol>")
}
r.output.WriteString("<li>")
r.RenderNodes(node.Children)
r.output.WriteString("</li>")
if nextSibling == nil || nextSibling.Type() != ast.OrderedListNode {
r.output.WriteString("</ol>")
}
}
func (r *HTMLRenderer) renderText(node *ast.Text) {
r.output.WriteString(node.Content)
}
func (r *HTMLRenderer) renderBold(node *ast.Bold) {
r.output.WriteString("<strong>")
r.RenderNodes(node.Children)
r.output.WriteString("</strong>")
}
func (r *HTMLRenderer) renderItalic(node *ast.Italic) {
r.output.WriteString("<em>")
r.output.WriteString(node.Content)
r.output.WriteString("</em>")
}
func (r *HTMLRenderer) renderBoldItalic(node *ast.BoldItalic) {
r.output.WriteString("<strong><em>")
r.output.WriteString(node.Content)
r.output.WriteString("</em></strong>")
}
func (r *HTMLRenderer) renderCode(node *ast.Code) {
r.output.WriteString("<code>")
r.output.WriteString(node.Content)
r.output.WriteString("</code>")
}
func (r *HTMLRenderer) renderImage(node *ast.Image) {
r.output.WriteString(`<img src="`)
r.output.WriteString(node.URL)
r.output.WriteString(`" alt="`)
r.output.WriteString(node.AltText)
r.output.WriteString(`" />`)
}
func (r *HTMLRenderer) renderLink(node *ast.Link) {
r.output.WriteString(`<a href="`)
r.output.WriteString(node.URL)
r.output.WriteString(`">`)
r.output.WriteString(node.Text)
r.output.WriteString("</a>")
}
func (r *HTMLRenderer) renderTag(node *ast.Tag) {
r.output.WriteString(`<span>`)
r.output.WriteString(`#`)
r.output.WriteString(node.Content)
r.output.WriteString(`</span>`)
}
func (r *HTMLRenderer) renderStrikethrough(node *ast.Strikethrough) {
r.output.WriteString(`<del>`)
r.output.WriteString(node.Content)
r.output.WriteString(`</del>`)
}
func (r *HTMLRenderer) renderEscapingCharacter(node *ast.EscapingCharacter) {
r.output.WriteString("\\")
r.output.WriteString(node.Symbol)
}

View File

@ -0,0 +1,66 @@
package html
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/usememos/memos/plugin/gomark/parser"
"github.com/usememos/memos/plugin/gomark/parser/tokenizer"
)
func TestHTMLRenderer(t *testing.T) {
tests := []struct {
text string
expected string
}{
{
text: "Hello world!",
expected: `<p>Hello world!</p>`,
},
{
text: "# Hello world!",
expected: `<h1>Hello world!</h1>`,
},
{
text: "> Hello\n> world!",
expected: `<blockquote><p>Hello</p><p>world!</p></blockquote>`,
},
{
text: "*Hello* world!",
expected: `<p><em>Hello</em> world!</p>`,
},
{
text: "Hello world!\n\nNew paragraph.",
expected: "<p>Hello world!</p><br><p>New paragraph.</p>",
},
{
text: "**Hello** world!",
expected: `<p><strong>Hello</strong> world!</p>`,
},
{
text: "#article #memo",
expected: `<p><span>#article</span> <span>#memo</span></p>`,
},
{
text: "#article \\#memo",
expected: `<p><span>#article</span> \#memo</p>`,
},
{
text: "* Hello\n* world!",
expected: `<ul><li>Hello</li><li>world!</li></ul>`,
},
{
text: "1. Hello\n2. world\n* !",
expected: `<ol><li>Hello</li><li>world</li></ol><ul><li>!</li></ul>`,
},
}
for _, test := range tests {
tokens := tokenizer.Tokenize(test.text)
nodes, err := parser.Parse(tokens)
require.NoError(t, err)
actual := NewHTMLRenderer().Render(nodes)
require.Equal(t, test.expected, actual)
}
}