diff options
Diffstat (limited to 'internal/processor/markdown.go')
| -rw-r--r-- | internal/processor/markdown.go | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/internal/processor/markdown.go b/internal/processor/markdown.go new file mode 100644 index 0000000..8d69bfe --- /dev/null +++ b/internal/processor/markdown.go @@ -0,0 +1,68 @@ +package processor + +import ( + "bytes" + "fmt" + "os" + "path/filepath" + "regexp" + "strings" + + "github.com/yuin/goldmark" + "github.com/yuin/goldmark/extension" + "github.com/yuin/goldmark/renderer/html" +) + +// imageRefPattern matches Markdown image syntax:  +// We use it to discover local asset references that must be copied. +var imageRefPattern = regexp.MustCompile(`!\[[^\]]*\]\(([^)]+)\)`) + +// processMd converts a Markdown file to an HTML snippet. +// Returns the HTML and a list of local image filenames referenced in the document. +// Referenced images that exist alongside the source file are returned so the +// caller can copy them into the post asset directory. +func processMd(path string) (htmlContent string, localImages []string, err error) { + data, err := os.ReadFile(path) + if err != nil { + return "", nil, fmt.Errorf("read markdown %s: %w", path, err) + } + + // Collect local image references so the caller can copy them as assets. + localImages = findLocalImages(string(data), filepath.Dir(path)) + + md := goldmark.New( + goldmark.WithExtensions(extension.GFM), + goldmark.WithRendererOptions( + html.WithUnsafe(), // Allow raw HTML in markdown (user-controlled content). + ), + ) + + var buf bytes.Buffer + if err := md.Convert(data, &buf); err != nil { + return "", nil, fmt.Errorf("convert markdown %s: %w", path, err) + } + + return buf.String(), localImages, nil +} + +// findLocalImages returns image filenames referenced in markdown that actually +// exist in sourceDir. Remote URLs (http/https) are ignored. +func findLocalImages(mdContent, sourceDir string) []string { + matches := imageRefPattern.FindAllStringSubmatch(mdContent, -1) + var locals []string + + for _, m := range matches { + ref := m[1] + // Skip remote URLs. + if strings.HasPrefix(ref, "http://") || strings.HasPrefix(ref, "https://") { + continue + } + + candidate := filepath.Join(sourceDir, ref) + if _, err := os.Stat(candidate); err == nil { + locals = append(locals, filepath.Base(ref)) + } + } + + return locals +} |
