// parse.go package main import ( "bytes" "fmt" "path/filepath" "strings" "git.else-if.org/jess/blog/templates" "github.com/yuin/goldmark" "github.com/yuin/goldmark/extension" "github.com/yuin/goldmark/parser" "github.com/yuin/goldmark/renderer/html" "go.abhg.dev/goldmark/frontmatter" ) // GetContent is the primary entry point for retrieving parsed content. func GetContent(file ContentFile) ([]byte, error) { // 1. Ask Cache if data, found := CheckCache(file.OriginalPath); found { return data, nil } // 2. Read Raw raw, err := ReadRaw(file.OriginalPath) if err != nil { return nil, fmt.Errorf("failed to read file: %w", err) } // If not markdown (e.g. css, images), return raw bytes immediately if !file.IsMarkdown { _ = StoreCache(file.OriginalPath, raw) return raw, nil } // 3. Configure Goldmark // We use the Extender pattern which is the standard way to add frontmatter support. // We also enable Unsafe mode to allow raw HTML tags (like ) to pass through // so we can replace them later. md := goldmark.New( goldmark.WithExtensions( extension.GFM, &frontmatter.Extender{}, ), goldmark.WithRendererOptions( html.WithUnsafe(), ), ) // 4. Parse Markdown var buf bytes.Buffer ctx := parser.NewContext() if err := md.Convert(raw, &buf, parser.WithContext(ctx)); err != nil { return nil, fmt.Errorf("failed to parse markdown: %w", err) } // 5. Extract Frontmatter // We retrieve the metadata using the context after parsing var meta templates.PageMetadata d := frontmatter.Get(ctx) if d != nil { if err := d.Decode(&meta); err != nil { // If decoding fails, we just proceed without metadata fmt.Printf("Warning: failed to decode frontmatter for %s: %v\n", file.OriginalPath, err) } } // If title is missing, try to grab the filename if meta.Title == "" { base := filepath.Base(file.OriginalPath) meta.Title = strings.TrimSuffix(base, filepath.Ext(base)) } // 6. Special Handling for Index (Dynamic Components) htmlContent := buf.String() if file.RoutePath == "/" { // Generate the list of posts var posts []templates.PostSnippet for _, f := range AllContent { if f.IsMarkdown && f.RoutePath != "/" { name := filepath.Base(f.OriginalPath) title := strings.TrimSuffix(name, filepath.Ext(name)) posts = append(posts, templates.PostSnippet{ Title: title, URL: f.RoutePath, Date: f.ModTime, }) } } latestPostsHTML := templates.RenderLatestPosts(posts) dirLink := templates.RenderDirectoryLink() // Replace custom tags if they exist in the markdown if strings.Contains(htmlContent, "") { htmlContent = strings.ReplaceAll(htmlContent, "", latestPostsHTML) } else { // Fallback: Append if not present htmlContent = htmlContent + "\n" + dirLink + "\n" + latestPostsHTML + "\n" + dirLink } // Handle site-headline if present // You can add Your Text in your markdown // For now, we just let it pass through as HTML, or you can add specific replacement logic here. } // 7. Build Full Page (HTML Shell) finalPage := templates.BuildFullPage([]byte(htmlContent), meta) // 8. Cache _ = StoreCache(file.OriginalPath, finalPage) return finalPage, nil }