diff --git a/render.go b/render.go index 2f9f185..0c4e5b6 100644 --- a/render.go +++ b/render.go @@ -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,118 +61,165 @@ 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) - if err != nil { - return "", fmt.Errorf("error while parsing %s: %s", block.Type, err.Error()) - } - - buf.WriteString("
") - buf.WriteString(col) - buf.WriteString(" | ") - } - buf.WriteString("
") - buf.WriteString(para.Text) - buf.WriteString("
") - 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("") - buf.WriteString(code.Code) - buf.WriteString("") - 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("
") - - buf.WriteString(``) - if item.Checked { - buf.WriteString(` `) - buf.WriteString(` `) - buf.WriteString(` `) - buf.WriteString(` `) - } - buf.WriteString(``) - buf.WriteString(item.Text) - buf.WriteString("
") - } - default: - return "", fmt.Errorf("unknown type: %s", block.Type) - } - - fmt.Fprintln(&buf) + err = document.Render(&buf) + if err != nil { + return "", err } - return buf.String(), nil } + +func (checklist *Checklist) Render(w io.Writer) error { + var buf bytes.Buffer + + buf.WriteString(`") + buf.WriteString(code.Code) + buf.WriteString("") + _, err := buf.WriteTo(w) + return err +} + +func (link *Link) Render(w io.Writer) error { + // TODO(peter): improve link rendering + _, err := fmt.Fprintf(w, `%s`, link.Link, link.Meta.Title) + return err +} + +func (table *Table) Render(w io.Writer) error { + var buf bytes.Buffer + buf.WriteString("
") + buf.WriteString(col) + buf.WriteString(" | ") + } + buf.WriteString("
") + buf.WriteString(para.Text) + buf.WriteString("
") + _, err := buf.WriteTo(w) + return err +}