// parse.go package main import ( "bytes" "fmt" "os" "path/filepath" "regexp" "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" ) // GetContentPath ensures the content is cached and returns the path to the cached file. func GetContentPath(file ContentFile) (string, error) { cachePath := GetCacheFilename(file.OriginalPath) // 1. Check Cache Freshness (if not in TestMode) if !TestMode { cacheInfo, errCache := os.Stat(cachePath) origInfo, errOrig := os.Stat(file.OriginalPath) if errCache == nil && errOrig == nil && cacheInfo.ModTime().After(origInfo.ModTime()) { return cachePath, nil } } // 2. Regenerate Content cacheMutex.Lock() defer cacheMutex.Unlock() if !TestMode { cacheInfo, errCache := os.Stat(cachePath) origInfo, errOrig := os.Stat(file.OriginalPath) if errCache == nil && errOrig == nil && cacheInfo.ModTime().After(origInfo.ModTime()) { return cachePath, nil } } // Read Raw File raw, err := ReadRaw(file.OriginalPath) if err != nil { return "", fmt.Errorf("failed to read file: %w", err) } var dataToWrite []byte if !file.IsMarkdown { dataToWrite = raw } else { // Configure Goldmark with the custom tag extension md := goldmark.New( goldmark.WithExtensions( extension.GFM, &frontmatter.Extender{}, templates.SidebarTag, // ||| -> templates.TopBanner, templates.Mathtext, ), goldmark.WithRendererOptions( html.WithUnsafe(), ), ) var buf bytes.Buffer ctx := parser.NewContext() if err := md.Convert(raw, &buf, parser.WithContext(ctx)); err != nil { return "", fmt.Errorf("failed to parse markdown: %w", err) } // Extract Frontmatter var meta templates.PageMetadata d := frontmatter.Get(ctx) if d != nil { if err := d.Decode(&meta); err != nil { fmt.Printf("Warning: failed to decode frontmatter for %s: %v\n", file.OriginalPath, err) } } if meta.Title == "" { base := filepath.Base(file.OriginalPath) meta.Title = strings.TrimSuffix(base, filepath.Ext(base)) } htmlContent := buf.String() // 3. Post-Process for Index (Dynamic Content Injection) if file.RoutePath == "/" { // Generate posts data 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, }) } } /** Add More Custom tags here. Add a customTag in tags.go as well, and the implementation in a template file. */ // ||| SideBar sidebarRegex := regexp.MustCompile(`(?s).*?`) if sidebarRegex.MatchString(htmlContent) { // Render the dynamic content latestPostsHTML := templates.RenderLatestPosts(posts) dirLink := templates.RenderDirectoryLink() // Wrap in