mirror of
https://github.com/usememos/memos.git
synced 2025-06-05 22:09:59 +02:00
feat: add markdown service
This commit is contained in:
90
api/v2/markdown_service.go
Normal file
90
api/v2/markdown_service.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package v2
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/usememos/memos/plugin/gomark/ast"
|
||||
"github.com/usememos/memos/plugin/gomark/parser"
|
||||
"github.com/usememos/memos/plugin/gomark/parser/tokenizer"
|
||||
apiv2pb "github.com/usememos/memos/proto/gen/api/v2"
|
||||
)
|
||||
|
||||
func (*APIV2Service) ParseMarkdown(_ context.Context, request *apiv2pb.ParseMarkdownRequest) (*apiv2pb.ParseMarkdownResponse, error) {
|
||||
rawNodes, err := parser.Parse(tokenizer.Tokenize(request.Markdown))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to parse memo content")
|
||||
}
|
||||
nodes := convertFromASTNodes(rawNodes)
|
||||
return &apiv2pb.ParseMarkdownResponse{
|
||||
Nodes: nodes,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func convertFromASTNodes(rawNodes []ast.Node) []*apiv2pb.Node {
|
||||
nodes := []*apiv2pb.Node{}
|
||||
for _, rawNode := range rawNodes {
|
||||
node := convertFromASTNode(rawNode)
|
||||
nodes = append(nodes, node)
|
||||
}
|
||||
return nodes
|
||||
}
|
||||
|
||||
func convertFromASTNode(rawNode ast.Node) *apiv2pb.Node {
|
||||
node := &apiv2pb.Node{
|
||||
Type: apiv2pb.NodeType(rawNode.Type()),
|
||||
}
|
||||
|
||||
switch n := rawNode.(type) {
|
||||
case *ast.LineBreak:
|
||||
node.Node = &apiv2pb.Node_LineBreakNode{}
|
||||
case *ast.Paragraph:
|
||||
children := convertFromASTNodes(n.Children)
|
||||
node.Node = &apiv2pb.Node_ParagraphNode{ParagraphNode: &apiv2pb.ParagraphNode{Children: children}}
|
||||
case *ast.CodeBlock:
|
||||
node.Node = &apiv2pb.Node_CodeBlockNode{CodeBlockNode: &apiv2pb.CodeBlockNode{Language: n.Language, Content: n.Content}}
|
||||
case *ast.Heading:
|
||||
children := convertFromASTNodes(n.Children)
|
||||
node.Node = &apiv2pb.Node_HeadingNode{HeadingNode: &apiv2pb.HeadingNode{Level: int32(n.Level), Children: children}}
|
||||
case *ast.HorizontalRule:
|
||||
node.Node = &apiv2pb.Node_HorizontalRuleNode{HorizontalRuleNode: &apiv2pb.HorizontalRuleNode{Symbol: n.Symbol}}
|
||||
case *ast.Blockquote:
|
||||
children := convertFromASTNodes(n.Children)
|
||||
node.Node = &apiv2pb.Node_BlockquoteNode{BlockquoteNode: &apiv2pb.BlockquoteNode{Children: children}}
|
||||
case *ast.OrderedList:
|
||||
children := convertFromASTNodes(n.Children)
|
||||
node.Node = &apiv2pb.Node_OrderedListNode{OrderedListNode: &apiv2pb.OrderedListNode{Number: n.Number, Children: children}}
|
||||
case *ast.UnorderedList:
|
||||
children := convertFromASTNodes(n.Children)
|
||||
node.Node = &apiv2pb.Node_UnorderedListNode{UnorderedListNode: &apiv2pb.UnorderedListNode{Symbol: n.Symbol, Children: children}}
|
||||
case *ast.TaskList:
|
||||
children := convertFromASTNodes(n.Children)
|
||||
node.Node = &apiv2pb.Node_TaskListNode{TaskListNode: &apiv2pb.TaskListNode{Symbol: n.Symbol, Complete: n.Complete, Children: children}}
|
||||
case *ast.Text:
|
||||
node.Node = &apiv2pb.Node_TextNode{TextNode: &apiv2pb.TextNode{Content: n.Content}}
|
||||
case *ast.Bold:
|
||||
children := convertFromASTNodes(n.Children)
|
||||
node.Node = &apiv2pb.Node_BoldNode{BoldNode: &apiv2pb.BoldNode{Symbol: n.Symbol, Children: children}}
|
||||
case *ast.Italic:
|
||||
node.Node = &apiv2pb.Node_ItalicNode{ItalicNode: &apiv2pb.ItalicNode{Symbol: n.Symbol, Content: n.Content}}
|
||||
case *ast.BoldItalic:
|
||||
node.Node = &apiv2pb.Node_BoldItalicNode{BoldItalicNode: &apiv2pb.BoldItalicNode{Symbol: n.Symbol, Content: n.Content}}
|
||||
case *ast.Code:
|
||||
node.Node = &apiv2pb.Node_CodeNode{CodeNode: &apiv2pb.CodeNode{Content: n.Content}}
|
||||
case *ast.Image:
|
||||
node.Node = &apiv2pb.Node_ImageNode{ImageNode: &apiv2pb.ImageNode{AltText: n.AltText, Url: n.URL}}
|
||||
case *ast.Link:
|
||||
node.Node = &apiv2pb.Node_LinkNode{LinkNode: &apiv2pb.LinkNode{Text: n.Text, Url: n.URL}}
|
||||
case *ast.Tag:
|
||||
node.Node = &apiv2pb.Node_TagNode{TagNode: &apiv2pb.TagNode{Content: n.Content}}
|
||||
case *ast.Strikethrough:
|
||||
node.Node = &apiv2pb.Node_StrikethroughNode{StrikethroughNode: &apiv2pb.StrikethroughNode{Content: n.Content}}
|
||||
case *ast.EscapingCharacter:
|
||||
node.Node = &apiv2pb.Node_EscapingCharacterNode{EscapingCharacterNode: &apiv2pb.EscapingCharacterNode{Symbol: n.Symbol}}
|
||||
default:
|
||||
node.Node = &apiv2pb.Node_TextNode{TextNode: &apiv2pb.TextNode{}}
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
Reference in New Issue
Block a user