Refactor renderer

This commit is contained in:
Peter Stuifzand 2019-08-25 15:40:56 +02:00
parent b7eaf1cc5c
commit eb3a072bcf

202
render.go
View File

@ -4,11 +4,18 @@ import (
"bytes"
"encoding/json"
"fmt"
"io"
)
type Renderer interface {
Render(w io.Writer) error
}
type Block struct {
Type string
Data json.RawMessage
renderer Renderer
}
type Paragraph struct {
@ -54,24 +61,116 @@ type Document struct {
Blocks []Block
}
func (block Block) getType() (Renderer, error) {
switch block.Type {
case "table":
return &Table{}, nil
case "link":
return &Link{}, nil
case "list":
return &List{}, nil
case "header":
return &Header{}, nil
case "paragraph":
return &Paragraph{}, nil
case "code":
return &Code{}, nil
case "checklist":
return &Checklist{}, nil
default:
return nil, fmt.Errorf("unknown type: %s", block.Type)
}
}
func (block Block) load() (Renderer, error) {
if block.renderer != nil {
return block.renderer, nil
}
renderer, err := block.getType()
if err != nil {
return nil, err
}
err = json.Unmarshal(block.Data, renderer)
if err != nil {
return nil, err
}
block.renderer = renderer
return renderer, nil
}
func (document *Document) Render(w io.Writer) error {
var buf bytes.Buffer
for _, block := range document.Blocks {
renderer, err := block.load()
if err != nil {
return err
}
if err = renderer.Render(&buf); err != nil {
return err
}
}
_, err := buf.WriteTo(w)
return err
}
func renderJSON(text string) (string, error) {
var data Document
err := json.Unmarshal([]byte(text), &data)
var document Document
err := json.Unmarshal([]byte(text), &document)
if err != nil {
return "", err
}
var buf bytes.Buffer
for _, block := range data.Blocks {
switch block.Type {
case "table":
var table Table
err = json.Unmarshal(block.Data, &table)
err = document.Render(&buf)
if err != nil {
return "", fmt.Errorf("error while parsing %s: %s", block.Type, err.Error())
return "", err
}
return buf.String(), nil
}
func (checklist *Checklist) Render(w io.Writer) error {
var buf bytes.Buffer
buf.WriteString(`<div class="checklist">`)
for _, item := range checklist.Items {
buf.WriteString(`<div class="checklist--item">`)
buf.WriteString(`<span class="icon is-medium">`)
if item.Checked {
buf.WriteString(`<i class="fa fa-check-circle has-text-success"></i>`)
}
buf.WriteString(`</span>`)
buf.WriteString(`<div class="checklist--item-text">`)
buf.WriteString(item.Text)
buf.WriteString("</div>")
buf.WriteString("</div>")
}
buf.WriteString("</div>")
_, err := buf.WriteTo(w)
return err
}
func (code *Code) Render(w io.Writer) error {
var buf bytes.Buffer
buf.WriteString("<pre>")
buf.WriteString(code.Code)
buf.WriteString("</pre>")
_, err := buf.WriteTo(w)
return err
}
func (link *Link) Render(w io.Writer) error {
// TODO(peter): improve link rendering
_, err := fmt.Fprintf(w, `<a href=%q>%s</a>`, link.Link, link.Meta.Title)
return err
}
func (table *Table) Render(w io.Writer) error {
var buf bytes.Buffer
buf.WriteString("<table class='table'>")
for _, row := range table.Content {
buf.WriteString("<tr>")
@ -83,21 +182,12 @@ func renderJSON(text string) (string, error) {
buf.WriteString("</tr>")
}
buf.WriteString("</table>")
break
case "link":
// TODO(peter): improve link rendering
var link Link
err = json.Unmarshal(block.Data, &link)
if err != nil {
return "", fmt.Errorf("error while parsing %s: %s", block.Type, err.Error())
}
fmt.Fprintf(&buf, `<a href=%q>%s</a>`, link.Link, link.Meta.Title)
case "list":
var list List
err = json.Unmarshal(block.Data, &list)
if err != nil {
return "", fmt.Errorf("error while parsing %s: %s", block.Type, err.Error())
}
_, err := buf.WriteTo(w)
return err
}
func (list *List) Render(w io.Writer) error {
var buf bytes.Buffer
var tag string
if list.Style == "ordered" {
tag = "ol"
@ -115,57 +205,21 @@ func renderJSON(text string) (string, error) {
buf.WriteString("</")
buf.WriteString(tag)
buf.WriteString(">")
case "header":
var header Header
err = json.Unmarshal(block.Data, &header)
if err != nil {
return "", fmt.Errorf("error while parsing %s: %s", block.Type, err.Error())
}
fmt.Fprintf(&buf, "<h%d>%s</h%d>", header.Level, header.Text, header.Level)
case "paragraph":
var para Paragraph
err = json.Unmarshal(block.Data, &para)
if err != nil {
return "", fmt.Errorf("error while parsing %s: %s", block.Type, err.Error())
}
_, err := buf.WriteTo(w)
return err
}
func (header *Header) Render(w io.Writer) error {
_, err := fmt.Fprintf(w, "<h%d>%s</h%d>", header.Level, header.Text, header.Level)
return err
}
func (para Paragraph) Render(w io.Writer) error {
var buf bytes.Buffer
buf.WriteString("<p>")
buf.WriteString(para.Text)
buf.WriteString("</p>")
case "code":
var code Code
err = json.Unmarshal(block.Data, &code)
if err != nil {
return "", fmt.Errorf("error while parsing %s: %s", block.Type, err.Error())
}
buf.WriteString("<pre>")
buf.WriteString(code.Code)
buf.WriteString("</pre>")
case "checklist":
var checklist Checklist
err = json.Unmarshal(block.Data, &checklist)
if err != nil {
return "", fmt.Errorf("error while parsing %s: %s", block.Type, err.Error())
}
for _, item := range checklist.Items {
buf.WriteString("<p>")
buf.WriteString(`<span class="icon is-medium">`)
if item.Checked {
buf.WriteString(` <span class="fa-stack">`)
buf.WriteString(` <i class="fa fa-circle fa-stack-2x has-text-success"></i>`)
buf.WriteString(` <i class="fa fa-check fa-stack-1x fa-inverse"></i>`)
buf.WriteString(` </span>`)
}
buf.WriteString(`</span>`)
buf.WriteString(item.Text)
buf.WriteString("</p>")
}
default:
return "", fmt.Errorf("unknown type: %s", block.Type)
}
fmt.Fprintln(&buf)
}
return buf.String(), nil
_, err := buf.WriteTo(w)
return err
}