112 lines
2.7 KiB
Go
112 lines
2.7 KiB
Go
package markdown
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"strings"
|
|
)
|
|
|
|
type jsonMark struct {
|
|
Type string `json:"type"`
|
|
Href string `json:"href,omitempty"`
|
|
}
|
|
|
|
type jsonText struct {
|
|
Type string `json:"type"`
|
|
Text string `json:"text"`
|
|
Marks []jsonMark `json:"marks"`
|
|
}
|
|
|
|
type jsonHeading struct {
|
|
Type string `json:"type"`
|
|
Level int `json:"level"`
|
|
Align string `json:"align,omitempty"`
|
|
Children []jsonText `json:"children"`
|
|
}
|
|
|
|
type jsonParagraph struct {
|
|
Type string `json:"type"`
|
|
Align string `json:"align,omitempty"`
|
|
Children []jsonText `json:"children"`
|
|
}
|
|
|
|
type jsonList struct {
|
|
Type string `json:"type"`
|
|
Ordered bool `json:"ordered"`
|
|
Items [][]any `json:"items"`
|
|
}
|
|
|
|
type jsonBlockquote struct {
|
|
Type string `json:"type"`
|
|
Children []any `json:"children"`
|
|
}
|
|
|
|
type jsonCode struct {
|
|
Type string `json:"type"`
|
|
Language string `json:"language"`
|
|
Text string `json:"text"`
|
|
}
|
|
|
|
type jsonRule struct {
|
|
Type string `json:"type"`
|
|
}
|
|
|
|
type jsonImage struct {
|
|
Type string `json:"type"`
|
|
Src string `json:"src"`
|
|
Alt string `json:"alt"`
|
|
}
|
|
|
|
func renderJSON(blocks []block) (string, error) {
|
|
var buffer bytes.Buffer
|
|
encoder := json.NewEncoder(&buffer)
|
|
encoder.SetEscapeHTML(false)
|
|
if err := encoder.Encode(toJSONBlocks(blocks)); err != nil {
|
|
return "", err
|
|
}
|
|
return strings.TrimSuffix(buffer.String(), "\n"), nil
|
|
}
|
|
|
|
func toJSONBlocks(blocks []block) []any {
|
|
result := make([]any, 0, len(blocks))
|
|
for _, b := range blocks {
|
|
result = append(result, toJSONBlock(b))
|
|
}
|
|
return result
|
|
}
|
|
|
|
func toJSONBlock(b block) any {
|
|
switch b.kind {
|
|
case kindHeading:
|
|
return jsonHeading{Type: "heading", Level: b.level, Align: b.align, Children: toJSONTexts(b.inlines)}
|
|
case kindParagraph:
|
|
return jsonParagraph{Type: "paragraph", Align: b.align, Children: toJSONTexts(b.inlines)}
|
|
case kindList:
|
|
items := make([][]any, 0, len(b.items))
|
|
for _, item := range b.items {
|
|
items = append(items, toJSONBlocks(item))
|
|
}
|
|
return jsonList{Type: "list", Ordered: b.ordered, Items: items}
|
|
case kindBlockquote:
|
|
return jsonBlockquote{Type: "blockquote", Children: toJSONBlocks(b.children)}
|
|
case kindCode:
|
|
return jsonCode{Type: "code", Language: b.language, Text: b.text}
|
|
case kindImage:
|
|
return jsonImage{Type: "image", Src: b.src, Alt: b.alt}
|
|
}
|
|
return jsonRule{Type: "hr"}
|
|
}
|
|
|
|
func toJSONTexts(inlines []inline) []jsonText {
|
|
plain := withoutCodeMarks(inlines)
|
|
texts := make([]jsonText, 0, len(plain))
|
|
for _, item := range plain {
|
|
marks := make([]jsonMark, 0, len(item.marks))
|
|
for _, m := range item.marks {
|
|
marks = append(marks, jsonMark{Type: m.kind, Href: m.href})
|
|
}
|
|
texts = append(texts, jsonText{Type: "text", Text: item.text, Marks: marks})
|
|
}
|
|
return texts
|
|
}
|