A deployable markdown editor that connects with your self hosted files and lets you edit in a beautiful interface
at main 97 lines 2.5 kB view raw
1package markdown 2 3import ( 4 "bytes" 5 "fmt" 6 "strings" 7 8 "gopkg.in/yaml.v3" 9) 10 11// ParsedContent represents a markdown file with frontmatter 12type ParsedContent struct { 13 Frontmatter map[string]interface{} 14 Content string 15} 16 17// Parse extracts YAML frontmatter and markdown content from a file 18func Parse(input string) (*ParsedContent, error) { 19 // Check if the file starts with frontmatter delimiter 20 if !strings.HasPrefix(input, "---\n") && !strings.HasPrefix(input, "---\r\n") { 21 // No frontmatter, return entire content as markdown 22 return &ParsedContent{ 23 Frontmatter: make(map[string]interface{}), 24 Content: input, 25 }, nil 26 } 27 28 // Find the end of frontmatter 29 lines := strings.Split(input, "\n") 30 endIdx := -1 31 32 for i := 1; i < len(lines); i++ { 33 trimmed := strings.TrimSpace(lines[i]) 34 if trimmed == "---" { 35 endIdx = i 36 break 37 } 38 } 39 40 // If we didn't find the closing delimiter, treat as no frontmatter 41 if endIdx == -1 { 42 return &ParsedContent{ 43 Frontmatter: make(map[string]interface{}), 44 Content: input, 45 }, nil 46 } 47 48 // Extract frontmatter YAML (between the delimiters) 49 frontmatterLines := lines[1:endIdx] 50 frontmatterYAML := strings.Join(frontmatterLines, "\n") 51 52 // Parse YAML 53 var frontmatter map[string]interface{} 54 if err := yaml.Unmarshal([]byte(frontmatterYAML), &frontmatter); err != nil { 55 return nil, fmt.Errorf("failed to parse frontmatter YAML: %w", err) 56 } 57 58 // Extract content (everything after the closing delimiter) 59 contentLines := lines[endIdx+1:] 60 content := strings.Join(contentLines, "\n") 61 // Trim leading newline if present 62 content = strings.TrimPrefix(content, "\n") 63 64 return &ParsedContent{ 65 Frontmatter: frontmatter, 66 Content: content, 67 }, nil 68} 69 70// Serialize combines frontmatter and content back into a single string 71func Serialize(frontmatter map[string]interface{}, content string) (string, error) { 72 // If no frontmatter, return just the content 73 if len(frontmatter) == 0 { 74 return content, nil 75 } 76 77 // Marshal frontmatter to YAML 78 var buf bytes.Buffer 79 encoder := yaml.NewEncoder(&buf) 80 encoder.SetIndent(2) 81 82 if err := encoder.Encode(frontmatter); err != nil { 83 return "", fmt.Errorf("failed to marshal frontmatter: %w", err) 84 } 85 86 if err := encoder.Close(); err != nil { 87 return "", fmt.Errorf("failed to close encoder: %w", err) 88 } 89 90 // Combine with delimiters 91 yamlStr := buf.String() 92 // Remove trailing newline from YAML output 93 yamlStr = strings.TrimSuffix(yamlStr, "\n") 94 95 result := fmt.Sprintf("---\n%s\n---\n%s", yamlStr, content) 96 return result, nil 97}